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,266 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import decimal
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Callable, Optional, Iterator, Sequence, overload, Union
|
|
5
|
+
from ..logging_.utils import get_logger
|
|
6
|
+
logger = get_logger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class frange(Sequence[float]):
|
|
10
|
+
"""This class is the same like the builtin range but with float values
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def from_range(r: range) -> 'frange':
|
|
15
|
+
"""will "downcast" `range` to `frange` correctly"""
|
|
16
|
+
return frange(r.start, r.stop, r.step)
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def _is_int(n: Union[int, float]) -> bool:
|
|
20
|
+
if isinstance(n, int):
|
|
21
|
+
return True
|
|
22
|
+
|
|
23
|
+
return n.is_integer()
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def _lcm_int(a: int, b: int) -> int:
|
|
27
|
+
if hasattr(math, "lcm"):
|
|
28
|
+
return math.lcm(a, b)
|
|
29
|
+
return abs(a * b) // math.gcd(a, b)
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def _lcm_float(a: float, b: float) -> float:
|
|
33
|
+
prec = min(5, max(decimal.getcontext().prec, 10))
|
|
34
|
+
a = round(a, prec)
|
|
35
|
+
b = round(b, prec)
|
|
36
|
+
return frange._lcm_int(int(a * 10 ** prec), int(b * 10 ** prec)) / 10 ** prec
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def _find_min_step(s1: float, s2: float) -> float:
|
|
40
|
+
"""
|
|
41
|
+
returns the minimum LCM for two step values
|
|
42
|
+
Args:
|
|
43
|
+
s1 (float): first step value:
|
|
44
|
+
s2 (float): second step value:
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
float: minimum LCM
|
|
48
|
+
"""
|
|
49
|
+
M = max(s1, s2)
|
|
50
|
+
m = min(s1, s2)
|
|
51
|
+
if float.is_integer(M / m):
|
|
52
|
+
return M
|
|
53
|
+
return frange._lcm_float(s1, s2)
|
|
54
|
+
|
|
55
|
+
def __init__(self, start: float, stop: Optional[float] = None,
|
|
56
|
+
step: float = 1, round_method: Callable[[float], float] = lambda f: round(f, 3)):
|
|
57
|
+
logger.debug("Initializing frange with start=%s, stop=%s, step=%s", start, stop, step)
|
|
58
|
+
if stop is None:
|
|
59
|
+
stop = start
|
|
60
|
+
start = 0
|
|
61
|
+
self.start = start
|
|
62
|
+
self.stop = stop
|
|
63
|
+
self.step = step
|
|
64
|
+
self.method = round_method
|
|
65
|
+
logger.debug("frange initialized: start=%s, stop=%s, step=%s", self.start, self.stop, self.step)
|
|
66
|
+
|
|
67
|
+
@overload
|
|
68
|
+
def __getitem__(self, index: int) -> float:
|
|
69
|
+
...
|
|
70
|
+
|
|
71
|
+
@overload
|
|
72
|
+
def __getitem__(self, index: slice) -> 'frange':
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
def __getitem__(self, index: Union[float, slice]) -> Union[float, 'frange']:
|
|
76
|
+
logger.debug("Getting item at index %s from frange", index)
|
|
77
|
+
if isinstance(index, slice):
|
|
78
|
+
logger.debug("Processing slice: start=%s, stop=%s, step=%s", index.start, index.stop, index.step)
|
|
79
|
+
index = slice(
|
|
80
|
+
index.start if index.start is not None else 0,
|
|
81
|
+
index.stop if index.stop is not None else len(self),
|
|
82
|
+
index.step if index.step is not None else 1,
|
|
83
|
+
)
|
|
84
|
+
if index.step > 0:
|
|
85
|
+
step = self.step * index.step
|
|
86
|
+
start = self.start + step * index.start
|
|
87
|
+
stop = self.start + step * index.stop
|
|
88
|
+
logger.debug("Creating new frange from slice: start=%s, stop=%s, step=%s", start, stop, step)
|
|
89
|
+
return frange(start, stop, step)
|
|
90
|
+
s = slice(index.start, index.stop, abs(index.step))
|
|
91
|
+
logger.debug("Reversing slice result")
|
|
92
|
+
return reversed(self[s])
|
|
93
|
+
if index < 0:
|
|
94
|
+
logger.error("Negative index %s not allowed in frange", index)
|
|
95
|
+
raise ValueError(f"At {self.__class__.__qualname__}.__getitem__ 'index' must be a positive integer")
|
|
96
|
+
result = self.start + self.step * index
|
|
97
|
+
logger.debug("Returning value %s for index %s", result, index)
|
|
98
|
+
return result
|
|
99
|
+
|
|
100
|
+
def __reversed__(self) -> 'frange':
|
|
101
|
+
return frange(self.stop - 1, self.start - 1, -self.step)
|
|
102
|
+
|
|
103
|
+
def __eq__(self, other):
|
|
104
|
+
if not isinstance(other, frange):
|
|
105
|
+
raise NotImplementedError
|
|
106
|
+
return self.start == other.start and self.stop == other.stop and self.step == other.step
|
|
107
|
+
|
|
108
|
+
def __iter__(self) -> Iterator[float]:
|
|
109
|
+
logger.debug("Starting iteration over frange: start=%s, stop=%s, step=%s", self.start, self.stop, self.step)
|
|
110
|
+
if self.stop < self.start and self.step > 0:
|
|
111
|
+
logger.debug("Empty range: stop < start with positive step")
|
|
112
|
+
return
|
|
113
|
+
if self.start > self.stop and self.step > 0:
|
|
114
|
+
logger.debug("Empty range: start > stop with positive step")
|
|
115
|
+
return
|
|
116
|
+
if abs(self.stop - self.start) < abs(self.step):
|
|
117
|
+
logger.debug("Empty range: step larger than range")
|
|
118
|
+
return
|
|
119
|
+
if self.stop > 0 and self.step < 0:
|
|
120
|
+
logger.debug("Empty range: positive stop with negative step")
|
|
121
|
+
return
|
|
122
|
+
if self.stop < 0 and self.step > 0:
|
|
123
|
+
logger.debug("Empty range: negative stop with positive step")
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
cur = self.start
|
|
127
|
+
count = 0
|
|
128
|
+
while (cur < self.stop and self.step > 0) or (cur > self.stop and self.step < 0):
|
|
129
|
+
yield self.method(cur)
|
|
130
|
+
cur += self.step
|
|
131
|
+
count += 1
|
|
132
|
+
logger.debug("Iteration completed, yielded %s values", count)
|
|
133
|
+
|
|
134
|
+
def __len__(self) -> int:
|
|
135
|
+
if self.stop in {float("inf"), -float("inf")}:
|
|
136
|
+
return float("inf")
|
|
137
|
+
return int(abs(self.stop - self.start) // abs(self.step))
|
|
138
|
+
|
|
139
|
+
def __str__(self) -> str:
|
|
140
|
+
return repr(self)
|
|
141
|
+
|
|
142
|
+
def __repr__(self):
|
|
143
|
+
return f"{self.__class__.__name__}({self.start}, {self.stop}, {self.step})"
|
|
144
|
+
|
|
145
|
+
def __contains__(self, item):
|
|
146
|
+
if item < self.start:
|
|
147
|
+
return False
|
|
148
|
+
if item >= self.stop:
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
if frange._is_int(self.step):
|
|
152
|
+
if not frange._is_int(item):
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
return item / self.step - item // self.step == 0
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def is_finite(self) -> bool:
|
|
159
|
+
"""
|
|
160
|
+
Returns `True` if the range is finite
|
|
161
|
+
inverse if `is_infinite`
|
|
162
|
+
Returns:
|
|
163
|
+
bool
|
|
164
|
+
"""
|
|
165
|
+
if self.stop in (float("inf"), float("-inf")):
|
|
166
|
+
return False
|
|
167
|
+
if self.start in (float("inf"), float("-inf")):
|
|
168
|
+
return False
|
|
169
|
+
try:
|
|
170
|
+
return len(self) != float("inf")
|
|
171
|
+
except TypeError:
|
|
172
|
+
return False
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def is_infinite(self) -> bool:
|
|
176
|
+
"""
|
|
177
|
+
Returns `True` if the range is infinite
|
|
178
|
+
inverse if `is_finite`
|
|
179
|
+
Returns:
|
|
180
|
+
bool
|
|
181
|
+
"""
|
|
182
|
+
return not self.is_finite
|
|
183
|
+
|
|
184
|
+
def normalize(self) -> 'frange':
|
|
185
|
+
"""
|
|
186
|
+
will normalize the `frange` object
|
|
187
|
+
Returns:
|
|
188
|
+
frange
|
|
189
|
+
"""
|
|
190
|
+
return frange(self.start / self.step, self.stop / self.step, 1)
|
|
191
|
+
|
|
192
|
+
def intersect(self, other: 'frange') -> 'frange':
|
|
193
|
+
logger.debug("Computing intersection of frange %s with %s", self, other)
|
|
194
|
+
if not isinstance(other, frange):
|
|
195
|
+
logger.error("intersect only accepts frange objects, got %s", type(other))
|
|
196
|
+
raise ValueError("frange.intercept only accepts frange objects")
|
|
197
|
+
a, b = self.normalize(), other.normalize()
|
|
198
|
+
start1, stop1 = a.start, a.stop
|
|
199
|
+
start2, stop2 = b.start, b.stop
|
|
200
|
+
remainder1, remainder2 = start1 - int(start1), start2 - int(start2)
|
|
201
|
+
start = max(self.start, other.start)
|
|
202
|
+
stop = min(self.stop, other.stop)
|
|
203
|
+
logger.debug("Normalized ranges: a=%s, b=%s, remainders: %s, %s", a, b, remainder1, remainder2)
|
|
204
|
+
if remainder1 == remainder2:
|
|
205
|
+
min_step = self._find_min_step(self.step, other.step)
|
|
206
|
+
logger.debug("Remainders match, min_step=%s", min_step)
|
|
207
|
+
if stop1 == float("inf") or stop2 == float("inf"):
|
|
208
|
+
logger.debug("One range is infinite, returning infinite result")
|
|
209
|
+
return frange(start, float("inf"), min_step)
|
|
210
|
+
logger.debug("Returning finite intersection: start=%s, stop=%s, step=%s", start, stop, min_step)
|
|
211
|
+
return frange(start, stop, min_step)
|
|
212
|
+
# find k; start1 + remainder1*k == start2 +remainder2*k
|
|
213
|
+
k = (start1 - start2) / (remainder2 - remainder1)
|
|
214
|
+
logger.debug("Computing k=%s for remainder intersection", k)
|
|
215
|
+
if k <= 0:
|
|
216
|
+
logger.debug("k <= 0, returning empty range")
|
|
217
|
+
return frange(0)
|
|
218
|
+
if stop1 == float("inf") or stop2 == float("inf"):
|
|
219
|
+
logger.error("Infinite range intersection not implemented")
|
|
220
|
+
raise NotImplementedError("this part is not implemented yet. one has inf")
|
|
221
|
+
logger.error("Complex remainder intersection not implemented")
|
|
222
|
+
raise NotImplementedError("this part is not implemented yet")
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class frange_iterator(Iterator[float]):
|
|
226
|
+
def __init__(self, obj: frange):
|
|
227
|
+
self.r = obj
|
|
228
|
+
|
|
229
|
+
def __next__(self):
|
|
230
|
+
if self.r.stop < self.r.start:
|
|
231
|
+
return
|
|
232
|
+
if self.r.start > self.r.stop:
|
|
233
|
+
return
|
|
234
|
+
if abs(self.r.stop - self.r.start) < abs(self.r.step):
|
|
235
|
+
return
|
|
236
|
+
if self.r.stop > 0 and self.r.step < 0:
|
|
237
|
+
return
|
|
238
|
+
if self.r.stop < 0 and self.r.step > 0:
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
cur = self.r.start
|
|
242
|
+
while cur < self.r.stop:
|
|
243
|
+
yield self.r.method(cur)
|
|
244
|
+
cur += self.r.step
|
|
245
|
+
|
|
246
|
+
def __iter__(self):
|
|
247
|
+
return self
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class brange(frange):
|
|
251
|
+
"""like frange but with tqdm
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
def __iter__(self):
|
|
255
|
+
itr = super().__iter__()
|
|
256
|
+
try:
|
|
257
|
+
from tqdm import tqdm # type:ignore # pylint: disable=import-error
|
|
258
|
+
return iter(tqdm(itr, desc=f"{self}", total=len(self)))
|
|
259
|
+
except:
|
|
260
|
+
return itr
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
__all__ = [
|
|
264
|
+
"frange",
|
|
265
|
+
"brange"
|
|
266
|
+
]
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import types
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
from typing import Any, Iterable, List as List, Set as Set, Dict as Dict, Tuple as Tuple
|
|
4
|
+
from ...functions import types_subseteq, isoftype
|
|
5
|
+
from ...reflection import get_caller_name, get_python_version
|
|
6
|
+
|
|
7
|
+
if get_python_version() >= (3, 9):
|
|
8
|
+
from builtins import list as List, set as Set, dict as Dict, tuple as Tuple # type:ignore
|
|
9
|
+
# needed for python 3.8
|
|
10
|
+
class_to_type = {
|
|
11
|
+
list: List,
|
|
12
|
+
set: Set,
|
|
13
|
+
dict: Dict,
|
|
14
|
+
Tuple: Tuple,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def create_typed_class(name: str, fallback_class: type = object) -> type:
|
|
19
|
+
"""will create a base class to inherit from which will enable enforcing runtime type safety.
|
|
20
|
+
|
|
21
|
+
### The following functions are added for use:
|
|
22
|
+
|
|
23
|
+
* get_params()->tuple which return the supplied type hins from the generic creation of the class
|
|
24
|
+
* subscribable_init(self,*args,**kwargs) which is the new "__init__"
|
|
25
|
+
* on_call(self,*args,**kwargs) which is the new "__call__"
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
name (str): name of class (can be the same of the derived?)
|
|
29
|
+
fallback_class (type): the fallback class to handle __str__, __repr__
|
|
30
|
+
and such. e.g for a typed version of list ('tlist') the fallback class would be 'list'
|
|
31
|
+
bases (tuple, optional): another additional bases that this class should inherit from. Defaults to None.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
type: new class type
|
|
35
|
+
"""
|
|
36
|
+
cls = types.new_class(name, (fallback_class,), {})
|
|
37
|
+
|
|
38
|
+
def __class_getitem__(cls, item: type):
|
|
39
|
+
return cls(item)
|
|
40
|
+
|
|
41
|
+
def __instancecheck__(self, instance: Any) -> bool:
|
|
42
|
+
if isinstance(instance, cls):
|
|
43
|
+
return types_subseteq(
|
|
44
|
+
instance.get_params(), # type:ignore
|
|
45
|
+
self.get_params()
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
return isoftype(
|
|
49
|
+
instance,
|
|
50
|
+
class_to_type[fallback_class][self.get_params()] # type:ignore
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def __init__(self, item) -> None:
|
|
54
|
+
if not get_caller_name(1) == "__class_getitem__":
|
|
55
|
+
raise ValueError(
|
|
56
|
+
f"Can't instantiate {self.__class__.__name__} without a supplied type")
|
|
57
|
+
fallback_class.__init__(self) # type: ignore
|
|
58
|
+
# pylint: disable=protected-access
|
|
59
|
+
self._params = (item,) if not isinstance(
|
|
60
|
+
item, Iterable) else tuple(item)
|
|
61
|
+
self._inited = False
|
|
62
|
+
|
|
63
|
+
def subscribable_init(self, *args, **kwargs) -> None:
|
|
64
|
+
raise NotImplementedError(
|
|
65
|
+
"'subscribable_init(self,*args,**kwargs) is an abstract method that must be implemented.")
|
|
66
|
+
|
|
67
|
+
def on_call(self, *args, **kwargs) -> Any:
|
|
68
|
+
raise NotImplementedError(
|
|
69
|
+
"'on_call(self,*args,**kwargs) is an abstract method that must be implemented.")
|
|
70
|
+
|
|
71
|
+
def __call__(self, *args, **kwargs):
|
|
72
|
+
# pylint: disable=protected-access
|
|
73
|
+
if not self._inited:
|
|
74
|
+
self_inited = True
|
|
75
|
+
# to work with overloading
|
|
76
|
+
type(self).subscribable_init(self, *args, **kwargs)
|
|
77
|
+
# self.subscribable_init(*args, **kwargs)
|
|
78
|
+
return self
|
|
79
|
+
return self.on_call(self, *args, **kwargs)
|
|
80
|
+
|
|
81
|
+
def __str__(self) -> str:
|
|
82
|
+
return repr(self)
|
|
83
|
+
|
|
84
|
+
def __repr__(self) -> str:
|
|
85
|
+
return f"{name} {fallback_class.__repr__(self)}" # type:ignore
|
|
86
|
+
|
|
87
|
+
def get_params(self) -> tuple:
|
|
88
|
+
# pylint: disable=protected-access
|
|
89
|
+
return self._params
|
|
90
|
+
|
|
91
|
+
def __eq__(self, other: Any) -> bool:
|
|
92
|
+
if isoftype(other, cls): # type:ignore
|
|
93
|
+
return self.get_params() == other.get_params()
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
# pylint: disable=unused-argument
|
|
97
|
+
def __init_subclass__(subcls, **kwargs):
|
|
98
|
+
if hasattr(subcls, "__init__"):
|
|
99
|
+
curr_init = getattr(subcls, "__init__")
|
|
100
|
+
if curr_init is not __init__:
|
|
101
|
+
raise ValueError(
|
|
102
|
+
"Can't override '__init__', use 'subscribable_init(self,*args,**kwargs)' instead.")
|
|
103
|
+
|
|
104
|
+
for func, tup in [
|
|
105
|
+
(__class_getitem__, ["__class_getitem__", classmethod]),
|
|
106
|
+
(__instancecheck__, ["__instancecheck__", None]),
|
|
107
|
+
(subscribable_init, ["subscribable_init", abstractmethod]),
|
|
108
|
+
(__init__, ["__init__", None]),
|
|
109
|
+
(__call__, ["__call__", None]),
|
|
110
|
+
(__str__, ["__str__", None]),
|
|
111
|
+
(__repr__, ["__repr__", None]),
|
|
112
|
+
(__eq__, ["__eq__", None]),
|
|
113
|
+
(get_params, ["get_params", None]),
|
|
114
|
+
(__init_subclass__, ["__init_subclass__", classmethod])
|
|
115
|
+
]:
|
|
116
|
+
name, decorator = tup # type:ignore
|
|
117
|
+
if decorator is not None: # type:ignore
|
|
118
|
+
func = decorator(func) # type:ignore
|
|
119
|
+
setattr(cls, name, func)
|
|
120
|
+
|
|
121
|
+
return cls
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
__all__ = [
|
|
125
|
+
"create_typed_class"
|
|
126
|
+
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import Generic, TypeVar
|
|
2
|
+
from .factory import create_typed_class
|
|
3
|
+
from ...functions import isoftype
|
|
4
|
+
parent: type = create_typed_class("tdict", dict)
|
|
5
|
+
K = TypeVar("K")
|
|
6
|
+
V = TypeVar("V")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class tdict(parent, Generic[K, V]):
|
|
10
|
+
"""like 'dict' but with runtime type safety
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def subscribable_init(self, *args, **kwargs): # pylint: disable=unused-argument
|
|
14
|
+
"""the "real" __init__ function
|
|
15
|
+
"""
|
|
16
|
+
print(self.get_params())
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def _key_t(self):
|
|
20
|
+
return self.get_params()[0]
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def _value_t(self):
|
|
24
|
+
return self.get_params()[1]
|
|
25
|
+
|
|
26
|
+
def __setitem__(self, key: K, value: V):
|
|
27
|
+
if not isoftype(key, self._key_t): # type:ignore
|
|
28
|
+
raise TypeError("")
|
|
29
|
+
if not isoftype(value, self._value_t): # type:ignore
|
|
30
|
+
raise TypeError("")
|
|
31
|
+
dict.__setitem__(self, key, value)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"tdict"
|
|
36
|
+
]
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
from typing import Generic, TypeVar, Any, Union, Iterable, SupportsIndex
|
|
2
|
+
# from ...metaclasses.OverloadMeta import OverloadMeta
|
|
3
|
+
from ...functions import isoftype, types_subseteq
|
|
4
|
+
# from ...reflection import get_caller_name
|
|
5
|
+
from ...decorators import overload
|
|
6
|
+
from .factory import create_typed_class
|
|
7
|
+
T = TypeVar("T", bound=Any)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# class ptlist(List[T], Generic[T]):
|
|
11
|
+
# """like 'list' but with runtime type safety
|
|
12
|
+
# """
|
|
13
|
+
|
|
14
|
+
# @classmethod
|
|
15
|
+
# def __class_getitem__(cls, item: type):
|
|
16
|
+
# return cls(item)
|
|
17
|
+
|
|
18
|
+
# def __instancecheck__(self, instance: Any) -> bool:
|
|
19
|
+
# if isinstance(instance, ptlist):
|
|
20
|
+
# return types_subseteq(instance._params, self._params)
|
|
21
|
+
# return isoftype(instance, List[self._params]) # type: ignore
|
|
22
|
+
|
|
23
|
+
# def __init__(self, item) -> None:
|
|
24
|
+
# if not get_caller_name(0) == "__class_getitem__":
|
|
25
|
+
# raise ValueError(
|
|
26
|
+
# f"Can't instantiate {self.__class__.__name__} without a supplied type")
|
|
27
|
+
# list.__init__(self)
|
|
28
|
+
# self._params = item
|
|
29
|
+
|
|
30
|
+
# def __call__(self, *args, **kwargs):
|
|
31
|
+
# # to work with the overloading
|
|
32
|
+
# type(self)._additional_init(self, *args, **kwargs)
|
|
33
|
+
# return self
|
|
34
|
+
|
|
35
|
+
# @OverloadMeta.overload
|
|
36
|
+
# def _additional_init(self, lst: Union[list, "ptlist"]):
|
|
37
|
+
# self.extend(lst)
|
|
38
|
+
|
|
39
|
+
# @_additional_init.overload
|
|
40
|
+
# def _init_empty(self) -> None:
|
|
41
|
+
# """inits an empty tlist
|
|
42
|
+
# """
|
|
43
|
+
|
|
44
|
+
# @_additional_init.overload
|
|
45
|
+
# def _init_from_set_and_dict(self, obj: Union[set, dict]):
|
|
46
|
+
# """inits the tlist from a set or a dict object
|
|
47
|
+
# Args:
|
|
48
|
+
# obj (set | dict): the set or dict instance
|
|
49
|
+
# """
|
|
50
|
+
# self.extend(list(obj))
|
|
51
|
+
|
|
52
|
+
# def extend(self, other: Iterable) -> None:
|
|
53
|
+
# """extends a tlist from a list or a tlist
|
|
54
|
+
|
|
55
|
+
# Args:
|
|
56
|
+
# other (list | tlist): the list to extend from
|
|
57
|
+
|
|
58
|
+
# Returns:
|
|
59
|
+
# tlist: Self
|
|
60
|
+
# """
|
|
61
|
+
# if isinstance(other, ptlist):
|
|
62
|
+
# if types_subseteq(other._params, self._params):
|
|
63
|
+
# list.extend(self, other)
|
|
64
|
+
# return
|
|
65
|
+
# for value in other:
|
|
66
|
+
# self.append(value)
|
|
67
|
+
|
|
68
|
+
# def append(self, value: T) -> None:
|
|
69
|
+
# """appends a value to the list
|
|
70
|
+
|
|
71
|
+
# Args:
|
|
72
|
+
# value (T): the value to append
|
|
73
|
+
|
|
74
|
+
# Raises:
|
|
75
|
+
# ValueError: if a value is not of the correct type
|
|
76
|
+
|
|
77
|
+
# Returns:
|
|
78
|
+
# tlist: self
|
|
79
|
+
# """
|
|
80
|
+
# if not isoftype(value, self._params):
|
|
81
|
+
# raise TypeError(
|
|
82
|
+
# f"In tlist.append: values must be of type {self._params}, but '{value}' is of type {type(value)}")
|
|
83
|
+
# list.append(self, value)
|
|
84
|
+
|
|
85
|
+
# def __str__(self) -> str:
|
|
86
|
+
# return "tlist "+list.__str__(self)
|
|
87
|
+
|
|
88
|
+
# def __repr__(self) -> str:
|
|
89
|
+
# return "tlist "+list.__repr__(self)
|
|
90
|
+
|
|
91
|
+
# def __setitem__(self, index: SupportsIndex, value: T): # type:ignore
|
|
92
|
+
# if not isoftype(value, self._params):
|
|
93
|
+
# raise TypeError(
|
|
94
|
+
# "Can't add value to tlist because it is of the wrong type")
|
|
95
|
+
# list.__setitem__(self, index, value)
|
|
96
|
+
|
|
97
|
+
# def __eq__(self, other: Any) -> bool:
|
|
98
|
+
# if not isoftype(other, Union[ptlist, list]):
|
|
99
|
+
# return list.__eq__(self, other)
|
|
100
|
+
# if isinstance(other, ptlist):
|
|
101
|
+
# if self._params != other._params:
|
|
102
|
+
# return False
|
|
103
|
+
# if len(self) != len(other):
|
|
104
|
+
# return False
|
|
105
|
+
# for a, b in zip(iter(self), iter(other)):
|
|
106
|
+
# if a != b:
|
|
107
|
+
# return False
|
|
108
|
+
# return True
|
|
109
|
+
|
|
110
|
+
# def __add__(self, other: Any) -> "ptlist":
|
|
111
|
+
# if not isoftype(other, Union[ptlist, list]):
|
|
112
|
+
# raise NotImplementedError()
|
|
113
|
+
|
|
114
|
+
# # no need to check because the error handling
|
|
115
|
+
# # will be done inside extend so the error will
|
|
116
|
+
# # propagate up
|
|
117
|
+
# res = ptlist[self._params](self) # type:ignore
|
|
118
|
+
# res.extend(other)
|
|
119
|
+
# return res
|
|
120
|
+
|
|
121
|
+
# def __mul__(self, other: Any) -> "ptlist":
|
|
122
|
+
# if not isinstance(other, int):
|
|
123
|
+
# raise NotImplementedError()
|
|
124
|
+
|
|
125
|
+
# res = ptlist[self._params](self) # type:ignore
|
|
126
|
+
# for _ in range(other-1):
|
|
127
|
+
# res.extend(self)
|
|
128
|
+
# return res
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
parent: type = create_typed_class("tlist", list)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class tlist(parent, Generic[T]):
|
|
135
|
+
"""like 'list' but with runtime type safety
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
def subscribable_init(self, *args, **kwargs):
|
|
139
|
+
"""the "real" __init__ function
|
|
140
|
+
"""
|
|
141
|
+
type(self)._additional_init(self, *args, **kwargs)
|
|
142
|
+
|
|
143
|
+
@overload # type:ignore
|
|
144
|
+
def _additional_init(self, lst: Union[list, "tlist"]):
|
|
145
|
+
self.extend(lst)
|
|
146
|
+
|
|
147
|
+
@_additional_init.overload
|
|
148
|
+
def _init_empty(self) -> None:
|
|
149
|
+
"""inits an empty tlist
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
@_additional_init.overload
|
|
153
|
+
def _init_from_set_and_dict(self, obj: Union[set, dict]):
|
|
154
|
+
"""inits the tlist from a set or a dict object
|
|
155
|
+
Args:
|
|
156
|
+
obj (set | dict): the set or dict instance
|
|
157
|
+
"""
|
|
158
|
+
self.extend(list(obj))
|
|
159
|
+
|
|
160
|
+
def extend(self, other: Iterable) -> None:
|
|
161
|
+
"""extends a tlist from a list or a tlist
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
other (list | tlist): the list to extend from
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
tlist: Self
|
|
168
|
+
"""
|
|
169
|
+
if isinstance(other, tlist):
|
|
170
|
+
if types_subseteq(other.get_params(), self.get_params()):
|
|
171
|
+
list.extend(self, other)
|
|
172
|
+
return
|
|
173
|
+
for value in other:
|
|
174
|
+
self.append(value)
|
|
175
|
+
|
|
176
|
+
def append(self, value: T) -> None:
|
|
177
|
+
"""appends a value to the list
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
value (T): the value to append
|
|
181
|
+
|
|
182
|
+
Raises:
|
|
183
|
+
ValueError: if a value is not of the correct type
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
tlist: self
|
|
187
|
+
"""
|
|
188
|
+
if not isoftype(value, self.get_params()[0]):
|
|
189
|
+
raise TypeError(
|
|
190
|
+
f"In tlist.append: values must be of type {self.get_params()[0]},"
|
|
191
|
+
" but '{value}' is of type {type(value)}")
|
|
192
|
+
list.append(self, value)
|
|
193
|
+
|
|
194
|
+
def __add__(self, other: Any) -> "tlist":
|
|
195
|
+
if not isoftype(other, Union[list, tlist]):
|
|
196
|
+
raise NotImplementedError()
|
|
197
|
+
|
|
198
|
+
# no need to check because the error handling
|
|
199
|
+
# will be done inside extend so the error will
|
|
200
|
+
# propagate up
|
|
201
|
+
res = tlist[self._params](self) # type:ignore
|
|
202
|
+
res.extend(other)
|
|
203
|
+
return res
|
|
204
|
+
|
|
205
|
+
def __mul__(self, other: Any) -> "tlist":
|
|
206
|
+
if not isinstance(other, int):
|
|
207
|
+
raise NotImplementedError()
|
|
208
|
+
|
|
209
|
+
res = tlist[self.get_params()[0]](self) # type:ignore
|
|
210
|
+
for _ in range(other-1):
|
|
211
|
+
res.extend(self)
|
|
212
|
+
return res
|
|
213
|
+
|
|
214
|
+
def __setitem__(self, index: SupportsIndex, value: T): # type:ignore
|
|
215
|
+
if not isoftype(value, self._params):
|
|
216
|
+
raise TypeError(
|
|
217
|
+
"Can't add value to tlist because it is of the wrong type")
|
|
218
|
+
list.__setitem__(self, index, value)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
__all__ = [
|
|
222
|
+
"tlist"
|
|
223
|
+
]
|