• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

data-8 / datascience / 3812983299

pending completion
3812983299

Pull #553

github

GitHub
Merge 2c833a0ba into 8d3fb1e07
Pull Request #553: Add pythonic aliases for comparison predicates.

1269 of 1436 branches covered (88.37%)

24 of 24 new or added lines in 1 file covered. (100.0%)

2305 of 2507 relevant lines covered (91.94%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.12
/datascience/predicates.py
1
"""Predicate functions."""
2

3
import functools
1✔
4
import numbers
1✔
5
import numpy as np
1✔
6
import warnings
1✔
7
warnings.simplefilter('always', SyntaxWarning)
1✔
8

9
__all__ = ['are']
1✔
10

11

12
class are:
1✔
13
    """Predicate functions. The class is named "are" for calls to where.
14

15
    For example, given a table, predicates can be used to pick rows as follows.
16

17
    >>> from datascience import Table
18
    >>> t = Table().with_columns([
19
    ...    'Sizes', ['S', 'M', 'L', 'XL'],
20
    ...    'Waists', [30, 34, 38, 42],
21
    ... ])
22
    >>> t.where('Sizes',  are.equal_to('L'))
23
    Sizes | Waists
24
    L     | 38
25
    >>> t.where('Waists', are.above(38))
26
    Sizes | Waists
27
    XL    | 42
28
    >>> t.where('Waists', are.above_or_equal_to(38))
29
    Sizes | Waists
30
    L     | 38
31
    XL    | 42
32
    >>> t.where('Waists', are.below(38))
33
    Sizes | Waists
34
    S     | 30
35
    M     | 34
36
    >>> t.where('Waists', are.below_or_equal_to(38))
37
    Sizes | Waists
38
    S     | 30
39
    M     | 34
40
    L     | 38
41
    >>> t.where('Waists', are.strictly_between(30, 38))
42
    Sizes | Waists
43
    M     | 34
44
    >>> t.where('Waists', are.between(30, 38))
45
    Sizes | Waists
46
    S     | 30
47
    M     | 34
48
    >>> t.where('Waists', are.between_or_equal_to(30, 38))
49
    Sizes | Waists
50
    S     | 30
51
    M     | 34
52
    L     | 38
53
    >>> t.where('Sizes',  are.equal_to('L'))
54
    Sizes | Waists
55
    L     | 38
56
    >>> t.where('Waists', are.not_above(38))
57
    Sizes | Waists
58
    S     | 30
59
    M     | 34
60
    L     | 38
61
    >>> t.where('Waists', are.not_above_or_equal_to(38))
62
    Sizes | Waists
63
    S     | 30
64
    M     | 34
65
    >>> t.where('Waists', are.not_below(38))
66
    Sizes | Waists
67
    L     | 38
68
    XL    | 42
69
    >>> t.where('Waists', are.not_below_or_equal_to(38))
70
    Sizes | Waists
71
    XL    | 42
72
    >>> t.where('Waists', are.not_strictly_between(30, 38))
73
    Sizes | Waists
74
    S     | 30
75
    L     | 38
76
    XL    | 42
77
    >>> t.where('Waists', are.not_between(30, 38))
78
    Sizes | Waists
79
    L     | 38
80
    XL    | 42
81
    >>> t.where('Waists', are.not_between_or_equal_to(30, 38))
82
    Sizes | Waists
83
    XL    | 42
84
    >>> t.where('Sizes', are.containing('L'))
85
    Sizes | Waists
86
    L     | 38
87
    XL    | 42
88
    >>> t.where('Sizes', are.not_containing('L'))
89
    Sizes | Waists
90
    S     | 30
91
    M     | 34
92
    >>> t.where('Sizes', are.contained_in('MXL'))
93
    Sizes | Waists
94
    M     | 34
95
    L     | 38
96
    XL    | 42
97
    >>> t.where('Sizes', are.contained_in('L'))
98
    Sizes | Waists
99
    L     | 38
100
    >>> t.where('Sizes', are.not_contained_in('MXL'))
101
    Sizes | Waists
102
    S     | 30
103
    """
104

105
    @staticmethod
1✔
106
    def equal_to(y):
1✔
107
        """Equal to y."""
108
        check_iterable(y)
1✔
109
        return _combinable(lambda x: _equal_or_float_equal(x, y))
1✔
110

111
    @staticmethod
1✔
112
    def above(y):
1✔
113
        """Greater than y."""
114
        check_iterable(y)
1✔
115
        return _combinable(lambda x: x > y)
1✔
116

117
    @staticmethod
1✔
118
    def below(y):
1✔
119
        """Less than y."""
120
        check_iterable(y)
1✔
121
        return _combinable(lambda x: x < y)
1✔
122

123
    @staticmethod
1✔
124
    def above_or_equal_to(y):
1✔
125
        """Greater than or equal to y."""
126
        check_iterable(y)
1✔
127
        return _combinable(lambda x: x >= y or _equal_or_float_equal(x, y))
1✔
128

129
    @staticmethod
1✔
130
    def below_or_equal_to(y):
1✔
131
        """Less than or equal to y."""
132
        check_iterable(y)
1✔
133
        return _combinable(lambda x: x <= y or _equal_or_float_equal(x, y))
1✔
134

135
    @staticmethod
1✔
136
    def strictly_between(y, z):
1✔
137
        """Greater than y and less than z."""
138
        return _combinable(lambda x: y < x < z)
1✔
139

140
    @staticmethod
1✔
141
    def between(y, z):
1✔
142
        """Greater than or equal to y and less than z."""
143
        return _combinable(lambda x: (y <= x < z) or _equal_or_float_equal(x, y))
1✔
144

145
    @staticmethod
1✔
146
    def between_or_equal_to(y, z):
1✔
147
        """Greater than or equal to y and less than or equal to z."""
148
        return _combinable(lambda x: (y <= x <= z) or _equal_or_float_equal(x, y) or _equal_or_float_equal(x, z))
1✔
149

150
    @staticmethod
1✔
151
    def containing(substring):
1✔
152
        """A string that contains within it the given substring."""
153
        return _combinable(lambda x: substring in x)
1✔
154

155
    @staticmethod
1✔
156
    def contained_in(superstring):
1✔
157
        """A string that is part of the given superstring."""
158
        return _combinable(lambda x: x in superstring)
1✔
159

160
    @staticmethod
1✔
161
    def not_equal_to(y):
1✔
162
        """Is not equal to y"""
163
        check_iterable(y)
×
164
        return -(are.equal_to(y))
×
165
    
166
    @staticmethod
1✔
167
    def not_above(y):
1✔
168
        """Is not above y"""
169
        check_iterable(y)
1✔
170
        return are.below_or_equal_to(y)
1✔
171
    
172
    @staticmethod
1✔
173
    def not_below(y):
1✔
174
        """Is not below y"""
175
        check_iterable(y)
1✔
176
        return are.above_or_equal_to(y)
1✔
177
    
178
    @staticmethod
1✔
179
    def not_below_or_equal_to(y):
1✔
180
        """Is neither below y nor equal to y"""
181
        check_iterable(y)
1✔
182
        return are.above(y)
1✔
183
    
184
    @staticmethod
1✔
185
    def not_above_or_equal_to(y):
1✔
186
        """Is neither above y nor equal to y"""
187
        check_iterable(y)
1✔
188
        return are.below(y)
1✔
189
    
190
    @staticmethod
1✔
191
    def not_strictly_between(y, z):
1✔
192
        """Is equal to y or equal to z or less than y or greater than z"""
193
        return  -(are.strictly_between(y,z))
1✔
194
    
195
    @staticmethod
1✔
196
    def not_between(y, z):
1✔
197
        """Is equal to y or less than y or greater than z"""
198
        return -(are.between(y,z))
1✔
199
    
200
    @staticmethod
1✔
201
    def not_between_or_equal_to(y,z):
1✔
202
        """Is less than y or greater than z"""
203
        return -(are.between_or_equal_to(y,z))
1✔
204
    
205
    @staticmethod
1✔
206
    def not_containing(substring):
1✔
207
        """A string that does not contain substring""" 
208
        return -(are.containing(substring))
1✔
209
    
210
    @staticmethod
1✔
211
    def not_contained_in(superstring):
1✔
212
        """A string that is not contained within the superstring"""
213
        return -(are.contained_in(superstring))
1✔
214

215
    ###############
216
    #   Aliases   #
217
    ###############
218

219
    @staticmethod
1✔
220
    def less_than(y):
1✔
221
        """Less than y."""
222
        return are.below(y)
1✔
223

224
    @staticmethod
1✔
225
    def greater_than(y):
1✔
226
        """Greater than y."""
227
        return are.above(y)
1✔
228

229
    @staticmethod
1✔
230
    def greater_than_or_equal_to(y):
1✔
231
        return are.above_or_equal_to(y)
1✔
232

233
    @staticmethod
1✔
234
    def less_than_or_equal_to(y):
1✔
235
        return are.below_or_equal_to(y)
×
236

237
    @staticmethod
1✔
238
    def not_greater_than_or_equal_to(y):
1✔
239
        """Is neither above y nor equal to y"""
240
        return are.not_above_or_equal_to(y)
×
241
    
242
    @staticmethod
1✔
243
    def not_less_than_or_equal_to(y):
1✔
244
        """Is neither below y nor equal to y"""
245
        return are.not_below_or_equal_to(y)
1✔
246

247
    @staticmethod
1✔
248
    def not_greater_than(y):
1✔
249
        """Is not above y"""
250
        return are.not_above(y)
×
251
    
252
    @staticmethod
1✔
253
    def not_less_than(y):
1✔
254
        """Is not below y"""
255
        return are.not_below(y)
1✔
256

257
###############
258
# Combination #
259
###############
260

261
class _combinable:
1✔
262
    """A wrapper that allows one-arg predicate functions to be combined."""
263
    def __init__(self, f):
1✔
264
        self.f = f
1✔
265
        functools.update_wrapper(self, f)
1✔
266

267
    def __call__(self, x):
1✔
268
        return self.f(x)
1✔
269

270
    def __and__(self, other):
1✔
271
        return _combinable(lambda x: self.f(x) and other.f(x))
1✔
272

273
    def __or__(self, other):
1✔
274
        return _combinable(lambda x: self.f(x) or other.f(x))
1✔
275

276
    def __neg__(self):
1✔
277
        return _combinable(lambda x: not self.f(x))
1✔
278

279
    def __xor__(self, other):
1✔
280
        return (self & -other) | (-self & other)
×
281

282
############
283
# Negation #
284
############
285

286
def _not(f):
1✔
287
    return lambda *args: -f(*args)
×
288

289
def _equal_or_float_equal(x, y):
1✔
290
    if isinstance(x, numbers.Real):
1✔
291
        return x == y or np.nextafter(x, 1) == y or np.nextafter(x, 0) == y
1✔
292
    else:
293
        return x == y
1✔
294

295
############
296
# Utility #
297
############
298
def check_iterable(y):
1✔
299
    if isinstance(y, list) or isinstance(y, np.ndarray):
1✔
300
            warnings.warn("Do not pass an array or list to a predicate. \
301
                If you are trying to find rows where two columns are the \
302
                same, use table.where('c', are.equal_to, table.column('d'))\
303
                instead of table.where('c', are.equal_to(table.column('d'))).", 
304
                SyntaxWarning)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc