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.

@@ -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
@@ -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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ jetpytools