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.
- danielutils/__init__.py +50 -0
- danielutils/abstractions/__init__.py +3 -0
- danielutils/abstractions/db/__init__.py +10 -0
- danielutils/abstractions/db/database.py +206 -0
- danielutils/abstractions/db/database_definitions.py +219 -0
- danielutils/abstractions/db/database_exceptions.py +34 -0
- danielutils/abstractions/db/database_factory.py +70 -0
- danielutils/abstractions/db/database_initializer.py +261 -0
- danielutils/abstractions/db/database_models.py +213 -0
- danielutils/abstractions/db/dependencies.py +6 -0
- danielutils/abstractions/db/implementations/__init__.py +4 -0
- danielutils/abstractions/db/implementations/in_memory_database.py +365 -0
- danielutils/abstractions/db/implementations/persistent_in_memory_database.py +174 -0
- danielutils/abstractions/db/implementations/redis_database.py +403 -0
- danielutils/abstractions/db/implementations/sqlite_database.py +491 -0
- danielutils/abstractions/multiprogramming/__init__.py +3 -0
- danielutils/abstractions/multiprogramming/multi_id.py +26 -0
- danielutils/abstractions/multiprogramming/worker.py +104 -0
- danielutils/abstractions/multiprogramming/worker_pool.py +98 -0
- danielutils/abstractions/repl.py +125 -0
- danielutils/aliases.py +174 -0
- danielutils/async_/__init__.py +7 -0
- danielutils/async_/async_cmd.py +28 -0
- danielutils/async_/async_command.py +879 -0
- danielutils/async_/async_layered_command.py +125 -0
- danielutils/async_/async_retry_executor.py +86 -0
- danielutils/async_/async_worker_pool.py +110 -0
- danielutils/async_/time_strategy.py +73 -0
- danielutils/async_/utils.py +57 -0
- danielutils/better_builtins/__init__.py +3 -0
- danielutils/better_builtins/counter.py +48 -0
- danielutils/better_builtins/frange.py +266 -0
- danielutils/better_builtins/typed_builtins/__init__.py +4 -0
- danielutils/better_builtins/typed_builtins/factory.py +126 -0
- danielutils/better_builtins/typed_builtins/tdict.py +36 -0
- danielutils/better_builtins/typed_builtins/tlist.py +223 -0
- danielutils/better_builtins/typed_builtins/tset.py +67 -0
- danielutils/better_builtins/typed_builtins/ttuple.py +15 -0
- danielutils/colors.py +203 -0
- danielutils/context_managers/__init__.py +5 -0
- danielutils/context_managers/attr_context.py +40 -0
- danielutils/context_managers/multi_context.py +34 -0
- danielutils/context_managers/optional_context.py +33 -0
- danielutils/context_managers/state_context.py +25 -0
- danielutils/context_managers/temporary_file.py +108 -0
- danielutils/convenience.py +12 -0
- danielutils/conversions/__init__.py +2 -0
- danielutils/conversions/main_conversions.py +131 -0
- danielutils/conversions/specialized_conversions/__init__.py +2 -0
- danielutils/conversions/specialized_conversions/to_hex.py +25 -0
- danielutils/conversions/specialized_conversions/to_int.py +19 -0
- danielutils/custom_types.py +18 -0
- danielutils/data_structures/__init__.py +8 -0
- danielutils/data_structures/algorithms.py +52 -0
- danielutils/data_structures/comparer.py +47 -0
- danielutils/data_structures/default_dict.py +23 -0
- danielutils/data_structures/functions.py +35 -0
- danielutils/data_structures/graph/__init__.py +4 -0
- danielutils/data_structures/graph/binary_node.py +71 -0
- danielutils/data_structures/graph/graph.py +208 -0
- danielutils/data_structures/graph/multinode.py +101 -0
- danielutils/data_structures/graph/node.py +60 -0
- danielutils/data_structures/heap/__init__.py +3 -0
- danielutils/data_structures/heap/heap.py +119 -0
- danielutils/data_structures/heap/max_heap.py +18 -0
- danielutils/data_structures/heap/min_heap.py +18 -0
- danielutils/data_structures/queue/__init__.py +3 -0
- danielutils/data_structures/queue/atomic_queue.py +15 -0
- danielutils/data_structures/queue/priority_queue.py +110 -0
- danielutils/data_structures/queue/queue.py +92 -0
- danielutils/data_structures/stack.py +102 -0
- danielutils/data_structures/trees/__init__.py +2 -0
- danielutils/data_structures/trees/binary_syntax_tree.py +84 -0
- danielutils/data_structures/trees/binary_tree.py +63 -0
- danielutils/date.py +43 -0
- danielutils/date_time.py +23 -0
- danielutils/decorators/__init__.py +18 -0
- danielutils/decorators/atomic.py +45 -0
- danielutils/decorators/attach.py +61 -0
- danielutils/decorators/chain_decorators.py +39 -0
- danielutils/decorators/decorate_conditionally.py +32 -0
- danielutils/decorators/delay_call.py +47 -0
- danielutils/decorators/deprecate.py +46 -0
- danielutils/decorators/final.py +39 -0
- danielutils/decorators/limit_recursion.py +63 -0
- danielutils/decorators/memo.py +68 -0
- danielutils/decorators/normalize_decorator.py +55 -0
- danielutils/decorators/overload.py +204 -0
- danielutils/decorators/partially_implemented.py +32 -0
- danielutils/decorators/processify.py +74 -0
- danielutils/decorators/property.py +42 -0
- danielutils/decorators/singleton.py +59 -0
- danielutils/decorators/threadify.py +40 -0
- danielutils/decorators/timeout.py +82 -0
- danielutils/decorators/total_ordering.py +82 -0
- danielutils/decorators/validate.py +227 -0
- danielutils/exceptions.py +90 -0
- danielutils/functions/__init__.py +13 -0
- danielutils/functions/areoneof.py +47 -0
- danielutils/functions/check_foreach.py +39 -0
- danielutils/functions/factorial.py +24 -0
- danielutils/functions/flatten.py +33 -0
- danielutils/functions/foreach.py +20 -0
- danielutils/functions/isoftype.py +475 -0
- danielutils/functions/isoneof.py +71 -0
- danielutils/functions/multiloop.py +51 -0
- danielutils/functions/parallel_for.py +47 -0
- danielutils/functions/partition.py +45 -0
- danielutils/functions/powerset.py +31 -0
- danielutils/functions/subseteq.py +25 -0
- danielutils/functions/types_subseteq.py +51 -0
- danielutils/generators/__init__.py +3 -0
- danielutils/generators/conditional_generator.py +59 -0
- danielutils/generators/generator_from_stream.py +31 -0
- danielutils/generators/join_generators.py +109 -0
- danielutils/internet.py +92 -0
- danielutils/io_.py +451 -0
- danielutils/java/__init__.py +18 -0
- danielutils/java/interfaces/__init__.py +1 -0
- danielutils/java/interfaces/comparable.py +31 -0
- danielutils/java/java_interface.py +59 -0
- danielutils/logging_/__init__.py +2 -0
- danielutils/logging_/_impl/__init__.py +4 -0
- danielutils/logging_/_impl/builtin_impls/__init__.py +2 -0
- danielutils/logging_/_impl/builtin_impls/file_logger.py +35 -0
- danielutils/logging_/_impl/builtin_impls/print_logger.py +21 -0
- danielutils/logging_/_impl/log_level.py +13 -0
- danielutils/logging_/_impl/logger.py +109 -0
- danielutils/logging_/_impl/logger_strategy_impl_base.py +37 -0
- danielutils/logging_/utils.py +199 -0
- danielutils/lombok/__init__.py +1 -0
- danielutils/lombok/builder.py +68 -0
- danielutils/math_/__init__.py +2 -0
- danielutils/math_/constants.py +103 -0
- danielutils/math_/functions.py +34 -0
- danielutils/math_/math_print.py +52 -0
- danielutils/math_/math_symbols.py +125 -0
- danielutils/metaclasses/__init__.py +5 -0
- danielutils/metaclasses/atomic_class_meta.py +36 -0
- danielutils/metaclasses/implicit_data_deleter_meta.py +87 -0
- danielutils/metaclasses/instance_cache_meta.py +66 -0
- danielutils/metaclasses/interface.py +328 -0
- danielutils/metaclasses/overload_meta.py +48 -0
- danielutils/mock_/__init__.py +1 -0
- danielutils/mock_/mock_module.py +27 -0
- danielutils/path.py +55 -0
- danielutils/print_.py +123 -0
- danielutils/progress_bar/__init__.py +3 -0
- danielutils/progress_bar/ascii_progress_bar.py +161 -0
- danielutils/progress_bar/progress_bar.py +75 -0
- danielutils/progress_bar/progress_bar_pool.py +72 -0
- danielutils/protocols/__init__.py +3 -0
- danielutils/protocols/dictable.py +38 -0
- danielutils/protocols/evaluable.py +26 -0
- danielutils/protocols/serializable.py +51 -0
- danielutils/py.typed +0 -0
- danielutils/random_.py +47 -0
- danielutils/reflection/__init__.py +6 -0
- danielutils/reflection/declarations.py +288 -0
- danielutils/reflection/file/__init__.py +1 -0
- danielutils/reflection/file/file_reflection.py +85 -0
- danielutils/reflection/function/__init__.py +1 -0
- danielutils/reflection/function/function_reflections.py +152 -0
- danielutils/reflection/info_classes/__init__.py +6 -0
- danielutils/reflection/info_classes/argument_info.py +278 -0
- danielutils/reflection/info_classes/class_info.py +204 -0
- danielutils/reflection/info_classes/decorator_info.py +54 -0
- danielutils/reflection/info_classes/file_info.py +1180 -0
- danielutils/reflection/info_classes/folder_info.py +592 -0
- danielutils/reflection/info_classes/function_info.py +551 -0
- danielutils/reflection/info_classes/import_info.py +207 -0
- danielutils/reflection/interpreter/__init__.py +9 -0
- danielutils/reflection/interpreter/callstack.py +57 -0
- danielutils/reflection/interpreter/get_traceback.py +27 -0
- danielutils/reflection/interpreter/interpreter.py +41 -0
- danielutils/reflection/interpreter/is_debugging.py +13 -0
- danielutils/reflection/interpreter/os_.py +33 -0
- danielutils/reflection/interpreter/packages.py +33 -0
- danielutils/reflection/interpreter/python_version.py +33 -0
- danielutils/reflection/interpreter/signals.py +18 -0
- danielutils/reflection/interpreter/tracer.py +175 -0
- danielutils/reflection/module/__init__.py +3 -0
- danielutils/reflection/module/lazy_module.py +104 -0
- danielutils/reflection/module/module_reflections.py +34 -0
- danielutils/reflection/module/package_reflection.py +161 -0
- danielutils/retry_executor/__init__.py +3 -0
- danielutils/retry_executor/backoff_strategies/__init__.py +6 -0
- danielutils/retry_executor/backoff_strategies/constant_backoff.py +25 -0
- danielutils/retry_executor/backoff_strategies/exponential_backoff.py +26 -0
- danielutils/retry_executor/backoff_strategies/functional_backoff.py +29 -0
- danielutils/retry_executor/backoff_strategies/linear_backoff.py +23 -0
- danielutils/retry_executor/backoff_strategies/multiplicative_backoff.py +23 -0
- danielutils/retry_executor/backoff_strategies/no_backoff.py +17 -0
- danielutils/retry_executor/backoff_strategy.py +28 -0
- danielutils/retry_executor/retry_executor.py +55 -0
- danielutils/snippets/__init__.py +1 -0
- danielutils/snippets/try_get.py +28 -0
- danielutils/system/__init__.py +3 -0
- danielutils/system/independent.py +197 -0
- danielutils/system/layered_command.py +130 -0
- danielutils/system/windows/__init__.py +2 -0
- danielutils/system/windows/utils/__init__.py +1 -0
- danielutils/system/windows/utils/filetime.py +19 -0
- danielutils/system/windows/win32_ctime.py +183 -0
- danielutils/system/windows/windows.py +78 -0
- danielutils/testing/__init__.py +1 -0
- danielutils/testing/unittest_/__init__.py +2 -0
- danielutils/testing/unittest_/always_teardown_testcase.py +75 -0
- danielutils/testing/unittest_/auto_cwd_testcase.py +114 -0
- danielutils/text.py +169 -0
- danielutils/time.py +64 -0
- danielutils/tools/__init__.py +1 -0
- danielutils/tools/unittest_test_runner/__init__.py +9 -0
- danielutils/tools/unittest_test_runner/cli.py +70 -0
- danielutils/tools/unittest_test_runner/core/__init__.py +17 -0
- danielutils/tools/unittest_test_runner/core/discovery.py +322 -0
- danielutils/tools/unittest_test_runner/core/execution.py +244 -0
- danielutils/tools/unittest_test_runner/core/parser.py +163 -0
- danielutils/tools/unittest_test_runner/core/runner.py +561 -0
- danielutils/tools/unittest_test_runner/models.py +82 -0
- danielutils/university/__init__.py +7 -0
- danielutils/university/computability_and_complexity/__init__.py +2 -0
- danielutils/university/computability_and_complexity/discreate_finite_automaton.py +89 -0
- danielutils/university/computability_and_complexity/languages/__init__.py +0 -0
- danielutils/university/computability_and_complexity/languages/language.py +17 -0
- danielutils/university/computability_and_complexity/languages/sat.py +71 -0
- danielutils/university/computability_and_complexity/turing_machine.py +47 -0
- danielutils/university/databases/__init__.py +1 -0
- danielutils/university/databases/all.py +756 -0
- danielutils/university/image_proccesing/__init__.py +1 -0
- danielutils/university/image_proccesing/encoding/__init__.py +3 -0
- danielutils/university/image_proccesing/encoding/encoding.py +35 -0
- danielutils/university/image_proccesing/encoding/lossless/__init__.py +4 -0
- danielutils/university/image_proccesing/encoding/lossless/huffman.py +0 -0
- danielutils/university/image_proccesing/encoding/lossless/lossless_encoding.py +10 -0
- danielutils/university/image_proccesing/encoding/lossless/lzw.py +0 -0
- danielutils/university/image_proccesing/encoding/lossless/run_length.py +22 -0
- danielutils/university/image_proccesing/encoding/lossy/__init__.py +1 -0
- danielutils/university/image_proccesing/encoding/lossy/lossy_encoding.py +10 -0
- danielutils/university/image_proccesing/tansformations/__init__.py +0 -0
- danielutils/university/image_proccesing/tansformations/gaussian.py +0 -0
- danielutils/university/image_proccesing/tansformations/gradient.py +0 -0
- danielutils/university/image_proccesing/tansformations/hough.py +0 -0
- danielutils/university/image_proccesing/tansformations/laplacian.py +0 -0
- danielutils/university/image_proccesing/tansformations/transformation.py +11 -0
- danielutils/university/linear_algebra/__init__.py +1 -0
- danielutils/university/linear_algebra/matrix.py +404 -0
- danielutils/university/machine_learning/__init__.py +0 -0
- danielutils/university/machine_learning/activation_functions/__init__.py +2 -0
- danielutils/university/machine_learning/activation_functions/activation_function.py +11 -0
- danielutils/university/machine_learning/activation_functions/relu.py +11 -0
- danielutils/university/machine_learning/neuron.py +15 -0
- danielutils/university/oop/__init__.py +1 -0
- danielutils/university/oop/observer.py +31 -0
- danielutils/university/oop/strategy.py +9 -0
- danielutils/university/probability/__init__.py +7 -0
- danielutils/university/probability/conditional_variable/__init__.py +3 -0
- danielutils/university/probability/conditional_variable/conditional_variable.py +138 -0
- danielutils/university/probability/conditional_variable/continuous/__init__.py +0 -0
- danielutils/university/probability/conditional_variable/discrete/__init__.py +8 -0
- danielutils/university/probability/conditional_variable/discrete/bernoulli.py +38 -0
- danielutils/university/probability/conditional_variable/discrete/bernoulli_sum.py +31 -0
- danielutils/university/probability/conditional_variable/discrete/binomial.py +40 -0
- danielutils/university/probability/conditional_variable/discrete/conditional_from_discrete_probability_func.py +36 -0
- danielutils/university/probability/conditional_variable/discrete/discrete.py +42 -0
- danielutils/university/probability/conditional_variable/discrete/geometric.py +43 -0
- danielutils/university/probability/conditional_variable/discrete/poisson.py +32 -0
- danielutils/university/probability/conditional_variable/discrete/uniform.py +33 -0
- danielutils/university/probability/distributions.py +35 -0
- danielutils/university/probability/expressions/__init__.py +2 -0
- danielutils/university/probability/expressions/accumulation_expression.py +291 -0
- danielutils/university/probability/expressions/probability_expression.py +110 -0
- danielutils/university/probability/funcs/__init__.py +4 -0
- danielutils/university/probability/funcs/covariance.py +12 -0
- danielutils/university/probability/funcs/expected_value.py +41 -0
- danielutils/university/probability/funcs/probability_function.py +14 -0
- danielutils/university/probability/funcs/variance.py +17 -0
- danielutils/university/probability/operator.py +79 -0
- danielutils/university/probability/protocols.py +32 -0
- danielutils/university/probability/supp.py +101 -0
- danielutils/university/probability/transformation.py +44 -0
- danielutils/versioned_imports.py +31 -0
- danielutils-1.1.28.dist-info/METADATA +390 -0
- danielutils-1.1.28.dist-info/RECORD +287 -0
- danielutils-1.1.28.dist-info/WHEEL +5 -0
- danielutils-1.1.28.dist-info/licenses/LICENSE +21 -0
- 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,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
|
+
]
|