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,227 @@
1
+ import functools
2
+ import inspect
3
+ import logging
4
+ from typing import Callable, get_type_hints, cast, TypeVar, Union
5
+ from ..functions.isoftype import isoftype
6
+ from ..reflection import get_function_return_type
7
+ from ..exceptions import EmptyAnnotationException, \
8
+ InvalidDefaultValueException, ValidationException, InvalidReturnValueException
9
+ from ..versioned_imports import ParamSpec
10
+ from ..logging_.utils import get_logger
11
+
12
+ logger = get_logger(__name__)
13
+
14
+ T = TypeVar("T")
15
+ P = ParamSpec("P")
16
+ FuncT = Callable[P, T] # type:ignore
17
+
18
+
19
+ def validate(strict: Union[FuncT, bool] = True) -> FuncT:
20
+ """A decorator that validates the annotations and types of the arguments and return
21
+ value of a function.
22
+
23
+ * 'None' is allowed as default value for everything
24
+ * Because of their wide known use, generally accepted keywords 'self', 'cls', 'args', 'kwargs'
25
+ are not validated.
26
+
27
+ Args:
28
+ func (Callable): The function to be decorated.
29
+
30
+ Raises:
31
+ TypeError: if the decorated object is nto a Callable
32
+ EmptyAnnotationException: If an argument is not annotated.
33
+ InvalidDefaultValueException: If an argument's default value is not of the annotated type.
34
+ ValidationException: If an argument's value is not of the expected type.
35
+ InvalidReturnValueException: If the return value is not of the expected type.
36
+
37
+ Returns:
38
+ Callable: A wrapper function that performs the validation and calls the original function.
39
+ """
40
+ logger.debug("Creating validate decorator with strict=%s", strict)
41
+ if not isoftype(strict, Union[bool, Callable]):
42
+ logger.error("Invalid strict parameter type: %s", type(strict))
43
+ raise TypeError(
44
+ "the argument for validate must be a Callable or a boolean to mark strict use")
45
+
46
+ def deco(func: FuncT) -> FuncT:
47
+ logger.debug("Applying validate decorator to function %s", func.__name__)
48
+ SKIP_SET = {"self", "cls", "args", "kwargs"}
49
+ if not callable(func):
50
+ logger.error("Object %s is not callable", func)
51
+ raise TypeError(
52
+ "The validate decorator must only decorate a function")
53
+ func_name = f"{func.__module__}.{func.__qualname__}"
54
+ logger.debug("Validating function: %s", func_name)
55
+ # get the signature of the function
56
+ signature = inspect.signature(func)
57
+ for arg_name, arg_param in signature.parameters.items():
58
+ if arg_name not in SKIP_SET:
59
+ arg_type = arg_param.annotation
60
+ # check if an annotation is missing
61
+ if arg_type == inspect.Parameter.empty:
62
+ raise EmptyAnnotationException(
63
+ f"In {func_name}, argument '{arg_name}' is not annotated")
64
+
65
+ # check if the argument has a default value
66
+ default_value = signature.parameters[arg_name].default
67
+ if default_value != inspect.Parameter.empty:
68
+ # allow everything to be set to None as default
69
+ if default_value is None:
70
+ continue
71
+ # if it does, check the type of the default value
72
+ if not isoftype(default_value, arg_type):
73
+ raise InvalidDefaultValueException(
74
+ f"In {func_name}, argument '{arg_name}'s default value is annotated \
75
+ as {arg_type} but got '{default_value}' which is {type(default_value)}")
76
+
77
+ @functools.wraps(func)
78
+ def wrapper(*args, **kwargs):
79
+ """wrapper function for the type validating - will run on each call independently
80
+ """
81
+ nonlocal strict
82
+ strict = cast(bool, strict)
83
+ hints = None
84
+ # check all arguments
85
+ bound = signature.bind(*args, **kwargs)
86
+ for variable_name, variable_value in bound.arguments.items():
87
+ if variable_name in SKIP_SET:
88
+ continue
89
+ expected_type = func.__annotations__[variable_name]
90
+
91
+ if isinstance(expected_type, str):
92
+ # why does this even happen?
93
+ if hints is None:
94
+ hints = get_type_hints(func)
95
+ expected_type = hints[variable_name]
96
+
97
+ if not isoftype(variable_value, expected_type, strict=strict):
98
+ raise ValidationException(
99
+ f"In {func_name}, argument '{variable_name}' is annotated as "
100
+ f"{expected_type} but got '{variable_value}' which is {type(variable_value)}")
101
+
102
+ # call the function
103
+ result = func(*args, **kwargs)
104
+
105
+ # check the return type
106
+ return_type = get_function_return_type(func, signature)
107
+ if isinstance(return_type, str):
108
+ # why does this even happen?
109
+ return_type = get_type_hints(func)["return"]
110
+ if return_type is not type(None) and not isoftype(result, return_type):
111
+ raise InvalidReturnValueException(
112
+ f"In function {func_name}, the return type is annotated as "
113
+ f"{return_type} but got '{result}' which is {type(result)}")
114
+ return result
115
+
116
+ return wrapper
117
+
118
+ if callable(strict):
119
+ func = strict
120
+ strict = True
121
+ return deco(func)
122
+ return deco
123
+
124
+
125
+ # def validate(func: Callable) -> Callable:
126
+ # """A decorator that validates the annotations and types of the arguments and return
127
+ # value of a function.
128
+
129
+ # * 'None' is allowed as default value for everything
130
+ # * Because of their use in better_builtins, the generally accepted keywords 'self' and 'cls'
131
+ # are not validated to not break intellisense when using 'Any'
132
+
133
+ # Args:
134
+ # func (Callable): The function to be decorated.
135
+
136
+ # Raises:
137
+ # TypeError: if the decorated object is nto a Callable
138
+ # EmptyAnnotationException: If an argument is not annotated.
139
+ # InvalidDefaultValueException: If an argument's default value is not of the annotated type.
140
+ # ValidationException: If an argument's value is not of the expected type.
141
+ # InvalidReturnValueException: If the return value is not of the expected type.
142
+
143
+ # Returns:
144
+ # Callable: A wrapper function that performs the validation and calls the original function.
145
+ # """
146
+ # SKIP_SET = {"self", "cls"}
147
+ # if not isinstance(func, Callable):
148
+ # raise TypeError("The validate decorator must only decorate a function")
149
+ # func_name = f"{func.__module__}.{func.__qualname__}"
150
+ # # get the signature of the function
151
+ # signature = inspect.signature(func)
152
+ # for arg_name, arg_param in signature.parameters.items():
153
+ # if arg_name not in SKIP_SET:
154
+ # arg_type = arg_param.annotation
155
+ # # check if an annotation is missing
156
+ # if arg_type == inspect.Parameter.empty:
157
+ # raise EmptyAnnotationException(
158
+ # f"In {func_name}, argument '{arg_name}' is not annotated")
159
+
160
+ # # check if the argument has a default value
161
+ # default_value = signature.parameters[arg_name].default
162
+ # if default_value != inspect.Parameter.empty:
163
+ # # allow everything to be set to None as default
164
+ # if default_value is None:
165
+ # continue
166
+ # # if it does, check the type of the default value
167
+ # if not isoftype(default_value, arg_type):
168
+ # raise InvalidDefaultValueException(
169
+ # f"In {func_name}, argument '{arg_name}'s default value is annotated \
170
+ # as {arg_type} but got '{default_value}' which is {type(default_value)}")
171
+
172
+ # @functools.wraps(func)
173
+ # def wrapper(*args, **kwargs):
174
+ # """wrapper function for the type validating - will run on each call independently
175
+ # """
176
+ # hints = None
177
+ # # check all arguments
178
+ # bound = signature.bind(*args, **kwargs)
179
+ # for variable_name, variable_value in bound.arguments.items():
180
+ # if variable_name in SKIP_SET:
181
+ # continue
182
+ # expected_type = func.__annotations__[variable_name]
183
+
184
+ # if isinstance(expected_type, str):
185
+ # # why does this even happen?
186
+ # if hints is None:
187
+ # hints = get_type_hints(func)
188
+ # expected_type = hints[variable_name]
189
+
190
+ # if not isoftype(variable_value, expected_type):
191
+ # raise ValidationException(
192
+ # f"In {func_name}, argument '{variable_name}' is annotated as \
193
+ # {expected_type} but got '{variable_value}' which is {type(variable_value)}")
194
+
195
+ # # call the function
196
+ # result = func(*args, **kwargs)
197
+
198
+ # # check the return type
199
+ # return_type = type(None) if ("inspect._empty" in str(signature.return_annotation)
200
+ # or signature.return_annotation is None) else signature.return_annotation
201
+ # if isinstance(return_type, str):
202
+ # # why does this even happen?
203
+ # return_type = get_type_hints(func)["return"]
204
+ # if return_type is not type(None) and not isoftype(result, return_type):
205
+ # raise InvalidReturnValueException(
206
+ # f"In function {func_name}, the return type is annotated as "
207
+ # f"{return_type} but got '{result}' which is {type(result)}")
208
+ # return result
209
+ # return wrapper
210
+
211
+ # @validate # type:ignore
212
+ # def NotImplemented(func: Callable) -> Callable:
213
+ # """decorator to mark function as not implemented for development purposes
214
+
215
+ # Args:
216
+ # func (Callable): the function to decorate
217
+ # """
218
+ # @ functools.wraps(func)
219
+ # def wrapper(*args, **kwargs) -> Any:
220
+ # raise NotImplementedError(
221
+ # f"As marked by the developer {func.__module__}.{func.__qualname__} is not implemented yet..")
222
+ # return wrapper
223
+
224
+
225
+ __all__ = [
226
+ "validate"
227
+ ]
@@ -0,0 +1,90 @@
1
+
2
+ import logging
3
+
4
+ from .logging_.utils import get_logger
5
+
6
+ logger = get_logger(__name__)
7
+
8
+
9
+ class OverloadException(Exception):
10
+ """Base exception for overload decorator
11
+ """
12
+
13
+
14
+ class OverloadNotFound(OverloadException):
15
+ """Exception to raise if a function is called with certain
16
+ argument types but this function hasn't been overloaded with those types
17
+ """
18
+
19
+
20
+ class OverloadDuplication(OverloadException):
21
+ """
22
+ Exception to raise if a function is overloaded twice with same argument types
23
+ """
24
+
25
+
26
+ # class ValidationError(Exception):
27
+ # """_summary_
28
+
29
+ # Args:
30
+ # Exception (_type_): _description_
31
+
32
+ # Returns:
33
+ # _type_: _description_
34
+ # """
35
+
36
+
37
+ # class ValidationTypeError(ValidationError, TypeError):
38
+ # pass
39
+
40
+
41
+ # class ValidationReturnTypeError(ValidationError, TypeError):
42
+ # pass
43
+
44
+
45
+ # class ValidationValueError(ValidationError, ValueError):
46
+ # pass
47
+
48
+
49
+ # class ValidationDuplicationError(ValidationError):
50
+ # pass
51
+
52
+
53
+ class ValidationException(Exception):
54
+ """generic validation exception for validate decorator
55
+ """
56
+
57
+
58
+ class EmptyAnnotationException(ValidationException):
59
+ """exception for validate decorator to be used if a function needs to
60
+ be validated but has an empty annotation for one of the arguments
61
+ """
62
+
63
+
64
+ class InvalidDefaultValueException(ValidationException):
65
+ """exception for validate decorator to be used if a function has
66
+ a default value that doesn't conform to the annotated type
67
+ """
68
+
69
+
70
+ class InvalidReturnValueException(ValidationException):
71
+ """exception for validate decorator to be used if a function has
72
+ an annotated return value but the actual return value doesn't conform to it
73
+ """
74
+
75
+
76
+ class PrintCatchOne:
77
+ """a utility class to be used with a "with" block to print
78
+ any exception that happens inside of it rather than exiting the program
79
+ """
80
+
81
+ def __enter__(self):
82
+ return self
83
+
84
+ def __exit__(self, cls, instance, traceback):
85
+ if instance:
86
+ logger.error("Exception caught in PrintCatchOne: %s %s", cls, instance)
87
+ from .colors import error # pylint: disable=cyclic-import
88
+ error(f"{cls} {instance}")
89
+ return isinstance(instance, cls)
90
+ return False
@@ -0,0 +1,13 @@
1
+ from .isoftype import *
2
+ from .areoneof import *
3
+ from .check_foreach import *
4
+ from .types_subseteq import *
5
+ from .isoneof import *
6
+ from .powerset import *
7
+ from .multiloop import *
8
+ from .flatten import *
9
+ from .subseteq import *
10
+ from .parallel_for import *
11
+ from .foreach import *
12
+ from .factorial import *
13
+ from .partition import *
@@ -0,0 +1,47 @@
1
+ import logging
2
+ from typing import Sequence, Any, Union
3
+ from .isoneof import isoneof
4
+ from ..reflection import get_python_version
5
+ from ..logging_.utils import get_logger
6
+
7
+ logger = get_logger(__name__)
8
+ if get_python_version() < (3, 9):
9
+ from typing import List as List, Tuple as Tuple
10
+ else:
11
+ from builtins import list as List, tuple as Tuple # type:ignore
12
+
13
+
14
+ def areoneof(values: Sequence[Any], types: Union[List[type], Tuple[type]]) -> bool:
15
+ """performs 'isoneof(values[0],types) and ... and isoneof(values[...],types)'
16
+
17
+ Args:
18
+ values (Sequence[Any]): Sequence of values
19
+ types (Sequence[Type]): Sequence of types
20
+
21
+ Raises:
22
+ TypeError: if types is not a Sequence
23
+ TypeError: if values is not a Sequence
24
+
25
+ Returns:
26
+ bool: the result of the check
27
+ """
28
+ logger.debug("Checking if %s values are one of types: %s", len(values), types)
29
+ if not isinstance(types, Sequence):
30
+ logger.error("'types' parameter is not a Sequence")
31
+ raise TypeError("'types' must be of type Sequence")
32
+ if not isinstance(values, Sequence):
33
+ logger.error("'values' parameter is not a Sequence")
34
+ raise TypeError("'values' must be of type Sequence")
35
+
36
+ for i, v in enumerate(values):
37
+ if not isoneof(v, types):
38
+ logger.debug("Value at index %s (%s) is not one of the specified types", i, v)
39
+ return False
40
+
41
+ logger.debug("All values match one of the specified types")
42
+ return True
43
+
44
+
45
+ __all__ = [
46
+ "areoneof"
47
+ ]
@@ -0,0 +1,39 @@
1
+ import logging
2
+ from typing import Sequence, Any, Callable
3
+ from ..logging_.utils import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+
8
+ def check_foreach(values: Sequence[Any], condition: Callable[[Any], bool]) -> bool:
9
+ """
10
+ Check if a condition is true for all values in a sequence.
11
+
12
+ Args:
13
+ values (Sequence[Any]): Values to perform check on
14
+ condition (Callable[[Any], bool]): Condition to check on all values
15
+
16
+ Returns:
17
+ bool: returns True iff condition return True for all values individually
18
+ """
19
+ logger.debug("Checking condition on %s values", len(values))
20
+
21
+ if not isinstance(values, Sequence):
22
+ logger.warning("Values parameter is not a Sequence")
23
+ return False
24
+ if not callable(condition):
25
+ logger.warning("Condition parameter is not callable")
26
+ return False
27
+
28
+ for i, v in enumerate(values):
29
+ if not condition(v):
30
+ logger.debug("Condition failed at index %s with value: %s", i, v)
31
+ return False
32
+
33
+ logger.debug("All values passed the condition check")
34
+ return True
35
+
36
+
37
+ __all__ = [
38
+ "check_foreach"
39
+ ]
@@ -0,0 +1,24 @@
1
+ import logging
2
+ from ..logging_.utils import get_logger
3
+
4
+ logger = get_logger(__name__)
5
+
6
+
7
+ def factorial(n: int) -> int:
8
+ logger.info("Computing factorial of %s", n)
9
+ if n < 0:
10
+ logger.error("Factorial not defined for negative numbers: %s", n)
11
+ raise ValueError("Factorial not defined for negative numbers")
12
+ if n == 0 or n == 1:
13
+ return 1
14
+
15
+ res = 1
16
+ for i in range(2, n + 1):
17
+ res *= i
18
+
19
+ logger.info("Factorial of %s computed: %s", n, res)
20
+ return res
21
+
22
+ __all__ = [
23
+ "factorial"
24
+ ]
@@ -0,0 +1,33 @@
1
+ import logging
2
+ from typing import Iterable
3
+ from ..logging_.utils import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+
8
+ def flatten(iterable: Iterable) -> list:
9
+ """
10
+ Flattens a given iterable into a list.
11
+
12
+ This function takes as input an iterable that may contain nested iterables (like lists or tuples),
13
+ and returns a flat list where all elements of the input are expanded.
14
+ Non-iterable elements in the input iterable are appended as they are.
15
+
16
+ Args:
17
+ iterable (Iterable): The iterable to flatten. Can contain nested iterables.
18
+
19
+ Returns:
20
+ list: A flat list containing all elements of the input iterable.
21
+ """
22
+ result = []
23
+ for i in iterable:
24
+ if isinstance(i, Iterable):
25
+ result.extend(flatten(i))
26
+ else:
27
+ result.append(i)
28
+
29
+ return result
30
+
31
+ __all__=[
32
+ "flatten"
33
+ ]
@@ -0,0 +1,20 @@
1
+ import logging
2
+ from typing import TypeVar, Iterable
3
+ from ..custom_types import Consumer
4
+ from ..logging_.utils import get_logger
5
+
6
+ logger = get_logger(__name__)
7
+
8
+ T = TypeVar('T')
9
+
10
+
11
+ def foreach(iterable: Iterable[T], consumer: Consumer[T]) -> None:
12
+ logger.info("Applying consumer to iterable")
13
+ for v in iterable:
14
+ consumer(v)
15
+ logger.info("Foreach operation completed")
16
+
17
+
18
+ __all__ = [
19
+ 'foreach'
20
+ ]