danielutils 1.1.28__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 (287) hide show
  1. danielutils/__init__.py +50 -0
  2. danielutils/abstractions/__init__.py +3 -0
  3. danielutils/abstractions/db/__init__.py +10 -0
  4. danielutils/abstractions/db/database.py +206 -0
  5. danielutils/abstractions/db/database_definitions.py +219 -0
  6. danielutils/abstractions/db/database_exceptions.py +34 -0
  7. danielutils/abstractions/db/database_factory.py +70 -0
  8. danielutils/abstractions/db/database_initializer.py +261 -0
  9. danielutils/abstractions/db/database_models.py +213 -0
  10. danielutils/abstractions/db/dependencies.py +6 -0
  11. danielutils/abstractions/db/implementations/__init__.py +4 -0
  12. danielutils/abstractions/db/implementations/in_memory_database.py +365 -0
  13. danielutils/abstractions/db/implementations/persistent_in_memory_database.py +174 -0
  14. danielutils/abstractions/db/implementations/redis_database.py +403 -0
  15. danielutils/abstractions/db/implementations/sqlite_database.py +491 -0
  16. danielutils/abstractions/multiprogramming/__init__.py +3 -0
  17. danielutils/abstractions/multiprogramming/multi_id.py +26 -0
  18. danielutils/abstractions/multiprogramming/worker.py +104 -0
  19. danielutils/abstractions/multiprogramming/worker_pool.py +98 -0
  20. danielutils/abstractions/repl.py +125 -0
  21. danielutils/aliases.py +174 -0
  22. danielutils/async_/__init__.py +7 -0
  23. danielutils/async_/async_cmd.py +28 -0
  24. danielutils/async_/async_command.py +879 -0
  25. danielutils/async_/async_layered_command.py +125 -0
  26. danielutils/async_/async_retry_executor.py +86 -0
  27. danielutils/async_/async_worker_pool.py +110 -0
  28. danielutils/async_/time_strategy.py +73 -0
  29. danielutils/async_/utils.py +57 -0
  30. danielutils/better_builtins/__init__.py +3 -0
  31. danielutils/better_builtins/counter.py +48 -0
  32. danielutils/better_builtins/frange.py +266 -0
  33. danielutils/better_builtins/typed_builtins/__init__.py +4 -0
  34. danielutils/better_builtins/typed_builtins/factory.py +126 -0
  35. danielutils/better_builtins/typed_builtins/tdict.py +36 -0
  36. danielutils/better_builtins/typed_builtins/tlist.py +223 -0
  37. danielutils/better_builtins/typed_builtins/tset.py +67 -0
  38. danielutils/better_builtins/typed_builtins/ttuple.py +15 -0
  39. danielutils/colors.py +203 -0
  40. danielutils/context_managers/__init__.py +5 -0
  41. danielutils/context_managers/attr_context.py +40 -0
  42. danielutils/context_managers/multi_context.py +34 -0
  43. danielutils/context_managers/optional_context.py +33 -0
  44. danielutils/context_managers/state_context.py +25 -0
  45. danielutils/context_managers/temporary_file.py +108 -0
  46. danielutils/convenience.py +12 -0
  47. danielutils/conversions/__init__.py +2 -0
  48. danielutils/conversions/main_conversions.py +131 -0
  49. danielutils/conversions/specialized_conversions/__init__.py +2 -0
  50. danielutils/conversions/specialized_conversions/to_hex.py +25 -0
  51. danielutils/conversions/specialized_conversions/to_int.py +19 -0
  52. danielutils/custom_types.py +18 -0
  53. danielutils/data_structures/__init__.py +8 -0
  54. danielutils/data_structures/algorithms.py +52 -0
  55. danielutils/data_structures/comparer.py +47 -0
  56. danielutils/data_structures/default_dict.py +23 -0
  57. danielutils/data_structures/functions.py +35 -0
  58. danielutils/data_structures/graph/__init__.py +4 -0
  59. danielutils/data_structures/graph/binary_node.py +71 -0
  60. danielutils/data_structures/graph/graph.py +208 -0
  61. danielutils/data_structures/graph/multinode.py +101 -0
  62. danielutils/data_structures/graph/node.py +60 -0
  63. danielutils/data_structures/heap/__init__.py +3 -0
  64. danielutils/data_structures/heap/heap.py +119 -0
  65. danielutils/data_structures/heap/max_heap.py +18 -0
  66. danielutils/data_structures/heap/min_heap.py +18 -0
  67. danielutils/data_structures/queue/__init__.py +3 -0
  68. danielutils/data_structures/queue/atomic_queue.py +15 -0
  69. danielutils/data_structures/queue/priority_queue.py +110 -0
  70. danielutils/data_structures/queue/queue.py +92 -0
  71. danielutils/data_structures/stack.py +102 -0
  72. danielutils/data_structures/trees/__init__.py +2 -0
  73. danielutils/data_structures/trees/binary_syntax_tree.py +84 -0
  74. danielutils/data_structures/trees/binary_tree.py +63 -0
  75. danielutils/date.py +43 -0
  76. danielutils/date_time.py +23 -0
  77. danielutils/decorators/__init__.py +18 -0
  78. danielutils/decorators/atomic.py +45 -0
  79. danielutils/decorators/attach.py +61 -0
  80. danielutils/decorators/chain_decorators.py +39 -0
  81. danielutils/decorators/decorate_conditionally.py +32 -0
  82. danielutils/decorators/delay_call.py +47 -0
  83. danielutils/decorators/deprecate.py +46 -0
  84. danielutils/decorators/final.py +39 -0
  85. danielutils/decorators/limit_recursion.py +63 -0
  86. danielutils/decorators/memo.py +68 -0
  87. danielutils/decorators/normalize_decorator.py +55 -0
  88. danielutils/decorators/overload.py +204 -0
  89. danielutils/decorators/partially_implemented.py +32 -0
  90. danielutils/decorators/processify.py +74 -0
  91. danielutils/decorators/property.py +42 -0
  92. danielutils/decorators/singleton.py +59 -0
  93. danielutils/decorators/threadify.py +40 -0
  94. danielutils/decorators/timeout.py +82 -0
  95. danielutils/decorators/total_ordering.py +82 -0
  96. danielutils/decorators/validate.py +227 -0
  97. danielutils/exceptions.py +90 -0
  98. danielutils/functions/__init__.py +13 -0
  99. danielutils/functions/areoneof.py +47 -0
  100. danielutils/functions/check_foreach.py +39 -0
  101. danielutils/functions/factorial.py +24 -0
  102. danielutils/functions/flatten.py +33 -0
  103. danielutils/functions/foreach.py +20 -0
  104. danielutils/functions/isoftype.py +475 -0
  105. danielutils/functions/isoneof.py +71 -0
  106. danielutils/functions/multiloop.py +51 -0
  107. danielutils/functions/parallel_for.py +47 -0
  108. danielutils/functions/partition.py +45 -0
  109. danielutils/functions/powerset.py +31 -0
  110. danielutils/functions/subseteq.py +25 -0
  111. danielutils/functions/types_subseteq.py +51 -0
  112. danielutils/generators/__init__.py +3 -0
  113. danielutils/generators/conditional_generator.py +59 -0
  114. danielutils/generators/generator_from_stream.py +31 -0
  115. danielutils/generators/join_generators.py +109 -0
  116. danielutils/internet.py +92 -0
  117. danielutils/io_.py +451 -0
  118. danielutils/java/__init__.py +18 -0
  119. danielutils/java/interfaces/__init__.py +1 -0
  120. danielutils/java/interfaces/comparable.py +31 -0
  121. danielutils/java/java_interface.py +59 -0
  122. danielutils/logging_/__init__.py +2 -0
  123. danielutils/logging_/_impl/__init__.py +4 -0
  124. danielutils/logging_/_impl/builtin_impls/__init__.py +2 -0
  125. danielutils/logging_/_impl/builtin_impls/file_logger.py +35 -0
  126. danielutils/logging_/_impl/builtin_impls/print_logger.py +21 -0
  127. danielutils/logging_/_impl/log_level.py +13 -0
  128. danielutils/logging_/_impl/logger.py +109 -0
  129. danielutils/logging_/_impl/logger_strategy_impl_base.py +37 -0
  130. danielutils/logging_/utils.py +199 -0
  131. danielutils/lombok/__init__.py +1 -0
  132. danielutils/lombok/builder.py +68 -0
  133. danielutils/math_/__init__.py +2 -0
  134. danielutils/math_/constants.py +103 -0
  135. danielutils/math_/functions.py +34 -0
  136. danielutils/math_/math_print.py +52 -0
  137. danielutils/math_/math_symbols.py +125 -0
  138. danielutils/metaclasses/__init__.py +5 -0
  139. danielutils/metaclasses/atomic_class_meta.py +36 -0
  140. danielutils/metaclasses/implicit_data_deleter_meta.py +87 -0
  141. danielutils/metaclasses/instance_cache_meta.py +66 -0
  142. danielutils/metaclasses/interface.py +328 -0
  143. danielutils/metaclasses/overload_meta.py +48 -0
  144. danielutils/mock_/__init__.py +1 -0
  145. danielutils/mock_/mock_module.py +27 -0
  146. danielutils/path.py +55 -0
  147. danielutils/print_.py +123 -0
  148. danielutils/progress_bar/__init__.py +3 -0
  149. danielutils/progress_bar/ascii_progress_bar.py +161 -0
  150. danielutils/progress_bar/progress_bar.py +75 -0
  151. danielutils/progress_bar/progress_bar_pool.py +72 -0
  152. danielutils/protocols/__init__.py +3 -0
  153. danielutils/protocols/dictable.py +38 -0
  154. danielutils/protocols/evaluable.py +26 -0
  155. danielutils/protocols/serializable.py +51 -0
  156. danielutils/py.typed +0 -0
  157. danielutils/random_.py +47 -0
  158. danielutils/reflection/__init__.py +6 -0
  159. danielutils/reflection/declarations.py +288 -0
  160. danielutils/reflection/file/__init__.py +1 -0
  161. danielutils/reflection/file/file_reflection.py +85 -0
  162. danielutils/reflection/function/__init__.py +1 -0
  163. danielutils/reflection/function/function_reflections.py +152 -0
  164. danielutils/reflection/info_classes/__init__.py +6 -0
  165. danielutils/reflection/info_classes/argument_info.py +278 -0
  166. danielutils/reflection/info_classes/class_info.py +204 -0
  167. danielutils/reflection/info_classes/decorator_info.py +54 -0
  168. danielutils/reflection/info_classes/file_info.py +1180 -0
  169. danielutils/reflection/info_classes/folder_info.py +592 -0
  170. danielutils/reflection/info_classes/function_info.py +551 -0
  171. danielutils/reflection/info_classes/import_info.py +207 -0
  172. danielutils/reflection/interpreter/__init__.py +9 -0
  173. danielutils/reflection/interpreter/callstack.py +57 -0
  174. danielutils/reflection/interpreter/get_traceback.py +27 -0
  175. danielutils/reflection/interpreter/interpreter.py +41 -0
  176. danielutils/reflection/interpreter/is_debugging.py +13 -0
  177. danielutils/reflection/interpreter/os_.py +33 -0
  178. danielutils/reflection/interpreter/packages.py +33 -0
  179. danielutils/reflection/interpreter/python_version.py +33 -0
  180. danielutils/reflection/interpreter/signals.py +18 -0
  181. danielutils/reflection/interpreter/tracer.py +175 -0
  182. danielutils/reflection/module/__init__.py +3 -0
  183. danielutils/reflection/module/lazy_module.py +104 -0
  184. danielutils/reflection/module/module_reflections.py +34 -0
  185. danielutils/reflection/module/package_reflection.py +161 -0
  186. danielutils/retry_executor/__init__.py +3 -0
  187. danielutils/retry_executor/backoff_strategies/__init__.py +6 -0
  188. danielutils/retry_executor/backoff_strategies/constant_backoff.py +25 -0
  189. danielutils/retry_executor/backoff_strategies/exponential_backoff.py +26 -0
  190. danielutils/retry_executor/backoff_strategies/functional_backoff.py +29 -0
  191. danielutils/retry_executor/backoff_strategies/linear_backoff.py +23 -0
  192. danielutils/retry_executor/backoff_strategies/multiplicative_backoff.py +23 -0
  193. danielutils/retry_executor/backoff_strategies/no_backoff.py +17 -0
  194. danielutils/retry_executor/backoff_strategy.py +28 -0
  195. danielutils/retry_executor/retry_executor.py +55 -0
  196. danielutils/snippets/__init__.py +1 -0
  197. danielutils/snippets/try_get.py +28 -0
  198. danielutils/system/__init__.py +3 -0
  199. danielutils/system/independent.py +197 -0
  200. danielutils/system/layered_command.py +130 -0
  201. danielutils/system/windows/__init__.py +2 -0
  202. danielutils/system/windows/utils/__init__.py +1 -0
  203. danielutils/system/windows/utils/filetime.py +19 -0
  204. danielutils/system/windows/win32_ctime.py +183 -0
  205. danielutils/system/windows/windows.py +78 -0
  206. danielutils/testing/__init__.py +1 -0
  207. danielutils/testing/unittest_/__init__.py +2 -0
  208. danielutils/testing/unittest_/always_teardown_testcase.py +75 -0
  209. danielutils/testing/unittest_/auto_cwd_testcase.py +114 -0
  210. danielutils/text.py +169 -0
  211. danielutils/time.py +64 -0
  212. danielutils/tools/__init__.py +1 -0
  213. danielutils/tools/unittest_test_runner/__init__.py +9 -0
  214. danielutils/tools/unittest_test_runner/cli.py +70 -0
  215. danielutils/tools/unittest_test_runner/core/__init__.py +17 -0
  216. danielutils/tools/unittest_test_runner/core/discovery.py +322 -0
  217. danielutils/tools/unittest_test_runner/core/execution.py +244 -0
  218. danielutils/tools/unittest_test_runner/core/parser.py +163 -0
  219. danielutils/tools/unittest_test_runner/core/runner.py +561 -0
  220. danielutils/tools/unittest_test_runner/models.py +82 -0
  221. danielutils/university/__init__.py +7 -0
  222. danielutils/university/computability_and_complexity/__init__.py +2 -0
  223. danielutils/university/computability_and_complexity/discreate_finite_automaton.py +89 -0
  224. danielutils/university/computability_and_complexity/languages/__init__.py +0 -0
  225. danielutils/university/computability_and_complexity/languages/language.py +17 -0
  226. danielutils/university/computability_and_complexity/languages/sat.py +71 -0
  227. danielutils/university/computability_and_complexity/turing_machine.py +47 -0
  228. danielutils/university/databases/__init__.py +1 -0
  229. danielutils/university/databases/all.py +756 -0
  230. danielutils/university/image_proccesing/__init__.py +1 -0
  231. danielutils/university/image_proccesing/encoding/__init__.py +3 -0
  232. danielutils/university/image_proccesing/encoding/encoding.py +35 -0
  233. danielutils/university/image_proccesing/encoding/lossless/__init__.py +4 -0
  234. danielutils/university/image_proccesing/encoding/lossless/huffman.py +0 -0
  235. danielutils/university/image_proccesing/encoding/lossless/lossless_encoding.py +10 -0
  236. danielutils/university/image_proccesing/encoding/lossless/lzw.py +0 -0
  237. danielutils/university/image_proccesing/encoding/lossless/run_length.py +22 -0
  238. danielutils/university/image_proccesing/encoding/lossy/__init__.py +1 -0
  239. danielutils/university/image_proccesing/encoding/lossy/lossy_encoding.py +10 -0
  240. danielutils/university/image_proccesing/tansformations/__init__.py +0 -0
  241. danielutils/university/image_proccesing/tansformations/gaussian.py +0 -0
  242. danielutils/university/image_proccesing/tansformations/gradient.py +0 -0
  243. danielutils/university/image_proccesing/tansformations/hough.py +0 -0
  244. danielutils/university/image_proccesing/tansformations/laplacian.py +0 -0
  245. danielutils/university/image_proccesing/tansformations/transformation.py +11 -0
  246. danielutils/university/linear_algebra/__init__.py +1 -0
  247. danielutils/university/linear_algebra/matrix.py +404 -0
  248. danielutils/university/machine_learning/__init__.py +0 -0
  249. danielutils/university/machine_learning/activation_functions/__init__.py +2 -0
  250. danielutils/university/machine_learning/activation_functions/activation_function.py +11 -0
  251. danielutils/university/machine_learning/activation_functions/relu.py +11 -0
  252. danielutils/university/machine_learning/neuron.py +15 -0
  253. danielutils/university/oop/__init__.py +1 -0
  254. danielutils/university/oop/observer.py +31 -0
  255. danielutils/university/oop/strategy.py +9 -0
  256. danielutils/university/probability/__init__.py +7 -0
  257. danielutils/university/probability/conditional_variable/__init__.py +3 -0
  258. danielutils/university/probability/conditional_variable/conditional_variable.py +138 -0
  259. danielutils/university/probability/conditional_variable/continuous/__init__.py +0 -0
  260. danielutils/university/probability/conditional_variable/discrete/__init__.py +8 -0
  261. danielutils/university/probability/conditional_variable/discrete/bernoulli.py +38 -0
  262. danielutils/university/probability/conditional_variable/discrete/bernoulli_sum.py +31 -0
  263. danielutils/university/probability/conditional_variable/discrete/binomial.py +40 -0
  264. danielutils/university/probability/conditional_variable/discrete/conditional_from_discrete_probability_func.py +36 -0
  265. danielutils/university/probability/conditional_variable/discrete/discrete.py +42 -0
  266. danielutils/university/probability/conditional_variable/discrete/geometric.py +43 -0
  267. danielutils/university/probability/conditional_variable/discrete/poisson.py +32 -0
  268. danielutils/university/probability/conditional_variable/discrete/uniform.py +33 -0
  269. danielutils/university/probability/distributions.py +35 -0
  270. danielutils/university/probability/expressions/__init__.py +2 -0
  271. danielutils/university/probability/expressions/accumulation_expression.py +291 -0
  272. danielutils/university/probability/expressions/probability_expression.py +110 -0
  273. danielutils/university/probability/funcs/__init__.py +4 -0
  274. danielutils/university/probability/funcs/covariance.py +12 -0
  275. danielutils/university/probability/funcs/expected_value.py +41 -0
  276. danielutils/university/probability/funcs/probability_function.py +14 -0
  277. danielutils/university/probability/funcs/variance.py +17 -0
  278. danielutils/university/probability/operator.py +79 -0
  279. danielutils/university/probability/protocols.py +32 -0
  280. danielutils/university/probability/supp.py +101 -0
  281. danielutils/university/probability/transformation.py +44 -0
  282. danielutils/versioned_imports.py +31 -0
  283. danielutils-1.1.28.dist-info/METADATA +390 -0
  284. danielutils-1.1.28.dist-info/RECORD +287 -0
  285. danielutils-1.1.28.dist-info/WHEEL +5 -0
  286. danielutils-1.1.28.dist-info/licenses/LICENSE +21 -0
  287. danielutils-1.1.28.dist-info/top_level.txt +1 -0
