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,125 @@
1
+ """file with math_ symbols constants"""
2
+ from typing import Union, Dict as Dict
3
+ from ..reflection import get_python_version
4
+ if get_python_version() >= (3, 9):
5
+ from builtins import dict as Dict
6
+ # https://unicode-table.com/en/sets/mathematical-signs/
7
+ SPECIAL_DOUBLE_N = "ℕ"
8
+ SPECIAL_DOUBLE_Q = "ℚ"
9
+ SPECIAL_DOUBLE_R = "ℝ"
10
+ SPECIAL_DOUBLE_Z = "ℤ"
11
+ SPECIAL_DOUBLE_C = "ℂ"
12
+ SPECIAL_RPAB = "〉" # right pointing angle bracket
13
+ SPECIAL_LPAB = "〈" # left pointing angle bracket
14
+ SPECIAL_FORALL = "∀"
15
+ SPECIAL_EXISTS = "∃"
16
+ SPEICAL_VL = "|"
17
+ SPECIAL_SIGMA = "∑"
18
+ SPECIAL_PI = "∏"
19
+ SPECIAL_CIRCLED_PLUS = "⊕"
20
+ SPECIAL_NE = "≠"
21
+ SPECIAL_EQUIV = "≡"
22
+ SPECIAL_LAMBDA = "λ"
23
+ SPECIAL_SQRT = "√"
24
+ SPECIAL_CUBE_ROOT = "∛"
25
+ SPECIAL_4TH_ROOT = "∜"
26
+
27
+
28
+ SUPERSCRIPT_SMALL_LETTERS = ['ᵃ', 'ᵇ', 'ᶜ', 'ᵈ', 'ᵉ', 'ᶠ', 'ᵍ', 'ʰ', 'ⁱ', 'ʲ', 'ᵏ', 'ˡ', 'ᵐ', 'ⁿ',
29
+ 'ᵒ', 'ᵖ', '𐞥', 'ʳ', 'ˢ', 'ᵗ', 'ᵘ', 'ᵛ', 'ʷ', 'ˣ', 'ʸ', 'ᶻ']
30
+
31
+ # superscript_big_case_a = 'ⁱ'
32
+ # superscript_big_case_b = 'ⁱ'
33
+ # superscript_big_case_c = 'ⁱ'
34
+ # superscript_big_case_d = 'ⁱ'
35
+ # superscript_big_case_e = 'ⁱ'
36
+ # superscript_big_case_f = 'ⁱ'
37
+ # superscript_big_case_g = 'ⁱ'
38
+ # superscript_big_case_h = 'ⁱ'
39
+ # superscript_big_case_i = 'ⁱ'
40
+ # superscript_big_case_j = 'ⁱ'
41
+ # superscript_big_case_k = 'ⁱ'
42
+ # superscript_big_case_l = 'ⁱ'
43
+ # superscript_big_case_m = 'ⁱ'
44
+ # superscript_big_case_n = 'ⁱ'
45
+ # superscript_big_case_o = 'ⁱ'
46
+ # superscript_big_case_p = 'ⁱ'
47
+ # superscript_big_case_q = 'ⁱ'
48
+ # superscript_big_case_r = 'ⁱ'
49
+ # superscript_big_case_s = 'ⁱ'
50
+ # superscript_big_case_t = 'ⁱ'
51
+ # superscript_big_case_u = 'ⁱ'
52
+ # superscript_big_case_v = 'ⁱ'
53
+ # superscript_big_case_w = 'ⁱ'
54
+ # superscript_big_case_x = 'ⁱ'
55
+ # superscript_big_case_y = 'ⁱ'
56
+ # superscript_big_case_z = 'ⁱ'
57
+
58
+
59
+ superscript_dict: Dict[Union[str, int], str] = {}
60
+ superscript_dict.update(
61
+ {chr(i+ord('a')): SUPERSCRIPT_SMALL_LETTERS[i] for i in range(26)}
62
+ )
63
+ superscript_digits = ["⁰", "¹", "²", "³",
64
+ "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"]
65
+ superscript_dict.update(
66
+ {i: superscript_digits[i] for i in range(len(superscript_digits))}
67
+ )
68
+ superscript_dict.update({
69
+ "+": "⁺",
70
+ "-": "⁻",
71
+ "=": "⁼",
72
+ "(": "⁽",
73
+ ")": "⁾",
74
+ })
75
+
76
+ SUBSCRIPT_SMALL_LETTERS = ['ₐ', '', '', '', 'ₑ', '', '', 'ₕ', 'ᵢ', 'ⱼ', 'ₖ', 'ₗ', 'ₘ',
77
+ 'ₙ', 'ₒ', 'ₚ', '', 'ᵣ', 'ₛ', 'ₜ', 'ᵤ', 'ᵥ', '', 'ₓ', '', '']
78
+ # subscript_big_case_a = 'ⁱ'
79
+ # subscript_big_case_b = 'ⁱ'
80
+ # subscript_big_case_c = 'ⁱ'
81
+ # subscript_big_case_d = 'ⁱ'
82
+ # subscript_big_case_e = 'ⁱ'
83
+ # subscript_big_case_f = 'ⁱ'
84
+ # subscript_big_case_g = 'ⁱ'
85
+ # subscript_big_case_h = 'ⁱ'
86
+ # subscript_big_case_i = 'ⁱ'
87
+ # subscript_big_case_j = 'ⁱ'
88
+ # subscript_big_case_k = 'ⁱ'
89
+ # subscript_big_case_l = 'ⁱ'
90
+ # subscript_big_case_m = 'ⁱ'
91
+ # subscript_big_case_n = 'ⁱ'
92
+ # subscript_big_case_o = 'ⁱ'
93
+ # subscript_big_case_p = 'ⁱ'
94
+ # subscript_big_case_q = 'ⁱ'
95
+ # subscript_big_case_r = 'ⁱ'
96
+ # subscript_big_case_s = 'ⁱ'
97
+ # subscript_big_case_t = 'ⁱ'
98
+ # subscript_big_case_u = 'ⁱ'
99
+ # subscript_big_case_v = 'ⁱ'
100
+ # subscript_big_case_w = 'ⁱ'
101
+ # subscript_big_case_x = 'ⁱ'
102
+ # subscript_big_case_y = 'ⁱ'
103
+ # subscript_big_case_z = 'ⁱ'
104
+ subscript_dict: Dict[Union[str, int], str] = {}
105
+ subscript_dict.update(
106
+ {chr(i+ord('a')): SUBSCRIPT_SMALL_LETTERS[i]
107
+ for i in range(len(SUBSCRIPT_SMALL_LETTERS))}
108
+ )
109
+
110
+ subscript_digits = ["\u2080", "\u2081", "\u2082", "\u2083",
111
+ "\u2084", "\u2085", "\u2086", "\u2087", "\u2088", "\u2089"]
112
+ subscript_dict.update(
113
+ {f'{i}': subscript_digits[i] for i in range(len(subscript_digits))}
114
+ )
115
+ subscript_dict.update({
116
+ "+": "\u208A",
117
+ "-": "\u208B",
118
+ "=": "\u208C",
119
+ "(": "\u208D",
120
+ ")": "\u208E",
121
+ })
122
+ __all__ = [
123
+ "subscript_dict",
124
+ "subscript_dict",
125
+ ]
@@ -0,0 +1,5 @@
1
+ from .interface import *
2
+ from .atomic_class_meta import *
3
+ from .implicit_data_deleter_meta import *
4
+ from .instance_cache_meta import *
5
+ from .overload_meta import *
@@ -0,0 +1,36 @@
1
+ import logging
2
+ from ..decorators import atomic
3
+ from ..logging_.utils import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+
8
+ class AtomicClassMeta(type):
9
+ """will make all of the class's function atomic
10
+ """
11
+ def __new__(mcs, name, bases, namespace):
12
+ logger.info("Creating atomic class: %s", name)
13
+
14
+ # Process class methods
15
+ class_methods_processed = 0
16
+ for k, v in namespace.items():
17
+ if callable(v):
18
+ namespace[k] = atomic(v) # type:ignore
19
+ class_methods_processed += 1
20
+
21
+ # Process inherited methods
22
+ inherited_methods_processed = 0
23
+ for base in bases:
24
+ for k, v in base.__dict__.items():
25
+ if callable(v):
26
+ if k not in namespace:
27
+ namespace[k] = atomic(v) # type:ignore
28
+ inherited_methods_processed += 1
29
+
30
+ logger.info("AtomicClassMeta: %s created with %s class methods and %s inherited methods made atomic", name, class_methods_processed, inherited_methods_processed)
31
+ return super().__new__(mcs, name, bases, namespace)
32
+
33
+
34
+ __all__ = [
35
+ "AtomicClassMeta"
36
+ ]
@@ -0,0 +1,87 @@
1
+ import logging
2
+ from typing import Optional
3
+ from ..logging_.utils import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+
8
+ class DeletedException(AttributeError):
9
+ """an exception to be raised if a function is deleted
10
+ """
11
+
12
+
13
+ def deleted(func, cls_name: Optional[str] = None):
14
+ """replaces a function with a pre-scripted deleted function
15
+
16
+ Args:
17
+ func (_type_): _description_
18
+ cls_name (Optional[str], optional): _description_. Defaults to None.
19
+
20
+ Raises:
21
+ DeletedException: _description_
22
+
23
+ Returns:
24
+ _type_: _description_
25
+ """
26
+ msg = f"'{func.__qualname__}' has been marked as deleted"
27
+ if cls_name:
28
+ msg = f"'{cls_name}.{func.__name__}' has been marked as deleted"
29
+
30
+ def new_func(*args, **kwargs): # pylint: disable=unused-argument
31
+ nonlocal func
32
+ logger.warning("Attempted to call deleted function: %s", func.__qualname__)
33
+ raise DeletedException(msg)
34
+ return new_func
35
+
36
+
37
+ class ImplicitDataDeleterMeta(type):
38
+ """Inheriting from this metaclass will 'delete' all non builtin function
39
+ and will replace them with a new function which will raise and error
40
+ """
41
+ def __new__(mcs, name, bases, namespace):
42
+ logger.info("Creating ImplicitDataDeleterMeta class: %s", name)
43
+
44
+ cls_functions = set()
45
+ for k, v in namespace.items():
46
+ if callable(v):
47
+ if hasattr(v, "__objclass__"):
48
+ if v.__objclass__ in {object}:
49
+ continue
50
+
51
+ elif hasattr(v, "__module__"):
52
+ if v.__module__ in {'builtins', None}:
53
+ continue
54
+
55
+ cls_functions.add(v)
56
+
57
+ parent_functions = set()
58
+ for base in bases:
59
+ for k, v in base.__dict__.items():
60
+ if callable(v):
61
+ parent_functions.add(v)
62
+
63
+ parent_dct = {func.__name__: func for func in parent_functions}
64
+ cls_dct = {func.__name__: func for func in cls_functions}
65
+ to_delete = set({k: v for k, v in parent_dct.items()
66
+ if k not in cls_dct}.values())
67
+
68
+ deleted_count = 0
69
+ for func in to_delete:
70
+ if func.__name__ in dir(object):
71
+ if func.__name__ in {"__init__"}:
72
+ continue
73
+ namespace[func.__name__] = object.__dict__[func.__name__]
74
+ elif func.__name__ in {"__len__", "__bool__"}:
75
+ namespace[func.__name__] = lambda self: True
76
+ else:
77
+ namespace[func.__name__] = deleted(func, name)
78
+ deleted_count += 1
79
+
80
+ logger.info("ImplicitDataDeleterMeta: %s created with %s functions marked as deleted", name, deleted_count)
81
+ return super().__new__(mcs, name, bases, namespace)
82
+
83
+
84
+ __all__ = [
85
+ "ImplicitDataDeleterMeta",
86
+ "DeletedException"
87
+ ]
@@ -0,0 +1,66 @@
1
+ import logging
2
+ from ..better_builtins.counter import Counter
3
+ from ..logging_.utils import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+
8
+ class InstanceCacheMeta(type):
9
+ """Adds automatic caching of all instances of the class
10
+
11
+ Adds the following API to the class
12
+ @staticmethod
13
+ instances() -> returns a generator of all of the instances
14
+
15
+ @staticmethod
16
+ get_id(instance) -> returns the id of the instance
17
+
18
+ @staticmethod
19
+ get_instance(id) -> return the id of an instance
20
+
21
+ """
22
+ def __new__(mcs, name, bases, namespace):
23
+ logger.info("Creating InstanceCacheMeta class: %s", name)
24
+
25
+ INIT = "__init__"
26
+ instance_2_id: dict = {}
27
+ id_2_instance: dict = {}
28
+ counter = Counter()
29
+ original_init = None
30
+ if INIT in namespace:
31
+ original_init = namespace[INIT]
32
+
33
+ def new_init(*args, **kwargs):
34
+ instance_id = counter.get()
35
+ instance = args[0]
36
+ id_2_instance[instance_id] = instance
37
+ instance_2_id[instance] = instance_id
38
+ counter.increment()
39
+ if original_init:
40
+ original_init(*args, **kwargs)
41
+
42
+ def get_id(instance):
43
+ if instance not in instance_2_id:
44
+ logger.warning("Instance %s not found in cache", instance)
45
+ raise KeyError(f"Instance {instance} not found in cache")
46
+ return instance_2_id[instance]
47
+
48
+ def get_instance(id_: int):
49
+ if id_ not in id_2_instance:
50
+ logger.warning("Instance with ID %s not found in cache", id_)
51
+ raise KeyError(f"Instance with ID {id_} not found in cache")
52
+ return id_2_instance[id_]
53
+
54
+ def instances():
55
+ return instance_2_id.keys()
56
+
57
+ namespace["instances"] = staticmethod(instances)
58
+ namespace["get_id"] = staticmethod(get_id)
59
+ namespace["get_instance"] = staticmethod(get_instance)
60
+ namespace[INIT] = new_init
61
+
62
+ logger.info("InstanceCacheMeta: %s created with instance caching enabled", name)
63
+ return super().__new__(mcs, name, bases, namespace)
64
+ __all__ =[
65
+ "InstanceCacheMeta"
66
+ ]
@@ -0,0 +1,328 @@
1
+ import inspect
2
+ import logging
3
+ import re
4
+ import traceback
5
+ import functools
6
+ from typing import Callable, Iterable, Any, Generator, Optional, Union, \
7
+ List as List, Set as Set, Type as t_type, Dict as Dict
8
+ from ..logging_.utils import get_logger
9
+ from ..reflection import get_python_version
10
+ from ..reflection.declarations import _should_use_runtime_introspection, _source_matches_class
11
+ if get_python_version() >= (3, 9):
12
+ from builtins import list as List, set as Set, type as t_type, dict as Dict # type:ignore
13
+ # from ..decorators.decorate_conditionally import decorate_conditionally
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ class InterfaceHelper:
19
+ """a helper class for Interface metaclass
20
+ """
21
+ ORIGINAL_INIT = "__original_init__"
22
+
23
+ @staticmethod
24
+ def flatten_iterables(iterable: Iterable) -> list:
25
+ """will flatten and iterable recursively
26
+
27
+ Args:
28
+ iterable (Iterable): iterable to flatten
29
+
30
+ Returns:
31
+ list: the flattened result
32
+ """
33
+ res = []
34
+ for obj in iterable:
35
+ if isinstance(obj, Iterable) and not isinstance(obj, str):
36
+ res.extend(InterfaceHelper.flatten_iterables(obj))
37
+ else:
38
+ res.append(obj)
39
+ return res
40
+
41
+ @staticmethod
42
+ def is_func_implemented(func: Callable) -> bool:
43
+ """will check if a function is implemented
44
+
45
+ Args:
46
+ func (Callable): the function to check
47
+
48
+ Returns:
49
+ bool: will return true iff the function is not implemented according to Interface.IMPLICIT_ABSTRACT
50
+ or not decorated with Interface.abstractmethod
51
+ or not an overridden instance of a default implementation of an Interface's function
52
+ """
53
+ if hasattr(func, Interface.FUNC_KEY):
54
+ return not func.__dict__[Interface.FUNC_KEY]
55
+
56
+ if getattr(func, "__is_interface_handler__", False):
57
+ return False
58
+
59
+ try:
60
+ src = inspect.getsource(func)
61
+ except (OSError, TypeError):
62
+ code = func.__code__
63
+ if code.co_code == b'd\x00S\x00' and code.co_consts == (None,):
64
+ return False
65
+ if code.co_code == (lambda: ...).__code__.co_code:
66
+ return False
67
+ return True
68
+
69
+ if re.match(Interface.IMPLICIT_ABSTRACT, src):
70
+ return False
71
+
72
+ is_default_override = (
73
+ func.__qualname__.startswith(InterfaceHelper.__name__))
74
+ return not is_default_override
75
+
76
+ @staticmethod
77
+ def unimplemented_functions(cls) -> Generator[str, None, None]:
78
+ """will yield all function that are unimplemented in a class according to InterfaceHelper.is_func_implemented
79
+
80
+ Yields:
81
+ Generator[str, None, None]: yields str which are function names
82
+ """
83
+ for func_name in InterfaceHelper.get_declared_function_names(cls):
84
+ if func_name not in cls.__dict__:
85
+ continue
86
+ func = cls.__dict__[func_name]
87
+ if not InterfaceHelper.is_func_implemented(func):
88
+ yield func_name
89
+
90
+ @staticmethod
91
+ def implemented_functions(cls) -> Generator[str, None, None]:
92
+ """will yield all function that are implemented in a class according to InterfaceHelper.is_func_implemented
93
+
94
+ Yields:
95
+ Generator[str, None, None]: yields str which are function names
96
+ """
97
+ for func_name in InterfaceHelper.get_declared_function_names(cls):
98
+ if func_name not in cls.__dict__:
99
+ continue
100
+ func = cls.__dict__[func_name]
101
+ if InterfaceHelper.is_func_implemented(func):
102
+ yield func_name
103
+
104
+ @staticmethod
105
+ def _runtime_declared_function_names(cls) -> Generator[str, None, None]:
106
+ expected_qualname_prefix = f"{cls.__qualname__}."
107
+ for name, value in cls.__dict__.items():
108
+ if not inspect.isfunction(value):
109
+ continue
110
+ if getattr(value, "__qualname__", "") != expected_qualname_prefix + name:
111
+ continue
112
+ yield name
113
+
114
+ @staticmethod
115
+ def get_declared_function_names(cls) -> Generator[str, None, None]:
116
+ """will yield the names of all the functions declared inside a class
117
+
118
+ Yields:
119
+ Generator[str, None, None]: yields str values which are names of declared functions
120
+ """
121
+ if _should_use_runtime_introspection(cls):
122
+ yield from InterfaceHelper._runtime_declared_function_names(cls)
123
+ return
124
+
125
+ try:
126
+ source = inspect.getsource(cls)
127
+ if not _source_matches_class(cls, source):
128
+ raise OSError("source does not match class")
129
+ source_lines = source.splitlines()
130
+ except (OSError, TypeError):
131
+ yield from InterfaceHelper._runtime_declared_function_names(cls)
132
+ return
133
+
134
+ for line in source_lines:
135
+ if re.match(r".*def \w+\(.*\).*:", line):
136
+ func_name = re.findall(r".*def (\w+)\(.*", line)[0]
137
+ if func_name in cls.__dict__:
138
+ yield func_name
139
+
140
+ @staticmethod
141
+ def create_init_handler(cls_name, missing: Optional[Union[List[str],
142
+ Set[str]]] = None, original: Optional[Callable] = None):
143
+ """this function will create the default interface __init__ function with the wanted behavior"""
144
+ # @decorate_conditionally(functools.wraps, original
145
+ # is not None, [original]) # TODO implement this decorator
146
+ def __interface_init__(*args, **kwargs):
147
+ instance = args[0]
148
+ caller_frame = traceback.format_stack()[-2]
149
+ is_super_call = bool(re.match(
150
+ fr"\s+File \".*\", line \d+, in __init__\n\s+(?:super\(\)|{cls_name})\.__init__\(.*\)\n", caller_frame))
151
+
152
+ if is_super_call:
153
+ mro = instance.__class__.mro()
154
+ i = 0
155
+ for i, cls in enumerate(mro):
156
+ if cls.__name__ == cls_name:
157
+ break
158
+ mro = mro[i:]
159
+ for cls in mro:
160
+ if hasattr(cls, InterfaceHelper.ORIGINAL_INIT):
161
+ result = getattr(cls, InterfaceHelper.ORIGINAL_INIT)(
162
+ *args, **kwargs)
163
+ return result
164
+ logger.error("No original init found in MRO for %s", cls_name)
165
+ raise NotImplementedError(
166
+ f"Can't use super().__init__(...) in {cls_name}.__init__(...) "
167
+ "if the __init__ function is not defined a parent interface")
168
+
169
+ if missing:
170
+ logger.warning("Interface %s missing implementations: %s", cls_name, missing)
171
+ raise NotImplementedError(f"Can't instantiate '{cls_name}' because it is an interface."
172
+ f" It is missing implementations for {missing}")
173
+ logger.warning("Attempting to instantiate interface %s", cls_name)
174
+ raise NotImplementedError(
175
+ f"'{cls_name}' is an interface, Can't create instances")
176
+ return __interface_init__
177
+
178
+ @staticmethod
179
+ def create_generic_handler(cls: str, original: Callable):
180
+ """this function will create the generic function handler
181
+
182
+ Args:
183
+ func_name (_type_): the name of the interface
184
+ """
185
+ @functools.wraps(original)
186
+ def __interface_handler__(*args, **kwargs):
187
+ logger.warning("Generic handler called for unimplemented method in interface %s", cls)
188
+ raise NotImplementedError(
189
+ f"Interface {cls} must be implemented")
190
+ __interface_handler__.__is_interface_handler__ = True
191
+ return __interface_handler__
192
+
193
+
194
+ class Interface(type):
195
+ """This is a metaclass that will enable better_builtins that inherit it directly (or indirectly)
196
+ to behave like interfaces in OOP languages like java
197
+ """
198
+ IMPLICIT_ABSTRACT = r"\s*def \w+\(.*?\)(?:\s*->\s*[\w\[\],\s]+)?:(?:[^\n]*)\n(?:\s*\"{3}.*\"{3}\n)?\s*\.{3}\n"
199
+ KEY = "__is_interface__"
200
+ FUNC_KEY = "__is_abstractmethod__"
201
+
202
+ @staticmethod
203
+ def abstractmethod(func):
204
+ """will explicitly mark a method as an abstract method"""
205
+ setattr(func, Interface.FUNC_KEY, True)
206
+ return func
207
+
208
+ def __new__(mcs: t_type['Interface'], name: str, bases: tuple, namespace: dict):
209
+ if len(bases) == 0:
210
+ return mcs._handle_new_interface(mcs, name, bases, namespace)
211
+ return mcs._handle_new_subclass(mcs, name, bases, namespace)
212
+
213
+ @staticmethod
214
+ def _handle_new_interface(mcs, name: str, bases: tuple, namespace: Dict[str, Any]) -> type:
215
+ logger.info("Handling new interface creation: %s", name)
216
+ namespace[InterfaceHelper.ORIGINAL_INIT] = None
217
+ if "__init__" in namespace:
218
+ namespace[InterfaceHelper.ORIGINAL_INIT] = namespace["__init__"]
219
+ namespace["__init__"] = InterfaceHelper.create_init_handler(
220
+ name, original=namespace[InterfaceHelper.ORIGINAL_INIT])
221
+
222
+ abstract_methods = 0
223
+ for k, v in namespace.items():
224
+ if callable(v) and not k == "__init__":
225
+ if not InterfaceHelper.is_func_implemented(v):
226
+ namespace[k] = InterfaceHelper.create_generic_handler(k, v)
227
+ abstract_methods += 1
228
+ logger.info("Created interface %s with %s abstract methods", name, abstract_methods)
229
+ namespace[Interface.KEY] = True
230
+ return type.__new__(mcs, name, bases, namespace)
231
+
232
+ @staticmethod
233
+ def _handle_new_subclass(mcs: t_type['Interface'], name: str, bases: tuple, namespace: Dict[str, Any]) -> type:
234
+ need_to_be_implemented: set = set()
235
+ ancestry = set()
236
+ for base in bases:
237
+ cls_tree = inspect.getclasstree([base], unique=True)
238
+ ancestry.update(InterfaceHelper.flatten_iterables(cls_tree))
239
+ for item in cls_tree:
240
+ if isinstance(item, tuple):
241
+ derived, parent = item
242
+ elif len(item) == 1:
243
+ item = item[0]
244
+ derived, parent = item
245
+ else:
246
+ # multiple inheritance case - need to be implemented
247
+ continue
248
+
249
+ if derived is object:
250
+ continue
251
+
252
+ if isinstance(parent, tuple):
253
+ if len(parent) != 1:
254
+ pass
255
+ parent = parent[0]
256
+
257
+ if parent is not object:
258
+ need_to_be_implemented.update(
259
+ InterfaceHelper.unimplemented_functions(parent))
260
+
261
+ need_to_be_implemented.difference_update(
262
+ InterfaceHelper.implemented_functions(derived))
263
+ need_to_be_implemented.update(
264
+ InterfaceHelper.unimplemented_functions(derived))
265
+
266
+ # cleanup
267
+ del cls_tree, derived, parent
268
+
269
+ if object in ancestry:
270
+ ancestry.remove(object)
271
+
272
+ missing: set = set()
273
+ for func_name in need_to_be_implemented:
274
+ has_been_declared = func_name in namespace
275
+ if not has_been_declared:
276
+ missing.add(func_name)
277
+ continue
278
+
279
+ is_implemented = InterfaceHelper.is_func_implemented(
280
+ namespace[func_name])
281
+ if is_implemented:
282
+ continue
283
+
284
+ for ancestor in ancestry:
285
+ if func_name in InterfaceHelper.implemented_functions(ancestor):
286
+ break
287
+ else:
288
+ missing.add(func_name)
289
+
290
+ # cleanup
291
+ del ancestry
292
+
293
+ if "__init__" in namespace:
294
+ namespace[InterfaceHelper.ORIGINAL_INIT] = namespace["__init__"]
295
+ else:
296
+ if InterfaceHelper.ORIGINAL_INIT in namespace:
297
+ del namespace[InterfaceHelper.ORIGINAL_INIT]
298
+
299
+ if missing:
300
+ namespace[Interface.KEY] = True
301
+ # if "__init__" in need_to_be_implemented:
302
+ namespace["__init__"] = InterfaceHelper.create_init_handler(
303
+ name, missing)
304
+ else:
305
+ namespace[Interface.KEY] = False
306
+ if "__init__" not in namespace:
307
+ namespace["__init__"] = object.__init__
308
+
309
+ return type.__new__(mcs, name, bases, namespace)
310
+
311
+ @staticmethod
312
+ def is_cls_interface(cls_to_check: type) -> bool:
313
+ """will check if a class is an interface
314
+
315
+ Args:
316
+ cls_to_check (type): the class to check
317
+
318
+ Returns:
319
+ bool: will return true iff a class is an interface
320
+ """
321
+ if hasattr(cls_to_check, Interface.KEY):
322
+ return cls_to_check.__dict__[Interface.KEY]
323
+ return False
324
+
325
+
326
+ __all__ = [
327
+ "Interface"
328
+ ]