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.
Files changed (43) hide show
  1. jetpytools-2.2.1/.gitignore +233 -0
  2. {jetpytools-2.1.1 → jetpytools-2.2.1}/PKG-INFO +6 -10
  3. jetpytools-2.2.1/README.md +13 -0
  4. jetpytools-2.2.1/jetpytools/__init__.py +16 -0
  5. jetpytools-2.2.1/jetpytools/_version.py +2 -0
  6. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/enums/base.py +9 -4
  7. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/enums/other.py +2 -1
  8. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/base.py +19 -52
  9. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/file.py +8 -0
  10. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/module.py +4 -3
  11. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/functions/funcs.py +43 -78
  12. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/functions/normalize.py +24 -22
  13. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/check.py +6 -2
  14. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/file.py +7 -8
  15. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/funcs.py +7 -3
  16. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/utils.py +97 -37
  17. jetpytools-2.2.1/jetpytools/utils/file.py +123 -0
  18. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/utils/math.py +2 -1
  19. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/utils/ranges.py +8 -6
  20. {jetpytools-2.1.1 → jetpytools-2.2.1}/pyproject.toml +23 -32
  21. jetpytools-2.2.1/tests/test_file.py +9 -0
  22. jetpytools-2.2.1/tests/test_funcs.py +20 -0
  23. jetpytools-2.2.1/tests/test_normalize.py +49 -0
  24. jetpytools-2.2.1/tests/test_types_utils.py +235 -0
  25. jetpytools-2.1.1/.gitignore +0 -12
  26. jetpytools-2.1.1/README.md +0 -17
  27. jetpytools-2.1.1/jetpytools/__init__.py +0 -5
  28. jetpytools-2.1.1/jetpytools/_metadata.py +0 -12
  29. jetpytools-2.1.1/jetpytools/utils/file.py +0 -282
  30. {jetpytools-2.1.1 → jetpytools-2.2.1}/LICENSE +0 -0
  31. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/enums/__init__.py +0 -0
  32. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/__init__.py +0 -0
  33. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/enum.py +0 -0
  34. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/exceptions/generic.py +0 -0
  35. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/functions/__init__.py +0 -0
  36. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/functions/other.py +0 -0
  37. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/py.typed +0 -0
  38. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/__init__.py +0 -0
  39. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/builtins.py +0 -0
  40. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/generic.py +0 -0
  41. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/types/supports.py +0 -0
  42. {jetpytools-2.1.1 → jetpytools-2.2.1}/jetpytools/utils/__init__.py +0 -0
  43. {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.1.1
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
- Collection of stuff that's useful in general python programming
24
+ [![PyPI Version](https://img.shields.io/pypi/v/jetpytools)](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
- Install `jetpytools` with the following command:
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
+ [![PyPI Version](https://img.shields.io/pypi/v/jetpytools)](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")
@@ -0,0 +1,2 @@
1
+ __version__ = "2.2.1"
2
+ __version_tuple__ = (2, 2, 1)
@@ -42,12 +42,15 @@ class CustomEnum(Enum):
42
42
  """
43
43
  Return the enum value from a parameter.
44
44
 
45
- :param value: Value to instantiate the enum class.
46
- :param func_except: Exception function.
45
+ Args:
46
+ value: Value to instantiate the enum class.
47
+ func_except: Exception function.
47
48
 
48
- :return: Enum value.
49
+ Returns:
50
+ Enum value.
49
51
 
50
- :raises NotFoundEnumValue: Variable not found in the given enum.
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: ...
@@ -9,7 +9,8 @@ class Coordinate:
9
9
  """
10
10
  Positive set of (x, y) coordinates.
11
11
 
12
- :raises ValueError: Negative values were passed.
12
+ Raises:
13
+ ValueError: Negative values were passed.
13
14
  """
14
15
 
15
16
  x: int
@@ -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 TYPE_CHECKING, Any
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](cls: type[MetaSelf], *args: Any) -> MetaSelf:
39
- return CustomErrorMeta.setup_exception(super().__new__(cls, *args))
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 exception.__qualname__.startswith("Custom"):
68
- exception.__qualname__ = exception.__qualname__[6:]
31
+ if cls.__qualname__.startswith("Custom"):
32
+ cls.__qualname__ = cls.__qualname__[6:]
69
33
 
70
34
  if sys.stdout and sys.stdout.isatty():
71
- exception.__qualname__ = f"\033[0;31;1m{exception.__qualname__}\033[0m"
35
+ cls.__qualname__ = f"\033[0;31;1m{cls.__qualname__}\033[0m"
72
36
 
73
- exception.__module__ = Exception.__module__
37
+ cls.__module__ = Exception.__module__
74
38
 
75
- return exception
39
+ return cls
76
40
 
77
41
 
78
- class CustomError(ExceptionError, metaclass=CustomErrorMeta):
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
- :param message: Message of the error.
88
- :param func: Function this exception was raised from.
89
- :param reason: Reason of the exception. For example, an optional parameter.
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
- :param message: Message of the error.
110
- :param func: Function this exception was raised from.
111
- :param reason: Reason of the exception. For example, an optional parameter.
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
- :param func: Function this error was raised from.
23
- :param package: Either the raised error or the name of the missing package.
24
- :param message: Custom error message.
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 MISSING, KwargsT, MissingT
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
- Examples:
22
-
23
- >>> iterate(5, lambda x: x * 2, 2)
20
+ - Example:
21
+ ```python
22
+ >>> iterate(5, lambda x: x * 2, 2)
24
23
  20
24
+ ```
25
25
 
26
- :param base: Base value, etc. to iterate over.
27
- :param function: Function to iterate over the base.
28
- :param count: Number of times to execute function.
29
- :param *args: Positional arguments to pass to the given function.
30
- :param **kwargs: Keyword arguments to pass to the given function.
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
- :return: Value, etc. with the given function run over it
33
- *n* amount of times based on the given count.
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
- fallback_missing = object()
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 | MissingT: ...
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
- :param value: Input value to evaluate. Can be None.
84
- :param fallback_value: Value to return if the input value is None.
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
- :return: Input value or fallback value if input value is None.
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 value is not None:
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](input_value: T | None, kwargs: tuple[KwargsT, str], fallback: T, /) -> 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
- input_value: T | None, kwargs: tuple[KwargsT, str], fallback0: T | None, fallback1: T | None, default: T, /
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
- :param func: The callable to filter kwargs for.
158
- :param kwargs: Dictionary of keyword arguments to filter.
159
- :param **kw: Keyword arguments to filter (used when kwargs is None).
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
- :return: A dictionary containing only the kwargs that match the callable's parameters.
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: