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,109 @@
1
+ import json
2
+ import logging
3
+ from datetime import datetime
4
+ from typing import Any, Type, Optional, Dict, List
5
+
6
+ from .log_level import LogLevel
7
+ from .logger_strategy_impl_base import LoggerStrategyImplBase
8
+ from ..utils import get_logger
9
+
10
+ logger = get_logger(__name__)
11
+
12
+
13
+ class _LoggerImpl:
14
+ def __init__(self, origin: Type):
15
+ self.origin = origin
16
+
17
+ @classmethod
18
+ def parse_message(
19
+ cls,
20
+ origin: Type,
21
+ logger_id: Optional[str],
22
+ channel: str,
23
+ level: LogLevel,
24
+ message: str,
25
+ module: Optional[str] = None,
26
+ cls_name: Optional[str] = None,
27
+ metadata: Optional[Dict[str, Any]] = None
28
+ ) -> str:
29
+ d = dict(
30
+ timestamp=str(datetime.now()),
31
+ origin=origin.__qualname__,
32
+ logger_id=logger_id,
33
+ channel=channel,
34
+ level=level.name,
35
+ message=message
36
+ )
37
+ if module:
38
+ d.update({'module': module})
39
+
40
+ if cls_name:
41
+ d.update({'cls': cls_name})
42
+
43
+ if metadata:
44
+ d.update({'metadata': metadata})
45
+ s = json.dumps(d)
46
+ return f"{s}\n"
47
+
48
+ def _log(self, level: LogLevel, message: str, channel: str, **metadata):
49
+ message = str(message)
50
+ loggers_count = len(LoggerStrategyImplBase._loggers[channel])
51
+
52
+ for logger_instance in LoggerStrategyImplBase._loggers[channel]:
53
+ logger_instance(self.parse_message(
54
+ self.origin,
55
+ logger_instance.logger_id,
56
+ channel,
57
+ level,
58
+ message,
59
+ metadata.get("cls", {}).get("__module__", None),
60
+ metadata.pop("cls", {}).get("__qualname__", None),
61
+ metadata
62
+ ))
63
+
64
+ def debug(self, message: str, channel: str = "all", **metadata):
65
+ self._log(LogLevel.DEBUG, message, channel, **metadata)
66
+
67
+ def info(self, message: str, channel: str = "all", **metadata):
68
+ self._log(LogLevel.INFO, message, channel, **metadata)
69
+
70
+ def warning(self, message: str, channel: str = "all", **metadata):
71
+ self._log(LogLevel.WARNING, message, channel, **metadata)
72
+
73
+ def error(self, message: str, channel: str = "all", **metadata):
74
+ self._log(LogLevel.ERROR, message, channel, **metadata)
75
+
76
+
77
+ class Logger:
78
+ @classmethod
79
+ def __init_subclass__(cls, **kwargs) -> None:
80
+ logger.info("Initializing Logger subclass: %s", cls.__qualname__)
81
+ cls._logger = _LoggerImpl(cls)
82
+ cls._registered_loggers: List[LoggerStrategyImplBase] = []
83
+ cls.init_subscribers()
84
+ logger.info("Logger subclass %s initialized successfully", cls.__qualname__)
85
+
86
+ @classmethod
87
+ @property
88
+ def logger(cls) -> _LoggerImpl:
89
+ return cls._logger
90
+
91
+ @classmethod
92
+ def init_subscribers(cls):
93
+ pass
94
+
95
+ @classmethod
96
+ def register_logger(cls, logger_instance: LoggerStrategyImplBase) -> None:
97
+ logger.info("Registering logger %s for class %s", logger_instance.logger_id, cls.__qualname__)
98
+ cls._registered_loggers.append(logger_instance)
99
+ logger.info("Logger registered successfully, total registered: %s", len(cls._registered_loggers))
100
+
101
+
102
+ class GlobalLogger(Logger):
103
+ pass
104
+
105
+
106
+ __all__ = [
107
+ "Logger",
108
+ "GlobalLogger"
109
+ ]
@@ -0,0 +1,37 @@
1
+ import logging
2
+ from collections import defaultdict
3
+ from typing import Dict, List, Callable
4
+ from ..utils import get_logger
5
+
6
+ logger = get_logger(__name__)
7
+
8
+
9
+ class LoggerStrategyImplBase:
10
+ _loggers: Dict[str, List['LoggerStrategyImplBase']] = defaultdict(list)
11
+
12
+ def __init__(self, output_func: Callable[[str], None], logger_id: str, channel: str = "all"):
13
+ logger.info("Initializing LoggerStrategyImplBase: id=%s, channel=%s", logger_id, channel)
14
+ self.output_func: Callable[[str], None] = output_func
15
+ self.channel: str = channel
16
+ self.logger_id: str = logger_id
17
+ LoggerStrategyImplBase._loggers[channel].append(self)
18
+ logger.info("Logger %s added to channel %s, total loggers: %s", logger_id, channel, len(LoggerStrategyImplBase._loggers[channel]))
19
+
20
+ def __call__(self, s: str) -> None:
21
+ self.output_func(s)
22
+
23
+ def delete(self) -> None:
24
+ logger.info("Deleting logger %s from channel %s", self.logger_id, self.channel)
25
+ LoggerStrategyImplBase._loggers[self.channel].remove(self)
26
+ logger.info("Logger deleted, remaining loggers in channel: %s", len(LoggerStrategyImplBase._loggers[self.channel]))
27
+
28
+ def __enter__(self):
29
+ return self
30
+
31
+ def __exit__(self, exc_type, exc_val, exc_tb):
32
+ self.delete()
33
+
34
+
35
+ __all__ = [
36
+ "LoggerStrategyImplBase"
37
+ ]
@@ -0,0 +1,199 @@
1
+ import logging
2
+ import sys
3
+ import io
4
+ from typing import Optional, Dict, List
5
+
6
+
7
+ class UTF8StreamHandler(logging.StreamHandler):
8
+ """Custom StreamHandler that ensures UTF-8 encoding."""
9
+
10
+ def __init__(self, stream=None) -> None:
11
+ if stream is None:
12
+ stream = sys.stdout
13
+ super().__init__(stream)
14
+ # Ensure the stream uses UTF-8 encoding
15
+ if hasattr(stream, 'reconfigure'):
16
+ try:
17
+ stream.reconfigure(encoding='utf-8', errors='replace')
18
+ except (AttributeError, OSError):
19
+ pass
20
+
21
+ def emit(self, record):
22
+ try:
23
+ msg = self.format(record)
24
+ # Ensure the message is properly encoded
25
+ if isinstance(msg, str):
26
+ # Write as UTF-8 bytes to handle Unicode properly
27
+ self.stream.write(msg + self.terminator)
28
+ else:
29
+ self.stream.write(str(msg) + self.terminator)
30
+ self.flush()
31
+ except UnicodeError:
32
+ # Fallback for Unicode issues
33
+ try:
34
+ self.stream.write(f"Unicode error in log: {record.getMessage()}\n")
35
+ self.flush()
36
+ except Exception:
37
+ # Last resort - write to stderr
38
+ sys.stderr.write(f"Critical logging error: {record.getMessage()}\n")
39
+
40
+
41
+ class ExtraDataFormatter(logging.Formatter):
42
+ """Custom formatter that includes extra data from log records."""
43
+
44
+ def format(self, record: logging.LogRecord) -> str:
45
+ try:
46
+ # Get the base formatted message
47
+ base_message = super().format(record)
48
+
49
+ # Check for data in two ways:
50
+ # 1. Direct 'data' attribute
51
+ # 2. 'data' key inside 'extra' dict
52
+ data = getattr(record, 'data', None)
53
+ if data is None:
54
+ extra = getattr(record, 'extra', None)
55
+ if extra and isinstance(extra, dict):
56
+ data = extra.get('data')
57
+
58
+ if data and isinstance(data, dict):
59
+ # Format data as key=value pairs, sorted alphabetically by key
60
+ # Handle Unicode characters safely
61
+ sorted_items = sorted(data.items())
62
+ data_pairs = []
63
+ for k, v in sorted_items:
64
+ try:
65
+ # Ensure both key and value are properly encoded
66
+ k_str = str(k) if k is not None else 'None'
67
+ v_str = str(v) if v is not None else 'None'
68
+ data_pairs.append(f"{k_str}={v_str}")
69
+ except UnicodeError:
70
+ # Fallback for problematic Unicode characters
71
+ data_pairs.append(f"{repr(k)}={repr(v)}")
72
+
73
+ data_str = " | " + " | ".join(data_pairs)
74
+ return base_message + data_str
75
+
76
+ return base_message
77
+ except UnicodeError as e:
78
+ # Fallback for any Unicode issues
79
+ return f"Unicode error in log formatting: {e} | {record.getMessage()}"
80
+
81
+
82
+ class DanielUtilsLogFilter(logging.Filter):
83
+ """Filter to exclude danielutils logs when requested."""
84
+
85
+ def __init__(self, exclude_danielutils_logs: bool = True):
86
+ super().__init__()
87
+ self.exclude_danielutils_logs = exclude_danielutils_logs
88
+
89
+ def filter(self, record: logging.LogRecord) -> bool:
90
+ """
91
+ Filter log records based on whether danielutils logs should be excluded.
92
+
93
+ Args:
94
+ record: The log record to filter
95
+
96
+ Returns:
97
+ True if the record should be logged, False otherwise
98
+ """
99
+ if not self.exclude_danielutils_logs:
100
+ return True
101
+
102
+ # Check if the logger name starts with 'danielutils'
103
+ logger_name = record.name
104
+ return not logger_name.startswith('danielutils')
105
+
106
+
107
+ def get_logger(name: str) -> logging.Logger:
108
+ """
109
+ Get a logger instance using Python's builtin logging.getLogger.
110
+
111
+ This function simply delegates to the builtin logger and returns the result.
112
+
113
+ Args:
114
+ name: The name of the logger
115
+
116
+ Returns:
117
+ Logger instance from Python's builtin logging module
118
+ """
119
+ return logging.getLogger(name)
120
+
121
+
122
+ def setup_stdout_logging_handler(
123
+ level: int = logging.INFO,
124
+ format_string: Optional[str] = None,
125
+ exclude_danielutils_logs: bool = True
126
+ ) -> logging.Logger:
127
+ """
128
+ Set up stdout logging handler for proper log propagation.
129
+
130
+ This function adds a handler to the root logger so that all child loggers
131
+ will have their messages handled. This is the recommended approach for
132
+ logging configuration as it allows proper log propagation without
133
+ duplicating handlers on every logger.
134
+
135
+ Args:
136
+ level: The logging level (default: INFO)
137
+ format_string: Custom format string for log messages
138
+ exclude_danielutils_logs: Whether to exclude logs from danielutils modules (default: True)
139
+
140
+ Returns:
141
+ Root logger instance with the new handler added
142
+ """
143
+ if format_string is None:
144
+ format_string = '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
145
+
146
+ # Get root logger
147
+ root_logger = logging.getLogger()
148
+ root_logger.setLevel(level)
149
+
150
+ # Create console handler that outputs to stdout with UTF-8 encoding
151
+ console_handler = UTF8StreamHandler(sys.stdout)
152
+ console_handler.setLevel(level)
153
+
154
+ # Add filter to exclude danielutils logs if requested
155
+ if exclude_danielutils_logs:
156
+ danielutils_filter = DanielUtilsLogFilter(exclude_danielutils_logs=True)
157
+ console_handler.addFilter(danielutils_filter)
158
+
159
+ # Create formatter
160
+ formatter = ExtraDataFormatter(format_string)
161
+ console_handler.setFormatter(formatter)
162
+
163
+ # Add handler to root logger
164
+ root_logger.addHandler(console_handler)
165
+
166
+ return root_logger
167
+
168
+
169
+ def get_logger_handlers() -> Dict[str, List[logging.Handler]]:
170
+ """
171
+ Get all registered loggers and their handlers.
172
+
173
+ Returns:
174
+ Dictionary mapping logger names to lists of their registered handlers
175
+ """
176
+ logger_dict = {}
177
+
178
+ # Get all existing loggers
179
+ for name in logging.Logger.manager.loggerDict:
180
+ logger = logging.getLogger(name)
181
+ if logger.handlers:
182
+ logger_dict[name] = logger.handlers.copy()
183
+
184
+ # Also include the root logger if it has handlers
185
+ root_logger = logging.getLogger()
186
+ if root_logger.handlers:
187
+ logger_dict['root'] = root_logger.handlers.copy()
188
+
189
+ return logger_dict
190
+
191
+
192
+ __all__ = [
193
+ "UTF8StreamHandler",
194
+ "ExtraDataFormatter",
195
+ "DanielUtilsLogFilter",
196
+ "get_logger",
197
+ "setup_stdout_logging_handler",
198
+ "get_logger_handlers",
199
+ ]
@@ -0,0 +1 @@
1
+ from .builder import *
@@ -0,0 +1,68 @@
1
+ import logging
2
+ from typing import Type, Generic, TypeVar
3
+ from ..logging_.utils import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+ T = TypeVar("T", bound=Type)
8
+
9
+
10
+ class Builder(Generic[T]):
11
+ PREFIX: str = "foo"
12
+
13
+ def __init__(self, dcls: T):
14
+ logger.info("Initializing Builder for class: %s", dcls.__qualname__)
15
+ setattr(self, f"{Builder.PREFIX}_dcls", dcls)
16
+ setattr(self, f"{Builder.PREFIX}_kwargs", {})
17
+
18
+ def __getattribute__(self, item: str):
19
+ if item.startswith(Builder.PREFIX) or item == "build":
20
+ return super().__getattribute__(item)
21
+
22
+ cls = super().__getattribute__(f"{Builder.PREFIX}_dcls")
23
+
24
+ if item not in cls.__dataclass_fields__:
25
+ error_msg = f"'{cls.__qualname__}' object has no attribute '{item}'"
26
+ logger.error("AttributeError: %s", error_msg)
27
+ raise AttributeError(error_msg)
28
+
29
+ def inner(o) -> Builder:
30
+ getattr(self, f"{Builder.PREFIX}_kwargs")[item] = o
31
+ return self
32
+
33
+ return inner
34
+
35
+ def build(self) -> T:
36
+ dcls = getattr(self, f"{Builder.PREFIX}_dcls")
37
+ kwargs = getattr(self, f"{Builder.PREFIX}_kwargs")
38
+ instance = dcls(**kwargs)
39
+ logger.info("Successfully built instance of %s", dcls.__qualname__)
40
+ return instance
41
+
42
+
43
+ def builder(dcls: T):
44
+ logger.info("Applying @builder decorator to class: %s", dcls.__qualname__)
45
+
46
+ if not hasattr(dcls, "__dataclass_fields__"):
47
+ error_msg = "Can only create builders out of @dataclass classes"
48
+ logger.error("RuntimeError: %s", error_msg)
49
+ raise RuntimeError(error_msg)
50
+
51
+ for name in dcls.__dataclass_fields__.keys():
52
+ if name.startswith("build"):
53
+ error_msg = f"@builder reserves attributes that has 'build' prefix. Invalid attribute: '{name}'"
54
+ logger.error("AttributeError: %s", error_msg)
55
+ raise AttributeError(error_msg)
56
+
57
+ @classmethod # type: ignore
58
+ def builder_impl(cls) -> Builder[T]:
59
+ return Builder[T](cls)
60
+
61
+ setattr(dcls, "builder", builder_impl)
62
+ logger.info("Successfully applied @builder decorator to %s", dcls.__qualname__)
63
+ return dcls
64
+
65
+
66
+ __all__ = [
67
+ "builder"
68
+ ]
@@ -0,0 +1,2 @@
1
+ from .constants import *
2
+ from .functions import *
@@ -0,0 +1,103 @@
1
+ """mathematical constants that are useful in calculations"""
2
+ PI = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
3
+ E = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
4
+ PRIMES_1000 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
5
+ 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
6
+ 79, 83, 89, 97, 101, 103, 107, 109, 113, 127,
7
+ 131, 137, 139, 149, 151, 157, 163, 167, 173, 179,
8
+ 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
9
+ 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
10
+ 293, 307, 311, 313, 317, 331, 337, 347, 349, 353,
11
+ 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
12
+ 421, 431, 433, 439, 443, 449, 457, 461, 463, 467,
13
+ 479, 487, 491, 499, 503, 509, 521, 523, 541, 547,
14
+ 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,
15
+ 613, 617, 619, 631, 641, 643, 647, 653, 659, 661,
16
+ 673, 677, 683, 691, 701, 709, 719, 727, 733, 739,
17
+ 743, 751, 757, 761, 769, 773, 787, 797, 809, 811,
18
+ 821, 823, 827, 829, 839, 853, 857, 859, 863, 877,
19
+ 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
20
+ 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019,
21
+ 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087,
22
+ 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153,
23
+ 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229,
24
+ 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297,
25
+ 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381,
26
+ 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453,
27
+ 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523,
28
+ 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597,
29
+ 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663,
30
+ 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741,
31
+ 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823,
32
+ 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901,
33
+ 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993,
34
+ 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063,
35
+ 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131,
36
+ 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221,
37
+ 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293,
38
+ 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371,
39
+ 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437,
40
+ 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539,
41
+ 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621,
42
+ 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689,
43
+ 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749,
44
+ 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833,
45
+ 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909,
46
+ 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001,
47
+ 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083,
48
+ 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187,
49
+ 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259,
50
+ 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343,
51
+ 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433,
52
+ 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517,
53
+ 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581,
54
+ 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659,
55
+ 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733,
56
+ 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823,
57
+ 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911,
58
+ 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001,
59
+ 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073,
60
+ 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153,
61
+ 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241,
62
+ 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327,
63
+ 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421,
64
+ 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507,
65
+ 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591,
66
+ 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663,
67
+ 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759,
68
+ 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861,
69
+ 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943,
70
+ 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009,
71
+ 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099,
72
+ 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189,
73
+ 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281,
74
+ 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393,
75
+ 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449,
76
+ 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527,
77
+ 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641,
78
+ 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701,
79
+ 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801,
80
+ 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861,
81
+ 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953,
82
+ 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067,
83
+ 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143,
84
+ 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229,
85
+ 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311,
86
+ 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373,
87
+ 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481,
88
+ 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577,
89
+ 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679,
90
+ 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763,
91
+ 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841,
92
+ 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947,
93
+ 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001,
94
+ 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109,
95
+ 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211,
96
+ 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307,
97
+ 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417,
98
+ 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507,
99
+ 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573,
100
+ 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649,
101
+ 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727,
102
+ 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841,
103
+ 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919]
@@ -0,0 +1,34 @@
1
+ from typing import Union
2
+ from ..decorators import validate
3
+
4
+
5
+ @validate # type:ignore
6
+ def sign(v: Union[int, float]) -> int:
7
+ """return the sign of the number
8
+
9
+ Args:
10
+ v (Union[int, float]): number
11
+
12
+ Returns:
13
+ int: either 1 or -1
14
+ """
15
+ if v >= 0:
16
+ return 1
17
+ return -1
18
+
19
+
20
+ def lp_norm(arr, p: Union[int, float]) -> float:
21
+ """calculates a norm over the data
22
+ """
23
+ return root(sum(abs(v)**p for v in arr), p)
24
+
25
+
26
+ def root(value, power: Union[int, float]) -> float:
27
+ """calculates any root over value
28
+ """
29
+ return value**(1/power)
30
+
31
+
32
+ __all__ = [
33
+ "sign"
34
+ ]
@@ -0,0 +1,52 @@
1
+ import logging
2
+ from .math_symbols import subscript_dict, superscript_dict
3
+ from ..logging_.utils import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+
8
+ def mprint_parse_one(s: str) -> str:
9
+ """a helper function that parses "mathematically" one string
10
+
11
+ Args:
12
+ s (str): the string to parse with math_ symbols
13
+
14
+ Returns:
15
+ str: the result
16
+ """
17
+ logger.info("Parsing mathematical string: %s", s)
18
+
19
+ def inner(res: str, index: int, dct: dict):
20
+ start = index
21
+ while index < len(s) and s[index] not in {' ', '*', '+', '-', '/', '_', '^'}:
22
+ index += 1
23
+ end = index
24
+ for char in s[start:end]:
25
+ if char in dct:
26
+ res += dct[char]
27
+ else:
28
+ res += char
29
+ index -= 1
30
+ return res, index
31
+
32
+ res: str = ""
33
+ i = 0
34
+ while i < len(s):
35
+ c = s[i]
36
+ if c == "^":
37
+ i += 1
38
+ res, i = inner(res, i, superscript_dict)
39
+ elif c == "_":
40
+ i += 1
41
+ res, i = inner(res, i, subscript_dict)
42
+ else:
43
+ res += c
44
+ i += 1
45
+
46
+ logger.info("Parsing completed, result: %s", res)
47
+ return res
48
+
49
+
50
+ __all__ = [
51
+ "mprint_parse_one"
52
+ ]