sdata 1.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sdata/__init__.py +140 -0
- sdata/base.py +684 -0
- sdata/contrib/__init__.py +0 -0
- sdata/contrib/piexif/__init__.py +12 -0
- sdata/contrib/piexif/_common.py +94 -0
- sdata/contrib/piexif/_dump.py +346 -0
- sdata/contrib/piexif/_exceptions.py +2 -0
- sdata/contrib/piexif/_exif.py +638 -0
- sdata/contrib/piexif/_insert.py +60 -0
- sdata/contrib/piexif/_load.py +270 -0
- sdata/contrib/piexif/_remove.py +56 -0
- sdata/contrib/piexif/_transplant.py +45 -0
- sdata/contrib/piexif/_webp.py +240 -0
- sdata/contrib/piexif/helper.py +66 -0
- sdata/contrib/ranger/__init__.py +8 -0
- sdata/contrib/ranger/collections/__init__.py +0 -0
- sdata/contrib/ranger/collections/rangebucketmap.py +346 -0
- sdata/contrib/ranger/collections/rangemap.py +396 -0
- sdata/contrib/ranger/collections/rangeset.py +483 -0
- sdata/contrib/ranger/range/__init__.py +0 -0
- sdata/contrib/ranger/range/cut.py +285 -0
- sdata/contrib/ranger/range/range.py +644 -0
- sdata/contrib/sobol_seq.py +394 -0
- sdata/contrib/sortedcontainers/LICENSE +13 -0
- sdata/contrib/sortedcontainers/__init__.py +74 -0
- sdata/contrib/sortedcontainers/sorteddict.py +789 -0
- sdata/contrib/sortedcontainers/sortedlist.py +2646 -0
- sdata/contrib/sortedcontainers/sortedset.py +733 -0
- sdata/contrib/sqlitedict.py +598 -0
- sdata/contrib/timeflake/__init__.py +40 -0
- sdata/contrib/timeflake/flake.py +69 -0
- sdata/contrib/timeflake/utils.py +47 -0
- sdata/deprecated/__init__.py +10 -0
- sdata/deprecated/data.py +1503 -0
- sdata/did/__init__.py +129 -0
- sdata/did/_http.py +67 -0
- sdata/did/base58btc.py +49 -0
- sdata/did/did_github.py +152 -0
- sdata/did/did_peer4.py +155 -0
- sdata/did/did_web.py +222 -0
- sdata/did/diddoc.py +75 -0
- sdata/did/ed25519.py +225 -0
- sdata/did/eddsa.py +107 -0
- sdata/did/errors.py +40 -0
- sdata/did/issue_vc.py +193 -0
- sdata/did/jose.py +126 -0
- sdata/did/keys.py +104 -0
- sdata/did/utils_didkey.py +161 -0
- sdata/did/verify_vp.py +158 -0
- sdata/doe.py +101 -0
- sdata/dtypes.py +510 -0
- sdata/experiments/__init__.py +331 -0
- sdata/experiments/blob0.py +131 -0
- sdata/experiments/file.py +42 -0
- sdata/experiments/filegroup.py +144 -0
- sdata/experiments/image_old.py +313 -0
- sdata/experiments/ks2.py +15 -0
- sdata/experiments/lapshear.py +8 -0
- sdata/experiments/material.py +7 -0
- sdata/experiments/parameters_deprecated.py +394 -0
- sdata/experiments/workbook.py +226 -0
- sdata/format.py +125 -0
- sdata/imagemeta.py +533 -0
- sdata/interactive.py +118 -0
- sdata/iolib/__init__.py +51 -0
- sdata/iolib/hashtree.py +264 -0
- sdata/iolib/json1sqlitestore.py +554 -0
- sdata/iolib/jsonsqlitestore.py +704 -0
- sdata/iolib/pud.py +242 -0
- sdata/iolib/reader.py +262 -0
- sdata/iolib/writer.py +419 -0
- sdata/metadata.py +882 -0
- sdata/parameter.py +414 -0
- sdata/schema.py +273 -0
- sdata/sclass/__init__.py +111 -0
- sdata/sclass/bfo_classes.py +362 -0
- sdata/sclass/blob.py +362 -0
- sdata/sclass/content.py +87 -0
- sdata/sclass/dataframe.py +1251 -0
- sdata/sclass/dataframegroup.py +187 -0
- sdata/sclass/dependency_graph.py +85 -0
- sdata/sclass/filereference.py +124 -0
- sdata/sclass/image.py +218 -0
- sdata/sclass/lazy_namespace.py +155 -0
- sdata/sclass/process.py +383 -0
- sdata/sclass/process_graph.py +221 -0
- sdata/sclass/zipfile.py +135 -0
- sdata/semantic.py +346 -0
- sdata/suuid.py +136 -0
- sdata/timestamp.py +336 -0
- sdata/tools.py +14 -0
- sdata/units.py +602 -0
- sdata/vocab.py +149 -0
- sdata-1.5.0.dist-info/METADATA +264 -0
- sdata-1.5.0.dist-info/RECORD +98 -0
- sdata-1.5.0.dist-info/WHEEL +5 -0
- sdata-1.5.0.dist-info/licenses/LICENSE-MIT +21 -0
- sdata-1.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,644 @@
|
|
|
1
|
+
from sdata.contrib.ranger.range.cut import Cut
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
class Range(object):
|
|
5
|
+
"""
|
|
6
|
+
Class used to represent a range along some 1-D domain. The range
|
|
7
|
+
is represented by 2 cutpoints can can be unbounded by specifying an
|
|
8
|
+
above_all or below_all Cut.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, lower_cut, upper_cut):
|
|
12
|
+
""" Instantiates a Range
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
lower_cut : Cut object
|
|
17
|
+
Specifies the lower cut for the range
|
|
18
|
+
upper_cut : Cut object
|
|
19
|
+
Specifies the upper cut for the range
|
|
20
|
+
|
|
21
|
+
Raises
|
|
22
|
+
------
|
|
23
|
+
ValueError
|
|
24
|
+
If bound(s) are not Cut objects or lower > upper
|
|
25
|
+
"""
|
|
26
|
+
if not all(map(lambda x: isinstance(x, Cut), (lower_cut, upper_cut))):
|
|
27
|
+
raise ValueError("Bounds must be Cut objects")
|
|
28
|
+
elif lower_cut > upper_cut:
|
|
29
|
+
raise ValueError("Lower bound cannot be greater than upper bound")
|
|
30
|
+
self.lower_cut = lower_cut
|
|
31
|
+
self.upper_cut = upper_cut
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def min(self):
|
|
35
|
+
return self.lower_cut.point
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def max(self):
|
|
39
|
+
return self.upper_cut.point
|
|
40
|
+
|
|
41
|
+
def mean(self):
|
|
42
|
+
return (self.lower_cut.point + self.upper_cut.point) / 2.
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def length(self):
|
|
46
|
+
return self.upper_cut.point - self.lower_cut.point
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def values(self):
|
|
50
|
+
return np.array((self.lower_cut.point, self.upper_cut.point))
|
|
51
|
+
|
|
52
|
+
def __repr__(self):
|
|
53
|
+
try:
|
|
54
|
+
return_str = '[' if self.is_lower_bound_closed() else '('
|
|
55
|
+
except TypeError:
|
|
56
|
+
return_str = '('
|
|
57
|
+
return_str += (str(self.lower_cut.point) if not self.lower_cut.below_all else '')
|
|
58
|
+
return_str += ' , '
|
|
59
|
+
return_str += (str(self.upper_cut.point) if not self.upper_cut.above_all else '')
|
|
60
|
+
try:
|
|
61
|
+
return_str += ']' if self.is_upper_bound_closed() else ')'
|
|
62
|
+
except TypeError:
|
|
63
|
+
return_str += ')'
|
|
64
|
+
return return_str
|
|
65
|
+
|
|
66
|
+
def __hash__(self):
|
|
67
|
+
return hash(self.lower_cut) * 31 + hash(self.upper_cut)
|
|
68
|
+
|
|
69
|
+
def __eq__(self, other):
|
|
70
|
+
if not isinstance(other, Range):
|
|
71
|
+
return False
|
|
72
|
+
else:
|
|
73
|
+
return ((self.lower_cut == other.lower_cut) and
|
|
74
|
+
(self.upper_cut == other.upper_cut))
|
|
75
|
+
|
|
76
|
+
def __ne__(self, other):
|
|
77
|
+
return not self.__eq__(other)
|
|
78
|
+
|
|
79
|
+
def contains(self, val):
|
|
80
|
+
""" Returns true if the range contains the value
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
val : Comparable object of the appropriate type for the range
|
|
85
|
+
Value to query whether in the range
|
|
86
|
+
|
|
87
|
+
Raises
|
|
88
|
+
------
|
|
89
|
+
ValueError
|
|
90
|
+
If the value type not compatible with cutpoint type
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
True if the range contains the value
|
|
95
|
+
"""
|
|
96
|
+
return (self.lower_cut < val and
|
|
97
|
+
self.upper_cut > val)
|
|
98
|
+
|
|
99
|
+
def contains_all(self, vals):
|
|
100
|
+
""" Returns True if the range contains all values in some
|
|
101
|
+
iterable
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
vals : Iterable of comparable object of appropriate type for range
|
|
106
|
+
Values to query against the range
|
|
107
|
+
|
|
108
|
+
Raises
|
|
109
|
+
------
|
|
110
|
+
ValueError
|
|
111
|
+
If there is a value type not compatible with the cutpoint type
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
True if the range contains all values
|
|
116
|
+
"""
|
|
117
|
+
for val in vals:
|
|
118
|
+
if not self.contains(val):
|
|
119
|
+
return False
|
|
120
|
+
return True
|
|
121
|
+
|
|
122
|
+
def get_distance_from_point(self, val, dist_func=lambda x1, x2: abs(x1 - x2)):
|
|
123
|
+
""" Returns the minimum distance of a Range from a Point, returning 0
|
|
124
|
+
if there is an overlap.
|
|
125
|
+
|
|
126
|
+
Note that both upper and lower bounds must be closed for this function
|
|
127
|
+
to work
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
val : comparable, compatible with cutpoint type
|
|
132
|
+
The value of the point where the distance is desired
|
|
133
|
+
dist_func : callable
|
|
134
|
+
Function that calculates the distance between two points in the
|
|
135
|
+
domain of the Range
|
|
136
|
+
|
|
137
|
+
Raises
|
|
138
|
+
------
|
|
139
|
+
TypeError
|
|
140
|
+
If the upper and/or lower bounds of this Range are not closed
|
|
141
|
+
or if the dist_func not compatible with the type
|
|
142
|
+
|
|
143
|
+
Returns
|
|
144
|
+
-------
|
|
145
|
+
The minimum distance between the Range and the Point. Returns 0
|
|
146
|
+
if there is an overlap
|
|
147
|
+
"""
|
|
148
|
+
if not all((self.is_lower_bound_closed(), self.is_upper_bound_closed())):
|
|
149
|
+
raise TypeError("Range is not closed")
|
|
150
|
+
if self.contains(val):
|
|
151
|
+
return 0.
|
|
152
|
+
else:
|
|
153
|
+
return min(dist_func(self.lower_cut.point, val),
|
|
154
|
+
dist_func(self.upper_cut.point, val))
|
|
155
|
+
|
|
156
|
+
def get_distance_from_range(self, other, dist_func=lambda x1, x2: abs(x1 - x2)):
|
|
157
|
+
""" Returns the minimum distance of a Range from another Range, returning
|
|
158
|
+
0 if there is any overlap
|
|
159
|
+
|
|
160
|
+
Note that both Ranges must be closed for this function to work
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
other : Range, compatible with this Range's domain
|
|
165
|
+
The Range to compare to
|
|
166
|
+
dist_func : callable
|
|
167
|
+
Function that calculates the distance between two points in the
|
|
168
|
+
domain of the Range
|
|
169
|
+
|
|
170
|
+
Raises
|
|
171
|
+
------
|
|
172
|
+
TypeError
|
|
173
|
+
If the upper and/or lower bounds of this Range are not closed
|
|
174
|
+
or if the dist_func not compatible with the type
|
|
175
|
+
|
|
176
|
+
Returns
|
|
177
|
+
-------
|
|
178
|
+
Minimum distance between the ranges
|
|
179
|
+
"""
|
|
180
|
+
if not isinstance(other, Range):
|
|
181
|
+
raise TypeError("other is not a Range")
|
|
182
|
+
if not all((self.is_lower_bound_closed(), self.is_upper_bound_closed(),
|
|
183
|
+
other.is_lower_bound_closed(), other.is_upper_bound_closed())):
|
|
184
|
+
raise TypeError("Not all Ranges closed")
|
|
185
|
+
if self.is_connected(other):
|
|
186
|
+
return 0.
|
|
187
|
+
else:
|
|
188
|
+
return min(dist_func(self.lower_cut.point, other.upper_cut.point),
|
|
189
|
+
dist_func(other.lower_cut.point, self.upper_cut.point))
|
|
190
|
+
|
|
191
|
+
def has_lower_bound(self):
|
|
192
|
+
""" Returns True if the range has a lower endpoint (not unbounded
|
|
193
|
+
at the lower end)
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
True if the range has a lower endpoint
|
|
198
|
+
"""
|
|
199
|
+
return not self.lower_cut.below_all
|
|
200
|
+
|
|
201
|
+
def has_upper_bound(self):
|
|
202
|
+
""" Returns True if the range has an upper endpoint (not unbounded
|
|
203
|
+
at the upper end)
|
|
204
|
+
|
|
205
|
+
Returns
|
|
206
|
+
-------
|
|
207
|
+
True if the range has an upper endpoint
|
|
208
|
+
"""
|
|
209
|
+
return not self.upper_cut.above_all
|
|
210
|
+
|
|
211
|
+
def lower_endpoint(self):
|
|
212
|
+
""" Returns the lower endpoint of the range if it exists. Otherwise
|
|
213
|
+
raises a TypeError
|
|
214
|
+
|
|
215
|
+
Raises
|
|
216
|
+
------
|
|
217
|
+
TypeError
|
|
218
|
+
If the range is unbounded below
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
The lower endpoint of the range
|
|
223
|
+
"""
|
|
224
|
+
if self.lower_cut.point is None:
|
|
225
|
+
raise TypeError("Range unbounded below")
|
|
226
|
+
else:
|
|
227
|
+
return self.lower_cut.point
|
|
228
|
+
|
|
229
|
+
def upper_endpoint(self):
|
|
230
|
+
""" Returns the upper endpoint of the range if it exists. Otherwise
|
|
231
|
+
raises a TypeError
|
|
232
|
+
|
|
233
|
+
Raises
|
|
234
|
+
------
|
|
235
|
+
TypeError
|
|
236
|
+
If the range is unbounded above
|
|
237
|
+
|
|
238
|
+
Returns
|
|
239
|
+
-------
|
|
240
|
+
The upper endpoint of the range
|
|
241
|
+
"""
|
|
242
|
+
if self.upper_cut.point is None:
|
|
243
|
+
raise TypeError("Range unbounded above")
|
|
244
|
+
else:
|
|
245
|
+
return self.upper_cut.point
|
|
246
|
+
|
|
247
|
+
def is_lower_bound_closed(self):
|
|
248
|
+
""" Returns whether the lower bound is closed (if there is a
|
|
249
|
+
lower bound)
|
|
250
|
+
|
|
251
|
+
Raises
|
|
252
|
+
------
|
|
253
|
+
TypeError
|
|
254
|
+
If the range is unbounded below
|
|
255
|
+
|
|
256
|
+
Returns
|
|
257
|
+
-------
|
|
258
|
+
True if the lower bound is closed
|
|
259
|
+
"""
|
|
260
|
+
if self.lower_cut.point is None:
|
|
261
|
+
raise TypeError("Range unbounded below")
|
|
262
|
+
else:
|
|
263
|
+
return self.lower_cut.below
|
|
264
|
+
|
|
265
|
+
def is_upper_bound_closed(self):
|
|
266
|
+
""" Returns whether the upper bound is closed (if there is an
|
|
267
|
+
upper bound)
|
|
268
|
+
|
|
269
|
+
Raises
|
|
270
|
+
------
|
|
271
|
+
TypeError
|
|
272
|
+
If the range is unbounded above
|
|
273
|
+
|
|
274
|
+
Returns
|
|
275
|
+
-------
|
|
276
|
+
True if the upper bound is closed
|
|
277
|
+
"""
|
|
278
|
+
if self.upper_cut.point is None:
|
|
279
|
+
raise TypeError("Range unbounded above")
|
|
280
|
+
else:
|
|
281
|
+
return not self.upper_cut.below
|
|
282
|
+
|
|
283
|
+
def is_empty(self):
|
|
284
|
+
""" Returns True if the range is of form [v, v) or (v, v]
|
|
285
|
+
|
|
286
|
+
Returns
|
|
287
|
+
-------
|
|
288
|
+
|
|
289
|
+
True if the range is of the form [v,v) or (v,v]
|
|
290
|
+
"""
|
|
291
|
+
return self.lower_cut == self.upper_cut
|
|
292
|
+
|
|
293
|
+
def encloses(self, other):
|
|
294
|
+
""" Returns True if the bounds of the other range do not extend
|
|
295
|
+
outside the bounds of this range
|
|
296
|
+
|
|
297
|
+
Examples:
|
|
298
|
+
[3,6] encloses [4,5]
|
|
299
|
+
(3,6) encloses (3,6)
|
|
300
|
+
[3,6] encloses [4,4]
|
|
301
|
+
(3,6] does not enclose [3,6]
|
|
302
|
+
[4,5] does not enclose (3,6)
|
|
303
|
+
|
|
304
|
+
Parameters
|
|
305
|
+
----------
|
|
306
|
+
other : A Range
|
|
307
|
+
The range to compare to
|
|
308
|
+
|
|
309
|
+
Raises
|
|
310
|
+
------
|
|
311
|
+
ValueError
|
|
312
|
+
If object passed in is not a Range
|
|
313
|
+
|
|
314
|
+
Returns
|
|
315
|
+
-------
|
|
316
|
+
True if the bounds of the other range do not extend outside
|
|
317
|
+
the bounds of this range
|
|
318
|
+
"""
|
|
319
|
+
if not isinstance(other, Range):
|
|
320
|
+
raise ValueError("Range required")
|
|
321
|
+
return ((self.lower_cut <= other.lower_cut) and
|
|
322
|
+
(self.upper_cut >= other.upper_cut))
|
|
323
|
+
|
|
324
|
+
def is_connected(self, other):
|
|
325
|
+
""" Returns True if there is a (possibly empty) range that is
|
|
326
|
+
enclosed by both this range and other
|
|
327
|
+
|
|
328
|
+
Examples:
|
|
329
|
+
[2,4] and [5,7] are not connected
|
|
330
|
+
[2,4] and [3,5] are connected
|
|
331
|
+
[2,4] and [4,6] are connected
|
|
332
|
+
[3,5] and (5,10) are connected
|
|
333
|
+
|
|
334
|
+
Parameters
|
|
335
|
+
----------
|
|
336
|
+
other : A range
|
|
337
|
+
The range to compare to
|
|
338
|
+
|
|
339
|
+
Raises
|
|
340
|
+
------
|
|
341
|
+
ValueError
|
|
342
|
+
If object passed in is not a Range
|
|
343
|
+
|
|
344
|
+
Returns
|
|
345
|
+
-------
|
|
346
|
+
True if there is a (possibly empty) range that is enclosed by
|
|
347
|
+
both this range and other
|
|
348
|
+
"""
|
|
349
|
+
if not isinstance(other, Range):
|
|
350
|
+
raise ValueError("Range required")
|
|
351
|
+
return ((self.lower_cut <= other.upper_cut) and
|
|
352
|
+
(other.lower_cut <= self.upper_cut))
|
|
353
|
+
|
|
354
|
+
def intersection(self, other):
|
|
355
|
+
""" Returns the maximal range enclosed by both this range and the
|
|
356
|
+
other range, if such a range exists
|
|
357
|
+
|
|
358
|
+
Examples:
|
|
359
|
+
Intersection of [1,5] and [3,7] is [3,5]
|
|
360
|
+
Intersection of [1,5] and [5,7] is [5,5]
|
|
361
|
+
|
|
362
|
+
Parameters
|
|
363
|
+
----------
|
|
364
|
+
other : A range
|
|
365
|
+
The range to compare to
|
|
366
|
+
|
|
367
|
+
Raises
|
|
368
|
+
------
|
|
369
|
+
ValueError
|
|
370
|
+
If object passed in is not a Range or if there is no intersection
|
|
371
|
+
|
|
372
|
+
Returns
|
|
373
|
+
-------
|
|
374
|
+
The intersection range
|
|
375
|
+
"""
|
|
376
|
+
if not isinstance(other, Range):
|
|
377
|
+
raise ValueError("Range required")
|
|
378
|
+
if (self.lower_cut >= other.lower_cut) and (self.upper_cut <= other.upper_cut):
|
|
379
|
+
return Range(self.lower_cut, self.upper_cut)
|
|
380
|
+
elif ((self.lower_cut <= other.lower_cut) and
|
|
381
|
+
(self.upper_cut >= other.upper_cut)):
|
|
382
|
+
return Range(other.lower_cut, other.upper_cut)
|
|
383
|
+
else:
|
|
384
|
+
new_lower = self.lower_cut if (self.lower_cut >= other.lower_cut) else other.lower_cut
|
|
385
|
+
new_upper = self.upper_cut if (self.upper_cut <= other.upper_cut) else other.upper_cut
|
|
386
|
+
return Range(new_lower, new_upper)
|
|
387
|
+
|
|
388
|
+
def span(self, other):
|
|
389
|
+
""" Returns the minimal range that encloses both this range and
|
|
390
|
+
the other. Note that if the input ranges are not connected, the span can
|
|
391
|
+
contain values that are not contained within either input range
|
|
392
|
+
|
|
393
|
+
Examples:
|
|
394
|
+
Span of [1,3] and [5,7] is [1,7]
|
|
395
|
+
|
|
396
|
+
Parameters
|
|
397
|
+
----------
|
|
398
|
+
other : A range
|
|
399
|
+
A range to span with
|
|
400
|
+
|
|
401
|
+
Raises
|
|
402
|
+
------
|
|
403
|
+
ValueError
|
|
404
|
+
If object passed in is not a Range or if there is no intersection
|
|
405
|
+
|
|
406
|
+
Returns
|
|
407
|
+
-------
|
|
408
|
+
The minimal range enclosing both with and the other range
|
|
409
|
+
"""
|
|
410
|
+
if ((self.lower_cut <= other.lower_cut) and (self.upper_cut >= other.upper_cut)):
|
|
411
|
+
return Range(self.lower_cut, self.upper_cut)
|
|
412
|
+
elif ((self.lower_cut >= other.lower_cut) and (self.upper_cut <= other.upper_cut)):
|
|
413
|
+
return Range(other.lower_cut, other.upper_cut)
|
|
414
|
+
else:
|
|
415
|
+
new_lower = self.lower_cut if (self.lower_cut <= other.lower_cut) else other.lower_cut
|
|
416
|
+
new_upper = self.upper_cut if (self.upper_cut >= other.upper_cut) else other.upper_cut
|
|
417
|
+
return Range(new_lower, new_upper)
|
|
418
|
+
|
|
419
|
+
##################
|
|
420
|
+
# Static methods #
|
|
421
|
+
##################
|
|
422
|
+
@staticmethod
|
|
423
|
+
def _validate_cutpoints(*pts):
|
|
424
|
+
if not all(map(lambda x: (hasattr(x, "__lt__") and hasattr(x, "__gt__")) or hasattr(x, '__cmp__'), pts)):
|
|
425
|
+
raise ValueError("Cutpoint type(s) not comparable")
|
|
426
|
+
if len(pts) == 2:
|
|
427
|
+
if not (issubclass(type(pts[0]), type(pts[1])) or issubclass(type(pts[1]), type(pts[0]))):
|
|
428
|
+
raise ValueError("Cutpoints are not compatible")
|
|
429
|
+
return True
|
|
430
|
+
|
|
431
|
+
@staticmethod
|
|
432
|
+
def _get_type(*pts):
|
|
433
|
+
if len(pts) == 1:
|
|
434
|
+
return type(pts[0])
|
|
435
|
+
elif len(pts) == 2:
|
|
436
|
+
if issubclass(type(pts[0]), type(pts[1])):
|
|
437
|
+
return type(pts[1])
|
|
438
|
+
elif issubclass(type(pts[1]), type(pts[0])):
|
|
439
|
+
return type(pts[0])
|
|
440
|
+
else:
|
|
441
|
+
raise ValueError("Cutpoints are not compatible")
|
|
442
|
+
|
|
443
|
+
@staticmethod
|
|
444
|
+
def closed(lower, upper):
|
|
445
|
+
""" Creates a range including the endpoints (i.e. [lower, upper])
|
|
446
|
+
|
|
447
|
+
Parameters
|
|
448
|
+
----------
|
|
449
|
+
lower : comparable, of same type as or subclass of upper type
|
|
450
|
+
The lower bound
|
|
451
|
+
upper : comparable, of same type as or subclass of lower type
|
|
452
|
+
The upper bound
|
|
453
|
+
|
|
454
|
+
Raises
|
|
455
|
+
------
|
|
456
|
+
ValueError
|
|
457
|
+
If type(s) are not comparable or compatible
|
|
458
|
+
|
|
459
|
+
Returns
|
|
460
|
+
-------
|
|
461
|
+
A Range object [lower, upper]
|
|
462
|
+
"""
|
|
463
|
+
# Ensure cutpoints are of compatible, appropriate types
|
|
464
|
+
Range._validate_cutpoints(lower, upper)
|
|
465
|
+
the_type = Range._get_type(lower, upper)
|
|
466
|
+
return Range(Cut.below_value(lower, the_type=the_type),
|
|
467
|
+
Cut.above_value(upper, the_type=the_type))
|
|
468
|
+
|
|
469
|
+
@staticmethod
|
|
470
|
+
def closed_open(lower, upper):
|
|
471
|
+
""" Creates a range including the lower endpoint (i.e. [lower, upper))
|
|
472
|
+
|
|
473
|
+
Parameters
|
|
474
|
+
----------
|
|
475
|
+
lower : comparable, of same type as or subclass of upper type
|
|
476
|
+
The lower bound
|
|
477
|
+
upper : comparable, of same type as or subclass of lower type
|
|
478
|
+
The upper bound
|
|
479
|
+
|
|
480
|
+
Raises
|
|
481
|
+
------
|
|
482
|
+
ValueError
|
|
483
|
+
If type(s) are not comparable or compatible
|
|
484
|
+
|
|
485
|
+
Returns
|
|
486
|
+
-------
|
|
487
|
+
A Range object [lower, upper)
|
|
488
|
+
"""
|
|
489
|
+
# Ensure cutpoints are of compatible, appropriate types
|
|
490
|
+
Range._validate_cutpoints(lower, upper)
|
|
491
|
+
the_type = Range._get_type(lower, upper)
|
|
492
|
+
return Range(Cut.below_value(lower, the_type=the_type),
|
|
493
|
+
Cut.below_value(upper, the_type=the_type))
|
|
494
|
+
|
|
495
|
+
@staticmethod
|
|
496
|
+
def open_closed(lower, upper):
|
|
497
|
+
""" Creates a range including the upper (i.e. (lower, upper])
|
|
498
|
+
|
|
499
|
+
Parameters
|
|
500
|
+
----------
|
|
501
|
+
lower : comparable, of same type as or subclass of upper type
|
|
502
|
+
The lower bound
|
|
503
|
+
upper : comparable, of same type as or subclass of lower type
|
|
504
|
+
The upper bound
|
|
505
|
+
|
|
506
|
+
Raises
|
|
507
|
+
------
|
|
508
|
+
ValueError
|
|
509
|
+
If type(s) are not comparable or compatible
|
|
510
|
+
|
|
511
|
+
Returns
|
|
512
|
+
-------
|
|
513
|
+
A Range object (lower, upper]
|
|
514
|
+
"""
|
|
515
|
+
# Ensure cutpoints are of compatible, appropriate types
|
|
516
|
+
Range._validate_cutpoints(lower, upper)
|
|
517
|
+
the_type = Range._get_type(lower, upper)
|
|
518
|
+
return Range(Cut.above_value(lower, the_type=the_type),
|
|
519
|
+
Cut.above_value(upper, the_type=the_type))
|
|
520
|
+
|
|
521
|
+
@staticmethod
|
|
522
|
+
def open(lower, upper):
|
|
523
|
+
""" Creates a range excluding the endpoints (i.e. (lower, upper))
|
|
524
|
+
|
|
525
|
+
Parameters
|
|
526
|
+
----------
|
|
527
|
+
lower : comparable, of same type as or subclass of upper type
|
|
528
|
+
The lower bound
|
|
529
|
+
upper : comparable, of same type as or subclass of lower type
|
|
530
|
+
The upper bound
|
|
531
|
+
|
|
532
|
+
Raises
|
|
533
|
+
------
|
|
534
|
+
ValueError
|
|
535
|
+
If type(s) are not comparable or compatible or if constructing
|
|
536
|
+
a range of type (v,v), which is invalid
|
|
537
|
+
|
|
538
|
+
Returns
|
|
539
|
+
-------
|
|
540
|
+
A Range object (lower, upper)
|
|
541
|
+
"""
|
|
542
|
+
# Ensure cutpoints are of compatible, appropriate types
|
|
543
|
+
Range._validate_cutpoints(lower, upper)
|
|
544
|
+
the_type = Range._get_type(lower, upper)
|
|
545
|
+
if lower == upper:
|
|
546
|
+
raise TypeError("Range of type (v,v) is not valid")
|
|
547
|
+
return Range(Cut.above_value(lower, the_type=the_type),
|
|
548
|
+
Cut.below_value(upper, the_type=the_type))
|
|
549
|
+
|
|
550
|
+
@staticmethod
|
|
551
|
+
def less_than(val):
|
|
552
|
+
""" Makes range including all values less than some value
|
|
553
|
+
(i.e. (-inf, val))
|
|
554
|
+
|
|
555
|
+
Parameters
|
|
556
|
+
----------
|
|
557
|
+
val : comparable
|
|
558
|
+
The upper bound
|
|
559
|
+
|
|
560
|
+
Raises
|
|
561
|
+
------
|
|
562
|
+
ValueError
|
|
563
|
+
If type not comparable
|
|
564
|
+
|
|
565
|
+
Returns
|
|
566
|
+
-------
|
|
567
|
+
A Range object (-inf, val)
|
|
568
|
+
"""
|
|
569
|
+
Range._validate_cutpoints(val)
|
|
570
|
+
the_type = Range._get_type(val)
|
|
571
|
+
return Range(Cut.below_all(the_type=the_type),
|
|
572
|
+
Cut.below_value(val, the_type=the_type))
|
|
573
|
+
|
|
574
|
+
@staticmethod
|
|
575
|
+
def at_most(val):
|
|
576
|
+
""" Makes range including all values less than or equal to
|
|
577
|
+
some value (i.e. (-inf, val])
|
|
578
|
+
|
|
579
|
+
Parameters
|
|
580
|
+
----------
|
|
581
|
+
val : comparable
|
|
582
|
+
The upper bound
|
|
583
|
+
|
|
584
|
+
Raises
|
|
585
|
+
------
|
|
586
|
+
ValueError
|
|
587
|
+
If type not comparable
|
|
588
|
+
|
|
589
|
+
Returns
|
|
590
|
+
-------
|
|
591
|
+
A Range object (-inf, val]
|
|
592
|
+
"""
|
|
593
|
+
Range._validate_cutpoints(val)
|
|
594
|
+
the_type = Range._get_type(val)
|
|
595
|
+
return Range(Cut.below_all(the_type=the_type),
|
|
596
|
+
Cut.above_value(val, the_type=the_type))
|
|
597
|
+
|
|
598
|
+
@staticmethod
|
|
599
|
+
def greater_than(val):
|
|
600
|
+
""" Makes range including all values greater than
|
|
601
|
+
some value (i.e. (val, inf])
|
|
602
|
+
|
|
603
|
+
Parameters
|
|
604
|
+
----------
|
|
605
|
+
val : comparable
|
|
606
|
+
The lower bound
|
|
607
|
+
|
|
608
|
+
Raises
|
|
609
|
+
------
|
|
610
|
+
ValueError
|
|
611
|
+
If type not comparable
|
|
612
|
+
|
|
613
|
+
Returns
|
|
614
|
+
-------
|
|
615
|
+
A Range object (val, inf)
|
|
616
|
+
"""
|
|
617
|
+
Range._validate_cutpoints(val)
|
|
618
|
+
the_type = Range._get_type(val)
|
|
619
|
+
return Range(Cut.above_value(val, the_type=the_type),
|
|
620
|
+
Cut.above_all(the_type=the_type))
|
|
621
|
+
|
|
622
|
+
@staticmethod
|
|
623
|
+
def at_least(val):
|
|
624
|
+
""" Makes range including all values greater than or equal to
|
|
625
|
+
some value (i.e. [val, inf))
|
|
626
|
+
|
|
627
|
+
Parameters
|
|
628
|
+
----------
|
|
629
|
+
val : comparable
|
|
630
|
+
The lower bound
|
|
631
|
+
|
|
632
|
+
Raises
|
|
633
|
+
------
|
|
634
|
+
ValueError
|
|
635
|
+
If type not comparable
|
|
636
|
+
|
|
637
|
+
Returns
|
|
638
|
+
-------
|
|
639
|
+
A Range object [val, inf)
|
|
640
|
+
"""
|
|
641
|
+
Range._validate_cutpoints(val)
|
|
642
|
+
the_type = Range._get_type(val)
|
|
643
|
+
return Range(Cut.below_value(val, the_type=the_type),
|
|
644
|
+
Cut.above_all(the_type=the_type))
|