danielutils 0.9.71__tar.gz → 0.9.73__tar.gz
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-0.9.71 → danielutils-0.9.73}/PKG-INFO +2 -2
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/__init__.py +28 -14
- danielutils-0.9.73/danielutils/classes/frange.py +226 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/repl.py +8 -5
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/typed_builtins/factory.py +2 -2
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/colors.py +7 -7
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/data_structures/Comparer.py +1 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/data_structures/Stack.py +18 -7
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/data_structures/__init__.py +2 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/data_structures/default_dict.py +4 -5
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/__init__.py +2 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/attach.py +0 -1
- danielutils-0.9.73/danielutils/decorators/decorate_conditionally.py +32 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/delay_call.py +0 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/deprecate.py +0 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/limit_recursion.py +0 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/memo.py +3 -3
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/overload.py +31 -19
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/partially_implemented.py +0 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/processify.py +3 -3
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/threadify.py +0 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/timeout.py +10 -2
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/validate.py +0 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/files_and_folders.py +7 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/generators/join_generators.py +2 -1
- danielutils-0.9.73/danielutils/multi_x.py +26 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/my_tqdm.py +17 -5
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/reflection/__init__.py +2 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/reflection/class_reflection.py +19 -4
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/reflection/file_reflection.py +4 -3
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/reflection/function_reflections.py +52 -66
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/reflection/get_traceback.py +1 -1
- danielutils-0.9.73/danielutils/reflection/system_reflections.py +33 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/system/windows/utils/filetime.py +2 -1
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/threads/worker.py +3 -5
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/threads/worker_pool.py +7 -3
- danielutils-0.9.73/danielutils/university/__init__.py +3 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils.egg-info/PKG-INFO +2 -2
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils.egg-info/SOURCES.txt +4 -4
- {danielutils-0.9.71 → danielutils-0.9.73}/pyproject.toml +4 -4
- danielutils-0.9.71/danielutils/classes/frange.py +0 -61
- danielutils-0.9.71/danielutils/decorators/decorate_conditionally.py +0 -33
- danielutils-0.9.71/danielutils/multi_x.py +0 -16
- danielutils-0.9.71/danielutils/reflection/get_prev_frame.py +0 -30
- danielutils-0.9.71/danielutils/reflection/system_reflections.py +0 -55
- danielutils-0.9.71/danielutils/university/__init__.py +0 -1
- danielutils-0.9.71/danielutils.egg-info/requires.txt +0 -1
- /danielutils-0.9.71/LISENCE → /danielutils-0.9.73/LICENSE +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/README.md +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/aliases.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/Convenience.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/Counter.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/Tree.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/sorted_builtins/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/sorted_builtins/sset.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/typed_builtins/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/typed_builtins/tdict.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/typed_builtins/tlist.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/typed_builtins/tset.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/classes/typed_builtins/ttuple.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/conversions/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/conversions/main_conversions.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/conversions/specialized_conversions/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/conversions/specialized_conversions/to_hex.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/conversions/specialized_conversions/to_int.py +0 -0
- /danielutils-0.9.71/danielutils/print.py → /danielutils-0.9.73/danielutils/d_print.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/data_structures/functions.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/date.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/date_time.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/atomic.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/chain_decorators.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/decorators/property.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/exceptions.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/functions/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/functions/areoneof.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/functions/check_foreach.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/functions/isoftype.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/functions/isoneof.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/functions/powerset.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/functions/types_subseteq.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/generators/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/generators/conditional_generator.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/generators/generator_from_stream.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/internet.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/loops.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/math/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/math/constants.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/math/functions.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/math/math_print.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/math/math_symbols.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/metaclasses/Interface.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/metaclasses/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/metaclasses/atomic_class_meta.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/metaclasses/implicit_data_deleter_meta.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/metaclasses/instance_cache_meta.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/metaclasses/overload_meta.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/path.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/py.typed +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/reflection/module_reflections.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/relations.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/signals.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/snippets/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/snippets/try_get.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/system/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/system/independent.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/system/windows/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/system/windows/utils/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/system/windows/win32_ctime.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/system/windows/windows.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/text.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/threads/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/time.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/university/databases/__init__.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils/university/databases/all.py +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils.egg-info/dependency_links.txt +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/danielutils.egg-info/top_level.txt +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/setup.cfg +0 -0
- {danielutils-0.9.71 → danielutils-0.9.73}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: danielutils
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.73
|
|
4
4
|
Summary: A python utils library for things I find useful
|
|
5
5
|
Author-email: danielnachumdev <danielnachumdev@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -33,7 +33,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
33
33
|
Classifier: Operating System :: Microsoft :: Windows
|
|
34
34
|
Requires-Python: >=3.8.0
|
|
35
35
|
Description-Content-Type: text/markdown
|
|
36
|
-
|
|
36
|
+
License-File: LICENSE
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
[](https://github.com/danielnachumdev/danielutils/actions/workflows/python-package.yml)
|
|
@@ -1,32 +1,46 @@
|
|
|
1
1
|
"""danielutils is a convenience library of functions decorators
|
|
2
2
|
data-structures and more that make my development workflow faster
|
|
3
3
|
"""
|
|
4
|
-
|
|
4
|
+
# =================================================================
|
|
5
|
+
# ============================= LEAFS =============================
|
|
6
|
+
# =================================================================
|
|
7
|
+
from .path import *
|
|
8
|
+
from .date_time import *
|
|
9
|
+
from .multi_x import *
|
|
10
|
+
from .loops import *
|
|
11
|
+
from .signals import *
|
|
12
|
+
from .aliases import *
|
|
13
|
+
from .exceptions import PrintCatchOne
|
|
14
|
+
from .snippets import *
|
|
15
|
+
from .abstractions import *
|
|
16
|
+
from .imports import *
|
|
17
|
+
# =================================================================
|
|
18
|
+
# ========================= ORDER MATTERS =========================
|
|
19
|
+
# =================================================================
|
|
20
|
+
|
|
21
|
+
from .reflection import *
|
|
5
22
|
from .decorators import *
|
|
23
|
+
|
|
24
|
+
# ========== NEEDS REFLECTION ==========
|
|
25
|
+
from .threads import *
|
|
26
|
+
from .my_tqdm import *
|
|
27
|
+
# ========== NEEDS DECORATORS ==========
|
|
28
|
+
from .colors import *
|
|
29
|
+
# ========== NEEDS BOTH ==========
|
|
30
|
+
|
|
31
|
+
from .functions import *
|
|
6
32
|
from .files_and_folders import *
|
|
7
33
|
from .system import *
|
|
8
34
|
from .text import *
|
|
9
35
|
from .conversions import *
|
|
10
36
|
from .classes import *
|
|
11
37
|
from .time import *
|
|
12
|
-
from .colors import *
|
|
13
38
|
from .date import *
|
|
14
39
|
from .data_structures import *
|
|
15
40
|
from .math import *
|
|
16
|
-
from .path import *
|
|
17
41
|
from .system import *
|
|
18
|
-
from .
|
|
19
|
-
from .exceptions import PrintCatchOne
|
|
20
|
-
from .reflection import *
|
|
42
|
+
from .d_print import *
|
|
21
43
|
from .metaclasses import *
|
|
22
|
-
from .date_time import *
|
|
23
44
|
from .generators import *
|
|
24
|
-
from .snippets import *
|
|
25
|
-
from .aliases import *
|
|
26
|
-
from .signals import *
|
|
27
45
|
from .university import *
|
|
28
|
-
from .my_tqdm import *
|
|
29
|
-
from .threads import *
|
|
30
|
-
from .loops import *
|
|
31
|
-
from .multi_x import *
|
|
32
46
|
from .package_utils import *
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import decimal
|
|
3
|
+
from typing import Callable, Optional, Iterator, Sequence, overload, Union
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class frange(Sequence[float]):
|
|
7
|
+
"""This class is the same like the builtin range but with float values
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def from_range(r: range) -> 'frange':
|
|
12
|
+
"""will "downcast" `range` to `frange` correctly"""
|
|
13
|
+
return frange(r.start, r.stop, r.step)
|
|
14
|
+
|
|
15
|
+
def __init__(self, start: float, stop: Optional[float] = None,
|
|
16
|
+
step: float = 1, round_method: Callable[[float], float] = lambda f: round(f, 3)):
|
|
17
|
+
if stop is None:
|
|
18
|
+
stop = start
|
|
19
|
+
start = 0
|
|
20
|
+
self.start = start
|
|
21
|
+
self.stop = stop
|
|
22
|
+
self.step = step
|
|
23
|
+
self.method = round_method
|
|
24
|
+
self._is_finite = len(self) != float("inf")
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def is_finite(self) -> bool:
|
|
28
|
+
"""
|
|
29
|
+
Returns `True` if the range is finite
|
|
30
|
+
inverse if `is_infinite`
|
|
31
|
+
Returns:
|
|
32
|
+
bool
|
|
33
|
+
"""
|
|
34
|
+
return self._is_finite
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def is_infinite(self) -> bool:
|
|
38
|
+
"""
|
|
39
|
+
Returns `True` if the range is infinite
|
|
40
|
+
inverse if `is_finite`
|
|
41
|
+
Returns:
|
|
42
|
+
bool
|
|
43
|
+
"""
|
|
44
|
+
return not self.is_finite
|
|
45
|
+
|
|
46
|
+
@overload
|
|
47
|
+
def __getitem__(self, index: int) -> float:
|
|
48
|
+
...
|
|
49
|
+
|
|
50
|
+
@overload
|
|
51
|
+
def __getitem__(self, index: slice) -> 'frange':
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
def __getitem__(self, index: Union[float, slice]) -> Union[float, 'frange']:
|
|
55
|
+
if isinstance(index, slice):
|
|
56
|
+
index = slice(
|
|
57
|
+
index.start if index.start is not None else 0,
|
|
58
|
+
index.stop if index.stop is not None else len(self),
|
|
59
|
+
index.step if index.step is not None else 1,
|
|
60
|
+
)
|
|
61
|
+
if index.step > 0:
|
|
62
|
+
step = self.step * index.step
|
|
63
|
+
start = self.start + step * index.start
|
|
64
|
+
stop = self.start + step * index.stop
|
|
65
|
+
return frange(start, stop, step)
|
|
66
|
+
s = slice(index.start, index.stop, abs(index.step))
|
|
67
|
+
return reversed(self[s])
|
|
68
|
+
if index < 0:
|
|
69
|
+
raise ValueError(f"At {self.__class__.__qualname__}.__getitem__ 'index' must be a positive integer")
|
|
70
|
+
return self.start + self.step * index
|
|
71
|
+
|
|
72
|
+
def __reversed__(self) -> 'frange':
|
|
73
|
+
return frange(self.stop - 1, self.start - 1, -self.step)
|
|
74
|
+
|
|
75
|
+
def __eq__(self, other):
|
|
76
|
+
if not isinstance(other, frange):
|
|
77
|
+
raise NotImplementedError
|
|
78
|
+
return self.start == other.start and self.stop == other.stop and self.step == other.step
|
|
79
|
+
|
|
80
|
+
def __iter__(self) -> Iterator[float]:
|
|
81
|
+
if self.stop < self.start:
|
|
82
|
+
return
|
|
83
|
+
if self.start > self.stop:
|
|
84
|
+
return
|
|
85
|
+
if abs(self.stop - self.start) < abs(self.step):
|
|
86
|
+
return
|
|
87
|
+
if self.stop > 0 and self.step < 0:
|
|
88
|
+
return
|
|
89
|
+
if self.stop < 0 and self.step > 0:
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
cur = self.start
|
|
93
|
+
while cur < self.stop:
|
|
94
|
+
yield self.method(cur)
|
|
95
|
+
cur += self.step
|
|
96
|
+
|
|
97
|
+
def __len__(self) -> int:
|
|
98
|
+
if self.stop in {float("inf"), -float("inf")}:
|
|
99
|
+
return float("inf")
|
|
100
|
+
return int((self.stop - self.start) // self.step)
|
|
101
|
+
|
|
102
|
+
def __str__(self) -> str:
|
|
103
|
+
return repr(self)
|
|
104
|
+
|
|
105
|
+
def __repr__(self):
|
|
106
|
+
return f"{self.__class__.__name__}({self.start}, {self.stop}, {self.step})"
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def _is_int(n: Union[int, float]) -> bool:
|
|
110
|
+
if isinstance(n, int):
|
|
111
|
+
return True
|
|
112
|
+
|
|
113
|
+
return n.is_integer()
|
|
114
|
+
|
|
115
|
+
def __contains__(self, item):
|
|
116
|
+
if item < self.start:
|
|
117
|
+
return False
|
|
118
|
+
if item >= self.stop:
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
if frange._is_int(self.step):
|
|
122
|
+
if not frange._is_int(item):
|
|
123
|
+
return False
|
|
124
|
+
|
|
125
|
+
return item / self.step - item // self.step == 0
|
|
126
|
+
|
|
127
|
+
def normalize(self) -> 'frange':
|
|
128
|
+
"""
|
|
129
|
+
will normalize the `frange` object
|
|
130
|
+
Returns:
|
|
131
|
+
frange
|
|
132
|
+
"""
|
|
133
|
+
return frange(self.start / self.step, self.stop / self.step, 1)
|
|
134
|
+
|
|
135
|
+
# def _normalize_with(self, other: 'frange') -> 'frange':
|
|
136
|
+
# return frange(self.start / (self.step * other.step), self.stop / (self.step * other.step), 1)
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def _lcm_float(a: float, b: float) -> float:
|
|
140
|
+
prec = min(5, max(decimal.getcontext().prec, 10))
|
|
141
|
+
a = round(a, prec)
|
|
142
|
+
b = round(b, prec)
|
|
143
|
+
return math.lcm(int(a * 10 ** prec), int(b * 10 ** prec)) / 10 ** prec
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def _find_min_step(s1: float, s2: float) -> float:
|
|
147
|
+
"""
|
|
148
|
+
returns the minimum LCM for two step values
|
|
149
|
+
Args:
|
|
150
|
+
s1 (float): first step value:
|
|
151
|
+
s2 (float): second step value:
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
float: minimum LCM
|
|
155
|
+
"""
|
|
156
|
+
M = max(s1, s2)
|
|
157
|
+
m = min(s1, s2)
|
|
158
|
+
if float.is_integer(M / m):
|
|
159
|
+
return M
|
|
160
|
+
return frange._lcm_float(s1, s2)
|
|
161
|
+
|
|
162
|
+
def intersect(self, other: 'frange') -> 'frange':
|
|
163
|
+
if not isinstance(other, frange):
|
|
164
|
+
raise ValueError("frange.intercept only accepts frange objects")
|
|
165
|
+
a, b = self.normalize(), other.normalize()
|
|
166
|
+
start1, stop1 = a.start, a.stop
|
|
167
|
+
start2, stop2 = b.start, b.stop
|
|
168
|
+
remainder1, remainder2 = start1 - int(start1), start2 - int(start2)
|
|
169
|
+
start = max(self.start, other.start)
|
|
170
|
+
stop = min(self.stop, other.stop)
|
|
171
|
+
if remainder1 == remainder2:
|
|
172
|
+
min_step = self._find_min_step(self.step, other.step)
|
|
173
|
+
if stop1 == float("inf") or stop2 == float("inf"):
|
|
174
|
+
return frange(start, float("inf"), min_step)
|
|
175
|
+
return frange(start, stop, min_step)
|
|
176
|
+
# find k; start1 + remainder1*k == start2 +remainder2*k
|
|
177
|
+
k = (start1 - start2) / (remainder2 - remainder1)
|
|
178
|
+
if k <= 0:
|
|
179
|
+
return frange(0)
|
|
180
|
+
if stop1 == float("inf") or stop2 == float("inf"):
|
|
181
|
+
raise NotImplementedError("this part is not implemented yet. one has inf")
|
|
182
|
+
raise NotImplementedError("this part is not implemented yet")
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class frange_iterator(Iterator[float]):
|
|
186
|
+
def __init__(self, obj: frange):
|
|
187
|
+
self.r = obj
|
|
188
|
+
|
|
189
|
+
def __next__(self):
|
|
190
|
+
if self.r.stop < self.r.start:
|
|
191
|
+
return
|
|
192
|
+
if self.r.start > self.r.stop:
|
|
193
|
+
return
|
|
194
|
+
if abs(self.r.stop - self.r.start) < abs(self.r.step):
|
|
195
|
+
return
|
|
196
|
+
if self.r.stop > 0 and self.r.step < 0:
|
|
197
|
+
return
|
|
198
|
+
if self.r.stop < 0 and self.r.step > 0:
|
|
199
|
+
return
|
|
200
|
+
|
|
201
|
+
cur = self.r.start
|
|
202
|
+
while cur < self.r.stop:
|
|
203
|
+
yield self.r.method(cur)
|
|
204
|
+
cur += self.r.step
|
|
205
|
+
|
|
206
|
+
def __iter__(self):
|
|
207
|
+
return self
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class brange(frange):
|
|
211
|
+
"""like frange but with tqdm
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
def __iter__(self):
|
|
215
|
+
itr = super().__iter__()
|
|
216
|
+
try:
|
|
217
|
+
from my_tqdm import tqdm # type:ignore # pylint: disable=import-error
|
|
218
|
+
return iter(tqdm(itr, desc=f"{self}", total=len(self)))
|
|
219
|
+
except:
|
|
220
|
+
return itr
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
__all__ = [
|
|
224
|
+
"frange",
|
|
225
|
+
"brange"
|
|
226
|
+
]
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import copy
|
|
1
2
|
from typing import Any, Callable, Union, Tuple as t_tuple, List as t_list, Dict as t_dict
|
|
2
3
|
import re
|
|
3
|
-
from ..reflection import get_python_version
|
|
4
|
+
from ..reflection import get_python_version # pylint :disable=relative-beyond-top-level
|
|
5
|
+
|
|
4
6
|
if get_python_version() >= (3, 9):
|
|
5
7
|
from builtins import tuple as t_tuple, list as t_list, dict as t_dict # type:ignore
|
|
6
8
|
|
|
@@ -39,9 +41,10 @@ class REPL:
|
|
|
39
41
|
"""a class to easily create a shell application and get functionality for free
|
|
40
42
|
"""
|
|
41
43
|
|
|
44
|
+
# pylint: disable=dangerous-default-value
|
|
42
45
|
def __init__(self, routes: t_list[Command], *, prompt_symbol: str = ">>> ", exit_keywords: set = {"exit", "quit"}):
|
|
43
46
|
self.prompt_symbol = prompt_symbol
|
|
44
|
-
self.exit_keywords = exit_keywords
|
|
47
|
+
self.exit_keywords = copy.copy(exit_keywords)
|
|
45
48
|
self.routes: t_dict[str, Command] = {
|
|
46
49
|
com.command.name: com for com in routes}
|
|
47
50
|
|
|
@@ -58,7 +61,7 @@ class REPL:
|
|
|
58
61
|
|
|
59
62
|
if prompt == "help":
|
|
60
63
|
print("Available commands:")
|
|
61
|
-
for com in list(self.routes.keys())+list(self.exit_keywords):
|
|
64
|
+
for com in list(self.routes.keys()) + list(self.exit_keywords):
|
|
62
65
|
print(f"\t{com}")
|
|
63
66
|
continue
|
|
64
67
|
|
|
@@ -70,9 +73,9 @@ class REPL:
|
|
|
70
73
|
except TypeError as e:
|
|
71
74
|
msg = str(e)
|
|
72
75
|
if re.match(r".*missing.*required.*argument.*", msg):
|
|
73
|
-
print(f"'{command}' "+msg[msg.find("missing"):])
|
|
76
|
+
print(f"'{command}' " + msg[msg.find("missing"):])
|
|
74
77
|
elif re.match(r".*takes.*arguments but.*given", msg):
|
|
75
|
-
print(f"'{command}' "+msg[msg.find("takes"):])
|
|
78
|
+
print(f"'{command}' " + msg[msg.find("takes"):])
|
|
76
79
|
else:
|
|
77
80
|
raise e
|
|
78
81
|
|
|
@@ -3,6 +3,7 @@ from abc import abstractmethod
|
|
|
3
3
|
from typing import Any, Iterable, List as t_list, Set as t_set, Dict as t_dict, Tuple as t_tuple
|
|
4
4
|
from ...functions import types_subseteq, isoftype
|
|
5
5
|
from ...reflection import get_caller_name, get_python_version
|
|
6
|
+
|
|
6
7
|
if get_python_version() >= (3, 9):
|
|
7
8
|
from builtins import list as t_list, set as t_set, dict as t_dict, tuple as t_tuple # type:ignore
|
|
8
9
|
# needed for python 3.8
|
|
@@ -39,7 +40,6 @@ def create_typed_class(name: str, fallback_class: type = object) -> type:
|
|
|
39
40
|
|
|
40
41
|
def __instancecheck__(self, instance: Any) -> bool:
|
|
41
42
|
if isinstance(instance, cls):
|
|
42
|
-
|
|
43
43
|
return types_subseteq(
|
|
44
44
|
instance.get_params(), # type:ignore
|
|
45
45
|
self.get_params()
|
|
@@ -51,7 +51,7 @@ def create_typed_class(name: str, fallback_class: type = object) -> type:
|
|
|
51
51
|
)
|
|
52
52
|
|
|
53
53
|
def __init__(self, item) -> None:
|
|
54
|
-
if not get_caller_name(
|
|
54
|
+
if not get_caller_name(1) == "__class_getitem__":
|
|
55
55
|
raise ValueError(
|
|
56
56
|
f"Can't instantiate {self.__class__.__name__} without a supplied type")
|
|
57
57
|
fallback_class.__init__(self) # type: ignore
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from typing import Optional, IO
|
|
2
|
-
from .decorators
|
|
3
|
-
|
|
2
|
+
from .decorators import validate
|
|
4
3
|
|
|
5
4
|
RESET = "\033[0m"
|
|
6
5
|
|
|
@@ -16,15 +15,16 @@ class ColoredText:
|
|
|
16
15
|
white,
|
|
17
16
|
black
|
|
18
17
|
"""
|
|
19
|
-
|
|
18
|
+
|
|
19
|
+
@staticmethod # type:ignore
|
|
20
20
|
@validate
|
|
21
21
|
def from_rgb(red: int, green: int, blue: int, text: str) -> str:
|
|
22
22
|
"""Applies an RGB color to the given text.
|
|
23
23
|
|
|
24
24
|
Args:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
red (int): The red component of the color.
|
|
26
|
+
green (int): The green component of the color.
|
|
27
|
+
blue (int): The blue component of the color.
|
|
28
28
|
text (str): The text to apply the color to.
|
|
29
29
|
|
|
30
30
|
Returns:
|
|
@@ -178,7 +178,7 @@ def error(*args, sep: str = " ", end: str = "\n"):
|
|
|
178
178
|
|
|
179
179
|
|
|
180
180
|
def info(*args, sep: str = " ", end: str = "\n"):
|
|
181
|
-
"""print an
|
|
181
|
+
"""print an info message
|
|
182
182
|
|
|
183
183
|
Args:
|
|
184
184
|
sep (str, optional): print separator. Defaults to " ".
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Optional, Generator,
|
|
1
|
+
from typing import Optional, Generator, TypeVar, Generic
|
|
2
2
|
from .graph import Node
|
|
3
3
|
|
|
4
4
|
T = TypeVar('T')
|
|
@@ -12,7 +12,7 @@ class Stack(Generic[T]):
|
|
|
12
12
|
self.head: Optional[Node[T]] = None
|
|
13
13
|
self.size = 0
|
|
14
14
|
|
|
15
|
-
def push(self, value:
|
|
15
|
+
def push(self, value: T):
|
|
16
16
|
"""push an item to the stack
|
|
17
17
|
|
|
18
18
|
Args:
|
|
@@ -25,23 +25,33 @@ class Stack(Generic[T]):
|
|
|
25
25
|
self.head = new_head
|
|
26
26
|
self.size += 1
|
|
27
27
|
|
|
28
|
-
def pop(self) ->
|
|
28
|
+
def pop(self) -> T:
|
|
29
29
|
"""pop an item from the stack
|
|
30
30
|
|
|
31
31
|
Returns:
|
|
32
32
|
Any: poped item
|
|
33
33
|
"""
|
|
34
34
|
if not self.is_empty():
|
|
35
|
-
|
|
36
|
-
res = self.head.data
|
|
35
|
+
res = self.head.data # type:ignore
|
|
37
36
|
self.size -= 1
|
|
38
|
-
self.head = self.head.next
|
|
37
|
+
self.head = self.head.next # type:ignore
|
|
39
38
|
return res
|
|
39
|
+
raise RuntimeError("Can't pop from an empty stack")
|
|
40
|
+
|
|
41
|
+
def peek(self) -> Optional[T]:
|
|
42
|
+
"""
|
|
43
|
+
Returns the top element of the stack
|
|
44
|
+
Returns:
|
|
45
|
+
Optional[T]
|
|
46
|
+
"""
|
|
47
|
+
if self.is_empty():
|
|
48
|
+
return None
|
|
49
|
+
return self.head.data
|
|
40
50
|
|
|
41
51
|
def __len__(self) -> int:
|
|
42
52
|
return self.size
|
|
43
53
|
|
|
44
|
-
def __iter__(self) -> Generator[
|
|
54
|
+
def __iter__(self) -> Generator[T, None, None]:
|
|
45
55
|
while self:
|
|
46
56
|
yield self.pop()
|
|
47
57
|
|
|
@@ -58,6 +68,7 @@ class Stack(Generic[T]):
|
|
|
58
68
|
while curr is not None:
|
|
59
69
|
if curr.data == value:
|
|
60
70
|
return True
|
|
71
|
+
curr = curr.next
|
|
61
72
|
return False
|
|
62
73
|
|
|
63
74
|
def __str__(self) -> str:
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
from typing import Callable, Optional, Union
|
|
3
|
+
from .validate import validate
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@validate(strict=False)
|
|
7
|
+
def decorate_conditionally(decorator: Callable, predicate: Union[bool, Callable[[], bool]], *,
|
|
8
|
+
decorator_args: Optional[list] = None, decorator_kwargs: Optional[dict] = None):
|
|
9
|
+
"""will decorate a function iff the predicate is True or returns True
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
decorator (Callable): the decorator to use
|
|
13
|
+
predicate (bool | Callable[[], bool]): the predicate
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def deco(func):
|
|
17
|
+
if (predicate() if callable(predicate) else predicate):
|
|
18
|
+
nonlocal decorator_args, decorator_kwargs, decorator
|
|
19
|
+
if decorator_args is None:
|
|
20
|
+
decorator_args = []
|
|
21
|
+
if decorator_kwargs is None:
|
|
22
|
+
decorator_kwargs = {}
|
|
23
|
+
decorator = functools.wraps(func)(decorator)
|
|
24
|
+
return decorator(*decorator_args, **decorator_kwargs)(func)
|
|
25
|
+
return func
|
|
26
|
+
|
|
27
|
+
return deco
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"decorate_conditionally"
|
|
32
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from typing import Callable, Any, TypeVar, Dict as t_dict
|
|
2
1
|
import functools
|
|
3
|
-
import
|
|
2
|
+
from typing import Callable, Any, TypeVar, Dict as t_dict
|
|
3
|
+
from copy import deepcopy
|
|
4
4
|
from .validate import validate
|
|
5
5
|
|
|
6
6
|
from ..reflection import get_python_version
|
|
@@ -27,7 +27,7 @@ def memo(func: FuncT) -> FuncT:
|
|
|
27
27
|
def wrapper(*args, **kwargs):
|
|
28
28
|
if (args, *kwargs.items()) not in cache:
|
|
29
29
|
cache[(args, *kwargs.items())] = func(*args, **kwargs)
|
|
30
|
-
return cache[(args, *kwargs.items())]
|
|
30
|
+
return deepcopy(cache[(args, *kwargs.items())])
|
|
31
31
|
return wrapper
|
|
32
32
|
|
|
33
33
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from typing import Callable, cast, Any, TypeVar, Dict as t_dict, List as t_list
|
|
2
2
|
import inspect
|
|
3
|
-
import platform
|
|
4
3
|
import functools
|
|
5
4
|
from ..reflection import is_function_annotated_properly
|
|
6
5
|
from ..functions import isoftype, isoneof, isoneof_strict
|
|
7
6
|
from ..exceptions import OverloadDuplication, OverloadNotFound
|
|
8
7
|
from .deprecate import deprecate
|
|
9
8
|
from ..reflection import get_python_version
|
|
9
|
+
|
|
10
10
|
if get_python_version() < (3, 9):
|
|
11
11
|
from typing_extensions import ParamSpec
|
|
12
12
|
else:
|
|
@@ -79,7 +79,7 @@ def explicit_global_overload(*types) -> Callable:
|
|
|
79
79
|
|
|
80
80
|
__overload_dict[name][types] = func
|
|
81
81
|
|
|
82
|
-
@
|
|
82
|
+
@functools.wraps(func)
|
|
83
83
|
def wrapper(*args, **kwargs) -> Any:
|
|
84
84
|
default_func = None
|
|
85
85
|
# select correct overload
|
|
@@ -112,6 +112,7 @@ def explicit_global_overload(*types) -> Callable:
|
|
|
112
112
|
f"function {func.__module__}.{func.__qualname__} is not overloaded with {[type(v) for v in args]}")
|
|
113
113
|
|
|
114
114
|
return wrapper
|
|
115
|
+
|
|
115
116
|
return deco
|
|
116
117
|
|
|
117
118
|
|
|
@@ -160,31 +161,42 @@ class overload:
|
|
|
160
161
|
return self
|
|
161
162
|
|
|
162
163
|
def __call__(self, *args, **kwargs):
|
|
163
|
-
num_args = len(args)+len(kwargs.keys())
|
|
164
|
+
num_args = len(args) + len(kwargs.keys())
|
|
164
165
|
if num_args not in self._functions:
|
|
165
166
|
raise AttributeError(
|
|
166
167
|
f"No overload with {num_args} argument found for {self._moudle}.{self._qualname}")
|
|
167
|
-
selected_func = None
|
|
168
|
-
if len(self._functions[num_args]) == 1:
|
|
169
|
-
selected_func = self._functions[num_args][0]
|
|
170
|
-
else:
|
|
171
|
-
for func in self._functions[num_args]:
|
|
172
|
-
signature = inspect.signature(func)
|
|
173
|
-
for i, tup in enumerate(signature.parameters.items()):
|
|
174
|
-
param_name, param_type = tup
|
|
175
|
-
if param_name in overload.__SKIP_SET:
|
|
176
|
-
continue
|
|
177
168
|
|
|
178
|
-
|
|
179
|
-
|
|
169
|
+
if num_args == 0:
|
|
170
|
+
return self._functions[num_args][0](*args, **kwargs)
|
|
171
|
+
|
|
172
|
+
max_score = 0
|
|
173
|
+
winner = self._functions[num_args][0]
|
|
174
|
+
EXACT_MATCH = 1 / num_args
|
|
175
|
+
SUBCLASS = 1 / num_args
|
|
176
|
+
for func in self._functions[num_args]:
|
|
177
|
+
score = 0
|
|
178
|
+
signature = inspect.signature(func)
|
|
179
|
+
for i, tup in enumerate(signature.parameters.items()):
|
|
180
|
+
param_name, param_type = tup
|
|
181
|
+
if param_name in overload.__SKIP_SET:
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
if type(args[i]) == param_type.annotation: # pylint :disable=unidiomatic-typecheck
|
|
185
|
+
score += EXACT_MATCH
|
|
186
|
+
|
|
187
|
+
elif isoftype(args[i], param_type.annotation):
|
|
188
|
+
score += SUBCLASS
|
|
180
189
|
else:
|
|
181
|
-
# reaching here means current function matches perfectly the annotation
|
|
182
|
-
selected_func = func
|
|
183
190
|
break
|
|
191
|
+
|
|
184
192
|
else:
|
|
185
|
-
|
|
193
|
+
# reaching here means current function matches perfectly the annotation
|
|
194
|
+
if score > max_score:
|
|
195
|
+
max_score = score
|
|
196
|
+
winner = func
|
|
197
|
+
# raise AttributeError("No overload found")
|
|
186
198
|
|
|
187
|
-
return
|
|
199
|
+
return winner(*args, **kwargs)
|
|
188
200
|
|
|
189
201
|
|
|
190
202
|
__all__ = [
|