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.
Files changed (76) hide show
  1. fastapi_startkit/__init__.py +3 -0
  2. fastapi_startkit/application.py +40 -0
  3. fastapi_startkit/configuration/Configuration.py +80 -0
  4. fastapi_startkit/configuration/__init__.py +2 -0
  5. fastapi_startkit/configuration/helpers.py +5 -0
  6. fastapi_startkit/configuration/providers/ConfigurationProvider.py +16 -0
  7. fastapi_startkit/configuration/providers/__init__.py +1 -0
  8. fastapi_startkit/container/__init__.py +1 -0
  9. fastapi_startkit/container/container.py +494 -0
  10. fastapi_startkit/environment/environment.py +76 -0
  11. fastapi_startkit/exceptions/DD.py +38 -0
  12. fastapi_startkit/exceptions/ExceptionHandler.py +76 -0
  13. fastapi_startkit/exceptions/__init__.py +38 -0
  14. fastapi_startkit/exceptions/exceptionite/__init__.py +0 -0
  15. fastapi_startkit/exceptions/exceptionite/blocks.py +101 -0
  16. fastapi_startkit/exceptions/exceptionite/controllers.py +13 -0
  17. fastapi_startkit/exceptions/exceptionite/solutions.py +66 -0
  18. fastapi_startkit/exceptions/exceptionite/tabs.py +19 -0
  19. fastapi_startkit/exceptions/exceptions.py +218 -0
  20. fastapi_startkit/exceptions/handlers/DumpExceptionHandler.py +104 -0
  21. fastapi_startkit/exceptions/handlers/HttpExceptionHandler.py +28 -0
  22. fastapi_startkit/exceptions/handlers/ModelNotFoundHandler.py +13 -0
  23. fastapi_startkit/facades/Auth.py +5 -0
  24. fastapi_startkit/facades/Auth.pyi +32 -0
  25. fastapi_startkit/facades/Broadcast.py +5 -0
  26. fastapi_startkit/facades/Cache.py +5 -0
  27. fastapi_startkit/facades/Config.py +5 -0
  28. fastapi_startkit/facades/Config.pyi +14 -0
  29. fastapi_startkit/facades/Dump.py +5 -0
  30. fastapi_startkit/facades/Dump.pyi +26 -0
  31. fastapi_startkit/facades/Facade.py +5 -0
  32. fastapi_startkit/facades/Gate.py +5 -0
  33. fastapi_startkit/facades/Gate.pyi +32 -0
  34. fastapi_startkit/facades/Hash.py +5 -0
  35. fastapi_startkit/facades/Hash.pyi +28 -0
  36. fastapi_startkit/facades/Loader.py +5 -0
  37. fastapi_startkit/facades/Loader.pyi +30 -0
  38. fastapi_startkit/facades/Mail.py +5 -0
  39. fastapi_startkit/facades/Mail.pyi +14 -0
  40. fastapi_startkit/facades/Notification.py +5 -0
  41. fastapi_startkit/facades/Notification.pyi +25 -0
  42. fastapi_startkit/facades/Queue.py +5 -0
  43. fastapi_startkit/facades/Queue.pyi +10 -0
  44. fastapi_startkit/facades/RateLimiter.py +5 -0
  45. fastapi_startkit/facades/RateLimiter.pyi +43 -0
  46. fastapi_startkit/facades/Request.py +5 -0
  47. fastapi_startkit/facades/Request.pyi +88 -0
  48. fastapi_startkit/facades/Response.py +5 -0
  49. fastapi_startkit/facades/Response.pyi +68 -0
  50. fastapi_startkit/facades/Session.py +5 -0
  51. fastapi_startkit/facades/Session.pyi +59 -0
  52. fastapi_startkit/facades/Storage.py +5 -0
  53. fastapi_startkit/facades/Storage.pyi +12 -0
  54. fastapi_startkit/facades/Url.py +5 -0
  55. fastapi_startkit/facades/Url.pyi +22 -0
  56. fastapi_startkit/facades/View.py +5 -0
  57. fastapi_startkit/facades/View.pyi +54 -0
  58. fastapi_startkit/facades/__init__.py +19 -0
  59. fastapi_startkit/loader/Loader.py +78 -0
  60. fastapi_startkit/loader/__init__.py +1 -0
  61. fastapi_startkit/providers/ConfigurationProvider.py +13 -0
  62. fastapi_startkit/providers/Provider.py +14 -0
  63. fastapi_startkit/providers/__init__.py +4 -0
  64. fastapi_startkit/utils/__init__.py +0 -0
  65. fastapi_startkit/utils/collections.py +545 -0
  66. fastapi_startkit/utils/console.py +39 -0
  67. fastapi_startkit/utils/data/mime.types +1863 -0
  68. fastapi_startkit/utils/filesystem.py +100 -0
  69. fastapi_startkit/utils/http.py +101 -0
  70. fastapi_startkit/utils/location.py +90 -0
  71. fastapi_startkit/utils/str.py +120 -0
  72. fastapi_startkit/utils/structures.py +97 -0
  73. fastapi_startkit/utils/time.py +58 -0
  74. fastapi_startkit-0.1.0.dist-info/METADATA +13 -0
  75. fastapi_startkit-0.1.0.dist-info/RECORD +76 -0
  76. 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")