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,207 @@
1
+ import ast
2
+ from enum import Enum
3
+ from typing import List, Union, Optional
4
+
5
+
6
+ class ImportType(Enum):
7
+ """Enumeration of import types."""
8
+ GLOBAL_PACKAGE = "global_package" # "import x"
9
+ GLOBAL_FROM_PACKAGE = "global_from_package" # "from x import y"
10
+ LOCAL_PACKAGE = "local_package" # "import .x" or "import ..x"
11
+ # "from .x import y" or "from ..x import y"
12
+ LOCAL_FROM_PACKAGE = "local_from_package"
13
+
14
+
15
+ class ImportInfo:
16
+ """
17
+ A class that encapsulates information about a single import statement.
18
+
19
+ This class provides detailed information about imports including:
20
+ - The type of import (global vs local, package vs from_package)
21
+ - Whether the import is absolute or relative
22
+ - Module names and imported object names
23
+ - Aliases used in the import
24
+ """
25
+
26
+ def __init__(self,
27
+ import_type: ImportType,
28
+ is_absolute: bool,
29
+ module_name: str,
30
+ imported_object: Optional[str] = None,
31
+ alias: Optional[str] = None,
32
+ relative_level: int = 0) -> None:
33
+ """
34
+ Initialize ImportInfo.
35
+
36
+ :param import_type: The type of import (from ImportType enum)
37
+ :param is_absolute: Whether the import is absolute (True) or relative (False)
38
+ :param module_name: The name of the module being imported from
39
+ :param imported_object: The name of the specific object being imported (for from imports)
40
+ :param alias: The alias used for the import (if any)
41
+ :param relative_level: The number of dots for relative imports (0 for absolute)
42
+ """
43
+ self._import_type = import_type
44
+ self._is_absolute = is_absolute
45
+ self._module_name = module_name
46
+ self._imported_object = imported_object
47
+ self._alias = alias
48
+ self._relative_level = relative_level
49
+
50
+ @property
51
+ def import_type(self) -> ImportType:
52
+ """Returns the type of import."""
53
+ return self._import_type
54
+
55
+ @property
56
+ def is_absolute(self) -> bool:
57
+ """Returns True if the import is absolute, False if relative."""
58
+ return self._is_absolute
59
+
60
+ @property
61
+ def is_relative(self) -> bool:
62
+ """Returns True if the import is relative, False if absolute."""
63
+ return not self._is_absolute
64
+
65
+ @property
66
+ def module_name(self) -> str:
67
+ """Returns the name of the module being imported from."""
68
+ return self._module_name
69
+
70
+ @property
71
+ def imported_object(self) -> Optional[str]:
72
+ """Returns the name of the imported object (for from imports)."""
73
+ return self._imported_object
74
+
75
+ @property
76
+ def alias(self) -> Optional[str]:
77
+ """Returns the alias used for the import (if any)."""
78
+ return self._alias
79
+
80
+ @property
81
+ def relative_level(self) -> int:
82
+ """Returns the number of dots for relative imports (0 for absolute)."""
83
+ return self._relative_level
84
+
85
+ @property
86
+ def effective_name(self) -> str:
87
+ """Returns the effective name used in the code (alias if provided, otherwise imported_object or module_name)."""
88
+ if self.alias:
89
+ return self.alias
90
+ elif self.imported_object:
91
+ return self.imported_object
92
+ else:
93
+ return self.module_name.split('.')[-1]
94
+
95
+ def __str__(self) -> str:
96
+ return (f"ImportInfo(type={self.import_type.value}, "
97
+ f"absolute={self.is_absolute}, "
98
+ f"module='{self.module_name}', "
99
+ f"object={self.imported_object}, "
100
+ f"alias={self.alias})")
101
+
102
+ def __repr__(self) -> str:
103
+ return self.__str__()
104
+
105
+ def to_dict(self) -> dict:
106
+ """Returns a dictionary representation of the import information."""
107
+ return {
108
+ "import_type": self.import_type.value,
109
+ "is_absolute": self.is_absolute,
110
+ "module_name": self.module_name,
111
+ "imported_object": self.imported_object,
112
+ "alias": self.alias,
113
+ "relative_level": self.relative_level,
114
+ "effective_name": self.effective_name
115
+ }
116
+
117
+ @classmethod
118
+ def from_ast(cls, node: Union[ast.Import, ast.ImportFrom]) -> List["ImportInfo"]:
119
+ """
120
+ Create ImportInfo instances from AST nodes.
121
+
122
+ :param node: An ast.Import or ast.ImportFrom node
123
+ :return: A list of ImportInfo objects
124
+ """
125
+ imports = []
126
+
127
+ if isinstance(node, ast.Import):
128
+ # Handle "import x" statements
129
+ for alias in node.names:
130
+ module_name = alias.name
131
+ is_absolute = not module_name.startswith('.')
132
+ relative_level = 0
133
+
134
+ if not is_absolute:
135
+ # Count leading dots for relative imports
136
+ relative_level = len(module_name) - \
137
+ len(module_name.lstrip('.'))
138
+ module_name = module_name[relative_level:]
139
+
140
+ import_type = ImportType.LOCAL_PACKAGE if not is_absolute else ImportType.GLOBAL_PACKAGE
141
+
142
+ imports.append(cls(
143
+ import_type=import_type,
144
+ is_absolute=is_absolute,
145
+ module_name=module_name,
146
+ imported_object=None,
147
+ alias=alias.asname,
148
+ relative_level=relative_level
149
+ ))
150
+
151
+ elif isinstance(node, ast.ImportFrom):
152
+ # Handle "from x import y" statements
153
+ module_name = node.module if node.module is not None else ""
154
+ is_absolute = True # Default to absolute
155
+ relative_level = 0
156
+
157
+ # Check if this is a relative import by looking at the level attribute
158
+ if hasattr(node, 'level') and node.level > 0:
159
+ is_absolute = False
160
+ relative_level = node.level
161
+ elif module_name.startswith('.'):
162
+ # Fallback: check if module name starts with dots
163
+ is_absolute = False
164
+ relative_level = len(module_name) - \
165
+ len(module_name.lstrip('.'))
166
+ module_name = module_name[relative_level:]
167
+
168
+ import_type = ImportType.LOCAL_FROM_PACKAGE if not is_absolute else ImportType.GLOBAL_FROM_PACKAGE
169
+
170
+ for alias in node.names:
171
+ imported_object = alias.name
172
+ imports.append(cls(
173
+ import_type=import_type,
174
+ is_absolute=is_absolute,
175
+ module_name=module_name,
176
+ imported_object=imported_object,
177
+ alias=alias.asname,
178
+ relative_level=relative_level
179
+ ))
180
+
181
+ return imports
182
+
183
+ @classmethod
184
+ def from_string(cls, import_string: str) -> List["ImportInfo"]:
185
+ """
186
+ Create ImportInfo instances from a string representation of import statements.
187
+
188
+ :param import_string: A string containing import statements
189
+ :return: A list of ImportInfo objects
190
+ """
191
+ try:
192
+ tree = ast.parse(import_string)
193
+ imports = []
194
+
195
+ for node in ast.walk(tree):
196
+ if isinstance(node, (ast.Import, ast.ImportFrom)):
197
+ imports.extend(cls.from_ast(node))
198
+
199
+ return imports
200
+ except SyntaxError:
201
+ raise ValueError(f"Invalid import string: {import_string}")
202
+
203
+
204
+ __all__ = [
205
+ "ImportInfo",
206
+ "ImportType"
207
+ ]
@@ -0,0 +1,9 @@
1
+ from .packages import *
2
+ from .python_version import *
3
+ from .tracer import *
4
+ from .os_ import *
5
+ from .callstack import *
6
+ from .get_traceback import *
7
+ from .signals import *
8
+ from .interpreter import *
9
+ from .is_debugging import *
@@ -0,0 +1,57 @@
1
+ import logging
2
+ import inspect
3
+ from typing import Optional
4
+ from types import FrameType
5
+ from ...logging_.utils import get_logger
6
+
7
+ logger = get_logger(__name__)
8
+
9
+
10
+ def _get_prev_frame_from(frame: Optional[FrameType]) -> Optional[FrameType]:
11
+ """Get the previous frame (caller's frame) in the call stack."""
12
+ return frame.f_back if frame is not None else None
13
+
14
+
15
+ def get_current_frame() -> Optional[FrameType]:
16
+ logger.debug("Getting current frame")
17
+ frame = _get_prev_frame_from(inspect.currentframe())
18
+ logger.debug("Current frame: %s", frame)
19
+ return frame
20
+
21
+
22
+ def get_prev_frame(n_steps: int = 1) -> Optional[FrameType]:
23
+ logger.debug("Getting previous frame with %s steps", n_steps)
24
+ if (f := get_current_frame()) is None:
25
+ logger.debug("No current frame available")
26
+ return None
27
+ i = 0
28
+ while i < n_steps:
29
+ if (f := f.f_back) is None:
30
+ logger.debug("Reached end of call stack at step %s", i)
31
+ return None
32
+ i += 1
33
+ logger.debug("Found previous frame after %s steps", n_steps)
34
+ return f
35
+
36
+
37
+ def get_prev_line_of_code(n_steps: int = 1) -> Optional[str]:
38
+ logger.debug("Getting previous line of code with %s steps", n_steps)
39
+ frame = get_prev_frame(n_steps + 1)
40
+ if frame is None:
41
+ logger.debug("No frame found for line of code")
42
+ return None
43
+ file = frame.f_back.f_code.co_filename # type:ignore
44
+ line_number = frame.f_back.f_lineno - 1 # type:ignore
45
+ logger.debug("Reading line %s from file: %s", line_number, file)
46
+ with open(file, "r", encoding="utf-8") as f:
47
+ lines = f.readlines()
48
+ line = lines[line_number]
49
+ logger.debug("Previous line of code: %s", line.strip())
50
+ return line
51
+
52
+
53
+ __all__ = [
54
+ "get_current_frame",
55
+ "get_prev_frame",
56
+ "get_prev_line_of_code"
57
+ ]
@@ -0,0 +1,27 @@
1
+ import traceback
2
+ from .python_version import get_python_version
3
+
4
+ if get_python_version() < (3, 9):
5
+ from typing import List as List
6
+ else:
7
+ from builtins import list as List
8
+
9
+ from .is_debugging import is_debugging
10
+
11
+
12
+ def get_traceback() -> List[str]:
13
+ """returns the traceback of the stack until current frame
14
+
15
+ Returns:
16
+ list[str]: list of frames as strings
17
+ """
18
+ s = slice(8, -2)
19
+ if not is_debugging():
20
+ # TODO: fix
21
+ s = s
22
+ return traceback.format_stack()[8:-2]
23
+
24
+
25
+ __all__ = [
26
+ "get_traceback"
27
+ ]
@@ -0,0 +1,41 @@
1
+ import os
2
+ import sys
3
+ from typing import Any
4
+
5
+
6
+ class Interpreter:
7
+ def get_version(self):
8
+ pass
9
+
10
+ def __init__(self, executable_path: str) -> None:
11
+ self._executable_path = executable_path
12
+
13
+ def _execute(self, command: str) -> None:
14
+ os.system(command)
15
+
16
+ def run_module(self, module_name: str, *args, **kwargs) -> None:
17
+ jargs = " ".join(args)
18
+ jkwargs = " ".join([f"{k}={v}" for k, v in kwargs.items()])
19
+ self._execute(f'{self._executable_path} -m {module_name} {jargs} {jkwargs}')
20
+
21
+ def execute_file(self, file_name: str, *args, **kwargs) -> None:
22
+ jargs = " ".join(args)
23
+ jkwargs = " ".join([f"{k}={v}" for k, v in kwargs.items()])
24
+ self._execute(f'{self._executable_path} {file_name} {jargs} {jkwargs}')
25
+
26
+ def execute_package(self, package_name: str, *args, **kwargs) -> None:
27
+ self.execute_file(package_name, *args, **kwargs)
28
+
29
+ def evaluate(self, expr: str) -> Any:
30
+ return self._execute(f"{self._executable_path} -c {expr}")
31
+
32
+
33
+ class CurrentInterpreter(Interpreter):
34
+ def __init__(self) -> None:
35
+ super().__init__(sys.executable)
36
+
37
+
38
+ __all__ = [
39
+ "Interpreter",
40
+ "CurrentInterpreter",
41
+ ]
@@ -0,0 +1,13 @@
1
+ import sys
2
+
3
+
4
+ def is_debugging() -> bool:
5
+ # TODO: fix
6
+ print("function 'is_debugging' might not work properly")
7
+ attr = getattr(sys, 'gettrace', None)
8
+ return bool(attr)
9
+
10
+
11
+ __all__ = [
12
+ "is_debugging"
13
+ ]
@@ -0,0 +1,33 @@
1
+ import sys
2
+ from enum import Enum
3
+
4
+
5
+ class OSType(Enum):
6
+ """enum result for possible results of get_os()
7
+ """
8
+ LINUX = "Linux"
9
+ WINDOWS = "Windows"
10
+ OSX = "OS X"
11
+ UNKNOWN = "Unknown"
12
+
13
+
14
+ def get_os() -> OSType:
15
+ """returns the type of operation system running this code
16
+
17
+ Returns:
18
+ OSType: enum result
19
+ """
20
+ p = sys.platform
21
+ if p in {"linux", "linux2"}:
22
+ return OSType.LINUX
23
+ if p == "darwin":
24
+ return OSType.OSX
25
+ if p == "win32":
26
+ return OSType.WINDOWS
27
+ return OSType.UNKNOWN
28
+
29
+
30
+ __all__ = [
31
+ "OSType",
32
+ "get_os",
33
+ ]
@@ -0,0 +1,33 @@
1
+ # from typing import Optional
2
+ # from ...system import cm
3
+ # from ...decorators import memo
4
+ #
5
+ # @memo
6
+ # def get_currently_installed_packages() -> list[tuple[str, str]]:
7
+ # ret, out, err = cm("pip", "list")
8
+ # text = out.decode("utf-8")
9
+ # res = []
10
+ # for line in text.splitlines()[2:]:
11
+ # splits = line.split(" ")
12
+ # dep = splits[0]
13
+ # ver = splits[-1]
14
+ # res.append((dep, ver))
15
+ # return res
16
+ #
17
+ #
18
+ # def is_package_installed(name: str, *, min_version: Optional[str] = None, max_version: Optional[str] = None) -> bool:
19
+ # for dep, ver in get_currently_installed_packages():
20
+ # if dep == name:
21
+ # res = True
22
+ # if min_version is not None:
23
+ # res = res and ver >= min_version
24
+ # if max_version is not None:
25
+ # res = res and ver <= max_version
26
+ # return res
27
+ # return False
28
+ #
29
+ #
30
+ # __all__ = [
31
+ # "get_currently_installed_packages",
32
+ # "is_package_installed"
33
+ # ]
@@ -0,0 +1,33 @@
1
+ import logging
2
+ import platform
3
+ from ...logging_.utils import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+
8
+ def _get_python_version_untyped() -> tuple:
9
+ values = (int(v) for v in platform.python_version().split("."))
10
+ version = tuple(values) # type:ignore
11
+ return version
12
+
13
+
14
+ if _get_python_version_untyped() < (3, 9):
15
+ from typing import Tuple as Tuple
16
+ else:
17
+ from builtins import tuple as Tuple # type:ignore
18
+
19
+
20
+ def get_python_version() -> Tuple[int, int, int]:
21
+ """return the version of python that is currently running this code
22
+
23
+ Returns:
24
+ tuple[int, int, int]: version
25
+ """
26
+ version = _get_python_version_untyped()
27
+ logger.info("Python version: %s", version)
28
+ return version # type:ignore
29
+
30
+
31
+ __all__ = [
32
+ "get_python_version"
33
+ ]
@@ -0,0 +1,18 @@
1
+ from typing import Callable, Optional
2
+ from types import FrameType
3
+ import signal
4
+
5
+
6
+ def register_signal_handler(signal_number: int, handler: Callable[[int, Optional[FrameType]], None]):
7
+ """register a signal handler for specified signal
8
+
9
+ Args:
10
+ signal_number (int): signal number to handle
11
+ handler (Callable[[int, FrameType], None]): the handler function
12
+ """
13
+ signal.signal(signal_number, handler)
14
+
15
+
16
+ __all__ = [
17
+ "register_signal_handler"
18
+ ]
@@ -0,0 +1,175 @@
1
+ import sys
2
+ from abc import ABC, abstractmethod
3
+ from enum import Enum
4
+ from types import FrameType
5
+ from typing import Any, Callable, Optional, Set as Set, Dict as Dict
6
+ from .python_version import get_python_version
7
+
8
+ if get_python_version() >= (3, 9):
9
+ from builtins import set as Set, dict as Dict
10
+
11
+
12
+ # from danielutils import singleton
13
+ # @singleton
14
+ class Tracer(ABC):
15
+ """
16
+ A class to trace (during runtime) the flow of the currently executing code
17
+ """
18
+ _INSTANCE = None
19
+
20
+ class EventType(Enum):
21
+ """
22
+ An enum class to represent all the types of possible events
23
+ """
24
+ CALL = "call"
25
+ C_CALL = "c_call"
26
+ RETURN = "return"
27
+ C_RETURN = "c_return"
28
+
29
+ @staticmethod
30
+ def from_value(value: str):
31
+ """
32
+ Converts the given value to a Tracer.EventType instance
33
+ """
34
+ if value not in Tracer.EventType._value2member_map_:
35
+ raise KeyError("Unknown value")
36
+ return Tracer.EventType._value2member_map_[value]
37
+
38
+ def __init__(
39
+ self,
40
+ *,
41
+ skip_call: bool = False,
42
+ skip_return: bool = False,
43
+ skip_c_call: bool = True,
44
+ skip_c_return: bool = True,
45
+ functions: bool = True,
46
+ classes: bool = True,
47
+ instance_methods: bool = True,
48
+ static_methods: bool = True,
49
+ class_methods: bool = True,
50
+ exclude: Optional[Set[str]] = None
51
+ ) -> None:
52
+
53
+ self._call_dict: Dict[Tracer.EventType, Callable] = {
54
+ Tracer.EventType.CALL: self.on_call,
55
+ Tracer.EventType.C_CALL: self.on_call_c,
56
+ Tracer.EventType.RETURN: self.on_return,
57
+ Tracer.EventType.C_RETURN: self.on_return_c,
58
+ }
59
+ self._skip_call = skip_call
60
+ self._skip_return = skip_return
61
+ self._skip_c_call = skip_c_call
62
+ self._skip_c_return = skip_c_return
63
+ self._functions = functions
64
+ self._classes = classes
65
+ self._instance_methods = instance_methods
66
+ self._static_methods = static_methods
67
+ self._class_methods = class_methods
68
+ self._exclude = exclude if exclude is not None else set()
69
+ from ...data_structures import Stack
70
+ self._exclude_stack: Stack[str] = Stack()
71
+
72
+ def _handler(self, stack_frame: FrameType, event_type: str, return_value: Optional[Any]):
73
+ et = Tracer.EventType.from_value(event_type)
74
+ if not self._should_skip(et, stack_frame):
75
+ values = self.parse_event(stack_frame, et, return_value)
76
+ self._call_dict[et](*values)
77
+ return self._handler
78
+
79
+ def _should_skip(self, et: 'Tracer.EventType', frame: FrameType) -> bool:
80
+ func_name = frame.f_code.co_qualname
81
+
82
+ if not self._exclude_stack.is_empty():
83
+ if et in {Tracer.EventType.CALL, Tracer.EventType.C_CALL}:
84
+ self._exclude_stack.push(func_name)
85
+ else:
86
+ self._exclude_stack.pop()
87
+ return True
88
+ if func_name in self._exclude:
89
+ self._exclude_stack.push(func_name)
90
+ return True
91
+
92
+ if et == Tracer.EventType.CALL and self._skip_call or \
93
+ et == Tracer.EventType.RETURN and self._skip_return or \
94
+ et == Tracer.EventType.C_CALL and self._skip_c_call or \
95
+ et == Tracer.EventType.C_RETURN and self._skip_c_return:
96
+ return True
97
+
98
+ # TODO add more cases
99
+ return False
100
+
101
+ def __enter__(self):
102
+ if Tracer._INSTANCE is not None:
103
+ raise RuntimeError("Can only have one active Tracer object at a time")
104
+ Tracer._INSTANCE = self
105
+ self.start_tracing()
106
+ return self
107
+
108
+ def __exit__(self, exc_type, exc_val, exc_tb):
109
+ Tracer._INSTANCE = None
110
+ self.stop_tracing()
111
+
112
+ def start_tracing(self) -> None:
113
+ sys.setprofile(self._handler)
114
+
115
+ def stop_tracing(self) -> None:
116
+ sys.setprofile(None)
117
+
118
+ @abstractmethod
119
+ def parse_event(self, frame: FrameType, et: EventType, return_value: Optional[Any]) -> tuple:
120
+ pass
121
+
122
+ @abstractmethod
123
+ def on_call(self, *args, **kwargs) -> None:
124
+ """
125
+ A Handler for when a function is called
126
+ """
127
+
128
+ @abstractmethod
129
+ def on_call_c(self, *args, **kwargs) -> None:
130
+ """
131
+ A Handler for when an underlying C function is called
132
+ """
133
+
134
+ @abstractmethod
135
+ def on_return(self, *args, **kwargs) -> None:
136
+ """
137
+ A Handler for when a function returns
138
+ """
139
+
140
+ @abstractmethod
141
+ def on_return_c(self, *args, **kwargs) -> None:
142
+ """
143
+ A Handler for when an underlying C function returns
144
+ """
145
+
146
+
147
+ class ConsoleTracer(Tracer):
148
+ # def __init__(self, *args, **kwargs) -> None:
149
+ # super().__init__(*args, **kwargs)
150
+
151
+ def parse_event(self, frame: FrameType, event_type: Tracer.EventType, return_value: Optional[Any]) -> tuple:
152
+ func_name: str = frame.f_code.co_qualname
153
+ base: tuple = event_type, func_name
154
+ final: tuple = base
155
+ if return_value is not None:
156
+ final = *base, return_value
157
+ return final
158
+
159
+ def on_call(self, *args, **kwargs) -> None:
160
+ print(*args, **kwargs)
161
+
162
+ def on_call_c(self, *args, **kwargs) -> None:
163
+ print(*args, **kwargs)
164
+
165
+ def on_return(self, *args, **kwargs) -> None:
166
+ print(*args, **kwargs)
167
+
168
+ def on_return_c(self, *args, **kwargs) -> None:
169
+ print(*args, **kwargs)
170
+
171
+
172
+ __all__ = [
173
+ "Tracer",
174
+ "ConsoleTracer"
175
+ ]
@@ -0,0 +1,3 @@
1
+ from .module_reflections import *
2
+ from .package_reflection import *
3
+ from .lazy_module import *