@@ -0,0 +1,266 @@
1
+ import math
2
+ import decimal
3
+ import logging
4
+ from typing import Callable, Optional, Iterator, Sequence, overload, Union
5
+ from ..logging_.utils import get_logger
6
+ logger = get_logger(__name__)
7
+
8
+
9
+ class frange(Sequence[float]):
10
+ """This class is the same like the builtin range but with float values
11
+ """
12
+
13
+ @staticmethod
14
+ def from_range(r: range) -> 'frange':
15
+ """will "downcast" `range` to `frange` correctly"""
16
+ return frange(r.start, r.stop, r.step)
17
+
18
+ @staticmethod
19
+ def _is_int(n: Union[int, float]) -> bool:
20
+ if isinstance(n, int):
21
+ return True
22
+
23
+ return n.is_integer()
24
+
25
+ @staticmethod
26
+ def _lcm_int(a: int, b: int) -> int:
27
+ if hasattr(math, "lcm"):
28
+ return math.lcm(a, b)
29
+ return abs(a * b) // math.gcd(a, b)
30
+
31
+ @staticmethod
32
+ def _lcm_float(a: float, b: float) -> float:
33
+ prec = min(5, max(decimal.getcontext().prec, 10))
34
+ a = round(a, prec)
35
+ b = round(b, prec)
36
+ return frange._lcm_int(int(a * 10 ** prec), int(b * 10 ** prec)) / 10 ** prec
37
+
38
+ @staticmethod
39
+ def _find_min_step(s1: float, s2: float) -> float:
40
+ """
41
+ returns the minimum LCM for two step values
42
+ Args:
43
+ s1 (float): first step value:
44
+ s2 (float): second step value:
45
+
46
+ Returns:
47
+ float: minimum LCM
48
+ """
49
+ M = max(s1, s2)
50
+ m = min(s1, s2)
51
+ if float.is_integer(M / m):
52
+ return M
53
+ return frange._lcm_float(s1, s2)
54
+
55
+ def __init__(self, start: float, stop: Optional[float] = None,
56
+ step: float = 1, round_method: Callable[[float], float] = lambda f: round(f, 3)):
57
+ logger.debug("Initializing frange with start=%s, stop=%s, step=%s", start, stop, step)
58
+ if stop is None:
59
+ stop = start
60
+ start = 0
61
+ self.start = start
62
+ self.stop = stop
63
+ self.step = step
64
+ self.method = round_method
65
+ logger.debug("frange initialized: start=%s, stop=%s, step=%s", self.start, self.stop, self.step)
66
+
67
+ @overload
68
+ def __getitem__(self, index: int) -> float:
69
+ ...
70
+
71
+ @overload
72
+ def __getitem__(self, index: slice) -> 'frange':
73
+ ...
74
+
75
+ def __getitem__(self, index: Union[float, slice]) -> Union[float, 'frange']:
76
+ logger.debug("Getting item at index %s from frange", index)
77
+ if isinstance(index, slice):
78
+ logger.debug("Processing slice: start=%s, stop=%s, step=%s", index.start, index.stop, index.step)
79
+ index = slice(
80
+ index.start if index.start is not None else 0,
81
+ index.stop if index.stop is not None else len(self),
82
+ index.step if index.step is not None else 1,
83
+ )
84
+ if index.step > 0:
85
+ step = self.step * index.step
86
+ start = self.start + step * index.start
87
+ stop = self.start + step * index.stop
88
+ logger.debug("Creating new frange from slice: start=%s, stop=%s, step=%s", start, stop, step)
89
+ return frange(start, stop, step)
90
+ s = slice(index.start, index.stop, abs(index.step))
91
+ logger.debug("Reversing slice result")
92
+ return reversed(self[s])
93
+ if index < 0:
94
+ logger.error("Negative index %s not allowed in frange", index)
95
+ raise ValueError(f"At {self.__class__.__qualname__}.__getitem__ 'index' must be a positive integer")
96
+ result = self.start + self.step * index
97
+ logger.debug("Returning value %s for index %s", result, index)
98
+ return result
99
+
100
+ def __reversed__(self) -> 'frange':
101
+ return frange(self.stop - 1, self.start - 1, -self.step)
102
+
103
+ def __eq__(self, other):
104
+ if not isinstance(other, frange):
105
+ raise NotImplementedError
106
+ return self.start == other.start and self.stop == other.stop and self.step == other.step
107
+
108
+ def __iter__(self) -> Iterator[float]:
109
+ logger.debug("Starting iteration over frange: start=%s, stop=%s, step=%s", self.start, self.stop, self.step)
110
+ if self.stop < self.start and self.step > 0:
111
+ logger.debug("Empty range: stop < start with positive step")
112
+ return
113
+ if self.start > self.stop and self.step > 0:
114
+ logger.debug("Empty range: start > stop with positive step")
115
+ return
116
+ if abs(self.stop - self.start) < abs(self.step):
117
+ logger.debug("Empty range: step larger than range")
118
+ return
119
+ if self.stop > 0 and self.step < 0:
120
+ logger.debug("Empty range: positive stop with negative step")
121
+ return
122
+ if self.stop < 0 and self.step > 0:
123
+ logger.debug("Empty range: negative stop with positive step")
124
+ return
125
+
126
+ cur = self.start
127
+ count = 0
128
+ while (cur < self.stop and self.step > 0) or (cur > self.stop and self.step < 0):
129
+ yield self.method(cur)
130
+ cur += self.step
131
+ count += 1
132
+ logger.debug("Iteration completed, yielded %s values", count)
133
+
134
+ def __len__(self) -> int:
135
+ if self.stop in {float("inf"), -float("inf")}:
136
+ return float("inf")
137
+ return int(abs(self.stop - self.start) // abs(self.step))
138
+
139
+ def __str__(self) -> str:
140
+ return repr(self)
141
+
142
+ def __repr__(self):
143
+ return f"{self.__class__.__name__}({self.start}, {self.stop}, {self.step})"
144
+
145
+ def __contains__(self, item):
146
+ if item < self.start:
147
+ return False
148
+ if item >= self.stop:
149
+ return False
150
+
151
+ if frange._is_int(self.step):
152
+ if not frange._is_int(item):
153
+ return False
154
+
155
+ return item / self.step - item // self.step == 0
156
+
157
+ @property
158
+ def is_finite(self) -> bool:
159
+ """
160
+ Returns `True` if the range is finite
161
+ inverse if `is_infinite`
162
+ Returns:
163
+ bool
164
+ """
165
+ if self.stop in (float("inf"), float("-inf")):
166
+ return False
167
+ if self.start in (float("inf"), float("-inf")):
168
+ return False
169
+ try:
170
+ return len(self) != float("inf")
171
+ except TypeError:
172
+ return False
173
+
174
+ @property
175
+ def is_infinite(self) -> bool:
176
+ """
177
+ Returns `True` if the range is infinite
178
+ inverse if `is_finite`
179
+ Returns:
180
+ bool
181
+ """
182
+ return not self.is_finite
183
+
184
+ def normalize(self) -> 'frange':
185
+ """
186
+ will normalize the `frange` object
187
+ Returns:
188
+ frange
189
+ """
190
+ return frange(self.start / self.step, self.stop / self.step, 1)
191
+
192
+ def intersect(self, other: 'frange') -> 'frange':
193
+ logger.debug("Computing intersection of frange %s with %s", self, other)
194
+ if not isinstance(other, frange):
195
+ logger.error("intersect only accepts frange objects, got %s", type(other))
196
+ raise ValueError("frange.intercept only accepts frange objects")
197
+ a, b = self.normalize(), other.normalize()
198
+ start1, stop1 = a.start, a.stop
199
+ start2, stop2 = b.start, b.stop
200
+ remainder1, remainder2 = start1 - int(start1), start2 - int(start2)
201
+ start = max(self.start, other.start)
202
+ stop = min(self.stop, other.stop)
203
+ logger.debug("Normalized ranges: a=%s, b=%s, remainders: %s, %s", a, b, remainder1, remainder2)
204
+ if remainder1 == remainder2:
205
+ min_step = self._find_min_step(self.step, other.step)
206
+ logger.debug("Remainders match, min_step=%s", min_step)
207
+ if stop1 == float("inf") or stop2 == float("inf"):
208
+ logger.debug("One range is infinite, returning infinite result")
209
+ return frange(start, float("inf"), min_step)
210
+ logger.debug("Returning finite intersection: start=%s, stop=%s, step=%s", start, stop, min_step)
211
+ return frange(start, stop, min_step)
212
+ # find k; start1 + remainder1*k == start2 +remainder2*k
213
+ k = (start1 - start2) / (remainder2 - remainder1)
214
+ logger.debug("Computing k=%s for remainder intersection", k)
215
+ if k <= 0:
216
+ logger.debug("k <= 0, returning empty range")
217
+ return frange(0)
218
+ if stop1 == float("inf") or stop2 == float("inf"):
219
+ logger.error("Infinite range intersection not implemented")
220
+ raise NotImplementedError("this part is not implemented yet. one has inf")
221
+ logger.error("Complex remainder intersection not implemented")
222
+ raise NotImplementedError("this part is not implemented yet")
223
+
224
+
225
+ class frange_iterator(Iterator[float]):
226
+ def __init__(self, obj: frange):
227
+ self.r = obj
228
+
229
+ def __next__(self):
230
+ if self.r.stop < self.r.start:
231
+ return
232
+ if self.r.start > self.r.stop:
233
+ return
234
+ if abs(self.r.stop - self.r.start) < abs(self.r.step):
235
+ return
236
+ if self.r.stop > 0 and self.r.step < 0:
237
+ return
238
+ if self.r.stop < 0 and self.r.step > 0:
239
+ return
240
+
241
+ cur = self.r.start
242
+ while cur < self.r.stop:
243
+ yield self.r.method(cur)
244
+ cur += self.r.step
245
+
246
+ def __iter__(self):
247
+ return self
248
+
249
+
250
+ class brange(frange):
251
+ """like frange but with tqdm
252
+ """
253
+
254
+ def __iter__(self):
255
+ itr = super().__iter__()
256
+ try:
257
+ from tqdm import tqdm # type:ignore # pylint: disable=import-error
258
+ return iter(tqdm(itr, desc=f"{self}", total=len(self)))
259
+ except:
260
+ return itr
261
+
262
+
263
+ __all__ = [
264
+ "frange",
265
+ "brange"
266
+ ]
@@ -0,0 +1,4 @@
1
+ from .tlist import *
2
+ from .tdict import *
3
+ from .tset import *
4
+ from .ttuple import *
@@ -0,0 +1,126 @@
1
+ import types
2
+ from abc import abstractmethod
3
+ from typing import Any, Iterable, List as List, Set as Set, Dict as Dict, Tuple as Tuple
4
+ from ...functions import types_subseteq, isoftype
5
+ from ...reflection import get_caller_name, get_python_version
6
+
7
+ if get_python_version() >= (3, 9):
8
+ from builtins import list as List, set as Set, dict as Dict, tuple as Tuple # type:ignore
9
+ # needed for python 3.8
10
+ class_to_type = {
11
+ list: List,
12
+ set: Set,
13
+ dict: Dict,
14
+ Tuple: Tuple,
15
+ }
16
+
17
+
18
+ def create_typed_class(name: str, fallback_class: type = object) -> type:
19
+ """will create a base class to inherit from which will enable enforcing runtime type safety.
20
+
21
+ ### The following functions are added for use:
22
+
23
+ * get_params()->tuple which return the supplied type hins from the generic creation of the class
24
+ * subscribable_init(self,*args,**kwargs) which is the new "__init__"
25
+ * on_call(self,*args,**kwargs) which is the new "__call__"
26
+
27
+ Args:
28
+ name (str): name of class (can be the same of the derived?)
29
+ fallback_class (type): the fallback class to handle __str__, __repr__
30
+ and such. e.g for a typed version of list ('tlist') the fallback class would be 'list'
31
+ bases (tuple, optional): another additional bases that this class should inherit from. Defaults to None.
32
+
33
+ Returns:
34
+ type: new class type
35
+ """
36
+ cls = types.new_class(name, (fallback_class,), {})
37
+
38
+ def __class_getitem__(cls, item: type):
39
+ return cls(item)
40
+
41
+ def __instancecheck__(self, instance: Any) -> bool:
42
+ if isinstance(instance, cls):
43
+ return types_subseteq(
44
+ instance.get_params(), # type:ignore
45
+ self.get_params()
46
+ )
47
+
48
+ return isoftype(
49
+ instance,
50
+ class_to_type[fallback_class][self.get_params()] # type:ignore
51
+ )
52
+
53
+ def __init__(self, item) -> None:
54
+ if not get_caller_name(1) == "__class_getitem__":
55
+ raise ValueError(
56
+ f"Can't instantiate {self.__class__.__name__} without a supplied type")
57
+ fallback_class.__init__(self) # type: ignore
58
+ # pylint: disable=protected-access
59
+ self._params = (item,) if not isinstance(
60
+ item, Iterable) else tuple(item)
61
+ self._inited = False
62
+
63
+ def subscribable_init(self, *args, **kwargs) -> None:
64
+ raise NotImplementedError(
65
+ "'subscribable_init(self,*args,**kwargs) is an abstract method that must be implemented.")
66
+
67
+ def on_call(self, *args, **kwargs) -> Any:
68
+ raise NotImplementedError(
69
+ "'on_call(self,*args,**kwargs) is an abstract method that must be implemented.")
70
+
71
+ def __call__(self, *args, **kwargs):
72
+ # pylint: disable=protected-access
73
+ if not self._inited:
74
+ self_inited = True
75
+ # to work with overloading
76
+ type(self).subscribable_init(self, *args, **kwargs)
77
+ # self.subscribable_init(*args, **kwargs)
78
+ return self
79
+ return self.on_call(self, *args, **kwargs)
80
+
81
+ def __str__(self) -> str:
82
+ return repr(self)
83
+
84
+ def __repr__(self) -> str:
85
+ return f"{name} {fallback_class.__repr__(self)}" # type:ignore
86
+
87
+ def get_params(self) -> tuple:
88
+ # pylint: disable=protected-access
89
+ return self._params
90
+
91
+ def __eq__(self, other: Any) -> bool:
92
+ if isoftype(other, cls): # type:ignore
93
+ return self.get_params() == other.get_params()
94
+ return False
95
+
96
+ # pylint: disable=unused-argument
97
+ def __init_subclass__(subcls, **kwargs):
98
+ if hasattr(subcls, "__init__"):
99
+ curr_init = getattr(subcls, "__init__")
100
+ if curr_init is not __init__:
101
+ raise ValueError(
102
+ "Can't override '__init__', use 'subscribable_init(self,*args,**kwargs)' instead.")
103
+
104
+ for func, tup in [
105
+ (__class_getitem__, ["__class_getitem__", classmethod]),
106
+ (__instancecheck__, ["__instancecheck__", None]),
107
+ (subscribable_init, ["subscribable_init", abstractmethod]),
108
+ (__init__, ["__init__", None]),
109
+ (__call__, ["__call__", None]),
110
+ (__str__, ["__str__", None]),
111
+ (__repr__, ["__repr__", None]),
112
+ (__eq__, ["__eq__", None]),
113
+ (get_params, ["get_params", None]),
114
+ (__init_subclass__, ["__init_subclass__", classmethod])
115
+ ]:
116
+ name, decorator = tup # type:ignore
117
+ if decorator is not None: # type:ignore
118
+ func = decorator(func) # type:ignore
119
+ setattr(cls, name, func)
120
+
121
+ return cls
122
+
123
+
124
+ __all__ = [
125
+ "create_typed_class"
126
+ ]
@@ -0,0 +1,36 @@
1
+ from typing import Generic, TypeVar
2
+ from .factory import create_typed_class
3
+ from ...functions import isoftype
4
+ parent: type = create_typed_class("tdict", dict)
5
+ K = TypeVar("K")
6
+ V = TypeVar("V")
7
+
8
+
9
+ class tdict(parent, Generic[K, V]):
10
+ """like 'dict' but with runtime type safety
11
+ """
12
+
13
+ def subscribable_init(self, *args, **kwargs): # pylint: disable=unused-argument
14
+ """the "real" __init__ function
15
+ """
16
+ print(self.get_params())
17
+
18
+ @property
19
+ def _key_t(self):
20
+ return self.get_params()[0]
21
+
22
+ @property
23
+ def _value_t(self):
24
+ return self.get_params()[1]
25
+
26
+ def __setitem__(self, key: K, value: V):
27
+ if not isoftype(key, self._key_t): # type:ignore
28
+ raise TypeError("")
29
+ if not isoftype(value, self._value_t): # type:ignore
30
+ raise TypeError("")
31
+ dict.__setitem__(self, key, value)
32
+
33
+
34
+ __all__ = [
35
+ "tdict"
36
+ ]
@@ -0,0 +1,223 @@
1
+ from typing import Generic, TypeVar, Any, Union, Iterable, SupportsIndex
2
+ # from ...metaclasses.OverloadMeta import OverloadMeta
3
+ from ...functions import isoftype, types_subseteq
4
+ # from ...reflection import get_caller_name
5
+ from ...decorators import overload
6
+ from .factory import create_typed_class
7
+ T = TypeVar("T", bound=Any)
8
+
9
+
10
+ # class ptlist(List[T], Generic[T]):
11
+ # """like 'list' but with runtime type safety
12
+ # """
13
+
14
+ # @classmethod
15
+ # def __class_getitem__(cls, item: type):
16
+ # return cls(item)
17
+
18
+ # def __instancecheck__(self, instance: Any) -> bool:
19
+ # if isinstance(instance, ptlist):
20
+ # return types_subseteq(instance._params, self._params)
21
+ # return isoftype(instance, List[self._params]) # type: ignore
22
+
23
+ # def __init__(self, item) -> None:
24
+ # if not get_caller_name(0) == "__class_getitem__":
25
+ # raise ValueError(
26
+ # f"Can't instantiate {self.__class__.__name__} without a supplied type")
27
+ # list.__init__(self)
28
+ # self._params = item
29
+
30
+ # def __call__(self, *args, **kwargs):
31
+ # # to work with the overloading
32
+ # type(self)._additional_init(self, *args, **kwargs)
33
+ # return self
34
+
35
+ # @OverloadMeta.overload
36
+ # def _additional_init(self, lst: Union[list, "ptlist"]):
37
+ # self.extend(lst)
38
+
39
+ # @_additional_init.overload
40
+ # def _init_empty(self) -> None:
41
+ # """inits an empty tlist
42
+ # """
43
+
44
+ # @_additional_init.overload
45
+ # def _init_from_set_and_dict(self, obj: Union[set, dict]):
46
+ # """inits the tlist from a set or a dict object
47
+ # Args:
48
+ # obj (set | dict): the set or dict instance
49
+ # """
50
+ # self.extend(list(obj))
51
+
52
+ # def extend(self, other: Iterable) -> None:
53
+ # """extends a tlist from a list or a tlist
54
+
55
+ # Args:
56
+ # other (list | tlist): the list to extend from
57
+
58
+ # Returns:
59
+ # tlist: Self
60
+ # """
61
+ # if isinstance(other, ptlist):
62
+ # if types_subseteq(other._params, self._params):
63
+ # list.extend(self, other)
64
+ # return
65
+ # for value in other:
66
+ # self.append(value)
67
+
68
+ # def append(self, value: T) -> None:
69
+ # """appends a value to the list
70
+
71
+ # Args:
72
+ # value (T): the value to append
73
+
74
+ # Raises:
75
+ # ValueError: if a value is not of the correct type
76
+
77
+ # Returns:
78
+ # tlist: self
79
+ # """
80
+ # if not isoftype(value, self._params):
81
+ # raise TypeError(
82
+ # f"In tlist.append: values must be of type {self._params}, but '{value}' is of type {type(value)}")
83
+ # list.append(self, value)
84
+
85
+ # def __str__(self) -> str:
86
+ # return "tlist "+list.__str__(self)
87
+
88
+ # def __repr__(self) -> str:
89
+ # return "tlist "+list.__repr__(self)
90
+
91
+ # def __setitem__(self, index: SupportsIndex, value: T): # type:ignore
92
+ # if not isoftype(value, self._params):
93
+ # raise TypeError(
94
+ # "Can't add value to tlist because it is of the wrong type")
95
+ # list.__setitem__(self, index, value)
96
+
97
+ # def __eq__(self, other: Any) -> bool:
98
+ # if not isoftype(other, Union[ptlist, list]):
99
+ # return list.__eq__(self, other)
100
+ # if isinstance(other, ptlist):
101
+ # if self._params != other._params:
102
+ # return False
103
+ # if len(self) != len(other):
104
+ # return False
105
+ # for a, b in zip(iter(self), iter(other)):
106
+ # if a != b:
107
+ # return False
108
+ # return True
109
+
110
+ # def __add__(self, other: Any) -> "ptlist":
111
+ # if not isoftype(other, Union[ptlist, list]):
112
+ # raise NotImplementedError()
113
+
114
+ # # no need to check because the error handling
115
+ # # will be done inside extend so the error will
116
+ # # propagate up
117
+ # res = ptlist[self._params](self) # type:ignore
118
+ # res.extend(other)
119
+ # return res
120
+
121
+ # def __mul__(self, other: Any) -> "ptlist":
122
+ # if not isinstance(other, int):
123
+ # raise NotImplementedError()
124
+
125
+ # res = ptlist[self._params](self) # type:ignore
126
+ # for _ in range(other-1):
127
+ # res.extend(self)
128
+ # return res
129
+
130
+
131
+ parent: type = create_typed_class("tlist", list)
132
+
133
+
134
+ class tlist(parent, Generic[T]):
135
+ """like 'list' but with runtime type safety
136
+ """
137
+
138
+ def subscribable_init(self, *args, **kwargs):
139
+ """the "real" __init__ function
140
+ """
141
+ type(self)._additional_init(self, *args, **kwargs)
142
+
143
+ @overload # type:ignore
144
+ def _additional_init(self, lst: Union[list, "tlist"]):
145
+ self.extend(lst)
146
+
147
+ @_additional_init.overload
148
+ def _init_empty(self) -> None:
149
+ """inits an empty tlist
150
+ """
151
+
152
+ @_additional_init.overload
153
+ def _init_from_set_and_dict(self, obj: Union[set, dict]):
154
+ """inits the tlist from a set or a dict object
155
+ Args:
156
+ obj (set | dict): the set or dict instance
157
+ """
158
+ self.extend(list(obj))
159
+
160
+ def extend(self, other: Iterable) -> None:
161
+ """extends a tlist from a list or a tlist
162
+
163
+ Args:
164
+ other (list | tlist): the list to extend from
165
+
166
+ Returns:
167
+ tlist: Self
168
+ """
169
+ if isinstance(other, tlist):
170
+ if types_subseteq(other.get_params(), self.get_params()):
171
+ list.extend(self, other)
172
+ return
173
+ for value in other:
174
+ self.append(value)
175
+
176
+ def append(self, value: T) -> None:
177
+ """appends a value to the list
178
+
179
+ Args:
180
+ value (T): the value to append
181
+
182
+ Raises:
183
+ ValueError: if a value is not of the correct type
184
+
185
+ Returns:
186
+ tlist: self
187
+ """
188
+ if not isoftype(value, self.get_params()[0]):
189
+ raise TypeError(
190
+ f"In tlist.append: values must be of type {self.get_params()[0]},"
191
+ " but '{value}' is of type {type(value)}")
192
+ list.append(self, value)
193
+
194
+ def __add__(self, other: Any) -> "tlist":
195
+ if not isoftype(other, Union[list, tlist]):
196
+ raise NotImplementedError()
197
+
198
+ # no need to check because the error handling
199
+ # will be done inside extend so the error will
200
+ # propagate up
201
+ res = tlist[self._params](self) # type:ignore
202
+ res.extend(other)
203
+ return res
204
+
205
+ def __mul__(self, other: Any) -> "tlist":
206
+ if not isinstance(other, int):
207
+ raise NotImplementedError()
208
+
209
+ res = tlist[self.get_params()[0]](self) # type:ignore
210
+ for _ in range(other-1):
211
+ res.extend(self)
212
+ return res
213
+
214
+ def __setitem__(self, index: SupportsIndex, value: T): # type:ignore
215
+ if not isoftype(value, self._params):
216
+ raise TypeError(
217
+ "Can't add value to tlist because it is of the wrong type")
218
+ list.__setitem__(self, index, value)
219
+
220
+
221
+ __all__ = [
222
+ "tlist"
223
+ ]