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
danielutils/io_.py ADDED
@@ -0,0 +1,451 @@
1
+ # -*- coding: utf-8 -*-
2
+ import logging
3
+ import subprocess
4
+ from typing import IO, Iterator, Generator, Optional, cast, Union, List as List
5
+ # import shutil
6
+ from pathlib import Path
7
+ import os
8
+ from .decorators import validate
9
+ from .reflection import get_python_version
10
+ from .logging_.utils import get_logger
11
+
12
+ logger = get_logger(__name__)
13
+
14
+ if get_python_version() >= (3, 9):
15
+ from builtins import list as List
16
+
17
+
18
+ @validate # type:ignore
19
+ def path_exists(path: str) -> bool:
20
+ """checks whether a path exists
21
+
22
+ Args:
23
+ path (str): path to check
24
+
25
+ Returns:
26
+ bool: result of check
27
+ """
28
+ return os.path.exists(path)
29
+
30
+
31
+ @validate # type:ignore
32
+ def file_exists(path: str) -> bool:
33
+ """checks whether a file exists at specified path
34
+
35
+ Args:
36
+ path (str): path to check
37
+
38
+ Returns:
39
+ bool: will return true iff the path exists and it is a path to a file
40
+ """
41
+ return path_exists(path) and is_file(path)
42
+
43
+
44
+ @validate # type:ignore
45
+ def directory_exists(path: str) -> bool:
46
+ """checks whether a directory exists at specified path
47
+
48
+ Args:
49
+ path (str): path to check
50
+
51
+ Returns:
52
+ bool: will return true iff the path exists and it is a path to a directory
53
+ """
54
+ return path_exists(path) and is_directory(path)
55
+
56
+
57
+ @validate # type:ignore
58
+ def delete_file(path: str) -> None:
59
+ """deletes a file if it exists
60
+
61
+ Args:
62
+ path (str): path of file
63
+ """
64
+ if file_exists(path):
65
+ os.remove(path)
66
+
67
+
68
+ @validate # type:ignore
69
+ # type:ignore
70
+ def read_file(path: str, read_bytes: bool = False) -> Union[List[str], List[bytes]]:
71
+ """read all lines from a file
72
+
73
+ Args:
74
+ path (str): the path to the file
75
+
76
+ Returns:
77
+ list[str]: a list of all the lines in the file
78
+ """
79
+ try:
80
+ if read_bytes:
81
+ with open(path, "rb") as f:
82
+ result = f.readlines()
83
+ else:
84
+ with open(path, "r", encoding="mbcs") as f:
85
+ result = f.readlines()
86
+ return result
87
+ except Exception as e:
88
+ logger.error("Error reading file %s: %s", path, e)
89
+ if isinstance(e, UnicodeDecodeError):
90
+ logger.error("Unicode decode error, suggesting to use read_bytes=True")
91
+ raise UnicodeDecodeError(e.encoding, e.object, e.start, e.end,
92
+ "Can't read byte in file.\nTo use with bytes use: read_bytes = True ") from e
93
+ raise e
94
+
95
+
96
+ @validate # type:ignore
97
+ def is_file(path: str) -> bool:
98
+ """return whether a path represents a file
99
+
100
+ Args:
101
+ path (str): path to check
102
+ """
103
+ return os.path.isfile(path)
104
+
105
+
106
+ @validate # type:ignore
107
+ def is_directory(path: str) -> bool:
108
+ """return whether a path represents a directory
109
+
110
+ Args:
111
+ path (str): path to check
112
+ """
113
+ return os.path.isdir(path)
114
+
115
+
116
+ @validate # type:ignore
117
+ def get_files(path: str) -> List[str]:
118
+ """return a list of names of all files inside specified directory
119
+
120
+ Args:
121
+ path (str): directory
122
+
123
+ Returns:
124
+ list[str]: all files
125
+ """
126
+ files_and_directories = get_files_and_directories(path)
127
+ return list(
128
+ filter(lambda name: is_file(os.path.join(path, name)), files_and_directories))
129
+
130
+
131
+ @validate # type:ignore
132
+ def get_files_and_directories(path: str) -> List[str]:
133
+ """get a list of all files and directories in specified path
134
+
135
+ Args:
136
+ path (str): path to check
137
+
138
+ Returns:
139
+ list[str]: all files and directories
140
+ """
141
+ return os.listdir(path)
142
+
143
+
144
+ @validate # type:ignore
145
+ def get_directories(path: str) -> List[str]:
146
+ """get all directories in specified path
147
+
148
+ Args:
149
+ path (str): path to check
150
+
151
+ Returns:
152
+ list[str]: all directories
153
+ """
154
+ files_and_directories = get_files_and_directories(path)
155
+ return list(
156
+ filter(lambda name: is_directory(os.path.join(path, name)), files_and_directories))
157
+
158
+
159
+ @validate # type:ignore
160
+ def delete_directory(path: str) -> None:
161
+ """delete a directory and all its contents
162
+
163
+ Args:
164
+ path (str): _description_
165
+ """
166
+ if is_directory(path):
167
+ clear_directory(path)
168
+ os.rmdir(path)
169
+
170
+
171
+ @validate # type:ignore
172
+ def clear_directory(path: str) -> None:
173
+ """clears the content of a directory
174
+
175
+ Args:
176
+ path (str): the path of the directory to clean
177
+ """
178
+ for file in get_files(path):
179
+ delete_file(os.path.join(path, file))
180
+ for subdir in get_directories(path):
181
+ delete_directory(os.path.join(path, subdir))
182
+
183
+
184
+ @validate # type:ignore
185
+ def create_directory(path: str) -> None:
186
+ """create a directory at the specified path if it doesn't already exists
187
+
188
+ Args:
189
+ path (str): the path to create a directory at
190
+ """
191
+ if not directory_exists(path):
192
+ os.makedirs(path)
193
+
194
+
195
+ @validate # type:ignore
196
+ def create_file(path: str) -> None:
197
+ """
198
+ Will create a file at the specified path if it doesn't already exists
199
+ Args:
200
+ path (str): the path to create a file at
201
+ Returns:
202
+ None
203
+ """
204
+ if not file_exists(path):
205
+ with open(path, "w", encoding='utf8') as f:
206
+ pass
207
+
208
+
209
+ @validate # type:ignore
210
+ def get_file_type_from_directory(path: str, file_type: str) -> Iterator[str]:
211
+ """returns all file with specific type from a directory
212
+
213
+ Args:
214
+ path (str): path of directory
215
+ file_type (str): the desired file type. eg: ".png"
216
+
217
+ Returns:
218
+ list[str]: result
219
+ """
220
+ return filter(
221
+ lambda name: Path(os.path.join(path, name)).suffix == file_type,
222
+ get_files(path)
223
+ )
224
+
225
+
226
+ @validate # type:ignore
227
+ def get_file_type_from_directory_recursively(path: str, file_type: str) -> Generator[str, None, None]:
228
+ """_summary_
229
+
230
+ Args:
231
+ path (str): _description_
232
+ file_type (str): _description_
233
+
234
+ Returns:
235
+ _type_: _description_
236
+ """
237
+ yield from filter(
238
+ lambda name: Path(os.path.join(path, name)).suffix == file_type,
239
+ get_files(path)
240
+ )
241
+ for subdir in get_directories(path):
242
+ for v in get_file_type_from_directory_recursively(os.path.join(path, subdir), file_type):
243
+ yield os.path.join(subdir, v)
244
+
245
+
246
+ @validate # type:ignore
247
+ def rename_file(path: str, new_name: str) -> None:
248
+ """renames a file
249
+
250
+ Args:
251
+ path (str): file to rename
252
+ new_name (str): the desired new name
253
+ """
254
+ new_path = "./" + \
255
+ "/".join(Path(path).parts[:-1]) + "/" + new_name + Path(path).suffix
256
+ move_file(path, new_path)
257
+
258
+
259
+ @validate # type:ignore
260
+ def move_file(old_path: str, new_path: str) -> None:
261
+ """moves a file
262
+
263
+ Args:
264
+ old_path (str): old path
265
+ new_path (str): new path
266
+ """
267
+ os.rename(old_path, new_path)
268
+
269
+
270
+ @validate # type:ignore
271
+ async def open_file(file_path: str, application_path: str) -> int:
272
+ """open a file with the specified application
273
+
274
+ Args:
275
+ file_path (str): the file to open
276
+ application_path (str): the application to open with
277
+ Returns:
278
+ int: return code
279
+ """
280
+ with subprocess.Popen([application_path, file_path]) as p:
281
+ return p.wait()
282
+
283
+
284
+ # @validate # type:ignore
285
+ # def move_directory(old_path: str, new_path: str) -> None:
286
+ # """moves a directory
287
+ #
288
+ # Args:
289
+ # old_path (str): old path
290
+ # new_path (str): new path
291
+ # """
292
+ # shutil.move(old_path, new_path)
293
+ #
294
+ #
295
+ # @validate # type:ignore
296
+ # def copy_file(src: str, dest: str) -> None:
297
+ # """copies file from src to dest
298
+ #
299
+ # Args:
300
+ # src (str): src
301
+ # dest (str): dest
302
+ # """
303
+ # shutil.copy(src, dest)
304
+ #
305
+ #
306
+ # @validate # type:ignore
307
+ # def copy_directory(src: str, dest: str) -> None:
308
+ # """copies a directory from src to dest
309
+ #
310
+ # Args:
311
+ # src (str): stc
312
+ # dest (str): dest
313
+ # """
314
+ # shutil.copy(src, dest)
315
+ #
316
+
317
+ class IndentedWriter:
318
+ """every class that will inherit this class will have the following functions available
319
+ write() with the same arguments a builtin print()
320
+ indent()
321
+ undent()
322
+
323
+ also, it is expected in the __init__ function to call super().__init__()
324
+ also, the output_stream must be set whether by the first argument io super().__init__(...)
325
+ or by set_stream() explicitly somewhere else.
326
+
327
+ this class will not function properly is the output_stream is not set!
328
+
329
+ """
330
+
331
+ def __init__(self, output_stream: Optional[IO] = None, indent_value: str = "\t"):
332
+ self.indent_level = 0
333
+ self.output_stream: Optional[IO] = output_stream
334
+ self.indent_value = indent_value
335
+
336
+ def write(self, *args, sep=" ", end="\n") -> None:
337
+ """writes the supplied arguments to the output_stream
338
+
339
+ Args:
340
+ sep (str, optional): the str to use as a separator between arguments. Defaults to " ".
341
+ end (str, optional): the str to use as the final value. Defaults to "\n".
342
+
343
+ Raises:
344
+ ValueError: _description_
345
+ """
346
+ if self.output_stream is None:
347
+ raise ValueError(
348
+ "Can't write to an empty stream. the stream must not be None:"
349
+ " either by set_stream or by initialization")
350
+ self.output_stream.write(
351
+ str(self.indent_level * self.indent_value + sep.join(args) + end))
352
+
353
+ def set_stream(self, stream: IO) -> None:
354
+ """explicitly sets the stream
355
+
356
+ Args:
357
+ stream (IO): stream
358
+ """
359
+ self.output_stream = stream
360
+ self.output_stream = cast(IO, self.output_stream)
361
+
362
+ def indent(self) -> None:
363
+ """indents the preceding output with write() by one quantity more
364
+ """
365
+ self.indent_level += 1
366
+
367
+ def undent(self) -> None:
368
+ """un-dents the preceding output with write() by one quantity less
369
+ has a minimum value of 0
370
+ """
371
+ self.indent_level = max(0, self.indent_level - 1)
372
+
373
+
374
+ class IndentedWriter2:
375
+ """every class that will inherit this class will have the following functions available
376
+ write() with the same arguments a builtin print()
377
+ indent()
378
+ undent()
379
+
380
+ also, it is expected in the __init__ function to call super().__init__()
381
+ also, the output_stream must be set whether by the first argument io super().__init__(...)
382
+ or by set_stream() explicitly somewhere else.
383
+
384
+ this class will not function properly is the output_stream is not set!
385
+
386
+ """
387
+
388
+ def __init__(self, indent_value: str = "\t"):
389
+ self.indent_level = 0
390
+ self.indent_value = indent_value
391
+ self.buffer: str = ""
392
+
393
+ def to_stream(self, stream: IO[str]) -> None:
394
+ """outputs the buffer to a stream
395
+
396
+ Args:
397
+ stream (IO[str]): the stream to output to
398
+ """
399
+ stream.write(self.buffer)
400
+
401
+ def write(self, *args, sep=" ", end="\n") -> None:
402
+ """writes the supplied arguments to the output_stream
403
+
404
+ Args:
405
+ sep (str, optional): the str to use as a separator between arguments. Defaults to " ".
406
+ end (str, optional): the str to use as the final value. Defaults to "\n".
407
+
408
+ Raises:
409
+ ValueError: _description_
410
+ """
411
+ self.buffer += str(self.indent_level *
412
+ self.indent_value + sep.join(args) + end)
413
+
414
+ def indent(self) -> None:
415
+ """indents the preceding output with write() by one quantity more
416
+ """
417
+ self.indent_level += 1
418
+
419
+ def undent(self) -> None:
420
+ """un-dents the preceding output with write() by one quantity less
421
+ has a minimum value of 0
422
+ """
423
+ self.indent_level = max(0, self.indent_level - 1)
424
+
425
+
426
+ __all__ = [
427
+ "path_exists",
428
+ "file_exists",
429
+ "directory_exists",
430
+ "delete_file",
431
+ "read_file",
432
+ "is_file",
433
+ "is_directory",
434
+ "get_files",
435
+ "get_files_and_directories",
436
+ "get_directories",
437
+ "delete_directory",
438
+ "clear_directory",
439
+ "create_directory",
440
+ 'create_file',
441
+ "get_file_type_from_directory",
442
+ "get_file_type_from_directory_recursively",
443
+ "rename_file",
444
+ "move_file",
445
+ "open_file",
446
+ # "move_directory",
447
+ # "copy_file",
448
+ # "copy_directory",
449
+ "IndentedWriter",
450
+ "IndentedWriter2"
451
+ ]
@@ -0,0 +1,18 @@
1
+ import logging
2
+ from ..logging_.utils import get_logger
3
+ logger = get_logger(__name__)
4
+
5
+ from .java_interface import *
6
+
7
+ try:
8
+ from ..reflection import get_python_version # type:ignore
9
+ except ImportError:
10
+ from reflection import get_python_version
11
+
12
+ python_version = get_python_version()
13
+
14
+ if python_version >= (3, 10):
15
+ logger.info("Python version >= 3.10, importing Java interface modules")
16
+ from .interfaces import *
17
+ else:
18
+ logger.debug("Skipping optional Java interface modules on Python %s", python_version)
@@ -0,0 +1 @@
1
+ from .comparable import *
@@ -0,0 +1,31 @@
1
+ # from abc import abstractmethod
2
+ # from typing import TypeVar, Generic
3
+ #
4
+ # from ..java_interface import JavaInterface
5
+ #
6
+ # T = TypeVar('T')
7
+ #
8
+ #
9
+ # class Comparable(JavaInterface, Generic[T]):
10
+ # @abstractmethod
11
+ # def __lt__(self, other: T) -> bool: ...
12
+ #
13
+ # @abstractmethod
14
+ # def __gt__(self, other: T) -> bool: ...
15
+ #
16
+ # @abstractmethod
17
+ # def __eq__(self, other: T) -> bool: ...
18
+ #
19
+ # @abstractmethod
20
+ # def __le__(self, other: T) -> bool: ...
21
+ #
22
+ # @abstractmethod
23
+ # def __ge__(self, other: T) -> bool: ...
24
+ #
25
+ # @abstractmethod
26
+ # def __ne__(self, other: T) -> bool: ...
27
+ #
28
+ #
29
+ # __all__ = [
30
+ # "Comparable",
31
+ # ]
@@ -0,0 +1,59 @@
1
+
2
+ import logging
3
+ from abc import abstractmethod, ABC
4
+ from typing import Protocol, runtime_checkable, Any, Callable, Generic
5
+ from ..reflection import ClassInfo
6
+ from ..logging_.utils import get_logger
7
+
8
+ logger = get_logger(__name__)
9
+
10
+
11
+ class InterfaceError(Exception):
12
+ ...
13
+
14
+
15
+ # @runtime_checkable
16
+ class JavaInterface(ABC):
17
+ InterfaceError = InterfaceError
18
+
19
+ @classmethod
20
+ def __init_subclass__(cls, **kwargs) -> None:
21
+ logger.info("Initializing JavaInterface subclass: %s", cls.__name__)
22
+ info = ClassInfo(cls)
23
+
24
+ # Check if this is a direct interface definition
25
+ is_interface = False
26
+ for base in info.bases:
27
+ if base.name == JavaInterface.__name__:
28
+ setattr(cls, "__is_interface__", True)
29
+ is_interface = True
30
+ break
31
+
32
+ if not is_interface:
33
+ setattr(cls, "__is_interface__", False)
34
+ logger.debug("Validating interface compliance for implementation class: %s", cls.__name__)
35
+ info = ClassInfo(cls)
36
+
37
+ actual_func_names = set(f.name for f in info.functions)
38
+ for to_remove in {"__class_getitem__", "__init_subclass__"}:
39
+ if hasattr(cls, to_remove) and getattr(cls, to_remove, None) is getattr(JavaInterface, to_remove, None):
40
+ actual_func_names.remove(to_remove)
41
+
42
+ # Validate interface implementation
43
+ for interface in (base for base in cls.__mro__ if getattr(base, "__is_interface__", False)):
44
+ expected_func_names = set(f.name for f in ClassInfo(interface).abstract_methods)
45
+
46
+ if subtraction := expected_func_names.difference(actual_func_names):
47
+ error_msg = f"class '{cls.__name__}' does not implement required methods {subtraction}"
48
+ logger.error("Interface validation failed: %s", error_msg)
49
+ raise InterfaceError(error_msg)
50
+ else:
51
+ logger.debug("Class %s successfully implements interface %s", cls.__name__, interface.__name__)
52
+
53
+ logger.info("JavaInterface subclass %s initialized successfully", cls.__name__)
54
+ super().__init_subclass__(**kwargs)
55
+
56
+
57
+ __all__ = [
58
+ "JavaInterface",
59
+ ]
@@ -0,0 +1,2 @@
1
+ from ._impl import *
2
+ from .utils import *
@@ -0,0 +1,4 @@
1
+ from .builtin_impls import *
2
+ from .log_level import *
3
+ from .logger import *
4
+ from .logger_strategy_impl_base import *
@@ -0,0 +1,2 @@
1
+ from .print_logger import *
2
+ from .file_logger import *
@@ -0,0 +1,35 @@
1
+ import logging
2
+ from pathlib import Path
3
+
4
+ from ....io_ import delete_file, directory_exists, create_directory
5
+ from ...utils import get_logger
6
+ from ..logger_strategy_impl_base import LoggerStrategyImplBase
7
+
8
+ logger = get_logger(__name__)
9
+
10
+
11
+ class FIleLogger(LoggerStrategyImplBase):
12
+ def __init__(self, output_path: str, logger_id: str, delete_if_already_exists: bool = True, channel: str = "all"):
13
+ logger.info("Initializing FileLogger: path=%s, id=%s, delete_existing=%s, channel=%s", output_path, logger_id, delete_if_already_exists, channel)
14
+
15
+ if delete_if_already_exists:
16
+ delete_file(output_path)
17
+
18
+ parent = str(Path(output_path).parent.absolute().resolve())
19
+ if not directory_exists(parent):
20
+ logger.info("Creating parent directory: %s", parent)
21
+ create_directory(parent)
22
+
23
+ self.output_path: str = str(Path(output_path).absolute().resolve())
24
+
25
+ def foo(s: str):
26
+ with open(self.output_path, "a+") as f:
27
+ f.write(s)
28
+
29
+ super().__init__(foo, logger_id, channel)
30
+ logger.info("FileLogger %s initialized successfully", logger_id)
31
+
32
+
33
+ __all__ = [
34
+ "FIleLogger"
35
+ ]
@@ -0,0 +1,21 @@
1
+ import logging
2
+ from ...utils import get_logger
3
+ from ..logger_strategy_impl_base import LoggerStrategyImplBase
4
+
5
+ logger = get_logger(__name__)
6
+
7
+
8
+ class PrintLogger(LoggerStrategyImplBase):
9
+ def __init__(self, logger_id: str, channel: str = "all"):
10
+ logger.info("Initializing PrintLogger: id=%s, channel=%s", logger_id, channel)
11
+
12
+ def print_func(s: str):
13
+ print(s, end="")
14
+
15
+ super().__init__(print_func, logger_id, channel)
16
+ logger.info("PrintLogger %s initialized successfully", logger_id)
17
+
18
+
19
+ __all__ = [
20
+ "PrintLogger"
21
+ ]
@@ -0,0 +1,13 @@
1
+ from enum import IntEnum
2
+
3
+
4
+ class LogLevel(IntEnum):
5
+ DEBUG = 0
6
+ INFO = 1
7
+ WARNING = 2
8
+ ERROR = 3
9
+
10
+
11
+ __all__ = [
12
+ "LogLevel"
13
+ ]