fastapi-startkit 0.1.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.
- fastapi_startkit/__init__.py +3 -0
- fastapi_startkit/application.py +40 -0
- fastapi_startkit/configuration/Configuration.py +80 -0
- fastapi_startkit/configuration/__init__.py +2 -0
- fastapi_startkit/configuration/helpers.py +5 -0
- fastapi_startkit/configuration/providers/ConfigurationProvider.py +16 -0
- fastapi_startkit/configuration/providers/__init__.py +1 -0
- fastapi_startkit/container/__init__.py +1 -0
- fastapi_startkit/container/container.py +494 -0
- fastapi_startkit/environment/environment.py +76 -0
- fastapi_startkit/exceptions/DD.py +38 -0
- fastapi_startkit/exceptions/ExceptionHandler.py +76 -0
- fastapi_startkit/exceptions/__init__.py +38 -0
- fastapi_startkit/exceptions/exceptionite/__init__.py +0 -0
- fastapi_startkit/exceptions/exceptionite/blocks.py +101 -0
- fastapi_startkit/exceptions/exceptionite/controllers.py +13 -0
- fastapi_startkit/exceptions/exceptionite/solutions.py +66 -0
- fastapi_startkit/exceptions/exceptionite/tabs.py +19 -0
- fastapi_startkit/exceptions/exceptions.py +218 -0
- fastapi_startkit/exceptions/handlers/DumpExceptionHandler.py +104 -0
- fastapi_startkit/exceptions/handlers/HttpExceptionHandler.py +28 -0
- fastapi_startkit/exceptions/handlers/ModelNotFoundHandler.py +13 -0
- fastapi_startkit/facades/Auth.py +5 -0
- fastapi_startkit/facades/Auth.pyi +32 -0
- fastapi_startkit/facades/Broadcast.py +5 -0
- fastapi_startkit/facades/Cache.py +5 -0
- fastapi_startkit/facades/Config.py +5 -0
- fastapi_startkit/facades/Config.pyi +14 -0
- fastapi_startkit/facades/Dump.py +5 -0
- fastapi_startkit/facades/Dump.pyi +26 -0
- fastapi_startkit/facades/Facade.py +5 -0
- fastapi_startkit/facades/Gate.py +5 -0
- fastapi_startkit/facades/Gate.pyi +32 -0
- fastapi_startkit/facades/Hash.py +5 -0
- fastapi_startkit/facades/Hash.pyi +28 -0
- fastapi_startkit/facades/Loader.py +5 -0
- fastapi_startkit/facades/Loader.pyi +30 -0
- fastapi_startkit/facades/Mail.py +5 -0
- fastapi_startkit/facades/Mail.pyi +14 -0
- fastapi_startkit/facades/Notification.py +5 -0
- fastapi_startkit/facades/Notification.pyi +25 -0
- fastapi_startkit/facades/Queue.py +5 -0
- fastapi_startkit/facades/Queue.pyi +10 -0
- fastapi_startkit/facades/RateLimiter.py +5 -0
- fastapi_startkit/facades/RateLimiter.pyi +43 -0
- fastapi_startkit/facades/Request.py +5 -0
- fastapi_startkit/facades/Request.pyi +88 -0
- fastapi_startkit/facades/Response.py +5 -0
- fastapi_startkit/facades/Response.pyi +68 -0
- fastapi_startkit/facades/Session.py +5 -0
- fastapi_startkit/facades/Session.pyi +59 -0
- fastapi_startkit/facades/Storage.py +5 -0
- fastapi_startkit/facades/Storage.pyi +12 -0
- fastapi_startkit/facades/Url.py +5 -0
- fastapi_startkit/facades/Url.pyi +22 -0
- fastapi_startkit/facades/View.py +5 -0
- fastapi_startkit/facades/View.pyi +54 -0
- fastapi_startkit/facades/__init__.py +19 -0
- fastapi_startkit/loader/Loader.py +78 -0
- fastapi_startkit/loader/__init__.py +1 -0
- fastapi_startkit/providers/ConfigurationProvider.py +13 -0
- fastapi_startkit/providers/Provider.py +14 -0
- fastapi_startkit/providers/__init__.py +4 -0
- fastapi_startkit/utils/__init__.py +0 -0
- fastapi_startkit/utils/collections.py +545 -0
- fastapi_startkit/utils/console.py +39 -0
- fastapi_startkit/utils/data/mime.types +1863 -0
- fastapi_startkit/utils/filesystem.py +100 -0
- fastapi_startkit/utils/http.py +101 -0
- fastapi_startkit/utils/location.py +90 -0
- fastapi_startkit/utils/str.py +120 -0
- fastapi_startkit/utils/structures.py +97 -0
- fastapi_startkit/utils/time.py +58 -0
- fastapi_startkit-0.1.0.dist-info/METADATA +13 -0
- fastapi_startkit-0.1.0.dist-info/RECORD +76 -0
- fastapi_startkit-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import random
|
|
3
|
+
import operator
|
|
4
|
+
from functools import reduce
|
|
5
|
+
from dotty_dict import Dotty
|
|
6
|
+
|
|
7
|
+
from .structures import data_get
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Collection:
|
|
11
|
+
"""Wraps various data types to make working with them easier."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, items=None):
|
|
14
|
+
self._items = items or []
|
|
15
|
+
self.__appends__ = []
|
|
16
|
+
|
|
17
|
+
def take(self, number: int):
|
|
18
|
+
"""Takes a specific number of results from the items.
|
|
19
|
+
|
|
20
|
+
Arguments:
|
|
21
|
+
number {integer} -- The number of results to take.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
int
|
|
25
|
+
"""
|
|
26
|
+
if number < 0:
|
|
27
|
+
return self[number:]
|
|
28
|
+
|
|
29
|
+
return self[:number]
|
|
30
|
+
|
|
31
|
+
def first(self, callback=None):
|
|
32
|
+
"""Takes the first result in the items.
|
|
33
|
+
|
|
34
|
+
If a callback is given then the first result will be the result after the filter.
|
|
35
|
+
|
|
36
|
+
Keyword Arguments:
|
|
37
|
+
callback {callable} -- Used to filter the results before returning the first item. (default: {None})
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
mixed -- Returns whatever the first item is.
|
|
41
|
+
"""
|
|
42
|
+
filtered = self
|
|
43
|
+
if callback:
|
|
44
|
+
filtered = self.filter(callback)
|
|
45
|
+
response = None
|
|
46
|
+
if filtered:
|
|
47
|
+
response = filtered[0]
|
|
48
|
+
return response
|
|
49
|
+
|
|
50
|
+
def last(self, callback=None):
|
|
51
|
+
"""Takes the last result in the items.
|
|
52
|
+
|
|
53
|
+
If a callback is given then the last result will be the result after the filter.
|
|
54
|
+
|
|
55
|
+
Keyword Arguments:
|
|
56
|
+
callback {callable} -- Used to filter the results before returning the last item. (default: {None})
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
mixed -- Returns whatever the last item is.
|
|
60
|
+
"""
|
|
61
|
+
filtered = self
|
|
62
|
+
if callback:
|
|
63
|
+
filtered = self.filter(callback)
|
|
64
|
+
return filtered[-1]
|
|
65
|
+
|
|
66
|
+
def all(self):
|
|
67
|
+
"""Returns all the items.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
mixed -- Returns all items.
|
|
71
|
+
"""
|
|
72
|
+
return self._items
|
|
73
|
+
|
|
74
|
+
def avg(self, key=None):
|
|
75
|
+
"""Returns the average of the items.
|
|
76
|
+
|
|
77
|
+
If a key is given it will return the average of all the values of the key.
|
|
78
|
+
|
|
79
|
+
Keyword Arguments:
|
|
80
|
+
key {string} -- The key to use to find the average of all the values of that key. (default: {None})
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
int -- Returns the average.
|
|
84
|
+
"""
|
|
85
|
+
result = 0
|
|
86
|
+
items = self._get_value(key) or self._items
|
|
87
|
+
try:
|
|
88
|
+
result = sum(items) / len(items)
|
|
89
|
+
except TypeError:
|
|
90
|
+
pass
|
|
91
|
+
return result
|
|
92
|
+
|
|
93
|
+
def max(self, key=None):
|
|
94
|
+
"""Returns the average of the items.
|
|
95
|
+
|
|
96
|
+
If a key is given it will return the average of all the values of the key.
|
|
97
|
+
|
|
98
|
+
Keyword Arguments:
|
|
99
|
+
key {string} -- The key to use to find the average of all the values of that key. (default: {None})
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
int -- Returns the average.
|
|
103
|
+
"""
|
|
104
|
+
result = 0
|
|
105
|
+
items = self._get_value(key) or self._items
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
return max(items)
|
|
109
|
+
except (TypeError, ValueError):
|
|
110
|
+
pass
|
|
111
|
+
return result
|
|
112
|
+
|
|
113
|
+
def chunk(self, size: int):
|
|
114
|
+
"""Chunks the items.
|
|
115
|
+
|
|
116
|
+
Keyword Arguments:
|
|
117
|
+
size {integer} -- The number of values in each chunk.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
int -- Returns the average.
|
|
121
|
+
"""
|
|
122
|
+
items = []
|
|
123
|
+
for i in range(0, self.count(), size):
|
|
124
|
+
items.append(self[i : i + size])
|
|
125
|
+
return self.__class__(items)
|
|
126
|
+
|
|
127
|
+
def collapse(self):
|
|
128
|
+
items = []
|
|
129
|
+
for item in self:
|
|
130
|
+
items += self.__get_items(item)
|
|
131
|
+
return self.__class__(items)
|
|
132
|
+
|
|
133
|
+
def contains(self, key, value=None):
|
|
134
|
+
if value:
|
|
135
|
+
return self.contains(lambda x: self._data_get(x, key) == value)
|
|
136
|
+
|
|
137
|
+
if self._check_is_callable(key, raise_exception=False):
|
|
138
|
+
return self.first(key) is not None
|
|
139
|
+
|
|
140
|
+
return key in self
|
|
141
|
+
|
|
142
|
+
def count(self):
|
|
143
|
+
return len(self._items)
|
|
144
|
+
|
|
145
|
+
def diff(self, items):
|
|
146
|
+
items = self.__get_items(items)
|
|
147
|
+
return self.__class__([x for x in self if x not in items])
|
|
148
|
+
|
|
149
|
+
def each(self, callback):
|
|
150
|
+
self._check_is_callable(callback)
|
|
151
|
+
|
|
152
|
+
for k, v in enumerate(self):
|
|
153
|
+
result = callback(v)
|
|
154
|
+
if not result:
|
|
155
|
+
break
|
|
156
|
+
self[k] = result
|
|
157
|
+
|
|
158
|
+
def every(self, callback):
|
|
159
|
+
self._check_is_callable(callback)
|
|
160
|
+
return all([callback(x) for x in self])
|
|
161
|
+
|
|
162
|
+
def filter(self, callback):
|
|
163
|
+
self._check_is_callable(callback)
|
|
164
|
+
return self.__class__(list(filter(callback, self)))
|
|
165
|
+
|
|
166
|
+
def flatten(self):
|
|
167
|
+
def _flatten(items):
|
|
168
|
+
if isinstance(items, dict):
|
|
169
|
+
for v in items.values():
|
|
170
|
+
for x in _flatten(v):
|
|
171
|
+
yield x
|
|
172
|
+
elif isinstance(items, list):
|
|
173
|
+
for i in items:
|
|
174
|
+
for j in _flatten(i):
|
|
175
|
+
yield j
|
|
176
|
+
else:
|
|
177
|
+
yield items
|
|
178
|
+
|
|
179
|
+
return self.__class__(list(_flatten(self._items)))
|
|
180
|
+
|
|
181
|
+
def forget(self, *keys):
|
|
182
|
+
keys = reversed(sorted(keys))
|
|
183
|
+
|
|
184
|
+
for key in keys:
|
|
185
|
+
del self[key]
|
|
186
|
+
|
|
187
|
+
return self
|
|
188
|
+
|
|
189
|
+
def for_page(self, page, number):
|
|
190
|
+
return self.__class__(self[page:number])
|
|
191
|
+
|
|
192
|
+
def get(self, key, default=None):
|
|
193
|
+
try:
|
|
194
|
+
return self[key]
|
|
195
|
+
except IndexError:
|
|
196
|
+
pass
|
|
197
|
+
|
|
198
|
+
return self._value(default)
|
|
199
|
+
|
|
200
|
+
def implode(self, glue=",", key=None):
|
|
201
|
+
first = self.first()
|
|
202
|
+
if not isinstance(first, str) and key:
|
|
203
|
+
return glue.join(self.pluck(key))
|
|
204
|
+
return glue.join([str(x) for x in self])
|
|
205
|
+
|
|
206
|
+
def is_empty(self):
|
|
207
|
+
return not self
|
|
208
|
+
|
|
209
|
+
def map(self, callback):
|
|
210
|
+
self._check_is_callable(callback)
|
|
211
|
+
items = [callback(x) for x in self]
|
|
212
|
+
return self.__class__(items)
|
|
213
|
+
|
|
214
|
+
def map_into(self, cls, method=None, **kwargs):
|
|
215
|
+
results = []
|
|
216
|
+
for item in self:
|
|
217
|
+
if method:
|
|
218
|
+
results.append(getattr(cls, method)(item, **kwargs))
|
|
219
|
+
else:
|
|
220
|
+
results.append(cls(item))
|
|
221
|
+
|
|
222
|
+
return self.__class__(results)
|
|
223
|
+
|
|
224
|
+
def merge(self, items):
|
|
225
|
+
if not isinstance(items, list):
|
|
226
|
+
raise ValueError("Unable to merge uncompatible types")
|
|
227
|
+
|
|
228
|
+
items = self.__get_items(items)
|
|
229
|
+
|
|
230
|
+
self._items += items
|
|
231
|
+
return self
|
|
232
|
+
|
|
233
|
+
def pluck(self, value, key=None):
|
|
234
|
+
if key:
|
|
235
|
+
attributes = {}
|
|
236
|
+
else:
|
|
237
|
+
attributes = []
|
|
238
|
+
|
|
239
|
+
if isinstance(self._items, dict):
|
|
240
|
+
return Collection([self._items.get(value)])
|
|
241
|
+
|
|
242
|
+
for item in self:
|
|
243
|
+
if isinstance(item, dict):
|
|
244
|
+
iterable = item.items()
|
|
245
|
+
elif hasattr(item, "serialize"):
|
|
246
|
+
iterable = item.serialize().items()
|
|
247
|
+
else:
|
|
248
|
+
iterable = self.all().items()
|
|
249
|
+
|
|
250
|
+
for k, v in iterable:
|
|
251
|
+
if k == value:
|
|
252
|
+
if key:
|
|
253
|
+
attributes[self._data_get(item, key)] = self._data_get(
|
|
254
|
+
item, value
|
|
255
|
+
)
|
|
256
|
+
else:
|
|
257
|
+
attributes.append(v)
|
|
258
|
+
|
|
259
|
+
return Collection(attributes)
|
|
260
|
+
|
|
261
|
+
def pop(self):
|
|
262
|
+
last = self._items.pop()
|
|
263
|
+
return last
|
|
264
|
+
|
|
265
|
+
def prepend(self, value):
|
|
266
|
+
self._items.insert(0, value)
|
|
267
|
+
return self
|
|
268
|
+
|
|
269
|
+
def pull(self, key):
|
|
270
|
+
value = self.get(key)
|
|
271
|
+
self.forget(key)
|
|
272
|
+
return value
|
|
273
|
+
|
|
274
|
+
def push(self, value):
|
|
275
|
+
self._items.append(value)
|
|
276
|
+
|
|
277
|
+
def put(self, key, value):
|
|
278
|
+
self[key] = value
|
|
279
|
+
return self
|
|
280
|
+
|
|
281
|
+
def random(self, count=None):
|
|
282
|
+
"""Returns a random item of the collection."""
|
|
283
|
+
collection_count = self.count()
|
|
284
|
+
if collection_count == 0:
|
|
285
|
+
return None
|
|
286
|
+
elif count and count > collection_count:
|
|
287
|
+
raise ValueError("count argument must be inferior to collection length.")
|
|
288
|
+
elif count:
|
|
289
|
+
self._items = random.sample(self._items, k=count)
|
|
290
|
+
return self
|
|
291
|
+
else:
|
|
292
|
+
return random.choice(self._items)
|
|
293
|
+
|
|
294
|
+
def reduce(self, callback, initial=0):
|
|
295
|
+
return reduce(callback, self, initial)
|
|
296
|
+
|
|
297
|
+
def reject(self, callback):
|
|
298
|
+
self._check_is_callable(callback)
|
|
299
|
+
|
|
300
|
+
items = self._get_value(callback) or self._items
|
|
301
|
+
self._items = items
|
|
302
|
+
|
|
303
|
+
def reverse(self):
|
|
304
|
+
self._items = self[::-1]
|
|
305
|
+
|
|
306
|
+
def serialize(self):
|
|
307
|
+
def _serialize(item):
|
|
308
|
+
if self.__appends__:
|
|
309
|
+
item.set_appends(self.__appends__)
|
|
310
|
+
|
|
311
|
+
if hasattr(item, "serialize"):
|
|
312
|
+
return item.serialize()
|
|
313
|
+
elif hasattr(item, "to_dict"):
|
|
314
|
+
return item.to_dict()
|
|
315
|
+
return item
|
|
316
|
+
|
|
317
|
+
return list(map(_serialize, self))
|
|
318
|
+
|
|
319
|
+
def add_relation(self, result=None):
|
|
320
|
+
for model in self._items:
|
|
321
|
+
model.add_relations(result or {})
|
|
322
|
+
|
|
323
|
+
return self
|
|
324
|
+
|
|
325
|
+
def shift(self):
|
|
326
|
+
return self.pull(0)
|
|
327
|
+
|
|
328
|
+
def sort(self, key=None):
|
|
329
|
+
if key:
|
|
330
|
+
self._items.sort(key=lambda x: x[key], reverse=False)
|
|
331
|
+
return self
|
|
332
|
+
|
|
333
|
+
self._items = sorted(self)
|
|
334
|
+
return self
|
|
335
|
+
|
|
336
|
+
def sum(self, key=None):
|
|
337
|
+
result = 0
|
|
338
|
+
items = self._get_value(key) or self._items
|
|
339
|
+
try:
|
|
340
|
+
result = sum(items)
|
|
341
|
+
except TypeError:
|
|
342
|
+
pass
|
|
343
|
+
return result
|
|
344
|
+
|
|
345
|
+
def to_json(self, **kwargs):
|
|
346
|
+
return json.dumps(self.serialize(), **kwargs)
|
|
347
|
+
|
|
348
|
+
def group_by(self, key):
|
|
349
|
+
|
|
350
|
+
from itertools import groupby
|
|
351
|
+
|
|
352
|
+
self.sort(key)
|
|
353
|
+
|
|
354
|
+
new_dict = {}
|
|
355
|
+
|
|
356
|
+
for k, v in groupby(self._items, key=lambda x: x[key]):
|
|
357
|
+
new_dict.update({k: list(v)})
|
|
358
|
+
|
|
359
|
+
return Collection(new_dict)
|
|
360
|
+
|
|
361
|
+
def transform(self, callback):
|
|
362
|
+
self._check_is_callable(callback)
|
|
363
|
+
self._items = self._get_value(callback)
|
|
364
|
+
|
|
365
|
+
def unique(self, key=None):
|
|
366
|
+
if not key:
|
|
367
|
+
items = list(set(self._items))
|
|
368
|
+
return self.__class__(items)
|
|
369
|
+
|
|
370
|
+
keys = set()
|
|
371
|
+
items = []
|
|
372
|
+
if isinstance(self.all(), dict):
|
|
373
|
+
return self
|
|
374
|
+
|
|
375
|
+
for item in self:
|
|
376
|
+
if isinstance(item, dict):
|
|
377
|
+
comparison = item.get(key)
|
|
378
|
+
elif isinstance(item, str):
|
|
379
|
+
comparison = item
|
|
380
|
+
else:
|
|
381
|
+
comparison = getattr(item, key)
|
|
382
|
+
if comparison not in keys:
|
|
383
|
+
items.append(item)
|
|
384
|
+
keys.add(comparison)
|
|
385
|
+
|
|
386
|
+
return self.__class__(items)
|
|
387
|
+
|
|
388
|
+
def where(self, key, *args):
|
|
389
|
+
op = "=="
|
|
390
|
+
value = args[0]
|
|
391
|
+
|
|
392
|
+
if len(args) >= 2:
|
|
393
|
+
op = args[0]
|
|
394
|
+
value = args[1]
|
|
395
|
+
|
|
396
|
+
attributes = []
|
|
397
|
+
|
|
398
|
+
for item in self._items:
|
|
399
|
+
if isinstance(item, dict):
|
|
400
|
+
comparison = item.get(key)
|
|
401
|
+
else:
|
|
402
|
+
comparison = getattr(item, key)
|
|
403
|
+
if self._make_comparison(comparison, value, op):
|
|
404
|
+
attributes.append(item)
|
|
405
|
+
|
|
406
|
+
return self.__class__(attributes)
|
|
407
|
+
|
|
408
|
+
def zip(self, items):
|
|
409
|
+
items = self.__get_items(items)
|
|
410
|
+
if not isinstance(items, list):
|
|
411
|
+
raise ValueError("The 'items' parameter must be a list or a Collection")
|
|
412
|
+
|
|
413
|
+
_items = []
|
|
414
|
+
for x, y in zip(self, items):
|
|
415
|
+
_items.append([x, y])
|
|
416
|
+
return self.__class__(_items)
|
|
417
|
+
|
|
418
|
+
def set_appends(self, appends):
|
|
419
|
+
"""
|
|
420
|
+
Set the attributes that should be appended to the Collection.
|
|
421
|
+
|
|
422
|
+
:rtype: list
|
|
423
|
+
"""
|
|
424
|
+
self.__appends__ += appends
|
|
425
|
+
return self
|
|
426
|
+
|
|
427
|
+
def _get_value(self, key):
|
|
428
|
+
if not key:
|
|
429
|
+
return None
|
|
430
|
+
|
|
431
|
+
items = []
|
|
432
|
+
for item in self:
|
|
433
|
+
if isinstance(key, str):
|
|
434
|
+
if hasattr(item, key) or (key in item):
|
|
435
|
+
items.append(getattr(item, key, item[key]))
|
|
436
|
+
elif callable(key):
|
|
437
|
+
result = key(item)
|
|
438
|
+
if result:
|
|
439
|
+
items.append(result)
|
|
440
|
+
return items
|
|
441
|
+
|
|
442
|
+
def _data_get(self, item, key, default=None):
|
|
443
|
+
try:
|
|
444
|
+
if isinstance(item, (list, tuple)):
|
|
445
|
+
item = item[key]
|
|
446
|
+
elif isinstance(item, (dict, Dotty)):
|
|
447
|
+
item = data_get(item, key, default)
|
|
448
|
+
elif isinstance(item, object):
|
|
449
|
+
item = getattr(item, key)
|
|
450
|
+
except (IndexError, AttributeError, KeyError, TypeError):
|
|
451
|
+
return self._value(default)
|
|
452
|
+
|
|
453
|
+
return item
|
|
454
|
+
|
|
455
|
+
def _value(self, value):
|
|
456
|
+
if callable(value):
|
|
457
|
+
return value()
|
|
458
|
+
return value
|
|
459
|
+
|
|
460
|
+
def _check_is_callable(self, callback, raise_exception=True):
|
|
461
|
+
if not callable(callback):
|
|
462
|
+
if not raise_exception:
|
|
463
|
+
return False
|
|
464
|
+
raise ValueError("The 'callback' should be a function")
|
|
465
|
+
return True
|
|
466
|
+
|
|
467
|
+
def _make_comparison(self, a, b, op):
|
|
468
|
+
operators = {
|
|
469
|
+
"<": operator.lt,
|
|
470
|
+
"<=": operator.le,
|
|
471
|
+
"==": operator.eq,
|
|
472
|
+
"!=": operator.ne,
|
|
473
|
+
">": operator.gt,
|
|
474
|
+
">=": operator.ge,
|
|
475
|
+
}
|
|
476
|
+
return operators[op](a, b)
|
|
477
|
+
|
|
478
|
+
def __iter__(self):
|
|
479
|
+
for item in self._items:
|
|
480
|
+
yield item
|
|
481
|
+
|
|
482
|
+
def __eq__(self, other):
|
|
483
|
+
if isinstance(other, Collection):
|
|
484
|
+
return other == other.all()
|
|
485
|
+
return other == self._items
|
|
486
|
+
|
|
487
|
+
def __getitem__(self, item):
|
|
488
|
+
if isinstance(item, slice):
|
|
489
|
+
return self.__class__(self._items[item])
|
|
490
|
+
|
|
491
|
+
return self._items[item]
|
|
492
|
+
|
|
493
|
+
def __setitem__(self, key, value):
|
|
494
|
+
self._items[key] = value
|
|
495
|
+
|
|
496
|
+
def __delitem__(self, key):
|
|
497
|
+
del self._items[key]
|
|
498
|
+
|
|
499
|
+
def __ne__(self, other):
|
|
500
|
+
other = self.__get_items(other)
|
|
501
|
+
return other != self._items
|
|
502
|
+
|
|
503
|
+
def __len__(self):
|
|
504
|
+
return len(self._items)
|
|
505
|
+
|
|
506
|
+
def __le__(self, other):
|
|
507
|
+
other = self.__get_items(other)
|
|
508
|
+
return self._items <= other
|
|
509
|
+
|
|
510
|
+
def __lt__(self, other):
|
|
511
|
+
other = self.__get_items(other)
|
|
512
|
+
return self._items < other
|
|
513
|
+
|
|
514
|
+
def __ge__(self, other):
|
|
515
|
+
other = self.__get_items(other)
|
|
516
|
+
return self._items >= other
|
|
517
|
+
|
|
518
|
+
def __gt__(self, other):
|
|
519
|
+
other = self.__get_items(other)
|
|
520
|
+
return self._items > other
|
|
521
|
+
|
|
522
|
+
@classmethod
|
|
523
|
+
def __get_items(cls, items):
|
|
524
|
+
if isinstance(items, Collection):
|
|
525
|
+
items = items.all()
|
|
526
|
+
|
|
527
|
+
return items
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def collect(iterable):
|
|
531
|
+
"""Transform an iterable into a collection."""
|
|
532
|
+
return Collection(iterable)
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def flatten(iterable):
|
|
536
|
+
"""Flatten all sub-iterables of an iterable structure (recursively)."""
|
|
537
|
+
flat_list = []
|
|
538
|
+
for item in iterable:
|
|
539
|
+
if isinstance(item, list):
|
|
540
|
+
for subitem in flatten(item):
|
|
541
|
+
flat_list.append(subitem)
|
|
542
|
+
else:
|
|
543
|
+
flat_list.append(item)
|
|
544
|
+
|
|
545
|
+
return flat_list
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
class HasColoredOutput:
|
|
2
|
+
"""Add level-colored output print functions to a class."""
|
|
3
|
+
|
|
4
|
+
def success(self, message):
|
|
5
|
+
print("\033[92m {0} \033[0m".format(message))
|
|
6
|
+
|
|
7
|
+
def warning(self, message):
|
|
8
|
+
print("\033[93m {0} \033[0m".format(message))
|
|
9
|
+
|
|
10
|
+
def danger(self, message):
|
|
11
|
+
print("\033[91m {0} \033[0m".format(message))
|
|
12
|
+
|
|
13
|
+
def info(self, message):
|
|
14
|
+
return self.success(message)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AddCommandColors:
|
|
18
|
+
"""The default style set used by Cleo is defined here:
|
|
19
|
+
https://github.com/sdispater/clikit/blob/master/src/clikit/formatter/default_style_set.py
|
|
20
|
+
This mixin add method helper to output errors and warnings.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def error(self, text):
|
|
24
|
+
"""
|
|
25
|
+
Write a string as information output.
|
|
26
|
+
|
|
27
|
+
:param text: The line to write
|
|
28
|
+
:type text: str
|
|
29
|
+
"""
|
|
30
|
+
self.line(text, "error")
|
|
31
|
+
|
|
32
|
+
def warning(self, text):
|
|
33
|
+
"""
|
|
34
|
+
Write a string as information output.
|
|
35
|
+
|
|
36
|
+
:param text: The line to write
|
|
37
|
+
:type text: str
|
|
38
|
+
"""
|
|
39
|
+
self.line(text, "c2")
|