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,114 @@
1
+ import asyncio
2
+ import functools
3
+ import logging
4
+ import os
5
+ import unittest
6
+ from inspect import iscoroutinefunction
7
+ from typing import Callable, Type, Coroutine, Union, Any
8
+
9
+ from ...random_ import RandomDataGenerator
10
+ from ...io_ import create_directory, delete_directory, directory_exists
11
+ from ...path import get_current_working_directory, set_current_working_directory
12
+ from ...logging_.utils import get_logger
13
+
14
+ logger = get_logger(__name__)
15
+
16
+
17
+ def dispatch_function(func: Union[Callable, Coroutine], *args, **kwargs) -> Any:
18
+ if asyncio.iscoroutinefunction(func):
19
+ return asyncio.run(func(*args, **kwargs))
20
+ elif asyncio.iscoroutine(func):
21
+ return asyncio.run(func)
22
+ else:
23
+ return func(*args, **kwargs)
24
+
25
+
26
+ def get_available_folder_name(prefix_path: str, random_suffix_length: int = 15) -> str:
27
+ res = f"{prefix_path}_{RandomDataGenerator.name(random_suffix_length)}"
28
+ while directory_exists(res):
29
+ res = f"{prefix_path}_{RandomDataGenerator.name(random_suffix_length)}"
30
+ return res
31
+
32
+
33
+ def improved_setup(func: Callable) -> Callable:
34
+ @functools.wraps(func)
35
+ def wrapper(self):
36
+ self.cwd = get_available_folder_name(f"./{self.__class__.__name__}_test_folder")
37
+ logger.debug("Creating test directory: %s", self.cwd)
38
+ create_directory(self.cwd)
39
+ self.prev_cwd = get_current_working_directory()
40
+ set_current_working_directory(os.path.join(self.prev_cwd, self.cwd))
41
+ logger.debug("Changed working directory to: %s", self.cwd)
42
+ if func is not None:
43
+ func(self)
44
+
45
+ @functools.wraps(func)
46
+ async def async_wrapper(self):
47
+ self.cwd = get_available_folder_name(f"./{self.__class__.__name__}_test_folder")
48
+ logger.debug("Creating async test directory: %s", self.cwd)
49
+ create_directory(self.cwd)
50
+ self.prev_cwd = get_current_working_directory()
51
+ set_current_working_directory(os.path.join(self.prev_cwd, self.cwd))
52
+ logger.debug("Changed working directory to: %s", self.cwd)
53
+ if func is not None:
54
+ await func(self)
55
+
56
+ return async_wrapper if iscoroutinefunction(func) else wrapper
57
+
58
+
59
+ def improved_teardown(func: Callable) -> Callable:
60
+ @functools.wraps(func)
61
+ def wrapper(self):
62
+ if func is not None:
63
+ func(self)
64
+ logger.debug("Restoring working directory to: %s", self.prev_cwd)
65
+ set_current_working_directory(self.prev_cwd)
66
+ logger.debug("Cleaning up test directory: %s", self.cwd)
67
+ delete_directory(self.cwd)
68
+
69
+ @functools.wraps(func)
70
+ async def async_wrapper(self):
71
+ if func is not None:
72
+ await func(self)
73
+ logger.debug("Restoring working directory to: %s", self.prev_cwd)
74
+ set_current_working_directory(self.prev_cwd)
75
+ logger.debug("Cleaning up async test directory: %s", self.cwd)
76
+ delete_directory(self.cwd)
77
+
78
+ return async_wrapper if iscoroutinefunction(func) else wrapper
79
+
80
+
81
+ class AutoCWDTestCase(unittest.TestCase):
82
+ @staticmethod
83
+ def _dummy(*args, **kwargs) -> None:
84
+ pass
85
+
86
+ @classmethod
87
+ def __init_subclass__(cls: Type, **kwargs) -> None:
88
+ logger.debug("Initializing AutoCWDTestCase subclass: %s", cls.__name__)
89
+ dct = dict(cls.__dict__)
90
+ impl_setUp = dct.get("setUp", cls._dummy)
91
+ impl_tearDown = dct.get("tearDown", cls._dummy)
92
+ setattr(cls, "setUp", improved_setup(impl_setUp))
93
+ setattr(cls, "tearDown", improved_teardown(impl_tearDown))
94
+
95
+
96
+ class AsyncAutoCWDTestCase(unittest.IsolatedAsyncioTestCase):
97
+ @staticmethod
98
+ async def _async_dummy(*args, **kwargs) -> None:
99
+ pass
100
+
101
+ @classmethod
102
+ def __init_subclass__(cls: Type, **kwargs) -> None:
103
+ logger.debug("Initializing AsyncAutoCWDTestCase subclass: %s", cls.__name__)
104
+ dct = dict(cls.__dict__)
105
+ async_impl_setUp = dct.get("asyncSetUp", cls._async_dummy)
106
+ async_impl_tearDown = dct.get("asyncTearDown", cls._async_dummy)
107
+ setattr(cls, "asyncSetUp", improved_setup(async_impl_setUp))
108
+ setattr(cls, "asyncTearDown", improved_teardown(async_impl_tearDown))
109
+
110
+
111
+ __all__ = [
112
+ 'AutoCWDTestCase',
113
+ "AsyncAutoCWDTestCase"
114
+ ]
danielutils/text.py ADDED
@@ -0,0 +1,169 @@
1
+ # -*- coding: utf-8 -*-
2
+ import logging
3
+ from typing import Union
4
+ from .decorators.validate import validate
5
+ from .functions.check_foreach import check_foreach
6
+ from .logging_.utils import get_logger
7
+
8
+ logger = get_logger(__name__)
9
+ HEBREW_LETTERS = ['\u05D0', '\u2135', '\uFB21', '\uFB2E', '\uFB2F',
10
+ '\uFB30', '\uFB4F', '\u05D1', '\u2136', '\uFB31',
11
+ '\uFB4C', '\u05D2', '\u2137', '\uFB32', '\u05D3',
12
+ '\u2138', '\uFB22', '\uFB33', '\u05D4', '\uFB23',
13
+ '\uFB34', '\u05D5', '\uFB4B', '\uFB35', '\u05F0',
14
+ '\u05F1', '\u05D6', '\uFB36', '\u05D7', '\u05D8',
15
+ '\uFB38', '\u05D9', '\uFB1D', '\uFB39', '\u05EF',
16
+ '\u05F2', '\uFB1F', '\u05DB', '\uFB24', '\u05DA',
17
+ '\uFB3B', '\uFB3A', '\uFB4D', '\u05DC', '\uFB25',
18
+ '\uFB3C', '\u05DE', '\uFB26', '\u05DD', '\uFB3E',
19
+ '\u05E0', '\u05DF', '\uFB40', '\u05E1', '\uFB41',
20
+ '\u05E2', '\uFB20', '\u05E4', '\u05E3', '\uFB44',
21
+ '\uFB43', '\uFB4E', '\u05E6', '\u05E5', '\uFB46',
22
+ '\u05E7', '\uFB47', '\u05E8', '\uFB27', '\uFB48',
23
+ '\u05E9', '\uFB2B', '\uFB2A', '\uFB49', '\uFB2D',
24
+ '\uFB2C', '\u05EA', '\uFB28', '\uFB4A']
25
+
26
+
27
+ HEBREW_LETTERS_DEC = [ord(v) for v in HEBREW_LETTERS]
28
+ HEBREW_LETTERS_HEX = [hex(v) for v in HEBREW_LETTERS_DEC]
29
+ ENGLISH_LETTERS = [chr(v) for v in range(65, 91)]+[chr(v)
30
+ for v in range(97, 123)]
31
+ ENGLISH_LETTERS_DEC = [ord(v) for v in ENGLISH_LETTERS]
32
+ ENGLISH_LETTERS_HEX = [hex(v) for v in ENGLISH_LETTERS_DEC]
33
+
34
+
35
+ @validate # type:ignore
36
+ def is_english(s: str) -> bool:
37
+ """returns whether the specified string is in the english language
38
+
39
+ Args:
40
+ s (str): the string to check
41
+
42
+ Returns:
43
+ bool: returns true if the string is in english
44
+ """
45
+ return check_foreach(s, lambda c: c in ENGLISH_LETTERS)
46
+
47
+
48
+ @validate # type:ignore
49
+ def is_number(s: str) -> bool:
50
+ """checks if a string is a number
51
+
52
+ Args:
53
+ text (str): string to check
54
+
55
+ Returns:
56
+ bool: true if string is a number
57
+ """
58
+ return s.isnumeric()
59
+
60
+
61
+ @validate # type:ignore
62
+ def is_int(num: Union[int, float]) -> bool:
63
+ """_summary_
64
+
65
+ Args:
66
+ num (Union[int, float]): is a number an int
67
+
68
+ Returns:
69
+ bool: return true if num is a while number
70
+ """
71
+ if isinstance(num, int):
72
+ return True
73
+
74
+ return int(num) == num
75
+
76
+
77
+ @validate # type:ignore
78
+ def is_float(s: str) -> bool:
79
+ """checks whether a string has a float value
80
+
81
+ Args:
82
+ s (str): string to check
83
+
84
+ Returns:
85
+ bool: result
86
+ """
87
+ try:
88
+ float(s)
89
+ logger.debug("String '%s' is a valid float", s)
90
+ return True
91
+ except ValueError:
92
+ logger.debug("String '%s' is not a valid float", s)
93
+ return False
94
+
95
+
96
+ @validate # type:ignore
97
+ def is_hebrew(s: str) -> bool:
98
+ """checks if a string is in hebrew
99
+
100
+ Args:
101
+ text (str): string to check
102
+
103
+ Returns:
104
+ bool: true iff all chars are hebrew
105
+ """
106
+ return check_foreach(s, lambda c: c in HEBREW_LETTERS)
107
+
108
+
109
+ @validate # type:ignore
110
+ def is_binary(s: str) -> bool:
111
+ """checks if s string has a binary value
112
+
113
+ Args:
114
+ s (str): string to check
115
+
116
+ Returns:
117
+ bool: result
118
+ """
119
+ return check_foreach(s, lambda c: c in {0, 1})
120
+
121
+
122
+ @validate # type:ignore
123
+ def is_decimal(s: str) -> bool:
124
+ """checks if a string has a decimal number
125
+
126
+ Args:
127
+ s (str): string to check
128
+
129
+ Returns:
130
+ bool: result
131
+ """
132
+ return check_foreach(s, lambda c: c in range(10))
133
+
134
+
135
+ @validate # type:ignore
136
+ def is_hex(s: str) -> bool:
137
+ """checks if a string has a hexadecimal value
138
+
139
+ Args:
140
+ s (str): string to check
141
+
142
+ Returns:
143
+ bool: result
144
+ """
145
+ try:
146
+ int(s, 16)
147
+ logger.debug("String '%s' is a valid hexadecimal", s)
148
+ return True
149
+ except ValueError:
150
+ logger.debug("String '%s' is not a valid hexadecimal", s)
151
+ return False
152
+
153
+
154
+ __all__ = [
155
+ "HEBREW_LETTERS",
156
+ "HEBREW_LETTERS_DEC",
157
+ "HEBREW_LETTERS_HEX",
158
+ "ENGLISH_LETTERS",
159
+ "ENGLISH_LETTERS_DEC",
160
+ "ENGLISH_LETTERS_HEX",
161
+ "is_english",
162
+ "is_number",
163
+ "is_int",
164
+ "is_float",
165
+ "is_hebrew",
166
+ "is_binary",
167
+ "is_decimal",
168
+ "is_hex"
169
+ ]
danielutils/time.py ADDED
@@ -0,0 +1,64 @@
1
+ import logging
2
+ import time
3
+ from datetime import datetime
4
+ from typing import Callable, TypeVar
5
+ from .versioned_imports import ParamSpec
6
+ from .logging_.utils import get_logger
7
+
8
+ logger = get_logger(__name__)
9
+
10
+ T = TypeVar("T")
11
+ P = ParamSpec("P")
12
+
13
+
14
+ def measure(func: Callable[P, T]) -> Callable[P, float]:
15
+ """A function to measure the execution time of a function.
16
+
17
+ Args:
18
+ func (function): The function to be measured.
19
+
20
+ Returns:
21
+ float: The time taken in seconds to execute the given function.
22
+ """
23
+
24
+ def wrapper(*args, **kwargs) -> float:
25
+ logger.debug("Measuring execution time of function: %s", func.__name__)
26
+ start = time.time()
27
+ func(*args, **kwargs)
28
+ end = time.time()
29
+ execution_time = end - start
30
+ logger.debug("Function %s executed in %.4f seconds", func.__name__, execution_time)
31
+ return execution_time
32
+
33
+ return wrapper
34
+
35
+
36
+ def epoch_to_datetime(epoch: float) -> datetime:
37
+ """Converts a POSIX timestamp to datetime
38
+
39
+ Args:
40
+ epoch (int): time from epoch
41
+
42
+ Returns:
43
+ datetime: resulting conversion
44
+ """
45
+ return datetime.fromtimestamp(epoch)
46
+
47
+
48
+ def datetime_to_epoch(dt: datetime) -> float:
49
+ """Converts a datetime to a POSIX timestamp
50
+
51
+ Args:
52
+ dt (datetime): datetime object
53
+
54
+ Returns:
55
+ int: resulting conversion
56
+ """
57
+ return dt.timestamp()
58
+
59
+
60
+ __all__ = [
61
+ "measure",
62
+ 'epoch_to_datetime',
63
+ 'datetime_to_epoch'
64
+ ]
@@ -0,0 +1 @@
1
+ from .unittest_test_runner import *
@@ -0,0 +1,9 @@
1
+ """
2
+ Test Runner Module
3
+
4
+ A comprehensive test runner with hierarchical execution and smart skipping capabilities.
5
+ """
6
+
7
+ from .core import *
8
+ from .models import *
9
+ from .cli import main
@@ -0,0 +1,70 @@
1
+ """
2
+ Command-line interface for the test runner using Google Fire.
3
+ """
4
+
5
+ import logging
6
+ import fire
7
+ from typing import Optional, Literal
8
+ from .core import UnittestRunner, VerboseLevel
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ def run_tests(python_path: Optional[str] = None,
14
+ results_file: str = "test_results.json",
15
+ skip_threshold: int = 24,
16
+ force: bool = False,
17
+ test_name: Optional[str] = None,
18
+ target: Optional[str] = None,
19
+ verbose: VerboseLevel = "class",
20
+ show_function_results: bool = False):
21
+ """
22
+ Run tests with smart skipping and detailed reporting.
23
+
24
+ Args:
25
+ python_path: Path to Python executable to use for running tests (defaults to current Python)
26
+ results_file: JSON file to store/load results (default: test_results.json)
27
+ skip_threshold: Hours after which to re-run previously passing tests (default: 24)
28
+ force: Force run all tests, ignoring previous results
29
+ test_name: Run only a specific test module (e.g., tests.abstractions.db.test_in_memory_database)
30
+ target: unittest dot-notation target (e.g., tests.module.class.function)
31
+ verbose: Verbose level - module/file/class/function (default: class)
32
+ show_function_results: Show pass/fail status for each individual test function within modules
33
+ """
34
+ logger.info("Starting test run with parameters: python_path=%s, results_file=%s, skip_threshold=%d, force=%s, target=%s, verbose=%s",
35
+ python_path, results_file, skip_threshold, force, target, verbose)
36
+
37
+ runner = UnittestRunner(
38
+ python_path=python_path,
39
+ results_file=results_file,
40
+ skip_threshold_hours=skip_threshold,
41
+ force_run=force,
42
+ test_name=test_name,
43
+ target=target,
44
+ verbose=verbose,
45
+ show_function_results=show_function_results
46
+ )
47
+
48
+ try:
49
+ logger.info("Executing all tests")
50
+ runner.run_all_tests()
51
+ logger.info("Saving results to JSON file: %s", results_file)
52
+ runner.save_results_json()
53
+ logger.info("Test run completed successfully")
54
+ except KeyboardInterrupt:
55
+ logger.warning("Test run interrupted by user")
56
+ print("\nTest run interrupted by user.")
57
+ except Exception as e:
58
+ logger.error("Error during test run: %s", e)
59
+ print(f"Error during test run: {e}")
60
+ raise
61
+
62
+
63
+ def main():
64
+ """Main entry point for the CLI."""
65
+ logger.info("Starting CLI main entry point")
66
+ fire.Fire(run_tests)
67
+
68
+
69
+ if __name__ == "__main__":
70
+ main()
@@ -0,0 +1,17 @@
1
+ """
2
+ Core test runner modules.
3
+
4
+ This package contains the core functionality split by responsibility:
5
+ - discovery: Test discovery and structure analysis
6
+ - execution: Test execution hierarchy
7
+ - parser: Output parsing and result processing
8
+ - runner: Main UnittestRunner orchestration
9
+ - types: Type definitions and data structures
10
+ """
11
+
12
+ from .runner import UnittestRunner
13
+
14
+ # Define VerboseLevel here since it's a simple type alias
15
+ from typing import Literal
16
+ VerboseLevel = Literal["module", "file", "class", "function"]
17
+