jetpytools 1.2.3__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.
Potentially problematic release.
This version of jetpytools might be problematic. Click here for more details.
- jetpytools/__init__.py +5 -0
- jetpytools/_metadata.py +12 -0
- jetpytools/enums/__init__.py +2 -0
- jetpytools/enums/base.py +78 -0
- jetpytools/enums/other.py +59 -0
- jetpytools/exceptions/__init__.py +5 -0
- jetpytools/exceptions/base.py +213 -0
- jetpytools/exceptions/enum.py +11 -0
- jetpytools/exceptions/file.py +38 -0
- jetpytools/exceptions/generic.py +45 -0
- jetpytools/exceptions/module.py +39 -0
- jetpytools/functions/__init__.py +3 -0
- jetpytools/functions/funcs.py +152 -0
- jetpytools/functions/normalize.py +254 -0
- jetpytools/functions/other.py +18 -0
- jetpytools/py.typed +0 -0
- jetpytools/types/__init__.py +6 -0
- jetpytools/types/builtins.py +77 -0
- jetpytools/types/file.py +193 -0
- jetpytools/types/funcs.py +109 -0
- jetpytools/types/generic.py +52 -0
- jetpytools/types/supports.py +127 -0
- jetpytools/types/utils.py +669 -0
- jetpytools/utils/__init__.py +4 -0
- jetpytools/utils/file.py +256 -0
- jetpytools/utils/funcs.py +35 -0
- jetpytools/utils/math.py +158 -0
- jetpytools/utils/ranges.py +89 -0
- jetpytools-1.2.3.dist-info/LICENSE +21 -0
- jetpytools-1.2.3.dist-info/METADATA +48 -0
- jetpytools-1.2.3.dist-info/RECORD +33 -0
- jetpytools-1.2.3.dist-info/WHEEL +5 -0
- jetpytools-1.2.3.dist-info/top_level.txt +1 -0
jetpytools/utils/file.py
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
import sys
|
|
5
|
+
from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper
|
|
6
|
+
from os import F_OK, R_OK, W_OK, X_OK, access, getenv, path
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import IO, Any, BinaryIO, Callable, Literal, overload
|
|
9
|
+
|
|
10
|
+
from ..exceptions import FileIsADirectoryError, FileNotExistsError, FilePermissionError, FileWasNotFoundError
|
|
11
|
+
from ..types import (
|
|
12
|
+
FileOpener, FilePathType, FuncExceptT, OpenBinaryMode, OpenBinaryModeReading, OpenBinaryModeUpdating,
|
|
13
|
+
OpenBinaryModeWriting, OpenTextMode, SPath
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
'add_script_path_hook',
|
|
18
|
+
'remove_script_path_hook',
|
|
19
|
+
|
|
20
|
+
'get_script_path',
|
|
21
|
+
|
|
22
|
+
'get_user_data_dir',
|
|
23
|
+
|
|
24
|
+
'check_perms',
|
|
25
|
+
'open_file'
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
_script_path_hooks = list[Callable[[], SPath | None]]()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def add_script_path_hook(hook: Callable[[], SPath | None]) -> None:
|
|
32
|
+
_script_path_hooks.append(hook)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def remove_script_path_hook(hook: Callable[[], SPath | None]) -> None:
|
|
36
|
+
_script_path_hooks.remove(hook)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_script_path() -> SPath:
|
|
40
|
+
for hook in reversed(_script_path_hooks):
|
|
41
|
+
if (script_path := hook()) is not None:
|
|
42
|
+
return script_path
|
|
43
|
+
|
|
44
|
+
import __main__
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
return SPath(__main__.__file__)
|
|
48
|
+
except AttributeError:
|
|
49
|
+
return SPath.cwd()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_user_data_dir() -> Path:
|
|
53
|
+
"""Get user data dir path."""
|
|
54
|
+
|
|
55
|
+
if sys.platform == 'win32':
|
|
56
|
+
buf = ctypes.create_unicode_buffer(1024)
|
|
57
|
+
ctypes.windll.shell32.SHGetFolderPathW(None, 28, None, 0, buf)
|
|
58
|
+
|
|
59
|
+
if any([ord(c) > 255 for c in buf]):
|
|
60
|
+
buf2 = ctypes.create_unicode_buffer(1024)
|
|
61
|
+
if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
|
|
62
|
+
buf = buf2
|
|
63
|
+
|
|
64
|
+
return Path(path.normpath(buf.value))
|
|
65
|
+
|
|
66
|
+
if sys.platform == 'darwin': # type: ignore[unreachable]
|
|
67
|
+
return Path(path.expanduser('~/Library/Application Support/'))
|
|
68
|
+
|
|
69
|
+
return Path(getenv('XDG_DATA_HOME', path.expanduser("~/.local/share")))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def check_perms(
|
|
73
|
+
file: FilePathType, mode: OpenTextMode | OpenBinaryMode, strict: bool = False,
|
|
74
|
+
*, func: FuncExceptT | None = None
|
|
75
|
+
) -> bool:
|
|
76
|
+
"""
|
|
77
|
+
Confirm whether the user has write/read access to a file.
|
|
78
|
+
|
|
79
|
+
:param file: Path to file.
|
|
80
|
+
:param mode: Read/Write mode.
|
|
81
|
+
:param func: Function that this was called from, only useful to *func writers.
|
|
82
|
+
|
|
83
|
+
:param: True if the user has write/read access, else False.
|
|
84
|
+
|
|
85
|
+
:raises FileNotExistsError: File could not be found.
|
|
86
|
+
:raises FilePermissionError: User does not have access to the file.
|
|
87
|
+
:raises FileIsADirectoryError: Given path is a directory, not a file.
|
|
88
|
+
:raises FileWasNotFoundError: Parent directories exist, but the given file could not be found.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
file = Path(str(file))
|
|
92
|
+
got_perms = False
|
|
93
|
+
|
|
94
|
+
mode_i = F_OK
|
|
95
|
+
|
|
96
|
+
if func is not None:
|
|
97
|
+
if not str(file):
|
|
98
|
+
raise FileNotExistsError(file, func)
|
|
99
|
+
|
|
100
|
+
for char in 'rbU':
|
|
101
|
+
mode_str = mode.replace(char, '')
|
|
102
|
+
|
|
103
|
+
if not mode_str:
|
|
104
|
+
mode_i = R_OK
|
|
105
|
+
elif 'x' in mode_str:
|
|
106
|
+
mode_i = X_OK
|
|
107
|
+
elif '+' in mode_str or 'w' in mode_str:
|
|
108
|
+
mode_i = W_OK
|
|
109
|
+
|
|
110
|
+
check_file = file
|
|
111
|
+
|
|
112
|
+
if not strict and mode_i != R_OK:
|
|
113
|
+
while not check_file.exists():
|
|
114
|
+
check_file = check_file.parent
|
|
115
|
+
|
|
116
|
+
if strict and file.is_dir():
|
|
117
|
+
raise FileIsADirectoryError(file, func)
|
|
118
|
+
|
|
119
|
+
got_perms = access(check_file, mode_i)
|
|
120
|
+
|
|
121
|
+
if func is not None:
|
|
122
|
+
if not got_perms:
|
|
123
|
+
if strict and not file.exists():
|
|
124
|
+
if file.parent.exists():
|
|
125
|
+
raise FileWasNotFoundError(file, func)
|
|
126
|
+
|
|
127
|
+
raise FileNotExistsError(file, func)
|
|
128
|
+
|
|
129
|
+
raise FilePermissionError(file, func)
|
|
130
|
+
|
|
131
|
+
return got_perms
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@overload
|
|
135
|
+
def open_file(
|
|
136
|
+
file: FilePathType, mode: OpenTextMode = 'r', buffering: int = ...,
|
|
137
|
+
encoding: str | None = None, errors: str | None = ..., newline: str | None = ...,
|
|
138
|
+
*, func: FuncExceptT | None = None
|
|
139
|
+
) -> TextIOWrapper:
|
|
140
|
+
...
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@overload
|
|
144
|
+
def open_file(
|
|
145
|
+
file: FilePathType, mode: OpenBinaryMode, buffering: Literal[0],
|
|
146
|
+
encoding: None = None, *, func: FuncExceptT | None = None
|
|
147
|
+
) -> FileIO:
|
|
148
|
+
...
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@overload
|
|
152
|
+
def open_file(
|
|
153
|
+
file: FilePathType, mode: OpenBinaryModeUpdating, buffering: Literal[-1, 1] = ...,
|
|
154
|
+
encoding: None = None, *, func: FuncExceptT | None = None
|
|
155
|
+
) -> BufferedRandom:
|
|
156
|
+
...
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@overload
|
|
160
|
+
def open_file(
|
|
161
|
+
file: FilePathType, mode: OpenBinaryModeWriting, buffering: Literal[-1, 1] = ...,
|
|
162
|
+
encoding: None = None, *, func: FuncExceptT | None = None
|
|
163
|
+
) -> BufferedWriter:
|
|
164
|
+
...
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@overload
|
|
168
|
+
def open_file(
|
|
169
|
+
file: FilePathType, mode: OpenBinaryModeReading, buffering: Literal[-1, 1] = ...,
|
|
170
|
+
encoding: None = None, *, func: FuncExceptT | None = None
|
|
171
|
+
) -> BufferedReader:
|
|
172
|
+
...
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@overload
|
|
176
|
+
def open_file(
|
|
177
|
+
file: FilePathType, mode: OpenBinaryMode, buffering: int = ...,
|
|
178
|
+
encoding: None = None, *, func: FuncExceptT | None = None
|
|
179
|
+
) -> BinaryIO:
|
|
180
|
+
...
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@overload
|
|
184
|
+
def open_file(
|
|
185
|
+
file: FilePathType, mode: str, buffering: int = ...,
|
|
186
|
+
encoding: str | None = ..., errors: str | None = ..., newline: str | None = ...,
|
|
187
|
+
closefd: bool = ..., opener: FileOpener | None = ..., *, func: FuncExceptT | None = None
|
|
188
|
+
) -> IO[Any]:
|
|
189
|
+
...
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def open_file(file: FilePathType, mode: Any = 'r+', *args: Any, func: FuncExceptT | None = None, **kwargs: Any) -> Any:
|
|
193
|
+
"""
|
|
194
|
+
Open file and return a stream. Raise OSError upon failure.
|
|
195
|
+
|
|
196
|
+
:param file: Is either a text or byte string giving the name of the file to be opened.
|
|
197
|
+
It is also possible to use a string or bytearray as a file for both reading and writing.
|
|
198
|
+
For strings, StringIO can be used like a file opened in a text mode.
|
|
199
|
+
For bytes a BytesIO can be used like a file opened in a binary mode.
|
|
200
|
+
:param mode: This is an optional string that specifies the mode in which the file is opened.
|
|
201
|
+
It defaults to 'r' which means open for reading in text mode.
|
|
202
|
+
Other common values are:
|
|
203
|
+
'w' for writing, and truncating the file if it already exists
|
|
204
|
+
'x' for creating and writing to a new file
|
|
205
|
+
'a' for appending, which on some Unix systems means that all writes append to the end
|
|
206
|
+
of the file regardless of the current seek position).
|
|
207
|
+
In text mode, if encoding is not specified the encoding used is platform dependent:
|
|
208
|
+
locale.getpreferredencoding(False) is called to get the current locale encoding.
|
|
209
|
+
For reading and writing raw bytes use binary mode and leave encoding unspecified.
|
|
210
|
+
:param buffering: This is an optional integer used to set the buffering policy.
|
|
211
|
+
Pass:
|
|
212
|
+
0 to switch buffering off (only allowed in binary mode)
|
|
213
|
+
1 to select line buffering (only usable in text mode)
|
|
214
|
+
Integer > 1 to indicate the size of a fixed-size chunk buffer.
|
|
215
|
+
When no buffering argument is given, the default buffering policy works as follows:
|
|
216
|
+
Binary files are buffered in fixed-size chunks;
|
|
217
|
+
the size of the buffer is chosen using a heuristic trying to determine the
|
|
218
|
+
underlying device's "block size" and falling back on io.DEFAULT_BUFFER_SIZE.
|
|
219
|
+
On many systems, the buffer will typically be 4096 or 8192 bytes long.
|
|
220
|
+
"Interactive" text files (files for which isatty() returns True) use line buffering.
|
|
221
|
+
Other text files use the policy described above for binary files.
|
|
222
|
+
:param: encoding: This is the name of the encoding used to decode or encode the file.
|
|
223
|
+
This should only be used in text mode
|
|
224
|
+
The default encoding is platform dependent, but any encoding supported by Python can be passed.
|
|
225
|
+
See the codecs module for the list of supported encodings.
|
|
226
|
+
:param newline: This parameter controls how universal newlines works (it only applies to text mode).
|
|
227
|
+
It can be None, '', '\n', '\r', and '\r\n'.
|
|
228
|
+
It works as follows:
|
|
229
|
+
On input,
|
|
230
|
+
if newline is None, universal newlines mode is enabled.
|
|
231
|
+
Lines in the input can end in '\n', '\r', or '\r\n',
|
|
232
|
+
and these are translated into '\n' before being returned to the caller.
|
|
233
|
+
If it is '', universal newline mode is enabled, but line endings are
|
|
234
|
+
returned to the caller untranslated.
|
|
235
|
+
If it has any of the other legal values, input lines are only terminated
|
|
236
|
+
by the given string, and the line ending is returned to the caller untranslated.
|
|
237
|
+
On output,
|
|
238
|
+
if newline is None, any '\n' characters written are translated to the system default
|
|
239
|
+
line separator, os.linesep. If newline is '' or '\n', no translation takes place.
|
|
240
|
+
If newline is any of the other legal values, any '\n' characters written are
|
|
241
|
+
translated to the given string.
|
|
242
|
+
|
|
243
|
+
:return: A file object whose type depends on the mode, and through which the standard file operations
|
|
244
|
+
such as reading and writing are performed.
|
|
245
|
+
When open_file is used to open a file in a text mode ('w', 'r', 'wt', 'rt', etc.),
|
|
246
|
+
it returns a TextIOWrapper.
|
|
247
|
+
When used to open a file in a binary mode, the returned class varies:
|
|
248
|
+
in read binary mode, it returns a BufferedReader
|
|
249
|
+
in write binary and append binary modes, it returns a BufferedWriter
|
|
250
|
+
in read/write mode, it returns a BufferedRandom
|
|
251
|
+
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
check_perms(file, mode, func=func)
|
|
255
|
+
|
|
256
|
+
return open(file, mode, *args, errors='strict', closefd=True, **kwargs) # type: ignore
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from functools import update_wrapper
|
|
4
|
+
from types import FunctionType
|
|
5
|
+
from typing import Sequence
|
|
6
|
+
|
|
7
|
+
from ..types import F
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
'copy_func',
|
|
11
|
+
'erase_module'
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def copy_func(f: F) -> FunctionType:
|
|
16
|
+
"""Try copying a function."""
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
g = FunctionType(
|
|
20
|
+
f.__code__, f.__globals__, name=f.__name__, argdefs=f.__defaults__, closure=f.__closure__
|
|
21
|
+
)
|
|
22
|
+
g = update_wrapper(g, f) # type: ignore
|
|
23
|
+
g.__kwdefaults__ = f.__kwdefaults__
|
|
24
|
+
return g
|
|
25
|
+
except BaseException: # for builtins
|
|
26
|
+
return f # type: ignore
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def erase_module(func: F, modules: Sequence[str] | None = None) -> F:
|
|
30
|
+
"""Delete the __module__ of the function."""
|
|
31
|
+
|
|
32
|
+
if hasattr(func, '__module__') and (True if modules is None else (func.__module__ in modules)):
|
|
33
|
+
func.__module__ = None # type: ignore
|
|
34
|
+
|
|
35
|
+
return func
|
jetpytools/utils/math.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from math import ceil, log, log10
|
|
4
|
+
from typing import Sequence
|
|
5
|
+
|
|
6
|
+
from ..types import Nb
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
'clamp', 'clamp_arr',
|
|
10
|
+
|
|
11
|
+
'cround',
|
|
12
|
+
|
|
13
|
+
'mod_x', 'mod2', 'mod4', 'mod8',
|
|
14
|
+
|
|
15
|
+
'next_power_of_y', 'next_power_of_2',
|
|
16
|
+
|
|
17
|
+
'spline_coeff',
|
|
18
|
+
|
|
19
|
+
'ndigits'
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def clamp(val: Nb, min_val: Nb, max_val: Nb) -> Nb:
|
|
24
|
+
"""Faster max(min(value, max_val), min_val) "wrapper" """
|
|
25
|
+
|
|
26
|
+
return min_val if val < min_val else max_val if val > max_val else val
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def clamp_arr(vals: Sequence[Nb], min_val: Nb, max_val: Nb) -> list[Nb]:
|
|
30
|
+
"""Map an array to clamp."""
|
|
31
|
+
|
|
32
|
+
return [clamp(x, min_val, max_val) for x in vals]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def cround(x: float, *, eps: float = 1e-6) -> int:
|
|
36
|
+
"""Rounding function that accounts for float's imprecision."""
|
|
37
|
+
|
|
38
|
+
return round(x + (eps if x > 0. else - eps))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def mod_x(val: int | float, x: int) -> int:
|
|
42
|
+
"""Force a value to be divisible by x (val % x == 0)."""
|
|
43
|
+
|
|
44
|
+
if x == 0:
|
|
45
|
+
return cround(val)
|
|
46
|
+
|
|
47
|
+
return cround(val / x) * x
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def mod2(val: int | float) -> int:
|
|
51
|
+
"""Force a value to be mod 2"""
|
|
52
|
+
|
|
53
|
+
return mod_x(val, x=2)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def mod4(val: int | float) -> int:
|
|
57
|
+
"""Force a value to be mod 4"""
|
|
58
|
+
|
|
59
|
+
return mod_x(val, x=4)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def mod8(val: int | float) -> int:
|
|
63
|
+
"""Force a value to be mod 8"""
|
|
64
|
+
|
|
65
|
+
return mod_x(val, x=8)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def next_power_of_2(x: float) -> int:
|
|
69
|
+
"""Get the next power of 2 of x."""
|
|
70
|
+
|
|
71
|
+
x = cround(x)
|
|
72
|
+
|
|
73
|
+
if x == 0:
|
|
74
|
+
return 1
|
|
75
|
+
|
|
76
|
+
if x & (x - 1) == 0:
|
|
77
|
+
return x
|
|
78
|
+
|
|
79
|
+
while x & (x - 1) > 0:
|
|
80
|
+
x &= (x - 1)
|
|
81
|
+
|
|
82
|
+
return x << 1
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def next_power_of_y(x: float, y: int) -> int:
|
|
86
|
+
"""Get the next power of y of x."""
|
|
87
|
+
|
|
88
|
+
if x == 0:
|
|
89
|
+
return 1
|
|
90
|
+
|
|
91
|
+
return int(y ** ceil(log(x, y)))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def spline_coeff(
|
|
95
|
+
x: int, coordinates: list[tuple[float, float]] = [
|
|
96
|
+
(0, 0), (0.5, 0.1), (1, 0.6), (2, 0.9), (2.5, 1), (3, 1.1), (3.5, 1.15), (4, 1.2), (8, 1.25), (255, 1.5)
|
|
97
|
+
]
|
|
98
|
+
) -> float:
|
|
99
|
+
"""Get spline coefficient of an index and coordinates."""
|
|
100
|
+
|
|
101
|
+
length = len(coordinates)
|
|
102
|
+
|
|
103
|
+
if length < 3:
|
|
104
|
+
raise ValueError("coordinates require at least three pairs")
|
|
105
|
+
|
|
106
|
+
px, py = zip(*coordinates)
|
|
107
|
+
|
|
108
|
+
matrix = [[1.0] + [0.0] * length]
|
|
109
|
+
|
|
110
|
+
for i in range(1, length - 1):
|
|
111
|
+
p = [0.0] * (length + 1)
|
|
112
|
+
|
|
113
|
+
p[i - 1] = px[i] - px[i - 1]
|
|
114
|
+
p[i] = 2 * (px[i + 1] - px[i - 1])
|
|
115
|
+
p[i + 1] = px[i + 1] - px[i]
|
|
116
|
+
p[length] = 6 * (((py[i + 1] - py[i]) / p[i + 1]) - (py[i] - py[i - 1]) / p[i - 1])
|
|
117
|
+
|
|
118
|
+
matrix.append(p)
|
|
119
|
+
|
|
120
|
+
matrix += [([0.0] * (length - 1) + [1.0, 0.0])]
|
|
121
|
+
|
|
122
|
+
for i in range(length):
|
|
123
|
+
num = matrix[i][i]
|
|
124
|
+
|
|
125
|
+
for j in range(length + 1):
|
|
126
|
+
matrix[i][j] /= num
|
|
127
|
+
|
|
128
|
+
for j in range(length):
|
|
129
|
+
if i != j:
|
|
130
|
+
a = matrix[j][i]
|
|
131
|
+
|
|
132
|
+
for k in range(i, length + 1):
|
|
133
|
+
matrix[j][k] -= a * matrix[i][k]
|
|
134
|
+
|
|
135
|
+
for i in range(length + 1):
|
|
136
|
+
if x >= px[i] and x <= px[i + 1]:
|
|
137
|
+
break
|
|
138
|
+
|
|
139
|
+
j = i + 1
|
|
140
|
+
|
|
141
|
+
h = px[j] - px[i]
|
|
142
|
+
|
|
143
|
+
s = matrix[j][length] * float((x - px[i]) ** 3)
|
|
144
|
+
s -= matrix[i][length] * float((x - px[j]) ** 3)
|
|
145
|
+
|
|
146
|
+
s /= 6 * h
|
|
147
|
+
|
|
148
|
+
s += (py[j] / h - h * matrix[j][length] / 6) * (x - px[i])
|
|
149
|
+
s -= (py[i] / h - h * matrix[i][length] / 6) * (x - px[j])
|
|
150
|
+
|
|
151
|
+
return s
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def ndigits(num: Nb) -> int:
|
|
155
|
+
if num == 0:
|
|
156
|
+
return 1
|
|
157
|
+
|
|
158
|
+
return int(log10(abs(num))) + 1
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from itertools import chain, zip_longest
|
|
4
|
+
from typing import Iterable, overload
|
|
5
|
+
|
|
6
|
+
from ..exceptions import CustomIndexError
|
|
7
|
+
from ..types import T0, T
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
'ranges_product',
|
|
11
|
+
|
|
12
|
+
'interleave_arr'
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@overload
|
|
17
|
+
def ranges_product(range0: range | int, range1: range | int, /) -> Iterable[tuple[int, int]]:
|
|
18
|
+
...
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@overload
|
|
22
|
+
def ranges_product(range0: range | int, range1: range | int, range2: range | int, /) -> Iterable[tuple[int, int, int]]:
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def ranges_product(*_iterables: range | int) -> Iterable[tuple[int, ...]]:
|
|
27
|
+
"""
|
|
28
|
+
Take two or three lengths/ranges and make a cartesian product of them.
|
|
29
|
+
|
|
30
|
+
Useful for getting all coordinates of an image.
|
|
31
|
+
For example ranges_product(1920, 1080) will give you [(0, 0), (0, 1), (0, 2), ..., (1919, 1078), (1919, 1079)].
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
n_iterables = len(_iterables)
|
|
35
|
+
|
|
36
|
+
if n_iterables <= 1:
|
|
37
|
+
raise CustomIndexError(f'Not enough ranges passed! ({n_iterables})', ranges_product)
|
|
38
|
+
|
|
39
|
+
iterables = [range(x) if isinstance(x, int) else x for x in _iterables]
|
|
40
|
+
|
|
41
|
+
if n_iterables == 2:
|
|
42
|
+
first_it, second_it = iterables
|
|
43
|
+
|
|
44
|
+
for xx in first_it:
|
|
45
|
+
for yy in second_it:
|
|
46
|
+
yield xx, yy
|
|
47
|
+
elif n_iterables == 3:
|
|
48
|
+
first_it, second_it, third_it = iterables
|
|
49
|
+
|
|
50
|
+
for xx in first_it:
|
|
51
|
+
for yy in second_it:
|
|
52
|
+
for zz in third_it:
|
|
53
|
+
yield xx, yy, zz
|
|
54
|
+
else:
|
|
55
|
+
raise CustomIndexError(f'Too many ranges passed! ({n_iterables})', ranges_product)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def interleave_arr(arr0: Iterable[T], arr1: Iterable[T0], n: int = 2) -> Iterable[T | T0]:
|
|
59
|
+
"""
|
|
60
|
+
Interleave two arrays of variable length.
|
|
61
|
+
|
|
62
|
+
:param arr0: First array to be interleaved.
|
|
63
|
+
:param arr1: Second array to be interleaved.
|
|
64
|
+
:param n: The number of elements from arr0 to include in the interleaved sequence
|
|
65
|
+
before including an element from arr1.
|
|
66
|
+
|
|
67
|
+
:yield: Elements from either arr0 or arr01.
|
|
68
|
+
"""
|
|
69
|
+
if n == 1:
|
|
70
|
+
yield from (x for x in chain.from_iterable(zip_longest(arr0, arr1)) if x is not None)
|
|
71
|
+
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
arr0_i, arr1_i = iter(arr0), iter(arr1)
|
|
75
|
+
arr1_vals = arr0_vals = True
|
|
76
|
+
|
|
77
|
+
while arr1_vals or arr0_vals:
|
|
78
|
+
if arr0_vals:
|
|
79
|
+
for _ in range(n):
|
|
80
|
+
try:
|
|
81
|
+
yield next(arr0_i)
|
|
82
|
+
except StopIteration:
|
|
83
|
+
arr0_vals = False
|
|
84
|
+
|
|
85
|
+
if arr1_vals:
|
|
86
|
+
try:
|
|
87
|
+
yield next(arr1_i)
|
|
88
|
+
except StopIteration:
|
|
89
|
+
arr1_vals = False
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 LightArrowsEXE
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: jetpytools
|
|
3
|
+
Version: 1.2.3
|
|
4
|
+
Summary: Collection of stuff that's useful in general python programming
|
|
5
|
+
Author: Jaded Encoding Thaumaturgy
|
|
6
|
+
Author-email: jaded.encoding.thaumaturgy@gmail.com
|
|
7
|
+
Maintainer: Jaded Encoding Thaumaturgy
|
|
8
|
+
Maintainer-email: jaded.encoding.thaumaturgy@gmail.com
|
|
9
|
+
Project-URL: Source Code, https://github.com/Jaded-Encoding-Thaumaturgy/jetpytools
|
|
10
|
+
Project-URL: Contact, https://discord.gg/XTpc6Fa9eB
|
|
11
|
+
Classifier: Natural Language :: English
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Other Audience
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: author-email
|
|
23
|
+
Dynamic: classifier
|
|
24
|
+
Dynamic: description
|
|
25
|
+
Dynamic: description-content-type
|
|
26
|
+
Dynamic: maintainer
|
|
27
|
+
Dynamic: maintainer-email
|
|
28
|
+
Dynamic: project-url
|
|
29
|
+
Dynamic: requires-python
|
|
30
|
+
Dynamic: summary
|
|
31
|
+
|
|
32
|
+
# jetpytools
|
|
33
|
+
|
|
34
|
+
Collection of stuff that's useful in general python programming
|
|
35
|
+
|
|
36
|
+
## How to install
|
|
37
|
+
|
|
38
|
+
Install `jetpytools` with the following command:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
pip install jetpytools
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or if you want the latest git version, install it with this command:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
pip install git+https://github.com/Jaded-Encoding-Thaumaturgy/jetpytools.git
|
|
48
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
jetpytools/__init__.py,sha256=FSVZdj69oy4mBXd6OXiRHrUhaSc4Exo1pQHBlXycV98,214
|
|
2
|
+
jetpytools/_metadata.py,sha256=h_0Q6daDjew31Bh1Mlh32FVTx8Srl8nedCU6pABa66g,414
|
|
3
|
+
jetpytools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
jetpytools/enums/__init__.py,sha256=5n6Cu8Yb9N6hIa_YTsyy_s0cCgCnh0vDb-NyXK2RwV0,81
|
|
5
|
+
jetpytools/enums/base.py,sha256=q0HUCl8NN66b4VXYNjP_AMrYqjlcLVlRs0GQHXt17zU,2083
|
|
6
|
+
jetpytools/enums/other.py,sha256=vQIouUJWRa039t8E1RQYc61MYS3uhe-o-5SBRlXs9x4,1416
|
|
7
|
+
jetpytools/exceptions/__init__.py,sha256=g8GT0XqcNuHFHgQGSRj6a_X1kBiBQGP05soYNbEIN_Q,205
|
|
8
|
+
jetpytools/exceptions/base.py,sha256=S3sqhT6yQSbPshmcy3XyVgfjDXic_xbpb8799TfD-cI,6342
|
|
9
|
+
jetpytools/exceptions/enum.py,sha256=9YoWwEfyd9k7NwanAqtXbhJaJQAnjRKqsAO73cDvcpA,223
|
|
10
|
+
jetpytools/exceptions/file.py,sha256=QwhUFAoG3NsFFYuPe5O_I6K969CzlrTCv3RTrfzx8B0,1107
|
|
11
|
+
jetpytools/exceptions/generic.py,sha256=jWCJ6ato12rJBXLmZx4ReMVWG0iMuStR5Tz9CJlVevI,1492
|
|
12
|
+
jetpytools/exceptions/module.py,sha256=drkcpa8hcE7Ee20N15j3qsX_grl8a3Jjv10XJ3xtDmE,1207
|
|
13
|
+
jetpytools/functions/__init__.py,sha256=CeDfQrPCYqjiXyCoZ6jcbfM2d7KmRM11lBSxUK2wl4g,127
|
|
14
|
+
jetpytools/functions/funcs.py,sha256=EMoJ_h2tl8Cgr1PXAsmRvgaOY5YL7AiEnGGo3-H76tk,3797
|
|
15
|
+
jetpytools/functions/normalize.py,sha256=dyEuLVOZ2WSR_qDgyVGILn-0MURizCn5Nk1KuppgbG8,6381
|
|
16
|
+
jetpytools/functions/other.py,sha256=TRz91spvdYJUh9vKe3Kuw6xZfSEJvrQs1mZVg7SyYmY,413
|
|
17
|
+
jetpytools/types/__init__.py,sha256=0veUJC8ioXsx1g3Nx-YQSKTnkenfyaD5y91qBDkyM8Q,253
|
|
18
|
+
jetpytools/types/builtins.py,sha256=moET0CgjQnUkis2V1RViL53OMCVAIV4zBDcClsaKn5g,1807
|
|
19
|
+
jetpytools/types/file.py,sha256=lUXszSZZbZHftCsDXbqoQumqUdZwGi3ocgW3p8tMJyE,6082
|
|
20
|
+
jetpytools/types/funcs.py,sha256=MOA-BdxDbvCPvAReKvUM2P87KnmGnIDjkqSmYycJXUo,3114
|
|
21
|
+
jetpytools/types/generic.py,sha256=sAyBwGVG5FZ-6HVpfRuczov_6zQ_Uyoi0QWnR2iMm9Q,1128
|
|
22
|
+
jetpytools/types/supports.py,sha256=--VZ-iCUiv-a6K8n-H8-6hSxHjrvdYg9mCLhr_lRplo,3051
|
|
23
|
+
jetpytools/types/utils.py,sha256=tBHAlMADYB5CiGb1zeh1m_C4RK8_Zi8Pbd_dStsZjYM,22243
|
|
24
|
+
jetpytools/utils/__init__.py,sha256=v5Bkl43-OBWlXx9OWpZoGH-QMaYNsPIi4vfuhC13ZLI,163
|
|
25
|
+
jetpytools/utils/file.py,sha256=9GhMGJ5D7CpvUFnvnwPFMloYTeIX-AJ7aKYKdoJQ374,10455
|
|
26
|
+
jetpytools/utils/funcs.py,sha256=ZuLz63kveBY1CLlBexEqmrQiGC67dY4gaXdNU3CeBMw,898
|
|
27
|
+
jetpytools/utils/math.py,sha256=lNTriLtTXgqN82DVSXJ5KUbhsWgxXoJ5eNGIZ0-_r_c,3335
|
|
28
|
+
jetpytools/utils/ranges.py,sha256=dL3WG235Pz9sk5su8A0VdwVf_oSt6obR7R_JNwLyCjQ,2572
|
|
29
|
+
jetpytools-1.2.3.dist-info/LICENSE,sha256=l0PN-qDtXcgOB5aXP_nSUsvCK5V3o9pQCGsTzyZhKL0,1071
|
|
30
|
+
jetpytools-1.2.3.dist-info/METADATA,sha256=ipieUMdlycXQ9NkzOWzLDB8QtnL5AExriLKaY0QP258,1399
|
|
31
|
+
jetpytools-1.2.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
32
|
+
jetpytools-1.2.3.dist-info/top_level.txt,sha256=Iy4HjIta33ADJxN9Nyt5t5jRIfotEkZkQcOSw4eG8Cs,11
|
|
33
|
+
jetpytools-1.2.3.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
jetpytools
|