jetpytools 2.1.1__tar.gz → 2.2.1__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.
- jetpytools-2.2.1/.gitignore +233 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/PKG-INFO +6 -10
- jetpytools-2.2.1/README.md +13 -0
- jetpytools-2.2.1/jetpytools/__init__.py +16 -0
- jetpytools-2.2.1/jetpytools/_version.py +2 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/enums/base.py +9 -4
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/enums/other.py +2 -1
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/base.py +19 -52
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/file.py +8 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/module.py +4 -3
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/functions/funcs.py +43 -78
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/functions/normalize.py +24 -22
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/check.py +6 -2
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/file.py +7 -8
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/funcs.py +7 -3
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/utils.py +97 -37
- jetpytools-2.2.1/jetpytools/utils/file.py +123 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/utils/math.py +2 -1
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/utils/ranges.py +8 -6
- {jetpytools-2.1.1 → jetpytools-2.2.1}/pyproject.toml +23 -32
- jetpytools-2.2.1/tests/test_file.py +9 -0
- jetpytools-2.2.1/tests/test_funcs.py +20 -0
- jetpytools-2.2.1/tests/test_normalize.py +49 -0
- jetpytools-2.2.1/tests/test_types_utils.py +235 -0
- jetpytools-2.1.1/.gitignore +0 -12
- jetpytools-2.1.1/README.md +0 -17
- jetpytools-2.1.1/jetpytools/__init__.py +0 -5
- jetpytools-2.1.1/jetpytools/_metadata.py +0 -12
- jetpytools-2.1.1/jetpytools/utils/file.py +0 -282
- {jetpytools-2.1.1 → jetpytools-2.2.1}/LICENSE +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/enums/__init__.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/__init__.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/enum.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/generic.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/functions/__init__.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/functions/other.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/py.typed +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/__init__.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/builtins.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/generic.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/supports.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/utils/__init__.py +0 -0
- {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/utils/funcs.py +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
.cache/
|
|
169
|
+
/site
|
|
170
|
+
|
|
171
|
+
# mypy
|
|
172
|
+
.mypy_cache/
|
|
173
|
+
.dmypy.json
|
|
174
|
+
dmypy.json
|
|
175
|
+
|
|
176
|
+
# Pyre type checker
|
|
177
|
+
.pyre/
|
|
178
|
+
|
|
179
|
+
# pytype static type analyzer
|
|
180
|
+
.pytype/
|
|
181
|
+
|
|
182
|
+
# Cython debug symbols
|
|
183
|
+
cython_debug/
|
|
184
|
+
|
|
185
|
+
# PyCharm
|
|
186
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
187
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
188
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
189
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
190
|
+
# .idea/
|
|
191
|
+
|
|
192
|
+
# Abstra
|
|
193
|
+
# Abstra is an AI-powered process automation framework.
|
|
194
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
195
|
+
# Learn more at https://abstra.io/docs
|
|
196
|
+
.abstra/
|
|
197
|
+
|
|
198
|
+
# Visual Studio Code
|
|
199
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
200
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
201
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
202
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
203
|
+
# .vscode/
|
|
204
|
+
|
|
205
|
+
# Ruff stuff:
|
|
206
|
+
.ruff_cache/
|
|
207
|
+
|
|
208
|
+
# PyPI configuration file
|
|
209
|
+
.pypirc
|
|
210
|
+
|
|
211
|
+
# Marimo
|
|
212
|
+
marimo/_static/
|
|
213
|
+
marimo/_lsp/
|
|
214
|
+
__marimo__/
|
|
215
|
+
|
|
216
|
+
# Streamlit
|
|
217
|
+
.streamlit/secrets.toml
|
|
218
|
+
|
|
219
|
+
# versioningit
|
|
220
|
+
jetpytools/_version.py
|
|
221
|
+
|
|
222
|
+
# DEVELOPERS:
|
|
223
|
+
# Before adding a file directory to this .gitignore,
|
|
224
|
+
# check if it should maybe go in your local .gitignore
|
|
225
|
+
# (.git/info/exclude), or your own user-wide .gitignore
|
|
226
|
+
# (https://sebastiandedeyne.com/setting-up-a-global-gitignore-file/)
|
|
227
|
+
# instead.
|
|
228
|
+
# Repository-specific files (Python cache files, build artifacts,
|
|
229
|
+
# coverage reports, etc.) should go in here, user-specific files
|
|
230
|
+
# (IDE folders, video index files, etc.) shouldn't.
|
|
231
|
+
|
|
232
|
+
# JET files
|
|
233
|
+
.vsjet/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jetpytools
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Summary: Collection of stuff that's useful in general python programming
|
|
5
5
|
Project-URL: Source Code, https://github.com/Jaded-Encoding-Thaumaturgy/jetpytools
|
|
6
6
|
Project-URL: Contact, https://discord.gg/XTpc6Fa9eB
|
|
@@ -16,23 +16,19 @@ Classifier: Programming Language :: Python :: 3
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
17
|
Classifier: Typing :: Typed
|
|
18
18
|
Requires-Python: >=3.12
|
|
19
|
-
Requires-Dist: typing-extensions>=4.15.0
|
|
19
|
+
Requires-Dist: typing-extensions>=4.15.0; python_version < '3.13'
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
|
|
22
22
|
# jetpytools
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
[](https://pypi.org/project/jetpytools/)
|
|
25
|
+
|
|
26
|
+
A collection of utilities useful for general Python programming.
|
|
25
27
|
|
|
26
28
|
## How to install
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
`jetpytools` is distributed via **PyPI**, and the latest stable release can be installed using:
|
|
29
31
|
|
|
30
32
|
```sh
|
|
31
33
|
pip install jetpytools
|
|
32
34
|
```
|
|
33
|
-
|
|
34
|
-
Or if you want the latest git version, install it with this command:
|
|
35
|
-
|
|
36
|
-
```sh
|
|
37
|
-
pip install git+https://github.com/Jaded-Encoding-Thaumaturgy/jetpytools.git
|
|
38
|
-
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# jetpytools
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/jetpytools/)
|
|
4
|
+
|
|
5
|
+
A collection of utilities useful for general Python programming.
|
|
6
|
+
|
|
7
|
+
## How to install
|
|
8
|
+
|
|
9
|
+
`jetpytools` is distributed via **PyPI**, and the latest stable release can be installed using:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pip install jetpytools
|
|
13
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""A collection of utilities useful for general Python programming."""
|
|
2
|
+
|
|
3
|
+
from .enums import *
|
|
4
|
+
from .exceptions import *
|
|
5
|
+
from .functions import *
|
|
6
|
+
from .types import *
|
|
7
|
+
from .utils import *
|
|
8
|
+
|
|
9
|
+
__version__: str
|
|
10
|
+
__version_tuple__: tuple[int | str, ...]
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from ._version import __version__, __version_tuple__
|
|
14
|
+
except ImportError:
|
|
15
|
+
__version__ = "0.0.0+unknown"
|
|
16
|
+
__version_tuple__ = (0, 0, 0, "+unknown")
|
|
@@ -42,12 +42,15 @@ class CustomEnum(Enum):
|
|
|
42
42
|
"""
|
|
43
43
|
Return the enum value from a parameter.
|
|
44
44
|
|
|
45
|
-
:
|
|
46
|
-
|
|
45
|
+
Args:
|
|
46
|
+
value: Value to instantiate the enum class.
|
|
47
|
+
func_except: Exception function.
|
|
47
48
|
|
|
48
|
-
:
|
|
49
|
+
Returns:
|
|
50
|
+
Enum value.
|
|
49
51
|
|
|
50
|
-
:
|
|
52
|
+
Raises:
|
|
53
|
+
NotFoundEnumValue: Variable not found in the given enum.
|
|
51
54
|
"""
|
|
52
55
|
func_except = func_except or cls.from_param
|
|
53
56
|
|
|
@@ -78,6 +81,7 @@ class CustomIntEnum(int, CustomEnum, ReprEnum):
|
|
|
78
81
|
|
|
79
82
|
if TYPE_CHECKING:
|
|
80
83
|
_value_: int
|
|
84
|
+
_value2member_map_: dict[int, Enum]
|
|
81
85
|
|
|
82
86
|
@enum_property
|
|
83
87
|
def value(self) -> int: ...
|
|
@@ -88,6 +92,7 @@ class CustomStrEnum(str, CustomEnum, ReprEnum):
|
|
|
88
92
|
|
|
89
93
|
if TYPE_CHECKING:
|
|
90
94
|
_value_: str
|
|
95
|
+
_value2member_map_: dict[str, Enum]
|
|
91
96
|
|
|
92
97
|
@enum_property
|
|
93
98
|
def value(self) -> str: ...
|
|
@@ -2,11 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
4
|
from contextlib import AbstractContextManager
|
|
5
|
-
from copy import deepcopy
|
|
6
5
|
from types import TracebackType
|
|
7
|
-
from typing import
|
|
8
|
-
|
|
9
|
-
from typing_extensions import Self
|
|
6
|
+
from typing import Any, Self
|
|
10
7
|
|
|
11
8
|
from ..types import MISSING, FuncExcept, MissingT, SupportsString
|
|
12
9
|
|
|
@@ -23,59 +20,26 @@ __all__ = [
|
|
|
23
20
|
]
|
|
24
21
|
|
|
25
22
|
|
|
26
|
-
if TYPE_CHECKING:
|
|
27
|
-
|
|
28
|
-
class ExceptionError(Exception):
|
|
29
|
-
__name__: str
|
|
30
|
-
__qualname__: str
|
|
31
|
-
else:
|
|
32
|
-
ExceptionError = Exception
|
|
33
|
-
|
|
34
|
-
|
|
35
23
|
class CustomErrorMeta(type):
|
|
36
24
|
"""Custom base exception meta class."""
|
|
37
25
|
|
|
38
|
-
def __new__[MetaSelf: CustomErrorMeta](
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
@staticmethod
|
|
42
|
-
def setup_exception[MetaSelf: CustomErrorMeta](
|
|
43
|
-
exception: MetaSelf, override: str | ExceptionError | None = None
|
|
26
|
+
def __new__[MetaSelf: CustomErrorMeta](
|
|
27
|
+
mcls: type[MetaSelf], name: str, bases: tuple[type, ...], namespace: dict[str, Any], /, **kwds: Any
|
|
44
28
|
) -> MetaSelf:
|
|
45
|
-
|
|
46
|
-
Setup an exception for later use in CustomError.
|
|
47
|
-
|
|
48
|
-
:param exception: Exception to update.
|
|
49
|
-
:param override: Optional name or exception from which get the override values.
|
|
50
|
-
|
|
51
|
-
:return: Set up exception.
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
if override:
|
|
55
|
-
if isinstance(override, str):
|
|
56
|
-
over_name = over_qual = override
|
|
57
|
-
else:
|
|
58
|
-
over_name, over_qual = override.__name__, override.__qualname__
|
|
59
|
-
|
|
60
|
-
if over_name.startswith("Custom"):
|
|
61
|
-
exception.__name__ = over_name
|
|
62
|
-
else:
|
|
63
|
-
exception.__name__ = f"Custom{over_name}"
|
|
64
|
-
|
|
65
|
-
exception.__qualname__ = over_qual
|
|
29
|
+
cls = super().__new__(mcls, name, bases, namespace, **kwds)
|
|
66
30
|
|
|
67
|
-
if
|
|
68
|
-
|
|
31
|
+
if cls.__qualname__.startswith("Custom"):
|
|
32
|
+
cls.__qualname__ = cls.__qualname__[6:]
|
|
69
33
|
|
|
70
34
|
if sys.stdout and sys.stdout.isatty():
|
|
71
|
-
|
|
35
|
+
cls.__qualname__ = f"\033[0;31;1m{cls.__qualname__}\033[0m"
|
|
72
36
|
|
|
73
|
-
|
|
37
|
+
cls.__module__ = Exception.__module__
|
|
74
38
|
|
|
75
|
-
return
|
|
39
|
+
return cls
|
|
76
40
|
|
|
77
41
|
|
|
78
|
-
class CustomError(
|
|
42
|
+
class CustomError(Exception, metaclass=CustomErrorMeta):
|
|
79
43
|
"""Custom base exception class."""
|
|
80
44
|
|
|
81
45
|
def __init__(
|
|
@@ -84,9 +48,10 @@ class CustomError(ExceptionError, metaclass=CustomErrorMeta):
|
|
|
84
48
|
"""
|
|
85
49
|
Instantiate a new exception with pretty printing and more.
|
|
86
50
|
|
|
87
|
-
:
|
|
88
|
-
|
|
89
|
-
|
|
51
|
+
Args:
|
|
52
|
+
message: Message of the error.
|
|
53
|
+
func: Function this exception was raised from.
|
|
54
|
+
reason: Reason of the exception. For example, an optional parameter.
|
|
90
55
|
"""
|
|
91
56
|
|
|
92
57
|
self.message = message
|
|
@@ -106,10 +71,12 @@ class CustomError(ExceptionError, metaclass=CustomErrorMeta):
|
|
|
106
71
|
"""
|
|
107
72
|
Copy an existing exception with defaults and instantiate a new one.
|
|
108
73
|
|
|
109
|
-
:
|
|
110
|
-
|
|
111
|
-
|
|
74
|
+
Args:
|
|
75
|
+
message: Message of the error.
|
|
76
|
+
func: Function this exception was raised from.
|
|
77
|
+
reason: Reason of the exception. For example, an optional parameter.
|
|
112
78
|
"""
|
|
79
|
+
from copy import deepcopy
|
|
113
80
|
|
|
114
81
|
err = deepcopy(self)
|
|
115
82
|
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import sys
|
|
4
|
+
|
|
3
5
|
from .base import CustomError, CustomPermissionError
|
|
4
6
|
|
|
7
|
+
if sys.version_info < (3, 13):
|
|
8
|
+
from typing_extensions import deprecated
|
|
9
|
+
else:
|
|
10
|
+
from warnings import deprecated
|
|
11
|
+
|
|
5
12
|
__all__ = [
|
|
6
13
|
"FileIsADirectoryError",
|
|
7
14
|
"FileNotExistsError",
|
|
@@ -24,6 +31,7 @@ class FilePermissionError(CustomPermissionError):
|
|
|
24
31
|
"""Raised when you try to access a file but haven't got permissions to do so"""
|
|
25
32
|
|
|
26
33
|
|
|
34
|
+
@deprecated("FileTypeMismatchError is deprecated and will be removed in a future version.", category=DeprecationWarning)
|
|
27
35
|
class FileTypeMismatchError(CustomError, OSError):
|
|
28
36
|
"""Raised when you try to access a file with a FileType != AUTO and it's another file type"""
|
|
29
37
|
|
|
@@ -19,9 +19,10 @@ class CustomImportError(CustomError, ImportError):
|
|
|
19
19
|
**kwargs: Any,
|
|
20
20
|
) -> None:
|
|
21
21
|
"""
|
|
22
|
-
:
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
Args:
|
|
23
|
+
func: Function this error was raised from.
|
|
24
|
+
package: Either the raised error or the name of the missing package.
|
|
25
|
+
message: Custom error message.
|
|
25
26
|
"""
|
|
26
27
|
|
|
27
28
|
super().__init__(message, func, package=package if isinstance(package, str) else package.name, **kwargs)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from inspect import signature
|
|
4
3
|
from typing import Any, Callable, Concatenate, overload
|
|
5
4
|
|
|
6
5
|
from ..exceptions import CustomRuntimeError, CustomValueError
|
|
7
|
-
from ..types import
|
|
6
|
+
from ..types import KwargsT
|
|
8
7
|
|
|
9
8
|
__all__ = ["fallback", "filter_kwargs", "iterate", "kwargs_fallback"]
|
|
10
9
|
|
|
@@ -18,19 +17,21 @@ def iterate[T, **P, R](
|
|
|
18
17
|
Different from regular iteration functions is that you do not need to pass a partial object.
|
|
19
18
|
This function accepts *args and **kwargs. These will be passed on to the given function.
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
- Example:
|
|
21
|
+
```python
|
|
22
|
+
>>> iterate(5, lambda x: x * 2, 2)
|
|
24
23
|
20
|
|
24
|
+
```
|
|
25
25
|
|
|
26
|
-
:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
Args:
|
|
27
|
+
base: Base value, etc. to iterate over.
|
|
28
|
+
function: Function to iterate over the base.
|
|
29
|
+
count: Number of times to execute function.
|
|
30
|
+
*args: Positional arguments to pass to the given function.
|
|
31
|
+
**kwargs: Keyword arguments to pass to the given function.
|
|
31
32
|
|
|
32
|
-
:
|
|
33
|
-
|
|
33
|
+
Returns:
|
|
34
|
+
Value, etc. with the given function run over it *n* amount of times based on the given count.
|
|
34
35
|
"""
|
|
35
36
|
|
|
36
37
|
if count <= 0:
|
|
@@ -44,90 +45,49 @@ def iterate[T, **P, R](
|
|
|
44
45
|
return result
|
|
45
46
|
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
@overload
|
|
51
|
-
def fallback[T](value: T | None, fallback: T, /) -> T: ...
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
@overload
|
|
55
|
-
def fallback[T](value: T | None, fallback0: T | None, default: T, /) -> T: ...
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@overload
|
|
59
|
-
def fallback[T](value: T | None, fallback0: T | None, fallback1: T | None, default: T, /) -> T: ...
|
|
48
|
+
_fallback_missing = object()
|
|
60
49
|
|
|
61
50
|
|
|
62
51
|
@overload
|
|
63
|
-
def fallback[T](value: T | None, *fallbacks: T | None) -> T
|
|
64
|
-
|
|
65
|
-
|
|
52
|
+
def fallback[T](value: T | None, *fallbacks: T | None) -> T: ...
|
|
66
53
|
@overload
|
|
67
54
|
def fallback[T](value: T | None, *fallbacks: T | None, default: T) -> T: ...
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def fallback[T](value: T | None, *fallbacks: T | None, default: Any | T = fallback_missing) -> T | MissingT:
|
|
55
|
+
def fallback[T](value: T | None, *fallbacks: T | None, default: Any = _fallback_missing) -> T:
|
|
71
56
|
"""
|
|
72
57
|
Utility function that returns a value or a fallback if the value is None.
|
|
73
58
|
|
|
74
|
-
Example:
|
|
75
|
-
|
|
76
|
-
.. code-block:: python
|
|
77
|
-
|
|
59
|
+
- Example:
|
|
60
|
+
```python
|
|
78
61
|
>>> fallback(5, 6)
|
|
79
62
|
5
|
|
80
63
|
>>> fallback(None, 6)
|
|
81
64
|
6
|
|
65
|
+
```
|
|
82
66
|
|
|
83
|
-
:
|
|
84
|
-
|
|
67
|
+
Args:
|
|
68
|
+
value: Input value to evaluate. Can be None.
|
|
69
|
+
*fallbacks: Value to return if the input value is None.
|
|
85
70
|
|
|
86
|
-
:
|
|
71
|
+
Returns:
|
|
72
|
+
Input value or fallback value if input value is None.
|
|
87
73
|
"""
|
|
74
|
+
for v in (value, *fallbacks):
|
|
75
|
+
if v is not None:
|
|
76
|
+
return v
|
|
88
77
|
|
|
89
|
-
if
|
|
90
|
-
return value
|
|
91
|
-
|
|
92
|
-
for fallback in fallbacks:
|
|
93
|
-
if fallback is not None:
|
|
94
|
-
return fallback
|
|
95
|
-
|
|
96
|
-
if default is not fallback_missing:
|
|
78
|
+
if default is not _fallback_missing:
|
|
97
79
|
return default
|
|
98
|
-
elif len(fallbacks) > 3:
|
|
99
|
-
return MISSING
|
|
100
80
|
|
|
101
81
|
raise CustomRuntimeError("You need to specify a default/fallback value!")
|
|
102
82
|
|
|
103
83
|
|
|
104
84
|
@overload
|
|
105
|
-
def kwargs_fallback[T](
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
@overload
|
|
109
|
-
def kwargs_fallback[T](input_value: T | None, kwargs: tuple[KwargsT, str], fallback0: T | None, default: T, /) -> T: ...
|
|
110
|
-
|
|
111
|
-
|
|
85
|
+
def kwargs_fallback[T](value: T | None, kwargs: tuple[KwargsT, str], *fallbacks: T | None) -> T: ...
|
|
112
86
|
@overload
|
|
87
|
+
def kwargs_fallback[T](value: T | None, kwargs: tuple[KwargsT, str], *fallbacks: T | None, default: T) -> T: ...
|
|
113
88
|
def kwargs_fallback[T](
|
|
114
|
-
|
|
115
|
-
) -> T:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
@overload
|
|
119
|
-
def kwargs_fallback[T](input_value: T | None, kwargs: tuple[KwargsT, str], /, *fallbacks: T | None) -> T | MissingT: ...
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
@overload
|
|
123
|
-
def kwargs_fallback[T](
|
|
124
|
-
input_value: T | None, kwargs: tuple[KwargsT, str], /, *fallbacks: T | None, default: T
|
|
125
|
-
) -> T: ...
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def kwargs_fallback[T](
|
|
129
|
-
value: T | None, kwargs: tuple[KwargsT, str], *fallbacks: T | None, default: Any | T = fallback_missing
|
|
130
|
-
) -> T | MissingT:
|
|
89
|
+
value: T | None, kwargs: tuple[KwargsT, str], *fallbacks: T | None, default: Any = _fallback_missing
|
|
90
|
+
) -> T:
|
|
131
91
|
"""Utility function to return a fallback value from kwargs if value was not found or is None."""
|
|
132
92
|
|
|
133
93
|
return fallback(value, kwargs[0].get(kwargs[1], None), *fallbacks, default=default)
|
|
@@ -145,25 +105,30 @@ def filter_kwargs(func: Callable[..., Any], kwargs: dict[str, Any] | None = None
|
|
|
145
105
|
"""
|
|
146
106
|
Filter kwargs to only include parameters that match the callable's signature, ignoring **kwargs.
|
|
147
107
|
|
|
148
|
-
Examples:
|
|
149
|
-
|
|
108
|
+
- Examples:
|
|
109
|
+
```python
|
|
150
110
|
>>> def my_func(a: int, b: str, c: bool = True):
|
|
151
111
|
... return a, b, c
|
|
152
112
|
>>> filter_kwargs(my_func, a=1, b="hello", c=False, d="extra")
|
|
153
113
|
{'a': 1, 'b': 'hello', 'c': False}
|
|
154
114
|
>>> filter_kwargs(my_func, {"a": 1, "b": "hello", "c": False, "d": "extra"})
|
|
155
115
|
{'a': 1, 'b': 'hello', 'c': False}
|
|
116
|
+
```
|
|
156
117
|
|
|
157
|
-
:
|
|
158
|
-
|
|
159
|
-
|
|
118
|
+
Args:
|
|
119
|
+
func: The callable to filter kwargs for.
|
|
120
|
+
kwargs: Dictionary of keyword arguments to filter.
|
|
121
|
+
**kw: Keyword arguments to filter (used when kwargs is None).
|
|
160
122
|
|
|
161
|
-
:
|
|
123
|
+
Returns:
|
|
124
|
+
A dictionary containing only the kwargs that match the callable's parameters.
|
|
162
125
|
"""
|
|
163
126
|
|
|
164
127
|
if not (filtered_kwargs := fallback(kwargs, kw)):
|
|
165
128
|
return {}
|
|
166
129
|
|
|
130
|
+
from inspect import signature
|
|
131
|
+
|
|
167
132
|
try:
|
|
168
133
|
sig = signature(func)
|
|
169
134
|
except Exception as e:
|