datatypes 0.12.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.
- datatypes/__init__.py +153 -0
- datatypes/collections/__init__.py +22 -0
- datatypes/collections/container.py +150 -0
- datatypes/collections/mapping.py +614 -0
- datatypes/collections/sequence.py +469 -0
- datatypes/command.py +572 -0
- datatypes/compat.py +205 -0
- datatypes/config/__init__.py +9 -0
- datatypes/config/environ.py +302 -0
- datatypes/config/parser.py +255 -0
- datatypes/copy.py +151 -0
- datatypes/csv.py +322 -0
- datatypes/datetime.py +888 -0
- datatypes/decorators/__init__.py +23 -0
- datatypes/decorators/base.py +343 -0
- datatypes/decorators/descriptor.py +389 -0
- datatypes/decorators/misc.py +118 -0
- datatypes/email.py +351 -0
- datatypes/enum.py +191 -0
- datatypes/event.py +207 -0
- datatypes/filetypes/__init__.py +12 -0
- datatypes/filetypes/html.py +556 -0
- datatypes/filetypes/toml.py +260 -0
- datatypes/http.py +723 -0
- datatypes/logging.py +384 -0
- datatypes/number.py +187 -0
- datatypes/parse.py +246 -0
- datatypes/path.py +3637 -0
- datatypes/profile.py +232 -0
- datatypes/reflection.py +1498 -0
- datatypes/server.py +408 -0
- datatypes/service.py +212 -0
- datatypes/string.py +1328 -0
- datatypes/token/__init__.py +16 -0
- datatypes/token/abnf.py +1704 -0
- datatypes/token/base.py +475 -0
- datatypes/token/word.py +259 -0
- datatypes/url.py +841 -0
- datatypes/utils.py +142 -0
- datatypes-0.12.0.dist-info/LICENSE.txt +21 -0
- datatypes-0.12.0.dist-info/METADATA +52 -0
- datatypes-0.12.0.dist-info/RECORD +44 -0
- datatypes-0.12.0.dist-info/WHEEL +5 -0
- datatypes-0.12.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
List like objects
|
|
4
|
+
|
|
5
|
+
https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence
|
|
6
|
+
"""
|
|
7
|
+
import heapq
|
|
8
|
+
import itertools
|
|
9
|
+
import bisect
|
|
10
|
+
|
|
11
|
+
from ..compat import *
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PriorityQueue(object):
|
|
15
|
+
"""A generic priority queue
|
|
16
|
+
|
|
17
|
+
if passing in a tuple (priority, value) then...
|
|
18
|
+
|
|
19
|
+
* MinQueue: priority=lambda x: x[0]
|
|
20
|
+
* MaxQueue: priority=lambda x: -x[0]
|
|
21
|
+
|
|
22
|
+
Inspiration:
|
|
23
|
+
|
|
24
|
+
* https://stackoverflow.com/a/3311765/5006
|
|
25
|
+
* https://docs.python.org/2/library/heapq.html#priority-queue-implementation-notes
|
|
26
|
+
|
|
27
|
+
https://en.wikipedia.org/wiki/Priority_queue
|
|
28
|
+
|
|
29
|
+
:Example:
|
|
30
|
+
# MinQueue example
|
|
31
|
+
pq = PriorityQueue(priority=lambda x: x[0])
|
|
32
|
+
pq.put((30, "che"))
|
|
33
|
+
pq.put((1, "foo"))
|
|
34
|
+
pq.put((4, "bar"))
|
|
35
|
+
pq.get() # (1, "foo")
|
|
36
|
+
|
|
37
|
+
This uses .put() and .get() because that is the same interface as Python's built-in
|
|
38
|
+
queue class.
|
|
39
|
+
|
|
40
|
+
If you never pass in priorities it defaults to a FIFO queue, this allows you
|
|
41
|
+
to pass in keys to .put() to set uniqueness and move items back to the top of
|
|
42
|
+
the queue if they have the same key, another name for this might be RefreshQueue
|
|
43
|
+
since a value with the same key will move to the bottom of the queue
|
|
44
|
+
"""
|
|
45
|
+
def __init__(self, maxsize=0, key=None, priority=None):
|
|
46
|
+
"""create an instance
|
|
47
|
+
|
|
48
|
+
:param maxsize: int, the size you want the key to be, 0 for unlimited
|
|
49
|
+
:param key: callable, a callback that will be passed value on every
|
|
50
|
+
call to .put() that doesn't have a key passed in
|
|
51
|
+
:param priority: callable, a callback that will be passed value on every
|
|
52
|
+
call to .put() that doesn't have a priority passed in
|
|
53
|
+
"""
|
|
54
|
+
self.clear()
|
|
55
|
+
|
|
56
|
+
self.maxsize = maxsize
|
|
57
|
+
|
|
58
|
+
if key:
|
|
59
|
+
self.key = key
|
|
60
|
+
|
|
61
|
+
if priority:
|
|
62
|
+
self.priority = priority
|
|
63
|
+
|
|
64
|
+
def clear(self):
|
|
65
|
+
self.pq = []
|
|
66
|
+
self.item_finder = {}
|
|
67
|
+
self.key_counter = itertools.count()
|
|
68
|
+
self.priority_counter = itertools.count()
|
|
69
|
+
self.removed_count = 0
|
|
70
|
+
|
|
71
|
+
def key(self, value):
|
|
72
|
+
"""If key isn't passed into the constructor then this method will be called"""
|
|
73
|
+
return next(self.key_counter)
|
|
74
|
+
|
|
75
|
+
def priority(self, value):
|
|
76
|
+
"""If priority isn't passed into the constructor then this method will be called"""
|
|
77
|
+
return next(self.priority_counter)
|
|
78
|
+
|
|
79
|
+
def push(self, value, key=None, priority=None):
|
|
80
|
+
"""Same interface as .put() but will remove the next element if the queue
|
|
81
|
+
is full so value can be placed into the queue"""
|
|
82
|
+
try:
|
|
83
|
+
self.put(value, key=key, priority=priority)
|
|
84
|
+
|
|
85
|
+
except OverflowError:
|
|
86
|
+
self.popitem()
|
|
87
|
+
self.put(value, key=key, priority=priority)
|
|
88
|
+
|
|
89
|
+
def put(self, value, key=None, priority=None):
|
|
90
|
+
"""add a value to the queue with priority, using the key to know uniqueness
|
|
91
|
+
|
|
92
|
+
:param value: mixed, the value to add to the queue
|
|
93
|
+
:param key: string|int, this is used to determine uniqueness in the queue,
|
|
94
|
+
if key is already in the queue, then the val will be replaced in the
|
|
95
|
+
queue with the new priority, if key is None then .key(value) will be
|
|
96
|
+
called to determine a key for value
|
|
97
|
+
:param priority: int, the priority of value, if None then .priority(value)
|
|
98
|
+
will be called to determine a priority for the value, defaults to FIFO
|
|
99
|
+
"""
|
|
100
|
+
deleted = False
|
|
101
|
+
|
|
102
|
+
if key is None:
|
|
103
|
+
key = self.key(value)
|
|
104
|
+
|
|
105
|
+
if priority is None:
|
|
106
|
+
priority = self.priority(value)
|
|
107
|
+
|
|
108
|
+
if key in self.item_finder:
|
|
109
|
+
self.remove(key)
|
|
110
|
+
|
|
111
|
+
else:
|
|
112
|
+
# keep the queue contained
|
|
113
|
+
if self.full():
|
|
114
|
+
raise OverflowError("Queue is full")
|
|
115
|
+
|
|
116
|
+
item = [priority, key, value, deleted]
|
|
117
|
+
self.item_finder[key] = item
|
|
118
|
+
heapq.heappush(self.pq, item)
|
|
119
|
+
|
|
120
|
+
def remove(self, key):
|
|
121
|
+
"""remove the value found at key from the queue"""
|
|
122
|
+
item = self.item_finder.pop(key)
|
|
123
|
+
item[-1] = True
|
|
124
|
+
self.removed_count += 1
|
|
125
|
+
|
|
126
|
+
def popitem(self):
|
|
127
|
+
"""remove the next prioritized (value, key, priority) and return it"""
|
|
128
|
+
pq = self.pq
|
|
129
|
+
while pq:
|
|
130
|
+
priority, key, value, deleted = heapq.heappop(pq)
|
|
131
|
+
if deleted:
|
|
132
|
+
self.removed_count -= 1
|
|
133
|
+
|
|
134
|
+
else:
|
|
135
|
+
del self.item_finder[key]
|
|
136
|
+
return value, key, priority
|
|
137
|
+
|
|
138
|
+
raise KeyError("Pop from an empty queue")
|
|
139
|
+
|
|
140
|
+
def get(self):
|
|
141
|
+
"""Remove the next prioritized val and return it"""
|
|
142
|
+
value, key, priority = self.popitem()
|
|
143
|
+
return value
|
|
144
|
+
|
|
145
|
+
def full(self):
|
|
146
|
+
"""Return True if the queue is full"""
|
|
147
|
+
if not self.maxsize: return False
|
|
148
|
+
return len(self.pq) >= (self.maxsize + self.removed_count)
|
|
149
|
+
|
|
150
|
+
def keys(self):
|
|
151
|
+
"""return the keys in the order they are in the queue"""
|
|
152
|
+
for x in self.pq:
|
|
153
|
+
if not x[3]:
|
|
154
|
+
yield x[1]
|
|
155
|
+
|
|
156
|
+
def values(self):
|
|
157
|
+
"""return the values in the order they are in the queue"""
|
|
158
|
+
for x in self.pq:
|
|
159
|
+
if not x[3]:
|
|
160
|
+
yield x[2]
|
|
161
|
+
|
|
162
|
+
def qsize(self):
|
|
163
|
+
"""for similarity to python's queue interface"""
|
|
164
|
+
return self.maxsize
|
|
165
|
+
|
|
166
|
+
def __len__(self):
|
|
167
|
+
return len(self.item_finder)
|
|
168
|
+
|
|
169
|
+
def __bool__(self):
|
|
170
|
+
return bool(len(self))
|
|
171
|
+
__nonzero__ = __bool__
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# class FrozenList(list): # a read only list that can only be set via constructor
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class AppendList(list):
|
|
178
|
+
"""A READ ONLY list that does all adding of items through the append method
|
|
179
|
+
To customize this list just extend the append() method
|
|
180
|
+
|
|
181
|
+
https://docs.python.org/3/tutorial/datastructures.html#more-on-lists
|
|
182
|
+
"""
|
|
183
|
+
def __init__(self, iterable=None):
|
|
184
|
+
"""
|
|
185
|
+
https://docs.python.org/3/library/stdtypes.html?highlight=list#list
|
|
186
|
+
"""
|
|
187
|
+
if iterable:
|
|
188
|
+
self.extend(iterable)
|
|
189
|
+
|
|
190
|
+
def append(self, x):
|
|
191
|
+
return super().append(x)
|
|
192
|
+
|
|
193
|
+
def extend(self, iterable):
|
|
194
|
+
for x in iterable:
|
|
195
|
+
self.append(x)
|
|
196
|
+
|
|
197
|
+
def pop(self, i):
|
|
198
|
+
raise NotImplementedError()
|
|
199
|
+
def insert(self, i, x):
|
|
200
|
+
raise NotImplementedError()
|
|
201
|
+
def __setitem__(self, i, x):
|
|
202
|
+
raise NotImplementedError()
|
|
203
|
+
def __delitem__(self, i):
|
|
204
|
+
raise NotImplementedError()
|
|
205
|
+
def remove(self, x):
|
|
206
|
+
raise NotImplementedError()
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class OrderedList(list):
|
|
210
|
+
"""Keep a list sorted as you append or extend it
|
|
211
|
+
|
|
212
|
+
An ordered list, this sorts items from smallest to largest using key, so
|
|
213
|
+
if you want MaxQueue like functionality use negative values: .pop(-1) and
|
|
214
|
+
if you want MinQueue like functionality use positive values: .pop(0)
|
|
215
|
+
|
|
216
|
+
https://docs.python.org/3/tutorial/datastructures.html#more-on-lists
|
|
217
|
+
"""
|
|
218
|
+
def __init__(self, iterable=None, key=None):
|
|
219
|
+
if key:
|
|
220
|
+
self.key = key
|
|
221
|
+
self._keys = []
|
|
222
|
+
super().__init__()
|
|
223
|
+
if iterable:
|
|
224
|
+
for x in iterable:
|
|
225
|
+
self.append(x)
|
|
226
|
+
|
|
227
|
+
def key(self, x):
|
|
228
|
+
"""Returns the key that will be used to order x
|
|
229
|
+
|
|
230
|
+
You can override this method to customize ordering
|
|
231
|
+
|
|
232
|
+
:param x: Any, the object being inserted
|
|
233
|
+
:returns: str|int|Any, the hashable object that will be used for
|
|
234
|
+
ordering
|
|
235
|
+
"""
|
|
236
|
+
return x
|
|
237
|
+
|
|
238
|
+
def inserted(self, i, x):
|
|
239
|
+
"""Called after x is inserted at position i
|
|
240
|
+
|
|
241
|
+
This is handy if you want to do some post insertion manipulation of the
|
|
242
|
+
list
|
|
243
|
+
|
|
244
|
+
:param i: int, the position x was inserted in the list, will be None if
|
|
245
|
+
x was inserted at the end of the list
|
|
246
|
+
:param x: Any, the object inserted into the list
|
|
247
|
+
"""
|
|
248
|
+
pass
|
|
249
|
+
|
|
250
|
+
def append(self, x):
|
|
251
|
+
k = self.key(x)
|
|
252
|
+
# https://docs.python.org/3/library/bisect.html#bisect.bisect_right
|
|
253
|
+
i = bisect.bisect_right(self._keys, k)
|
|
254
|
+
if i is None:
|
|
255
|
+
super().append((self.key(x), x))
|
|
256
|
+
self._keys.append(k)
|
|
257
|
+
|
|
258
|
+
else:
|
|
259
|
+
super().insert(i, (self.key(x), x))
|
|
260
|
+
self._keys.insert(i, k)
|
|
261
|
+
|
|
262
|
+
self.inserted(i, x)
|
|
263
|
+
|
|
264
|
+
def extend(self, iterable):
|
|
265
|
+
for x in iterable:
|
|
266
|
+
self.append(x)
|
|
267
|
+
|
|
268
|
+
def remove(self, x):
|
|
269
|
+
k = self.key(x)
|
|
270
|
+
self._keys.remove(k)
|
|
271
|
+
super().remove((k, x))
|
|
272
|
+
|
|
273
|
+
def pop(self, i=-1):
|
|
274
|
+
self._keys.pop(i)
|
|
275
|
+
return super().pop(i)[-1]
|
|
276
|
+
|
|
277
|
+
def clear(self):
|
|
278
|
+
super().clear()
|
|
279
|
+
self._keys.clear()
|
|
280
|
+
|
|
281
|
+
def __iter__(self):
|
|
282
|
+
for x in super().__iter__():
|
|
283
|
+
yield x[-1]
|
|
284
|
+
|
|
285
|
+
def __reversed__(self):
|
|
286
|
+
index = len(self)
|
|
287
|
+
while index > 0:
|
|
288
|
+
index -= 1
|
|
289
|
+
yield self[index]
|
|
290
|
+
|
|
291
|
+
def __getitem__(self, i):
|
|
292
|
+
return super().__getitem__(i)[-1]
|
|
293
|
+
|
|
294
|
+
def __delitem__(self, i):
|
|
295
|
+
self.pop(i)
|
|
296
|
+
|
|
297
|
+
def insert(self, i, x):
|
|
298
|
+
raise NotImplementedError()
|
|
299
|
+
def __setitem__(self, i, x):
|
|
300
|
+
raise NotImplementedError()
|
|
301
|
+
def reverse(self):
|
|
302
|
+
raise NotImplementedError()
|
|
303
|
+
def sort(self):
|
|
304
|
+
raise NotImplementedError()
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class Stack(list):
|
|
308
|
+
"""An incredibly simple stack implementation"""
|
|
309
|
+
def push(self, v):
|
|
310
|
+
self.append(v)
|
|
311
|
+
|
|
312
|
+
def pop(self):
|
|
313
|
+
return super().pop(-1)
|
|
314
|
+
|
|
315
|
+
def peek(self):
|
|
316
|
+
return self[-1]
|
|
317
|
+
|
|
318
|
+
def __iter__(self):
|
|
319
|
+
"""By default stacks are LIFO"""
|
|
320
|
+
for i in reversed(range(0, len(self))):
|
|
321
|
+
yield self[i]
|
|
322
|
+
|
|
323
|
+
def __reversed__(self):
|
|
324
|
+
"""calling reverse on a stack would switch to normal list FIFO"""
|
|
325
|
+
return super().__iter__()
|
|
326
|
+
|
|
327
|
+
def insert(self, i, x):
|
|
328
|
+
raise NotImplementedError()
|
|
329
|
+
def __setitem__(self, i, x):
|
|
330
|
+
raise NotImplementedError()
|
|
331
|
+
def __delitem__(self, i):
|
|
332
|
+
raise NotImplementedError()
|
|
333
|
+
def reverse(self):
|
|
334
|
+
raise NotImplementedError()
|
|
335
|
+
def sort(self):
|
|
336
|
+
raise NotImplementedError()
|
|
337
|
+
def remove(self, x):
|
|
338
|
+
raise NotImplementedError()
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class ListIterator(list):
|
|
342
|
+
"""A base interface for iterators that should quack like a builtin list
|
|
343
|
+
|
|
344
|
+
it defines the list interface as much as possible
|
|
345
|
+
|
|
346
|
+
Taken from prom.query.BaseIterator on 12-15-2020
|
|
347
|
+
|
|
348
|
+
list interface methods:
|
|
349
|
+
https://docs.python.org/3/tutorial/datastructures.html#more-on-lists
|
|
350
|
+
|
|
351
|
+
http://docs.python.org/2/library/stdtypes.html#iterator-types
|
|
352
|
+
"""
|
|
353
|
+
def __init__(self, *args, **kwargs):
|
|
354
|
+
super(Iterator, self).__init__(*args, **kwargs)
|
|
355
|
+
|
|
356
|
+
def __next__(self):
|
|
357
|
+
"""needed for py3 api compatibility"""
|
|
358
|
+
return self.next()
|
|
359
|
+
|
|
360
|
+
def __iter__(self):
|
|
361
|
+
return self
|
|
362
|
+
|
|
363
|
+
def __nonzero__(self):
|
|
364
|
+
return self.__bool__()
|
|
365
|
+
|
|
366
|
+
def __bool__(self):
|
|
367
|
+
for _ in self:
|
|
368
|
+
return True
|
|
369
|
+
return False
|
|
370
|
+
|
|
371
|
+
def __len__(self):
|
|
372
|
+
return self.count()
|
|
373
|
+
|
|
374
|
+
def __deepcopy__(self, *args, **kwargs):
|
|
375
|
+
return self.copy()
|
|
376
|
+
|
|
377
|
+
def __getslice__(self, i, j):
|
|
378
|
+
"""required for slicing in python 2 when extending built-in types like list
|
|
379
|
+
|
|
380
|
+
https://docs.python.org/2/reference/datamodel.html#object.__getslice__
|
|
381
|
+
https://stackoverflow.com/questions/2936863/implementing-slicing-in-getitem#comment39878974_2936876
|
|
382
|
+
"""
|
|
383
|
+
return self.__getitem__(slice(i, j))
|
|
384
|
+
|
|
385
|
+
def __reversed__(self):
|
|
386
|
+
it = self.copy()
|
|
387
|
+
it.reverse()
|
|
388
|
+
return it
|
|
389
|
+
|
|
390
|
+
def __iter__(self):
|
|
391
|
+
return self
|
|
392
|
+
|
|
393
|
+
def __getitem__(self, i):
|
|
394
|
+
if isinstance(i, slice):
|
|
395
|
+
return self.get_slice(i)
|
|
396
|
+
|
|
397
|
+
else:
|
|
398
|
+
return self.get_index(i)
|
|
399
|
+
|
|
400
|
+
def get_slice(self, s):
|
|
401
|
+
"""s is a slice object
|
|
402
|
+
|
|
403
|
+
* s.start - lower bound
|
|
404
|
+
* s.stop - uppder bound
|
|
405
|
+
* s.step - step value
|
|
406
|
+
|
|
407
|
+
Any property of the slice instance can be None:
|
|
408
|
+
|
|
409
|
+
* [:N:N] - start is None
|
|
410
|
+
* [N:] - stop and step are None
|
|
411
|
+
* [:N] - start and step are None
|
|
412
|
+
* [N:N] - step is None
|
|
413
|
+
* [N::N] - stop and step are None
|
|
414
|
+
|
|
415
|
+
slice objects are described here: https://docs.python.org/3/reference/datamodel.html
|
|
416
|
+
under section 3.2 in the "slice objects" section
|
|
417
|
+
"""
|
|
418
|
+
raise NotImplementedError()
|
|
419
|
+
|
|
420
|
+
def get_index(self, i):
|
|
421
|
+
raise NotImplementedError()
|
|
422
|
+
|
|
423
|
+
def next(self):
|
|
424
|
+
raise NotImplementedError()
|
|
425
|
+
|
|
426
|
+
def count(self):
|
|
427
|
+
"""list interface compatibility"""
|
|
428
|
+
raise NotImplementedError()
|
|
429
|
+
|
|
430
|
+
def reverse(self):
|
|
431
|
+
"""list interface compatibility"""
|
|
432
|
+
raise NotImplementedError()
|
|
433
|
+
|
|
434
|
+
def sort(self, *args, **kwargs):
|
|
435
|
+
"""list interface compatibility"""
|
|
436
|
+
raise NotImplementedError()
|
|
437
|
+
|
|
438
|
+
def copy(self):
|
|
439
|
+
"""list interface compatibility"""
|
|
440
|
+
raise NotImplementedError()
|
|
441
|
+
|
|
442
|
+
def index(self, x, start=None, end=None):
|
|
443
|
+
"""list interface compatibility"""
|
|
444
|
+
raise NotImplementedError()
|
|
445
|
+
|
|
446
|
+
def append(self, x):
|
|
447
|
+
"""list interface compatibility"""
|
|
448
|
+
raise NotImplementedError()
|
|
449
|
+
|
|
450
|
+
def extend(self, iterable):
|
|
451
|
+
"""list interface compatibility"""
|
|
452
|
+
raise NotImplementedError()
|
|
453
|
+
|
|
454
|
+
def remove(self, x):
|
|
455
|
+
"""list interface compatibility"""
|
|
456
|
+
raise NotImplementedError()
|
|
457
|
+
|
|
458
|
+
def pop(self, i=-1):
|
|
459
|
+
"""list interface compatibility"""
|
|
460
|
+
raise NotImplementedError()
|
|
461
|
+
|
|
462
|
+
def clear(self):
|
|
463
|
+
"""list interface compatibility"""
|
|
464
|
+
raise NotImplementedError()
|
|
465
|
+
|
|
466
|
+
def insert(self, i, x):
|
|
467
|
+
"""list interface compatibility"""
|
|
468
|
+
raise NotImplementedError()
|
|
469
|
+
|