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,67 @@
|
|
|
1
|
+
from typing import Generic, TypeVar, Iterable
|
|
2
|
+
from .factory import create_typed_class
|
|
3
|
+
from ...functions import isoftype
|
|
4
|
+
T = TypeVar("T")
|
|
5
|
+
parent: type = create_typed_class("tset", set)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class tset(parent, Generic[T]): # type:ignore
|
|
9
|
+
"""like 'set' but with runtime type safety
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def subscribable_init(self, *args, **kwargs): # pylint: disable=unused-argument
|
|
13
|
+
"""the "real" __init__ function
|
|
14
|
+
"""
|
|
15
|
+
print(self.get_params())
|
|
16
|
+
|
|
17
|
+
def add(self, value: T) -> None:
|
|
18
|
+
"""adds an item to the set
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
value (T): item
|
|
22
|
+
|
|
23
|
+
Raises:
|
|
24
|
+
TypeError: if item is if the wrong type
|
|
25
|
+
"""
|
|
26
|
+
if not isoftype(value, self.get_params()): # type:ignore
|
|
27
|
+
raise TypeError(
|
|
28
|
+
f"Can't add. Expected {self.get_params()} but got '{value}' which is {type(value)}")
|
|
29
|
+
set.add(self, value)
|
|
30
|
+
|
|
31
|
+
def update(self, *s: Iterable[T]) -> None:
|
|
32
|
+
"""updates the set with another iterable
|
|
33
|
+
"""
|
|
34
|
+
for value in s:
|
|
35
|
+
if isinstance(value, Iterable):
|
|
36
|
+
for subv in value:
|
|
37
|
+
self.update(subv) # type:ignore
|
|
38
|
+
else:
|
|
39
|
+
self.add(value) # type:ignore
|
|
40
|
+
|
|
41
|
+
def union(self, *s: Iterable[T]) -> "tset[T]":
|
|
42
|
+
"""creates a union of two sets
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
tset[T]: the resulting set
|
|
46
|
+
"""
|
|
47
|
+
type_set = set(self.get_params())
|
|
48
|
+
for value in s:
|
|
49
|
+
if isinstance(value, Iterable):
|
|
50
|
+
for subv in value:
|
|
51
|
+
type_set.add(type(subv))
|
|
52
|
+
else:
|
|
53
|
+
type_set.add(type(value))
|
|
54
|
+
final_type = next(iter(type_set))
|
|
55
|
+
for t in type_set:
|
|
56
|
+
final_type = final_type | t
|
|
57
|
+
res = tset[final_type]() # type:ignore
|
|
58
|
+
# we can skip the type checking because they will be okay
|
|
59
|
+
set.update(res, self)
|
|
60
|
+
for value in s:
|
|
61
|
+
set.update(res, value)
|
|
62
|
+
return res
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
__all__ = [
|
|
66
|
+
"tset"
|
|
67
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Generic, TypeVar
|
|
3
|
+
from .factory import create_typed_class
|
|
4
|
+
T = TypeVar("T")
|
|
5
|
+
parent_ttuple: type = create_typed_class("ttuple", tuple)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ttuple(parent_ttuple, Generic[T]):
|
|
9
|
+
"""like tuple but with runtime type safety
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"ttuple"
|
|
15
|
+
]
|
danielutils/colors.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional, IO
|
|
3
|
+
from .decorators import validate
|
|
4
|
+
from .logging_.utils import get_logger
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
RESET = "\033[0m"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ColoredText:
|
|
11
|
+
"""static utility class with static functions:\n
|
|
12
|
+
from_rgb,
|
|
13
|
+
green,
|
|
14
|
+
red,
|
|
15
|
+
blue,
|
|
16
|
+
red,
|
|
17
|
+
yellow,
|
|
18
|
+
white,
|
|
19
|
+
black
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
@staticmethod # type:ignore
|
|
23
|
+
@validate # type:ignore
|
|
24
|
+
def from_rgb(red: int, green: int, blue: int, text: str) -> str:
|
|
25
|
+
"""Applies an RGB color to the given text.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
red (int): The red component of the color.
|
|
29
|
+
green (int): The green component of the color.
|
|
30
|
+
blue (int): The blue component of the color.
|
|
31
|
+
text (str): The text to apply the color to.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
str: The given text with an RGB color applied to it.
|
|
35
|
+
"""
|
|
36
|
+
logger.debug("Applying RGB color (%s, %s, %s) to text: %s...", red, green, blue, text[:50])
|
|
37
|
+
return f"\033[38;2;{red};{green};{blue}m{text}{RESET}"
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def green(text: str) -> str:
|
|
41
|
+
"""Applies green color to the given text.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
text (str): The text to apply the green color to.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
str: The given text with green color applied to it.
|
|
48
|
+
"""
|
|
49
|
+
return ColoredText.from_rgb(0, 255, 0, text)
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def blue(text: str):
|
|
53
|
+
"""Applies blue color to the given text.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
text (str): The text to apply the blue color to.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
str: The given text with blue color applied to it.
|
|
60
|
+
"""
|
|
61
|
+
return ColoredText.from_rgb(0, 0, 255, text)
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def red(text: str):
|
|
65
|
+
"""Applies red color to the given text.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
text (str): The text to apply the red color to.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
str: The given text with red color applied to it.
|
|
72
|
+
"""
|
|
73
|
+
return ColoredText.from_rgb(255, 0, 0, text)
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def yellow(text: str):
|
|
77
|
+
"""Applies yellow color to the given text.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
text (str): The text to apply the yellow color to.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
str: The given text with yellow color applied to it.
|
|
84
|
+
"""
|
|
85
|
+
return ColoredText.from_rgb(255, 255, 0, text)
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def orange(text: str):
|
|
89
|
+
"""Applies yellow color to the given text.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
text (str): The text to apply the yellow color to.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
str: The given text with yellow color applied to it.
|
|
96
|
+
"""
|
|
97
|
+
return ColoredText.from_rgb(255, 165, 0, text)
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def white(text: str):
|
|
101
|
+
"""Applies white color to the given text.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
text (str): The text to apply the white color to.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
str: The given text with white color applied to it.
|
|
108
|
+
"""
|
|
109
|
+
return ColoredText.from_rgb(255, 255, 255, text)
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def black(text: str):
|
|
113
|
+
"""Applies black color to the given text.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
text (str): The text to apply the black color to.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
str: The given text with black color applied to it.
|
|
120
|
+
"""
|
|
121
|
+
return ColoredText.from_rgb(0, 0, 0, text)
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def supports_color(stream: IO) -> bool:
|
|
125
|
+
"""return whether a stream will support colored text
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
stream (IO): stream to check
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
bool: boolean result
|
|
132
|
+
"""
|
|
133
|
+
result = stream.isatty()
|
|
134
|
+
logger.debug("Color support check for stream: %s", result)
|
|
135
|
+
return result
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def __special_print(*args, sep: str = " ", end: str = "\n", start_with: Optional[str] = None):
|
|
139
|
+
"""inner helper function"""
|
|
140
|
+
if start_with:
|
|
141
|
+
if "\n" not in sep:
|
|
142
|
+
print(f"{start_with}: ", end="")
|
|
143
|
+
print(sep.join([str(arg) for arg in args]), sep="", end=end)
|
|
144
|
+
else:
|
|
145
|
+
print(
|
|
146
|
+
sep.join([f"{start_with}: {str(arg)}" for arg in args]), sep="", end=end)
|
|
147
|
+
else:
|
|
148
|
+
print(*args, sep=sep, end=end)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def success(*args, sep: str = " ", end: str = "\n"):
|
|
152
|
+
"""print a success message
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
sep (str, optional): print separator. Defaults to " ".
|
|
156
|
+
end (str, optional): print endline. Defaults to "\\n".
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
__special_print(*args, sep=sep, end=end,
|
|
160
|
+
start_with=ColoredText.green("SUCCESS"))
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def warning(*args, sep: str = " ", end: str = "\n"):
|
|
164
|
+
"""print a warning message
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
sep (str, optional): print separator. Defaults to " ".
|
|
168
|
+
end (str, optional): print endline. Defaults to "\\n".
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
__special_print(*args, sep=sep, end=end,
|
|
172
|
+
start_with=ColoredText.orange("WARNING"))
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def error(*args, sep: str = " ", end: str = "\n"):
|
|
176
|
+
"""print an error message
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
sep (str, optional): print separator. Defaults to " ".
|
|
180
|
+
end (str, optional): print endline. Defaults to "\\n".
|
|
181
|
+
"""
|
|
182
|
+
__special_print(*args, sep=sep, end=end,
|
|
183
|
+
start_with=ColoredText.red("ERROR"))
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def info(*args, sep: str = " ", end: str = "\n"):
|
|
187
|
+
"""print an info message
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
sep (str, optional): print separator. Defaults to " ".
|
|
191
|
+
end (str, optional): print endline. Defaults to "\\n".
|
|
192
|
+
"""
|
|
193
|
+
__special_print(*args, sep=sep, end=end,
|
|
194
|
+
start_with=ColoredText.yellow("INFO"))
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
__all__ = [
|
|
198
|
+
"ColoredText",
|
|
199
|
+
"success",
|
|
200
|
+
"warning",
|
|
201
|
+
"error",
|
|
202
|
+
"info"
|
|
203
|
+
]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import ContextManager
|
|
3
|
+
from ..logging_.utils import get_logger
|
|
4
|
+
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AttrContext(ContextManager):
|
|
9
|
+
def __init__(self, obj: object, attr: str, new_value: object, *, nonexistent_is_error: bool = True) -> None:
|
|
10
|
+
logger.debug("Initializing AttrContext for %s.%s = %s", type(obj).__name__, attr, new_value)
|
|
11
|
+
self.obj = obj
|
|
12
|
+
self.attr = attr
|
|
13
|
+
self.new_value = new_value
|
|
14
|
+
self.old_value = None
|
|
15
|
+
self._has_attr: bool = hasattr(self.obj, self.attr)
|
|
16
|
+
if nonexistent_is_error and not self._has_attr:
|
|
17
|
+
logger.error("Attribute '%s' does not exist on %s", self.attr, type(obj).__name__)
|
|
18
|
+
raise RuntimeError(f"Nonexistent attribute '{self.attr}' in '{self.obj}'")
|
|
19
|
+
logger.debug("AttrContext initialized successfully, has_attr=%s", self._has_attr)
|
|
20
|
+
|
|
21
|
+
def __enter__(self) -> 'AttrContext':
|
|
22
|
+
logger.debug("Entering AttrContext for %s.%s", type(self.obj).__name__, self.attr)
|
|
23
|
+
self.old_value = getattr(self.obj, self.attr, None)
|
|
24
|
+
setattr(self.obj, self.attr, self.new_value)
|
|
25
|
+
logger.info("Attribute %s set to %s (was %s)", self.attr, self.new_value, self.old_value)
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
29
|
+
logger.debug("Exiting AttrContext for %s.%s, exc_type=%s", type(self.obj).__name__, self.attr, exc_type)
|
|
30
|
+
if self._has_attr:
|
|
31
|
+
setattr(self.obj, self.attr, self.old_value)
|
|
32
|
+
logger.info("Attribute %s restored to %s", self.attr, self.old_value)
|
|
33
|
+
else:
|
|
34
|
+
delattr(self.obj, self.attr)
|
|
35
|
+
logger.info("Temporary attribute %s removed", self.attr)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
'AttrContext'
|
|
40
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import ContextManager
|
|
3
|
+
from ..logging_.utils import get_logger
|
|
4
|
+
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MultiContext(ContextManager):
|
|
9
|
+
def __init__(self, *contexts: ContextManager):
|
|
10
|
+
logger.debug("Initializing MultiContext with %s contexts", len(contexts))
|
|
11
|
+
self.contexts = contexts
|
|
12
|
+
|
|
13
|
+
def __enter__(self):
|
|
14
|
+
logger.info("Entering MultiContext with %s contexts", len(self.contexts))
|
|
15
|
+
for i, context in enumerate(self.contexts):
|
|
16
|
+
logger.debug("Entering context %s/%s: %s", i+1, len(self.contexts), type(context).__name__)
|
|
17
|
+
context.__enter__()
|
|
18
|
+
logger.debug("All contexts entered successfully")
|
|
19
|
+
return self
|
|
20
|
+
|
|
21
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
22
|
+
logger.debug("Exiting MultiContext with %s contexts, exc_type=%s", len(self.contexts), exc_type)
|
|
23
|
+
for i, context in enumerate(self.contexts):
|
|
24
|
+
logger.debug("Exiting context %s/%s: %s", i+1, len(self.contexts), type(context).__name__)
|
|
25
|
+
context.__exit__(exc_type, exc_val, exc_tb)
|
|
26
|
+
logger.info("All contexts exited")
|
|
27
|
+
|
|
28
|
+
def __getitem__(self, index):
|
|
29
|
+
return self.contexts[index]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
"MultiContext",
|
|
34
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import ContextManager
|
|
3
|
+
from ..logging_.utils import get_logger
|
|
4
|
+
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class OptionalContext(ContextManager):
|
|
9
|
+
def __init__(self, predicate: bool, context: ContextManager):
|
|
10
|
+
logger.debug("Initializing OptionalContext with predicate=%s, context=%s", predicate, type(context).__name__)
|
|
11
|
+
self.predicate = predicate
|
|
12
|
+
self.context = context
|
|
13
|
+
|
|
14
|
+
def __enter__(self):
|
|
15
|
+
logger.debug("Entering OptionalContext with predicate=%s", self.predicate)
|
|
16
|
+
if self.predicate:
|
|
17
|
+
logger.info("Condition met, entering context: %s", type(self.context).__name__)
|
|
18
|
+
self.context.__enter__()
|
|
19
|
+
else:
|
|
20
|
+
logger.debug("Condition not met, skipping context entry")
|
|
21
|
+
|
|
22
|
+
def __exit__(self, __exc_type, __exc_value, __traceback):
|
|
23
|
+
logger.debug("Exiting OptionalContext with predicate=%s, exc_type=%s", self.predicate, __exc_type)
|
|
24
|
+
if self.predicate:
|
|
25
|
+
logger.info("Condition was met, exiting context: %s", type(self.context).__name__)
|
|
26
|
+
self.context.__exit__(__exc_type, __exc_value, __traceback)
|
|
27
|
+
else:
|
|
28
|
+
logger.debug("Condition was not met, no context to exit")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
__all__=[
|
|
32
|
+
"OptionalContext"
|
|
33
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from ..custom_types import Procedure
|
|
4
|
+
from ..logging_.utils import get_logger
|
|
5
|
+
|
|
6
|
+
logger = get_logger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@contextmanager
|
|
10
|
+
def StateContext(set_state: Procedure, restore_state: Procedure):
|
|
11
|
+
logger.debug("Entering StateContext")
|
|
12
|
+
try:
|
|
13
|
+
logger.info("Setting state")
|
|
14
|
+
set_state()
|
|
15
|
+
logger.debug("State set successfully, yielding control")
|
|
16
|
+
yield
|
|
17
|
+
finally:
|
|
18
|
+
logger.info("Restoring state")
|
|
19
|
+
restore_state()
|
|
20
|
+
logger.debug("State restored successfully")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
'StateContext'
|
|
25
|
+
]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import atexit
|
|
2
|
+
import logging
|
|
3
|
+
import random
|
|
4
|
+
from typing import ContextManager, Set, List, Literal, Optional
|
|
5
|
+
from ..io_ import file_exists, delete_file
|
|
6
|
+
from ..logging_.utils import get_logger
|
|
7
|
+
|
|
8
|
+
logger = get_logger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TemporaryFile(ContextManager):
|
|
12
|
+
_instances: Set['TemporaryFile'] = set()
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def random(cls, length: int = 10, /, type: Literal["file", "folder"] = "file", prefix: Optional[str] = None,
|
|
16
|
+
suffix: Optional[str] = None) -> 'TemporaryFile':
|
|
17
|
+
from danielutils import RandomDataGenerator
|
|
18
|
+
temp_name = f"{type}_"
|
|
19
|
+
if prefix is not None:
|
|
20
|
+
temp_name += f"{prefix}_"
|
|
21
|
+
|
|
22
|
+
temp_name += RandomDataGenerator.name(length)
|
|
23
|
+
if suffix is not None:
|
|
24
|
+
temp_name += f"_{suffix}"
|
|
25
|
+
logger.debug("Creating random temporary file: %s", temp_name)
|
|
26
|
+
return TemporaryFile(temp_name)
|
|
27
|
+
|
|
28
|
+
def __init__(self, path: str):
|
|
29
|
+
if file_exists(path):
|
|
30
|
+
logger.error("Can't create temporary file - file already exists: %s", path)
|
|
31
|
+
raise RuntimeError(f"Can't create a temporary file if file '{path}' already exists.")
|
|
32
|
+
self.path = path
|
|
33
|
+
TemporaryFile._instances.add(self)
|
|
34
|
+
logger.debug("TemporaryFile created: %s", path)
|
|
35
|
+
|
|
36
|
+
def __enter__(self):
|
|
37
|
+
logger.debug("TemporaryFile context entered: %s", self.path)
|
|
38
|
+
return self
|
|
39
|
+
|
|
40
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
41
|
+
if exc_type is not None:
|
|
42
|
+
logger.warning("TemporaryFile context exited with exception: %s: %s", exc_type.__name__, exc_val)
|
|
43
|
+
else:
|
|
44
|
+
logger.debug("TemporaryFile context exited successfully: %s", self.path)
|
|
45
|
+
self.close()
|
|
46
|
+
|
|
47
|
+
def __str__(self) -> str:
|
|
48
|
+
return self.path
|
|
49
|
+
|
|
50
|
+
def close(self) -> None:
|
|
51
|
+
logger.debug("Closing temporary file: %s", self.path)
|
|
52
|
+
delete_file(self.path)
|
|
53
|
+
|
|
54
|
+
def read(self) -> str:
|
|
55
|
+
if not file_exists(self.path):
|
|
56
|
+
logger.debug("Temporary file does not exist for reading: %s", self.path)
|
|
57
|
+
return ""
|
|
58
|
+
logger.debug("Reading temporary file: %s", self.path)
|
|
59
|
+
with open(self.path, 'r') as f:
|
|
60
|
+
return f.read()
|
|
61
|
+
|
|
62
|
+
def readbinary(self) -> bytes:
|
|
63
|
+
if not file_exists(self.path):
|
|
64
|
+
logger.debug("Temporary file does not exist for binary reading: %s", self.path)
|
|
65
|
+
return b""
|
|
66
|
+
logger.debug("Reading temporary file as binary: %s", self.path)
|
|
67
|
+
with open(self.path, 'rb') as f:
|
|
68
|
+
return f.read()
|
|
69
|
+
|
|
70
|
+
def readlines(self) -> List[str]:
|
|
71
|
+
if not file_exists(self.path):
|
|
72
|
+
logger.debug("Temporary file does not exist for reading lines: %s", self.path)
|
|
73
|
+
return []
|
|
74
|
+
logger.debug("Reading lines from temporary file: %s", self.path)
|
|
75
|
+
with open(self.path, 'r') as f:
|
|
76
|
+
return f.readlines()
|
|
77
|
+
|
|
78
|
+
def write(self, s: str) -> None:
|
|
79
|
+
logger.debug("Writing to temporary file: %s", self.path)
|
|
80
|
+
with open(self.path, 'a') as f:
|
|
81
|
+
f.write(s)
|
|
82
|
+
|
|
83
|
+
def writebinary(self, s: bytes) -> None:
|
|
84
|
+
logger.debug("Writing binary data to temporary file: %s", self.path)
|
|
85
|
+
with open(self.path, 'ab') as f:
|
|
86
|
+
f.write(s)
|
|
87
|
+
|
|
88
|
+
def writelines(self, lines: List[str]) -> None:
|
|
89
|
+
logger.debug("Writing %s lines to temporary file: %s", len(lines), self.path)
|
|
90
|
+
with open(self.path, 'a') as f:
|
|
91
|
+
f.writelines(lines)
|
|
92
|
+
|
|
93
|
+
def clear(self):
|
|
94
|
+
logger.debug("Clearing temporary file: %s", self.path)
|
|
95
|
+
with open(self.path, 'w') as _:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@atexit.register
|
|
100
|
+
def __close_all():
|
|
101
|
+
logger.debug("Closing %s temporary files at exit", len(TemporaryFile._instances))
|
|
102
|
+
for inst in TemporaryFile._instances: # type:ignore #pylint: disable=all
|
|
103
|
+
inst.close()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
__all__ = [
|
|
107
|
+
'TemporaryFile'
|
|
108
|
+
]
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from ..decorators import validate
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@validate # type:ignore
|
|
5
|
+
def char_to_int(c: str) -> int:
|
|
6
|
+
"""convert char to its representing int value
|
|
7
|
+
|
|
8
|
+
Args:
|
|
9
|
+
c (str): char to convert
|
|
10
|
+
|
|
11
|
+
Returns:
|
|
12
|
+
int: int value
|
|
13
|
+
"""
|
|
14
|
+
return ord(c)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@validate # type:ignore
|
|
18
|
+
def int_to_char(num: int) -> str:
|
|
19
|
+
"""convert int to its corresponding char
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
num (int): number to convert
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
str: result character
|
|
26
|
+
"""
|
|
27
|
+
return chr(num)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@validate # type:ignore
|
|
31
|
+
def hex_to_char(h: str) -> str:
|
|
32
|
+
"""convert hex number to char
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
h (str): number to convert
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
str: result char
|
|
39
|
+
"""
|
|
40
|
+
return int_to_char(hex_to_dec(h))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@validate # type:ignore
|
|
44
|
+
def hex_to_dec(h: str) -> int:
|
|
45
|
+
"""convert hex to dec
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
h (str): converts base 16 to base 10
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
int: decimal value for hex number
|
|
52
|
+
"""
|
|
53
|
+
return int(h, 16)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@validate # type:ignore
|
|
57
|
+
def char_to_hex(c: str) -> str:
|
|
58
|
+
"""convert char to hex
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
c (str): char to convert
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
str: hex representation
|
|
65
|
+
"""
|
|
66
|
+
return int_to_hex(char_to_int(c))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@validate # type:ignore
|
|
70
|
+
def dec_to_hex(num: int) -> str:
|
|
71
|
+
"""convert decimal number to hex
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
num (int): number to convert
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
str: _description_
|
|
78
|
+
"""
|
|
79
|
+
return int_to_hex(num)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@validate # type:ignore
|
|
83
|
+
def int_to_hex(num: int) -> str:
|
|
84
|
+
"""converts an int to it's hex representation
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
num (int): int to convert
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
str: the hex representation of the int
|
|
91
|
+
"""
|
|
92
|
+
return hex(num)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@validate # type:ignore
|
|
96
|
+
def bytes_to_str(b: bytes) -> str:
|
|
97
|
+
"""decodes bytes to str
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
b (bytes): bytes to decode
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
str: result
|
|
104
|
+
"""
|
|
105
|
+
return b.decode("utf-8")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@validate # type:ignore
|
|
109
|
+
def str_to_bytes(s: str) -> bytes:
|
|
110
|
+
"""encodes a string to bytes
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
s (str): the string to encode
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
bytes: result
|
|
117
|
+
"""
|
|
118
|
+
return bytes(s, encoding='utf-8')
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
__all__ = [
|
|
122
|
+
"char_to_int",
|
|
123
|
+
"int_to_char",
|
|
124
|
+
"hex_to_char",
|
|
125
|
+
"hex_to_dec",
|
|
126
|
+
"char_to_hex",
|
|
127
|
+
"dec_to_hex",
|
|
128
|
+
"int_to_hex",
|
|
129
|
+
"bytes_to_str",
|
|
130
|
+
"str_to_bytes"
|
|
131
|
+
]
|