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,475 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import get_args, get_origin, get_type_hints, Any, Union, TypeVar, \
|
|
3
|
+
ForwardRef, Literal, Optional, Protocol, Generic, Type, List, Tuple, Set, Dict
|
|
4
|
+
import inspect
|
|
5
|
+
from collections.abc import Callable, Generator, Iterable
|
|
6
|
+
from ..reflection import get_python_version
|
|
7
|
+
from ..logging_.utils import get_logger
|
|
8
|
+
logger = get_logger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _tmp(Protocol): ...
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_ProtocolMeta = type(_tmp)
|
|
15
|
+
del _tmp
|
|
16
|
+
|
|
17
|
+
T = TypeVar('T')
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class _tmp2(Generic[T]): ...
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_GenericAlias = type(_tmp2[int])
|
|
24
|
+
del _tmp2, T
|
|
25
|
+
cmethod = type(getattr(1, "__lt__"))
|
|
26
|
+
try:
|
|
27
|
+
implicit_union_type = type(int | str)
|
|
28
|
+
except:
|
|
29
|
+
implicit_union_type = Union
|
|
30
|
+
|
|
31
|
+
ellipsis_ = ...
|
|
32
|
+
|
|
33
|
+
PARAMSPEC_STRICT: bool = True
|
|
34
|
+
try:
|
|
35
|
+
from typing import ParamSpec
|
|
36
|
+
except ImportError:
|
|
37
|
+
PARAMSPEC_STRICT = False
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def __isoftype_inquire(obj: Any) -> Tuple[Optional[type], Optional[tuple], Optional[dict]]:
|
|
41
|
+
"""
|
|
42
|
+
Inquires the origin, arguments, and type hints of an object.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
obj: The object to inquire.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
A tuple containing the origin, arguments, and type hints of the object.
|
|
49
|
+
"""
|
|
50
|
+
origin = None
|
|
51
|
+
args = None
|
|
52
|
+
type_hints = None
|
|
53
|
+
try:
|
|
54
|
+
origin = get_origin(obj)
|
|
55
|
+
except:
|
|
56
|
+
pass
|
|
57
|
+
try:
|
|
58
|
+
args = get_args(obj)
|
|
59
|
+
except:
|
|
60
|
+
pass
|
|
61
|
+
try:
|
|
62
|
+
type_hints = get_type_hints(obj)
|
|
63
|
+
except:
|
|
64
|
+
pass
|
|
65
|
+
return origin, args, type_hints
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def __handle_list_set_iterable(params: tuple) -> bool:
|
|
69
|
+
"""
|
|
70
|
+
Handles the 'list', 'set', and 'Iterable' origin types.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
params: A tuple containing the required parameters.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
True if the object matches the 'list', 'set', or 'Iterable' origin type, False otherwise.
|
|
77
|
+
"""
|
|
78
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
79
|
+
value_t = t_args[0]
|
|
80
|
+
for value in V:
|
|
81
|
+
if not isoftype(value, value_t, strict=strict):
|
|
82
|
+
return False
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def __handle_tuple(params: tuple) -> bool:
|
|
87
|
+
"""
|
|
88
|
+
Handles the 'tuple' origin type.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
params: A tuple containing the required parameters.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
True if the object matches the 'tuple' origin type, False otherwise.
|
|
95
|
+
"""
|
|
96
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
97
|
+
if len(V) != len(t_args):
|
|
98
|
+
return False
|
|
99
|
+
for sub_obj, sub_t in zip(V, t_args):
|
|
100
|
+
if not isoftype(sub_obj, sub_t, strict=strict):
|
|
101
|
+
return False
|
|
102
|
+
return True
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def __handle_dict(params: tuple) -> bool:
|
|
106
|
+
"""
|
|
107
|
+
Handles the 'dict' origin type.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
params: A tuple containing the required parameters.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
True if the object matches the 'dict' origin type, False otherwise.
|
|
114
|
+
"""
|
|
115
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
116
|
+
key_t, value_t = t_args[0], t_args[1]
|
|
117
|
+
for k, v in V.items():
|
|
118
|
+
if not isoftype(k, key_t, strict=strict):
|
|
119
|
+
return False
|
|
120
|
+
if not isoftype(v, value_t, strict=strict):
|
|
121
|
+
return False
|
|
122
|
+
return True
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def __handle_union(params: tuple) -> bool:
|
|
126
|
+
"""
|
|
127
|
+
Handles the 'Union' origin type.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
params: A tuple containing the required parameters.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
True if the object matches the 'Union' origin type, False otherwise.
|
|
134
|
+
"""
|
|
135
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
136
|
+
for sub_t in t_args:
|
|
137
|
+
if isoftype(V, sub_t, strict=strict):
|
|
138
|
+
return True
|
|
139
|
+
return False
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def __handle_generator(params: tuple) -> bool:
|
|
143
|
+
"""
|
|
144
|
+
Handles the 'Generator' origin type.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
params: A tuple containing the required parameters.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
True if the object matches the 'Generator' origin type, False otherwise.
|
|
151
|
+
"""
|
|
152
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
153
|
+
yield_t, send_t, return_t = t_args
|
|
154
|
+
return isinstance(V, Generator)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def __handle_literal(params: tuple) -> bool:
|
|
158
|
+
"""
|
|
159
|
+
Handles the 'Literal' origin type.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
params: A tuple containing the required parameters.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
True if the object matches the 'Literal' origin type, False otherwise.
|
|
166
|
+
"""
|
|
167
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
168
|
+
for literal in t_args:
|
|
169
|
+
if V is literal:
|
|
170
|
+
return True
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def __handle_callable(params: tuple) -> bool:
|
|
175
|
+
"""
|
|
176
|
+
Handles the 'Callable' origin type.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
params: A tuple containing the required parameters.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
True if the object matches the 'Callable' origin type, False otherwise.
|
|
183
|
+
"""
|
|
184
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
185
|
+
|
|
186
|
+
if not callable(V):
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
if V.__name__ == "<lambda>":
|
|
190
|
+
if strict:
|
|
191
|
+
print("Using lambda function with isoftype is ambiguous.")
|
|
192
|
+
return not strict
|
|
193
|
+
|
|
194
|
+
if t_args is None:
|
|
195
|
+
return True
|
|
196
|
+
if len(t_args) == 0:
|
|
197
|
+
return True
|
|
198
|
+
try:
|
|
199
|
+
from typing import Concatenate, ParamSpec
|
|
200
|
+
concatenate_t = type(Concatenate[str, ParamSpec("P_")])
|
|
201
|
+
if get_python_version() < (3, 10):
|
|
202
|
+
if isoftype(t_args[0][0], [ParamSpec, concatenate_t]):
|
|
203
|
+
return True
|
|
204
|
+
else:
|
|
205
|
+
if isoftype(t_args[0], [ParamSpec, concatenate_t]):
|
|
206
|
+
return True
|
|
207
|
+
except ImportError:
|
|
208
|
+
pass
|
|
209
|
+
|
|
210
|
+
obj_return_type = obj_hints.get('return')
|
|
211
|
+
obj_param_types = list(obj_hints.values())[:-1] if obj_hints else None
|
|
212
|
+
t_return_type = t_args[1]
|
|
213
|
+
|
|
214
|
+
if not PARAMSPEC_STRICT:
|
|
215
|
+
if t_args[0] == Ellipsis:
|
|
216
|
+
return True
|
|
217
|
+
if t_args[0] == [Any]:
|
|
218
|
+
return True
|
|
219
|
+
|
|
220
|
+
if isinstance(t_args[0], Iterable):
|
|
221
|
+
t_param_types = list(t_args[0])
|
|
222
|
+
A = obj_param_types + [obj_return_type] if obj_param_types else None
|
|
223
|
+
B = t_param_types + [t_return_type]
|
|
224
|
+
|
|
225
|
+
if A is None or B is None or len(A) != len(B):
|
|
226
|
+
return False
|
|
227
|
+
for a, b in zip(A, B):
|
|
228
|
+
if hasattr(b, "__args__"): # Union
|
|
229
|
+
if a not in b.__args__:
|
|
230
|
+
return False
|
|
231
|
+
elif a is not b: # otherwise
|
|
232
|
+
return False
|
|
233
|
+
return True
|
|
234
|
+
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def __handle_type_origin(params: tuple) -> bool:
|
|
239
|
+
"""
|
|
240
|
+
Handles the type origin.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
params: A tuple containing the required parameters.
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
True if the object matches the type origin, False otherwise.
|
|
247
|
+
"""
|
|
248
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
249
|
+
if T is Any:
|
|
250
|
+
return True
|
|
251
|
+
|
|
252
|
+
if type(T) in (list, tuple):
|
|
253
|
+
for sub_t in T:
|
|
254
|
+
if isoftype(V, sub_t, strict=strict):
|
|
255
|
+
return True
|
|
256
|
+
return False
|
|
257
|
+
|
|
258
|
+
if obj_origin is not None and obj_origin is Union:
|
|
259
|
+
return T is type(Union)
|
|
260
|
+
|
|
261
|
+
if isinstance(T, TypeVar):
|
|
262
|
+
t_args = T.__constraints__
|
|
263
|
+
if t_args:
|
|
264
|
+
for sub_t in t_args:
|
|
265
|
+
if isoftype(V, sub_t):
|
|
266
|
+
return True
|
|
267
|
+
return False
|
|
268
|
+
|
|
269
|
+
return True
|
|
270
|
+
|
|
271
|
+
if isinstance(T, ForwardRef):
|
|
272
|
+
name_of_type = T.__forward_arg__
|
|
273
|
+
return type(V).__name__ == name_of_type
|
|
274
|
+
|
|
275
|
+
return isinstance(V, T)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def _is_java_interface_type(cls: Any) -> bool:
|
|
279
|
+
try:
|
|
280
|
+
from ..java import JavaInterface
|
|
281
|
+
except ImportError:
|
|
282
|
+
return False
|
|
283
|
+
return JavaInterface in getattr(cls, "__mro__", [])
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def __handle_protocol(params: tuple, /, allow_classes: bool = False) -> bool:
|
|
287
|
+
# TODO is_protocol, _is_runtime_protocol
|
|
288
|
+
from ..reflection import FunctionDeclaration, ClassDeclaration
|
|
289
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
290
|
+
|
|
291
|
+
if T is Protocol:
|
|
292
|
+
mro = getattr(V, "__mro__", [])
|
|
293
|
+
if Protocol in mro:
|
|
294
|
+
return True
|
|
295
|
+
try:
|
|
296
|
+
from ..java import JavaInterface
|
|
297
|
+
except ImportError:
|
|
298
|
+
return False
|
|
299
|
+
return JavaInterface in mro or any(getattr(base, "__is_interface__", False) for base in mro)
|
|
300
|
+
if T in getattr(V, "__mro__", []):
|
|
301
|
+
return False
|
|
302
|
+
if type(V) == type and type(T) == _GenericAlias and not allow_classes:
|
|
303
|
+
return False
|
|
304
|
+
if type(V) == type and len(t_args) == 0:
|
|
305
|
+
return isinstance(V, T)
|
|
306
|
+
if type(V) != type:
|
|
307
|
+
V = type(V)
|
|
308
|
+
|
|
309
|
+
interface_cls = T if inspect.isclass(T) else t_origin
|
|
310
|
+
if interface_cls is Protocol:
|
|
311
|
+
return False
|
|
312
|
+
|
|
313
|
+
cls = ClassDeclaration.from_cls(interface_cls)
|
|
314
|
+
declared_funcs: List[FunctionDeclaration] = list(FunctionDeclaration.get_declared_functions(V))
|
|
315
|
+
required_funcs: List[FunctionDeclaration] = list(FunctionDeclaration.get_declared_functions(interface_cls))
|
|
316
|
+
|
|
317
|
+
for i, req_func in enumerate(required_funcs):
|
|
318
|
+
if req_func.has_generics:
|
|
319
|
+
if req_func.return_type in req_func.generics:
|
|
320
|
+
new_req_func = req_func.duplicate(
|
|
321
|
+
return_type=t_args[req_func.generics.index(req_func.return_type)].__name__)
|
|
322
|
+
required_funcs[i] = new_req_func
|
|
323
|
+
for aindex, arg in enumerate(required_funcs[i].arguments):
|
|
324
|
+
for generic in req_func.generics:
|
|
325
|
+
if arg.type is not None and generic in arg.type:
|
|
326
|
+
if generic not in cls.generics:
|
|
327
|
+
return False
|
|
328
|
+
correct_type = t_args[cls.generics.index(generic)]
|
|
329
|
+
if getattr(correct_type, "__origin__", None) is Union:
|
|
330
|
+
new_name = str(correct_type).replace("typing.Union", "Union")
|
|
331
|
+
elif hasattr(correct_type, "__name__"):
|
|
332
|
+
new_name = correct_type.__name__
|
|
333
|
+
else:
|
|
334
|
+
new_name = str(correct_type).replace("typing.", "")
|
|
335
|
+
changed_argument = required_funcs[i].arguments[aindex].duplicate(type=new_name)
|
|
336
|
+
new_arguments = list(required_funcs[i].arguments)[::]
|
|
337
|
+
new_arguments[aindex] = changed_argument
|
|
338
|
+
required_funcs[i] = required_funcs[i].duplicate(arguments=tuple(new_arguments))
|
|
339
|
+
|
|
340
|
+
for req in required_funcs:
|
|
341
|
+
for dec in declared_funcs:
|
|
342
|
+
if not len(req.arguments) == len(dec.arguments):
|
|
343
|
+
return False
|
|
344
|
+
|
|
345
|
+
if not req.return_type == dec.return_type: return False
|
|
346
|
+
|
|
347
|
+
for rarg in req.arguments:
|
|
348
|
+
for darg in dec.arguments:
|
|
349
|
+
a = rarg.type
|
|
350
|
+
if a is not None and ("[" in a or "]" in a):
|
|
351
|
+
a = set([s.strip() for s in a[a.index("[") + 1:a.rindex("]")].split(",")])
|
|
352
|
+
else:
|
|
353
|
+
a = set([a])
|
|
354
|
+
b = darg.type
|
|
355
|
+
if b is not None and ("[" in b or "]" in b):
|
|
356
|
+
b = set([s.strip() for s in b[b.index("[") + 1:b.rindex("]")].split(",")])
|
|
357
|
+
else:
|
|
358
|
+
b = set([b])
|
|
359
|
+
if (len(list(b - a))) == 0: break
|
|
360
|
+
else:
|
|
361
|
+
return False
|
|
362
|
+
|
|
363
|
+
return True
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def __handle_type(params: tuple) -> bool:
|
|
367
|
+
V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints = params
|
|
368
|
+
if type(V) != type:
|
|
369
|
+
return False
|
|
370
|
+
if t_args[0] in V.__mro__:
|
|
371
|
+
return True
|
|
372
|
+
t_origin, t_args, t_hints = __isoftype_inquire(t_args[0])
|
|
373
|
+
if type(t_origin) is _ProtocolMeta:
|
|
374
|
+
return __handle_protocol((V, T, strict, obj_origin, obj_args, obj_hints, t_origin, t_args, t_hints),
|
|
375
|
+
allow_classes=True)
|
|
376
|
+
return False
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def __handle_unpack(params: tuple) -> bool:
|
|
380
|
+
# TODO see test_tlist.py -> test_wrong_values -> with self.assertRaises(TypeError):
|
|
381
|
+
# tlist[Tuple[int]]([[1], [2], [3], ["4"]])
|
|
382
|
+
raise NotImplemented
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
HANDLERS: Dict[type, Callable] = {
|
|
386
|
+
list: __handle_list_set_iterable,
|
|
387
|
+
tuple: __handle_tuple,
|
|
388
|
+
dict: __handle_dict,
|
|
389
|
+
set: __handle_list_set_iterable,
|
|
390
|
+
type: __handle_type,
|
|
391
|
+
List: __handle_list_set_iterable,
|
|
392
|
+
Tuple: __handle_tuple,
|
|
393
|
+
Dict: __handle_dict,
|
|
394
|
+
Set: __handle_list_set_iterable,
|
|
395
|
+
Type: __handle_type,
|
|
396
|
+
Iterable: __handle_list_set_iterable,
|
|
397
|
+
Union: __handle_union,
|
|
398
|
+
implicit_union_type: __handle_union,
|
|
399
|
+
Generator: __handle_generator,
|
|
400
|
+
Literal: __handle_literal,
|
|
401
|
+
Callable: __handle_callable,
|
|
402
|
+
Protocol: __handle_protocol,
|
|
403
|
+
}
|
|
404
|
+
try:
|
|
405
|
+
# This exists only from python version 3.11 onwards
|
|
406
|
+
from typing import Unpack
|
|
407
|
+
|
|
408
|
+
HANDLERS[Unpack] = __handle_unpack
|
|
409
|
+
except:
|
|
410
|
+
pass
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def isoftype(V: Any, T: Any, /, strict: bool = True) -> bool:
|
|
414
|
+
"""
|
|
415
|
+
Checks if an object is of a certain type.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
V: The object to check.
|
|
419
|
+
T: The type to check against.
|
|
420
|
+
strict: Whether to perform strict type checking.
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
True if the object is of the specified type, False otherwise.
|
|
424
|
+
"""
|
|
425
|
+
if not isinstance(strict, bool):
|
|
426
|
+
logger.error("'strict' parameter must be of type bool")
|
|
427
|
+
raise TypeError("'strict' must be of type bool")
|
|
428
|
+
|
|
429
|
+
obj_origin, obj_args, obj_hints = __isoftype_inquire(V)
|
|
430
|
+
t_origin, t_args, t_hints = __isoftype_inquire(T)
|
|
431
|
+
|
|
432
|
+
params = (
|
|
433
|
+
V, T, strict,
|
|
434
|
+
obj_origin, obj_args, obj_hints,
|
|
435
|
+
t_origin, t_args, t_hints
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
if t_args is not None and Ellipsis in t_args and PARAMSPEC_STRICT:
|
|
439
|
+
from ..colors import warning # pylint: disable=cyclic-import
|
|
440
|
+
warning(
|
|
441
|
+
"using an ellipsis (as in '...') with isoftype is ambiguous returning False")
|
|
442
|
+
return False
|
|
443
|
+
|
|
444
|
+
if T is Union:
|
|
445
|
+
t_origin = Union # type:ignore
|
|
446
|
+
elif T is Protocol or Protocol in getattr(T, "__mro__", []) or _is_java_interface_type(T):
|
|
447
|
+
t_origin = Protocol # type:ignore
|
|
448
|
+
elif Protocol in getattr(V, "__mro__", []):
|
|
449
|
+
t_origin = Protocol # type:ignore
|
|
450
|
+
|
|
451
|
+
if t_origin is not None:
|
|
452
|
+
if getattr(t_origin, "_is_protocol", False) or isinstance(t_origin, _ProtocolMeta):
|
|
453
|
+
t_origin = Protocol # type:ignore
|
|
454
|
+
|
|
455
|
+
if t_origin in HANDLERS:
|
|
456
|
+
if t_origin in (list, tuple, dict, set, dict, Iterable):
|
|
457
|
+
if not isinstance(V, t_origin): # type:ignore
|
|
458
|
+
return False
|
|
459
|
+
result = HANDLERS[t_origin](params) # type:ignore
|
|
460
|
+
return result
|
|
461
|
+
# These imports must explicitly be specifically here and not at the top
|
|
462
|
+
logger.warning("Unhandled t_origin: %s, returning True", t_origin)
|
|
463
|
+
from danielutils import warning, get_traceback
|
|
464
|
+
warning(
|
|
465
|
+
f"In function isoftype, unhandled t_origin: {t_origin} returning True. stacktrace:")
|
|
466
|
+
print(*get_traceback())
|
|
467
|
+
return True
|
|
468
|
+
|
|
469
|
+
result = __handle_type_origin(params)
|
|
470
|
+
return result
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
__all__ = [
|
|
474
|
+
"isoftype"
|
|
475
|
+
]
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, Union, Sequence
|
|
3
|
+
from .isoftype import isoftype
|
|
4
|
+
from ..reflection import get_python_version
|
|
5
|
+
from ..logging_.utils import get_logger
|
|
6
|
+
|
|
7
|
+
logger = get_logger(__name__)
|
|
8
|
+
if get_python_version() < (3, 9):
|
|
9
|
+
from typing import List as List, Tuple as Tuple
|
|
10
|
+
else:
|
|
11
|
+
from builtins import list as List, tuple as Tuple # type:ignore
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def isoneof(v: Any, types: Union[List[type], Tuple[type]]) -> bool:
|
|
15
|
+
"""performs isoftype() or ... or isoftype()
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
v (Any): the value to check it's type
|
|
19
|
+
types (Union[list[Type], tuple[Type]): A Sequence of approved types
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
TypeError: if the second argument is not from Union[list[Type], tuple[Type]
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
bool: return True iff isoftype(v, types[0]) or ... isoftype(v, types[...])
|
|
26
|
+
"""
|
|
27
|
+
logger.debug("Checking if %s is one of types: %s", v, types)
|
|
28
|
+
if not isinstance(types, (list, tuple)):
|
|
29
|
+
logger.error("'types' parameter must be of type 'list' or 'tuple'")
|
|
30
|
+
raise TypeError("'types' must be of type 'list' or 'tuple'")
|
|
31
|
+
|
|
32
|
+
for i, T in enumerate(types):
|
|
33
|
+
if isoftype(v, T):
|
|
34
|
+
logger.debug("Value %s matches type at index %s: %s", v, i, T)
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
logger.debug("Value %s does not match any of the specified types", v)
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def isoneof_strict(v: Any, types: Union[List[type], Tuple[type]]) -> bool:
|
|
42
|
+
"""performs 'type(v) in types' efficiently
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
v (Any): value to check
|
|
46
|
+
types (Sequence[Type]): sequence of approved types
|
|
47
|
+
|
|
48
|
+
Raises:
|
|
49
|
+
TypeError: if types is not a sequence
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
bool: true if type of value appears in types
|
|
53
|
+
"""
|
|
54
|
+
logger.debug("Strict type checking if %s (type: %s) is one of: %s", v, type(v), types)
|
|
55
|
+
if not isinstance(types, Sequence):
|
|
56
|
+
logger.error("'types' parameter must be of type Sequence")
|
|
57
|
+
raise TypeError("lst must be of type Sequence")
|
|
58
|
+
|
|
59
|
+
for i, T in enumerate(types):
|
|
60
|
+
if type(v) in {T}:
|
|
61
|
+
logger.debug("Value %s type matches at index %s: %s", v, i, T)
|
|
62
|
+
return True
|
|
63
|
+
|
|
64
|
+
logger.debug("Value %s type does not match any of the specified types", v)
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
__all__ = [
|
|
69
|
+
"isoneof",
|
|
70
|
+
"isoneof_strict"
|
|
71
|
+
]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Iterable, Generator, List
|
|
3
|
+
from .flatten import flatten
|
|
4
|
+
from ..logging_.utils import get_logger
|
|
5
|
+
|
|
6
|
+
logger = get_logger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _combine2(iter1: Iterable, iter2: Iterable) -> Generator:
|
|
10
|
+
for v1 in iter1:
|
|
11
|
+
for v2 in iter2:
|
|
12
|
+
yield v1, v2
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def multiloop(*iterables: Iterable, pre_load: bool = False) -> Generator:
|
|
16
|
+
"""
|
|
17
|
+
Generates all combinations of values from multiple iterables.
|
|
18
|
+
|
|
19
|
+
This function takes as input any number of iterables and generates all possible combinations of their values.
|
|
20
|
+
It also has an option to pre-load the iterables into memory before generating combinations.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
*iterables (list[Iterable]): The iterables to generate combinations from.
|
|
24
|
+
pre_load (bool, optional): If True, pre-loads the iterables into memory. Defaults to False.
|
|
25
|
+
|
|
26
|
+
Yields:
|
|
27
|
+
Generator: A generator that yields tuples, each containing one combination of values from the iterables.
|
|
28
|
+
"""
|
|
29
|
+
logger.info("Starting multiloop with %s iterables, pre_load=%s", len(iterables), pre_load)
|
|
30
|
+
|
|
31
|
+
if len(iterables) == 1:
|
|
32
|
+
yield from iterables[0]
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
arr: List[Iterable] = list(iterables)
|
|
36
|
+
if pre_load:
|
|
37
|
+
logger.info("Pre-loading iterables into memory")
|
|
38
|
+
arr = [list(itr) for itr in iterables]
|
|
39
|
+
|
|
40
|
+
cur = _combine2(*arr[:2])
|
|
41
|
+
for itr in arr[2:]:
|
|
42
|
+
cur = _combine2(cur, itr)
|
|
43
|
+
|
|
44
|
+
for v in cur:
|
|
45
|
+
flattened = tuple(flatten(v))
|
|
46
|
+
yield flattened
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
__all__ = [
|
|
50
|
+
"multiloop"
|
|
51
|
+
]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import threading
|
|
3
|
+
from typing import TypeVar, Callable
|
|
4
|
+
from ..logging_.utils import get_logger
|
|
5
|
+
|
|
6
|
+
logger = get_logger(__name__)
|
|
7
|
+
|
|
8
|
+
T = TypeVar("T")
|
|
9
|
+
Consumer = Callable[[T], None]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def parallel_for(func: Consumer[T], *args: T, wait: bool = True) -> None:
|
|
13
|
+
"""
|
|
14
|
+
This function will run 'func' in parallel with the given args individually
|
|
15
|
+
Args:
|
|
16
|
+
func: function to run in parallel
|
|
17
|
+
*args: args to call the function each time
|
|
18
|
+
wait: whether to wait for all the threads to join before returning
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
logger.info("Starting parallel execution of %s with %s arguments, wait=%s", func.__name__, len(args), wait)
|
|
24
|
+
# this is safer... What if some other threads that were running will also end in the meantime?
|
|
25
|
+
threads = [threading.Thread(target=func, args=[arg]) for arg in args]
|
|
26
|
+
|
|
27
|
+
for t in threads:
|
|
28
|
+
t.start()
|
|
29
|
+
|
|
30
|
+
if wait:
|
|
31
|
+
for t in threads:
|
|
32
|
+
t.join()
|
|
33
|
+
logger.info("All threads completed successfully")
|
|
34
|
+
else:
|
|
35
|
+
logger.info("Threads started, not waiting for completion")
|
|
36
|
+
# before = threading.active_count()
|
|
37
|
+
# for arg in args:
|
|
38
|
+
# threadify(func)(arg)
|
|
39
|
+
#
|
|
40
|
+
# if wait:
|
|
41
|
+
# while threading.active_count() > before:
|
|
42
|
+
# pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = [
|
|
46
|
+
'parallel_for'
|
|
47
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import List, Generator, Tuple, Union
|
|
3
|
+
from ..logging_.utils import get_logger
|
|
4
|
+
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def partitions(n: int, k: int) -> Generator[List[int], None, None]:
|
|
9
|
+
logger.info("Generating partitions of %s into %s parts", n, k)
|
|
10
|
+
from ..decorators import memo_generator
|
|
11
|
+
|
|
12
|
+
@memo_generator
|
|
13
|
+
def helper(n: int, target_sum: int, current_sum: int, topLevel: int, arr: Union[List[int], Tuple[int]]) -> \
|
|
14
|
+
Generator[List[int], None, None]:
|
|
15
|
+
arr = list(arr)
|
|
16
|
+
if n == 1:
|
|
17
|
+
if current_sum <= target_sum:
|
|
18
|
+
if topLevel == 1 or (target_sum - current_sum >= arr[-2]):
|
|
19
|
+
arr[-1] = target_sum - current_sum
|
|
20
|
+
yield tuple(arr)
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
start = 0
|
|
24
|
+
if n != topLevel:
|
|
25
|
+
start = arr[-1 * n - 1]
|
|
26
|
+
|
|
27
|
+
for i in range(start, target_sum + 1):
|
|
28
|
+
arr[-1 * n] = i
|
|
29
|
+
yield from helper(n - 1, target_sum, current_sum + i, topLevel, tuple(arr))
|
|
30
|
+
|
|
31
|
+
arr: List[int] = [0] * k
|
|
32
|
+
yield from helper(k, n, 0, k, tuple(arr))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def num_partitions(n: int, k: int) -> int:
|
|
36
|
+
logger.info("Counting number of partitions of %s into %s parts", n, k)
|
|
37
|
+
result = len(list(partitions(n, k)))
|
|
38
|
+
logger.info("Found %s partitions", result)
|
|
39
|
+
return result
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"partitions",
|
|
44
|
+
"num_partitions"
|
|
45
|
+
]
|