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,48 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import functools
|
|
3
|
+
from typing import Callable
|
|
4
|
+
from ..decorators import overload
|
|
5
|
+
from ..logging_.utils import get_logger
|
|
6
|
+
|
|
7
|
+
logger = get_logger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OverloadMeta(type):
|
|
11
|
+
"""A meta-class for overloading functions in a class
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@staticmethod # type:ignore
|
|
15
|
+
def overload(func: Callable) -> overload:
|
|
16
|
+
"""overloads a function
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
func (Callable): function ot overload
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
overload: _description_
|
|
23
|
+
"""
|
|
24
|
+
return overload(func) # type:ignore
|
|
25
|
+
|
|
26
|
+
def __new__(mcs, name, bases, namespace):
|
|
27
|
+
logger.info("Creating overload class: %s", name)
|
|
28
|
+
|
|
29
|
+
def create_wrapper(v: overload):
|
|
30
|
+
@functools.wraps(next(iter(v._functions.values()))[0]) # type:ignore# pylint: disable=protected-access
|
|
31
|
+
def wrapper(*args, **kwargs):
|
|
32
|
+
return v(*args, **kwargs)
|
|
33
|
+
|
|
34
|
+
return wrapper
|
|
35
|
+
|
|
36
|
+
overloaded_functions = 0
|
|
37
|
+
for k, v in namespace.items():
|
|
38
|
+
if isinstance(v, overload): # type:ignore
|
|
39
|
+
namespace[k] = create_wrapper(v)
|
|
40
|
+
overloaded_functions += 1
|
|
41
|
+
|
|
42
|
+
logger.info("OverloadMeta: %s created with %s overloaded functions", name, overloaded_functions)
|
|
43
|
+
return super().__new__(mcs, name, bases, namespace)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"OverloadMeta"
|
|
48
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .mock_module import *
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from ..logging_.utils import get_logger
|
|
3
|
+
|
|
4
|
+
logger = get_logger(__name__)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MockImportObject:
|
|
8
|
+
"""
|
|
9
|
+
A class to create a mock object that will raise an import error when you try to interact with it in some way
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, msg: str):
|
|
13
|
+
logger.info("Initializing MockImportObject with message: %s", msg)
|
|
14
|
+
self._msg = msg
|
|
15
|
+
|
|
16
|
+
def __getattr__(self, item):
|
|
17
|
+
logger.warning("MockImportObject attribute access blocked: %s - %s", item, self._msg)
|
|
18
|
+
raise ImportError(self._msg)
|
|
19
|
+
|
|
20
|
+
def __call__(self, *args, **kwargs):
|
|
21
|
+
logger.warning("MockImportObject call blocked with %s args and %s kwargs - %s", len(args), len(kwargs), self._msg)
|
|
22
|
+
raise ImportError(self._msg)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"MockImportObject"
|
|
27
|
+
]
|
danielutils/path.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from .logging_.utils import get_logger
|
|
4
|
+
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_current_working_directory() -> str:
|
|
9
|
+
"""return the current working directory
|
|
10
|
+
|
|
11
|
+
Returns:
|
|
12
|
+
str: current working directory
|
|
13
|
+
"""
|
|
14
|
+
return os.getcwd()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def set_current_working_directory(path: str) -> None:
|
|
18
|
+
"""sets the current working directory
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
path (str): directory to set to
|
|
22
|
+
"""
|
|
23
|
+
os.chdir(path)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_absolute_path(path: str) -> str:
|
|
27
|
+
"""return the absolute path of given path
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
path (str): a path
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
str: absolute version of that path
|
|
34
|
+
"""
|
|
35
|
+
return os.path.abspath(path)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_relative_path(path: str) -> str:
|
|
39
|
+
"""return the relative path of given path
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
path (str): a path
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
str: relative (to current working directory) version of that path
|
|
46
|
+
"""
|
|
47
|
+
return os.path.realpath(path)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
"get_current_working_directory",
|
|
52
|
+
"set_current_working_directory",
|
|
53
|
+
"get_absolute_path",
|
|
54
|
+
"get_relative_path"
|
|
55
|
+
]
|
danielutils/print_.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
from typing import IO, List
|
|
4
|
+
from .functions.areoneof import areoneof
|
|
5
|
+
from .math_.math_print import mprint_parse_one
|
|
6
|
+
from .decorators import atomic, deprecate
|
|
7
|
+
from .colors import warning
|
|
8
|
+
from .logging_.utils import get_logger
|
|
9
|
+
|
|
10
|
+
logger = get_logger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def mprint(*args, sep: str = " ", end: str = "\n", stream=sys.stdout) -> None:
|
|
14
|
+
"""Prints a formatted representation of mathematical expressions to the specified stream.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
*args: The mathematical expressions to print.
|
|
18
|
+
sep (str, optional): The separator to use between the expressions. Defaults to " ".
|
|
19
|
+
end (str, optional): The string to append to the end of the printed expressions. Defaults to "\n".
|
|
20
|
+
stream (file object, optional): The stream to write the output to. Defaults to sys.stdout.
|
|
21
|
+
|
|
22
|
+
Raises:
|
|
23
|
+
TypeError: If any of the arguments is not a string.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
None
|
|
27
|
+
"""
|
|
28
|
+
if not areoneof(args, [str]):
|
|
29
|
+
raise TypeError("s must be a string")
|
|
30
|
+
logger.debug("Printing %d mathematical expressions to %s", len(args), stream)
|
|
31
|
+
stream.write(sep.join([mprint_parse_one(s) for s in args]) + end)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@deprecate("The built-in 'print' function has an argument called 'file', use this instead") # type:ignore
|
|
35
|
+
def sprint(*args, sep: str = " ", end: str = "\n", stream=sys.stdout) -> None:
|
|
36
|
+
"""Writes a string representation of the given arguments to the specified stream.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
*args: The arguments to print.
|
|
40
|
+
sep (str, optional): The separator to use between the arguments. Defaults to " ".
|
|
41
|
+
end (str, optional): The string to append to the end of the printed arguments. Defaults to "\n".
|
|
42
|
+
stream (file object, optional): The stream to write the output to. Defaults to sys.stdout.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
None
|
|
46
|
+
"""
|
|
47
|
+
stream.write(sep.join(args) + end)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@atomic # type:ignore
|
|
51
|
+
def aprint(*args, sep=" ", end="\n") -> None:
|
|
52
|
+
"""Prints a string representation of the given arguments to the console.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
*args: The arguments to print.
|
|
56
|
+
sep (str, optional): The separator to use between the arguments. Defaults to " ".
|
|
57
|
+
end (str, optional): The string to append to the end of the printed arguments. Defaults to "\n".
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
None
|
|
61
|
+
"""
|
|
62
|
+
print(*args, sep=sep, end=end)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class BetterPrinter:
|
|
66
|
+
def __init__(self, stream: IO = sys.stdout, thread_safe: bool = False):
|
|
67
|
+
self.stream: IO = stream
|
|
68
|
+
if thread_safe:
|
|
69
|
+
self.__call__ = atomic(self.__call__) # type:ignore
|
|
70
|
+
self._current_row: int = 0
|
|
71
|
+
self.rows: List[str] = []
|
|
72
|
+
|
|
73
|
+
def clear(self, flush: bool = True) -> None:
|
|
74
|
+
if not self.stream.isatty():
|
|
75
|
+
warning(f"Cannot clear because {self.stream} is not a terminal stream")
|
|
76
|
+
return
|
|
77
|
+
self.write("\033[2J", flush=flush)
|
|
78
|
+
self.rows.pop()
|
|
79
|
+
|
|
80
|
+
def clear_line(self) -> None:
|
|
81
|
+
self.write("\033[2K", end="")
|
|
82
|
+
self.rows.pop()
|
|
83
|
+
|
|
84
|
+
def move_up(self, num_lines: int = 1) -> None:
|
|
85
|
+
self.write(f"\033[{num_lines}A", end="")
|
|
86
|
+
self.rows.pop()
|
|
87
|
+
self._current_row -= 1
|
|
88
|
+
|
|
89
|
+
def write(self, *args, sep: str = " ", end: str = "\n", flush: bool = True):
|
|
90
|
+
text = sep.join(args) + end
|
|
91
|
+
self._current_row += text.count("\n")
|
|
92
|
+
self.rows.extend([f"{s}\n" for s in text.splitlines() if len(s) > 0])
|
|
93
|
+
self.stream.write(text)
|
|
94
|
+
if flush:
|
|
95
|
+
self.stream.flush()
|
|
96
|
+
|
|
97
|
+
def __call__(self, *args, sep: str = " ", end: str = "\n", flush: bool = True) -> None:
|
|
98
|
+
self.write(*args, sep=sep, end=end, flush=flush)
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def current_row(self) -> int:
|
|
102
|
+
return self._current_row
|
|
103
|
+
|
|
104
|
+
def insert(self, text: str, row: int) -> None:
|
|
105
|
+
for _ in range(len(self.rows)):
|
|
106
|
+
bprint.move_up()
|
|
107
|
+
bprint.clear_line()
|
|
108
|
+
self.rows.insert(row, text)
|
|
109
|
+
num = len(self.rows)
|
|
110
|
+
self.write(*self.rows, end="")
|
|
111
|
+
for _ in range(num):
|
|
112
|
+
self.rows.pop()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
bprint = BetterPrinter()
|
|
116
|
+
|
|
117
|
+
__all__ = [
|
|
118
|
+
"sprint",
|
|
119
|
+
"mprint",
|
|
120
|
+
"aprint",
|
|
121
|
+
"bprint",
|
|
122
|
+
'BetterPrinter'
|
|
123
|
+
]
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
from typing import Optional, Iterable, Sized, Iterator
|
|
4
|
+
|
|
5
|
+
from .progress_bar import ProgressBar
|
|
6
|
+
from .progress_bar_pool import ProgressBarPool
|
|
7
|
+
from ..print_ import bprint
|
|
8
|
+
from ..logging_.utils import get_logger
|
|
9
|
+
|
|
10
|
+
logger = get_logger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AsciiProgressBar(ProgressBar):
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
iterator: Iterator,
|
|
18
|
+
position: int,
|
|
19
|
+
*,
|
|
20
|
+
total: Optional[float] = None,
|
|
21
|
+
desc: str = "",
|
|
22
|
+
leave: bool = True,
|
|
23
|
+
num_bars: int = 1,
|
|
24
|
+
ncols: int = 50,
|
|
25
|
+
pool: Optional[ProgressBarPool] = None,
|
|
26
|
+
**kwargs
|
|
27
|
+
):
|
|
28
|
+
total_ = 1
|
|
29
|
+
if isinstance(iterator, Sized):
|
|
30
|
+
total_ = len(iterator)
|
|
31
|
+
if total is not None:
|
|
32
|
+
total_ = total # type:ignore
|
|
33
|
+
ProgressBar.__init__(self, total_, position, desc=desc)
|
|
34
|
+
self.iterator: Iterator = iterator
|
|
35
|
+
self.pool: ProgressBarPool = pool # type:ignore
|
|
36
|
+
self.num_bars: int = num_bars
|
|
37
|
+
self.leave: bool = leave
|
|
38
|
+
self.initial_value: float = 0
|
|
39
|
+
self.current_value: float = 0
|
|
40
|
+
self.ncols: int = ncols
|
|
41
|
+
self.unit: str = "it"
|
|
42
|
+
self.pbar_format = "{l_bar} |{bar}| {n_fmt:.2f}/{total_fmt:.2f}{unit}" \
|
|
43
|
+
" [{elapsed:.2f}<{remaining}, {rate_fmt:.2f}{unit}{postfix}]"
|
|
44
|
+
self.__dict__.update(kwargs)
|
|
45
|
+
self.initial_start_time = time.time()
|
|
46
|
+
self.prev_update: float = self.initial_start_time
|
|
47
|
+
self.delta: float = 0
|
|
48
|
+
self.prev_value: float = self.initial_value
|
|
49
|
+
self.bprint_row_index = bprint.current_row
|
|
50
|
+
logger.info("AsciiProgressBar initialized: %s (total=%s, position=%s)", desc, total_, position)
|
|
51
|
+
|
|
52
|
+
def __iter__(self):
|
|
53
|
+
logger.info("Starting iteration over AsciiProgressBar: %s", self.desc)
|
|
54
|
+
self.bprint_row_index = bprint.current_row
|
|
55
|
+
items_processed = 0
|
|
56
|
+
for v in self.iterator:
|
|
57
|
+
self.update(0)
|
|
58
|
+
yield v
|
|
59
|
+
bprint.move_up()
|
|
60
|
+
bprint.clear_line()
|
|
61
|
+
if len(bprint.rows) > 0:
|
|
62
|
+
bprint.rows.pop()
|
|
63
|
+
self.update(1)
|
|
64
|
+
items_processed += 1
|
|
65
|
+
bprint.move_up()
|
|
66
|
+
bprint.clear_line()
|
|
67
|
+
if len(bprint.rows) > 0:
|
|
68
|
+
bprint.rows.pop()
|
|
69
|
+
logger.info("Completed iteration: processed %s items", items_processed)
|
|
70
|
+
if self.position > 0:
|
|
71
|
+
self.reset()
|
|
72
|
+
else:
|
|
73
|
+
self.draw()
|
|
74
|
+
|
|
75
|
+
def draw(self, *, refresh: bool = False) -> None:
|
|
76
|
+
percent = self.current_value / self.total
|
|
77
|
+
num_to_fill = int(percent * self.ncols)
|
|
78
|
+
progress_str = num_to_fill * "#" + (self.ncols - num_to_fill) * " "
|
|
79
|
+
to_print = self.pbar_format.format(
|
|
80
|
+
l_bar=self.desc,
|
|
81
|
+
bar=progress_str,
|
|
82
|
+
n_fmt=self.current_value,
|
|
83
|
+
total_fmt=self.total,
|
|
84
|
+
elapsed=self.prev_update - self.initial_start_time,
|
|
85
|
+
remaining="?",
|
|
86
|
+
rate_fmt=(self.current_value - self.prev_value) /
|
|
87
|
+
self.delta if self.delta != 0 else 0,
|
|
88
|
+
postfix="/s",
|
|
89
|
+
unit=self.unit
|
|
90
|
+
)
|
|
91
|
+
if refresh and self.pool is not None and len(self.pool.bars) > 1:
|
|
92
|
+
i = bprint.rows.index(f"{self.prev_print}\n") # type:ignore
|
|
93
|
+
rows = [to_print]
|
|
94
|
+
for j, row in enumerate(bprint.rows[i + 1:]):
|
|
95
|
+
rows.append(row)
|
|
96
|
+
for row in rows:
|
|
97
|
+
bprint.move_up(1)
|
|
98
|
+
bprint.clear_line()
|
|
99
|
+
bprint.rows.pop()
|
|
100
|
+
for row in rows:
|
|
101
|
+
bprint(row)
|
|
102
|
+
else:
|
|
103
|
+
bprint(to_print)
|
|
104
|
+
self.prev_print = to_print
|
|
105
|
+
|
|
106
|
+
def update(self, amount: float = 1, refresh: bool = False): # type:ignore
|
|
107
|
+
self.prev_value = self.current_value
|
|
108
|
+
self.current_value = min(
|
|
109
|
+
self.current_value + amount, self.total) # type:ignore
|
|
110
|
+
current_time = time.time()
|
|
111
|
+
self.delta = current_time - self.prev_update
|
|
112
|
+
self.prev_update = current_time
|
|
113
|
+
self.draw(refresh=refresh)
|
|
114
|
+
|
|
115
|
+
def _write(self, *args: str, sep: str = " ", end: str = "\n") -> None:
|
|
116
|
+
if not end.endswith("\n"):
|
|
117
|
+
end += "\n"
|
|
118
|
+
if self.pool is not None and len(self.pool.bars) > 0:
|
|
119
|
+
succeeding_bars = self.pool.bars[self.position + 1:]
|
|
120
|
+
if succeeding_bars:
|
|
121
|
+
for succeeding_bar in succeeding_bars:
|
|
122
|
+
# clear child
|
|
123
|
+
bprint.move_up()
|
|
124
|
+
bprint.clear_line()
|
|
125
|
+
bprint.rows.pop()
|
|
126
|
+
for _ in range(succeeding_bar.num_writes):
|
|
127
|
+
# clear child's writes
|
|
128
|
+
bprint.move_up()
|
|
129
|
+
bprint.clear_line()
|
|
130
|
+
bprint.rows.pop()
|
|
131
|
+
# clear self
|
|
132
|
+
bprint.move_up()
|
|
133
|
+
bprint.clear_line()
|
|
134
|
+
bprint.rows.pop()
|
|
135
|
+
bprint(sep.join(map(str, args)), end=end)
|
|
136
|
+
self.draw()
|
|
137
|
+
for succeeding_bar in succeeding_bars:
|
|
138
|
+
succeeding_bar.update(0, refresh=True)
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
bprint.move_up()
|
|
142
|
+
bprint.clear_line()
|
|
143
|
+
bprint.rows.pop()
|
|
144
|
+
bprint(sep.join(map(str, args)), end=end)
|
|
145
|
+
self.draw()
|
|
146
|
+
|
|
147
|
+
def reset(self) -> None:
|
|
148
|
+
self.current_value = self.initial_value
|
|
149
|
+
self.initial_start_time = time.time()
|
|
150
|
+
self.delta = 0
|
|
151
|
+
self.prev_value = self.initial_value
|
|
152
|
+
for _ in range(self.num_writes):
|
|
153
|
+
bprint.move_up()
|
|
154
|
+
bprint.clear_line()
|
|
155
|
+
bprint.rows.pop()
|
|
156
|
+
self.writes.clear()
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
__all__ = [
|
|
160
|
+
'AsciiProgressBar'
|
|
161
|
+
]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import math
|
|
3
|
+
import time
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from typing import Optional, Type, List, Iterable, Any
|
|
6
|
+
from ..logging_.utils import get_logger
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from tqdm import tqdm
|
|
10
|
+
except ImportError:
|
|
11
|
+
from ..mock_ import MockImportObject
|
|
12
|
+
|
|
13
|
+
tqdm = MockImportObject("`tqdm` is not installed") # type:ignore
|
|
14
|
+
|
|
15
|
+
logger = get_logger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ProgressBar(ABC):
|
|
19
|
+
"""An interface
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
ABC (_type_): _description_
|
|
23
|
+
"""
|
|
24
|
+
DEFAULT_BAR_FORMAT = "{desc}: {percentage:3.0f}%|{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}"
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def __init__(self, total, position: int, unit="it", bar_format: str = DEFAULT_BAR_FORMAT, *, desc: str,
|
|
28
|
+
**kwargs) -> None:
|
|
29
|
+
self.desc: str = desc
|
|
30
|
+
self.total = total
|
|
31
|
+
self.position = position
|
|
32
|
+
self.unit = unit
|
|
33
|
+
self.bar_format = bar_format
|
|
34
|
+
self.writes: List[str] = []
|
|
35
|
+
logger.info("ProgressBar initialized: %s (total=%s, position=%s, unit=%s)", desc, total, position, unit)
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def num_writes(self):
|
|
39
|
+
return len(self.writes)
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def update(self, amount: float = 1, **kwargs) -> None:
|
|
43
|
+
"""A function to update the progress-bar's value by a positive relative amount
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def _write(self, *args: str, sep: str = " ", end: str = "\n") -> None: ...
|
|
48
|
+
|
|
49
|
+
def write(self, *args: Any, sep: str = " ", end: str = "\n") -> None:
|
|
50
|
+
"""A function to write additional text with the progress bar
|
|
51
|
+
"""
|
|
52
|
+
processed = list(map(str, args))
|
|
53
|
+
message = sep.join(processed) + end
|
|
54
|
+
self._write(*processed, sep=sep, end=end)
|
|
55
|
+
self.writes.append(message)
|
|
56
|
+
|
|
57
|
+
@abstractmethod
|
|
58
|
+
def reset(self) -> None:
|
|
59
|
+
"""A function to reset the progress-bar's progress
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
@abstractmethod
|
|
63
|
+
def __iter__(self): ...
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
from tqdm import tqdm
|
|
68
|
+
|
|
69
|
+
ProgressBar.register(tqdm)
|
|
70
|
+
except ImportError:
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
__all__ = [
|
|
74
|
+
'ProgressBar',
|
|
75
|
+
]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Type, List, Optional, Iterator
|
|
3
|
+
from .progress_bar import ProgressBar
|
|
4
|
+
from ..print_ import bprint
|
|
5
|
+
from ..logging_.utils import get_logger
|
|
6
|
+
|
|
7
|
+
logger = get_logger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ProgressBarPool:
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
pbar_class: Type[ProgressBar],
|
|
14
|
+
num_of_bars: int = 1,
|
|
15
|
+
global_options: Optional[dict] = None,
|
|
16
|
+
individual_options: Optional[List[Optional[dict]]] = None
|
|
17
|
+
) -> None:
|
|
18
|
+
logger.info("Creating ProgressBarPool with %s bars using %s", num_of_bars, pbar_class.__name__)
|
|
19
|
+
self.bars: List[ProgressBar] = []
|
|
20
|
+
if global_options is None:
|
|
21
|
+
global_options = {}
|
|
22
|
+
if individual_options is None:
|
|
23
|
+
individual_options = [{} for _ in range(num_of_bars)]
|
|
24
|
+
if len(individual_options) != num_of_bars:
|
|
25
|
+
error_msg = "must supply the same number of options as there are bars"
|
|
26
|
+
logger.error("ProgressBarPool initialization failed: %s", error_msg)
|
|
27
|
+
raise ValueError(error_msg)
|
|
28
|
+
for i in range(num_of_bars):
|
|
29
|
+
if individual_options[i] is None:
|
|
30
|
+
individual_options[i] = {}
|
|
31
|
+
max_desc_length: int = max([len(individual_options[i].get("desc", f"pbar {i}")) for i in range(num_of_bars)])
|
|
32
|
+
|
|
33
|
+
for i in range(num_of_bars):
|
|
34
|
+
final_options: dict = global_options.copy()
|
|
35
|
+
final_options.update(individual_options[i]) # type:ignore
|
|
36
|
+
if "desc" not in final_options:
|
|
37
|
+
final_options["desc"] = f"pbar {i}"
|
|
38
|
+
final_options["desc"] = final_options["desc"].ljust(max_desc_length, " ")
|
|
39
|
+
t = pbar_class(
|
|
40
|
+
position=i,
|
|
41
|
+
pool=self,
|
|
42
|
+
**final_options
|
|
43
|
+
)
|
|
44
|
+
self.bars.append(t)
|
|
45
|
+
self.writes: List[str] = []
|
|
46
|
+
logger.info("ProgressBarPool created successfully with %s progress bars", len(self.bars))
|
|
47
|
+
|
|
48
|
+
def __getitem__(self, index: int) -> ProgressBar:
|
|
49
|
+
return self.bars[index]
|
|
50
|
+
|
|
51
|
+
def write(self, msg: str, end: str = "\n") -> None:
|
|
52
|
+
prev_rows = bprint.rows.copy()
|
|
53
|
+
for w in self.writes:
|
|
54
|
+
prev_rows.remove(w)
|
|
55
|
+
self.writes.append(msg + end)
|
|
56
|
+
rows = self.writes.copy() + prev_rows
|
|
57
|
+
for _ in bprint.rows:
|
|
58
|
+
bprint.move_up()
|
|
59
|
+
bprint.clear_line()
|
|
60
|
+
bprint.rows.clear()
|
|
61
|
+
|
|
62
|
+
for row in rows:
|
|
63
|
+
bprint(row, end="")
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
def __iter__(self) -> Iterator[ProgressBar]:
|
|
67
|
+
return iter(self.bars)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
__all__ = [
|
|
71
|
+
"ProgressBarPool",
|
|
72
|
+
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Protocol, TypeVar, runtime_checkable,Dict as Dict
|
|
3
|
+
from ..reflection import get_python_version
|
|
4
|
+
from ..logging_.utils import get_logger
|
|
5
|
+
|
|
6
|
+
logger = get_logger(__name__)
|
|
7
|
+
|
|
8
|
+
if get_python_version() >= (3, 9):
|
|
9
|
+
from builtins import dict as Dict
|
|
10
|
+
|
|
11
|
+
K = TypeVar('K')
|
|
12
|
+
V = TypeVar('V')
|
|
13
|
+
|
|
14
|
+
@runtime_checkable
|
|
15
|
+
class Dictable(Protocol[K, V]):
|
|
16
|
+
@classmethod
|
|
17
|
+
def from_dict(cls, d: Dict[K, V]) -> 'Dictable[K,V]':
|
|
18
|
+
"""
|
|
19
|
+
Create a Dictable object from a dictionary.
|
|
20
|
+
|
|
21
|
+
Note: This is a protocol method. Implementations should add logging
|
|
22
|
+
to track dictionary conversion operations.
|
|
23
|
+
"""
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
def to_dict(self) -> Dict[K, V]:
|
|
27
|
+
"""
|
|
28
|
+
Convert the object to a dictionary.
|
|
29
|
+
|
|
30
|
+
Note: This is a protocol method. Implementations should add logging
|
|
31
|
+
to track dictionary conversion operations.
|
|
32
|
+
"""
|
|
33
|
+
...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
'Dictable'
|
|
38
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
from typing import Protocol, TypeVar, runtime_checkable
|
|
4
|
+
from ..logging_.utils import get_logger
|
|
5
|
+
|
|
6
|
+
logger = get_logger(__name__)
|
|
7
|
+
|
|
8
|
+
T = TypeVar('T', covariant=True)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@runtime_checkable
|
|
12
|
+
class Evaluable(Protocol[T]):
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def evaluate(self) -> T:
|
|
15
|
+
"""
|
|
16
|
+
Evaluate the object and return a value of type T.
|
|
17
|
+
|
|
18
|
+
Note: This is a protocol method. Implementations should add logging
|
|
19
|
+
to track evaluation operations.
|
|
20
|
+
"""
|
|
21
|
+
...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"Evaluable"
|
|
26
|
+
]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Protocol, runtime_checkable, Any
|
|
3
|
+
from ..logging_.utils import get_logger
|
|
4
|
+
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@runtime_checkable
|
|
9
|
+
class Serializable(Protocol):
|
|
10
|
+
def serialize(self) -> bytes:
|
|
11
|
+
"""
|
|
12
|
+
Serialize the object to bytes.
|
|
13
|
+
|
|
14
|
+
Note: This is a protocol method. Implementations should add logging
|
|
15
|
+
to track serialization operations.
|
|
16
|
+
"""
|
|
17
|
+
...
|
|
18
|
+
|
|
19
|
+
def deserialize(self, serealized: bytes) -> 'Serializable':
|
|
20
|
+
"""
|
|
21
|
+
Deserialize bytes back to a Serializable object.
|
|
22
|
+
|
|
23
|
+
Note: This is a protocol method. Implementations should add logging
|
|
24
|
+
to track deserialization operations.
|
|
25
|
+
"""
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def serialize(obj: Any) -> bytes:
|
|
30
|
+
logger.info("Serializing object of type: %s", type(obj).__name__)
|
|
31
|
+
if isinstance(obj, Serializable):
|
|
32
|
+
result = obj.serialize()
|
|
33
|
+
logger.info("Serialization successful, returned %s bytes", len(result))
|
|
34
|
+
return result
|
|
35
|
+
logger.warning("Object %s does not implement Serializable protocol", type(obj).__name__)
|
|
36
|
+
#TODO
|
|
37
|
+
return b""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def deserialize(obj: bytes) -> Any:
|
|
41
|
+
logger.info("Deserializing %s bytes", len(obj))
|
|
42
|
+
logger.warning("Deserialize function not implemented (TODO)")
|
|
43
|
+
#TODO
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
'Serializable',
|
|
49
|
+
'serialize',
|
|
50
|
+
'deserialize',
|
|
51
|
+
]
|
danielutils/py.typed
ADDED
|
File without changes
|