dycw-utilities 0.168.1__py3-none-any.whl → 0.168.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 dycw-utilities might be problematic. Click here for more details.
- {dycw_utilities-0.168.1.dist-info → dycw_utilities-0.168.3.dist-info}/METADATA +1 -1
- {dycw_utilities-0.168.1.dist-info → dycw_utilities-0.168.3.dist-info}/RECORD +7 -7
- utilities/__init__.py +1 -1
- utilities/pydantic_settings.py +77 -7
- {dycw_utilities-0.168.1.dist-info → dycw_utilities-0.168.3.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.168.1.dist-info → dycw_utilities-0.168.3.dist-info}/entry_points.txt +0 -0
- {dycw_utilities-0.168.1.dist-info → dycw_utilities-0.168.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
utilities/__init__.py,sha256=
|
|
1
|
+
utilities/__init__.py,sha256=akCN41GmYDQTP5HE40wt3_aYKHnVSsekCRG-YWzaPys,60
|
|
2
2
|
utilities/aeventkit.py,sha256=OmDBhYGgbsKrB7cdC5FFpJHUatX9O76eTeKVVTksp2Y,12673
|
|
3
3
|
utilities/altair.py,sha256=nHdpWt8ZwdUwRQN970MvHd5bRWokNqzHcZQEdSHKRuE,9033
|
|
4
4
|
utilities/asyncio.py,sha256=60l1IwjnRGeaVphAFiwDIHyfKoZYKY-XGpptUxGiU-M,17034
|
|
@@ -55,7 +55,7 @@ utilities/pottery.py,sha256=nA0SsF9irvfC0tk68YAr08tuL9lGRSlBKihSx7Ibk84,3963
|
|
|
55
55
|
utilities/pqdm.py,sha256=idv2seRVP2f6NeSfpeEnT5A-tQezaHZKDyeu16g2-0E,3091
|
|
56
56
|
utilities/psutil.py,sha256=KUlu4lrUw9Zg1V7ZGetpWpGb9DB8l_SSDWGbANFNCPU,2104
|
|
57
57
|
utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
58
|
-
utilities/pydantic_settings.py,sha256=
|
|
58
|
+
utilities/pydantic_settings.py,sha256=dUDGQZLlydPncxBblM1DPBfeSNqhQMb7CghNhF1ojJM,7501
|
|
59
59
|
utilities/pydantic_settings_sops.py,sha256=9Ou6Cx6PiYOU49vtkKqqW1Sdp_i3WlVyg8KkUUKNliM,2310
|
|
60
60
|
utilities/pyinstrument.py,sha256=hnXaL-4HE7wWBI5JKaPfYTpsrXe68YiuZKahHV0VJn8,841
|
|
61
61
|
utilities/pytest.py,sha256=6o2qoAPygQLveU8t1JOdzAGmZ96Hs5jFn9OT_mcDNCk,10062
|
|
@@ -93,8 +93,8 @@ utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
|
|
|
93
93
|
utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
94
94
|
utilities/pytest_plugins/pytest_randomly.py,sha256=B1qYVlExGOxTywq2r1SMi5o7btHLk2PNdY_b1p98dkE,409
|
|
95
95
|
utilities/pytest_plugins/pytest_regressions.py,sha256=mnHYBfdprz50UGVkVzV1bZERZN5CFfoF8YbokGxdFwU,1639
|
|
96
|
-
dycw_utilities-0.168.
|
|
97
|
-
dycw_utilities-0.168.
|
|
98
|
-
dycw_utilities-0.168.
|
|
99
|
-
dycw_utilities-0.168.
|
|
100
|
-
dycw_utilities-0.168.
|
|
96
|
+
dycw_utilities-0.168.3.dist-info/METADATA,sha256=C-u-XyBFD2YANapH8wgw8GOkrMgHTFbj0pzPd9U_Fvw,1699
|
|
97
|
+
dycw_utilities-0.168.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
98
|
+
dycw_utilities-0.168.3.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
|
|
99
|
+
dycw_utilities-0.168.3.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
|
100
|
+
dycw_utilities-0.168.3.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/pydantic_settings.py
CHANGED
|
@@ -2,10 +2,12 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from functools import reduce
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import TYPE_CHECKING, Any, ClassVar, assert_never, override
|
|
5
|
+
from typing import TYPE_CHECKING, Any, ClassVar, assert_never, cast, override
|
|
6
6
|
|
|
7
|
+
from pydantic import Field, create_model
|
|
7
8
|
from pydantic_settings import (
|
|
8
9
|
BaseSettings,
|
|
10
|
+
CliSettingsSource,
|
|
9
11
|
JsonConfigSettingsSource,
|
|
10
12
|
PydanticBaseSettingsSource,
|
|
11
13
|
SettingsConfigDict,
|
|
@@ -14,6 +16,7 @@ from pydantic_settings import (
|
|
|
14
16
|
)
|
|
15
17
|
from pydantic_settings.sources import DEFAULT_PATH
|
|
16
18
|
|
|
19
|
+
from utilities.errors import ImpossibleCaseError
|
|
17
20
|
from utilities.iterables import always_iterable
|
|
18
21
|
|
|
19
22
|
if TYPE_CHECKING:
|
|
@@ -29,7 +32,7 @@ type PathLikeOrWithSection = PathLike | PathLikeWithSection
|
|
|
29
32
|
|
|
30
33
|
|
|
31
34
|
class CustomBaseSettings(BaseSettings):
|
|
32
|
-
"""Base settings for loading JSON files."""
|
|
35
|
+
"""Base settings for loading JSON/TOML/YAML files."""
|
|
33
36
|
|
|
34
37
|
# paths
|
|
35
38
|
json_files: ClassVar[Sequence[PathLikeOrWithSection]] = []
|
|
@@ -76,11 +79,6 @@ class CustomBaseSettings(BaseSettings):
|
|
|
76
79
|
)
|
|
77
80
|
|
|
78
81
|
|
|
79
|
-
def load_settings[T: BaseSettings](cls: type[T], /) -> T:
|
|
80
|
-
"""Load a set of settings."""
|
|
81
|
-
return cls()
|
|
82
|
-
|
|
83
|
-
|
|
84
82
|
class JsonConfigSectionSettingsSource(JsonConfigSettingsSource):
|
|
85
83
|
@override
|
|
86
84
|
def __init__(
|
|
@@ -158,8 +156,80 @@ def _get_section(
|
|
|
158
156
|
return reduce(lambda acc, el: acc.get(el, {}), always_iterable(section), mapping)
|
|
159
157
|
|
|
160
158
|
|
|
159
|
+
##
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class HashableBaseSettings(BaseSettings):
|
|
163
|
+
"""Base settings for loading JSON files."""
|
|
164
|
+
|
|
165
|
+
# config
|
|
166
|
+
model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(frozen=True)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
##
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def load_settings[T: BaseSettings](cls: type[T], /, *, cli: bool = False) -> T:
|
|
173
|
+
"""Load a set of settings."""
|
|
174
|
+
_ = cls.model_rebuild()
|
|
175
|
+
if cli:
|
|
176
|
+
cls_with_defaults = _load_settings_create_model(cls)
|
|
177
|
+
|
|
178
|
+
@classmethod
|
|
179
|
+
def settings_customise_sources(
|
|
180
|
+
cls: type[BaseSettings],
|
|
181
|
+
settings_cls: type[BaseSettings],
|
|
182
|
+
init_settings: PydanticBaseSettingsSource,
|
|
183
|
+
env_settings: PydanticBaseSettingsSource,
|
|
184
|
+
dotenv_settings: PydanticBaseSettingsSource,
|
|
185
|
+
file_secret_settings: PydanticBaseSettingsSource,
|
|
186
|
+
) -> tuple[PydanticBaseSettingsSource, ...]:
|
|
187
|
+
parent = cast(
|
|
188
|
+
"Any", super(cls_with_defaults, cls)
|
|
189
|
+
).settings_customise_sources(
|
|
190
|
+
settings_cls=settings_cls,
|
|
191
|
+
init_settings=init_settings,
|
|
192
|
+
env_settings=env_settings,
|
|
193
|
+
dotenv_settings=dotenv_settings,
|
|
194
|
+
file_secret_settings=file_secret_settings,
|
|
195
|
+
)
|
|
196
|
+
return (
|
|
197
|
+
CliSettingsSource(
|
|
198
|
+
settings_cls, cli_parse_args=True, case_sensitive=False
|
|
199
|
+
),
|
|
200
|
+
*parent,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
cls_use = type(
|
|
204
|
+
cls.__name__,
|
|
205
|
+
(cls_with_defaults,),
|
|
206
|
+
{"settings_customise_sources": settings_customise_sources},
|
|
207
|
+
)
|
|
208
|
+
cls_use = cast("type[T]", cls_use)
|
|
209
|
+
else:
|
|
210
|
+
cls_use = cls
|
|
211
|
+
return cls_use()
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _load_settings_create_model[T: BaseSettings](
|
|
215
|
+
cls: type[T], /, *, values: T | None = None
|
|
216
|
+
) -> type[T]:
|
|
217
|
+
values_use = cls() if values is None else values
|
|
218
|
+
kwargs: dict[str, Any] = {}
|
|
219
|
+
for name, field in cls.model_fields.items():
|
|
220
|
+
if (ann := field.annotation) is None:
|
|
221
|
+
raise ImpossibleCaseError(case=[f"{ann=}"]) # pragma: no cover
|
|
222
|
+
value = getattr(values_use, name)
|
|
223
|
+
if issubclass(ann, BaseSettings):
|
|
224
|
+
kwargs[name] = _load_settings_create_model(ann, values=value)
|
|
225
|
+
else:
|
|
226
|
+
kwargs[name] = (field.annotation, Field(default=value))
|
|
227
|
+
return create_model(cls.__name__, __base__=cls, **kwargs)
|
|
228
|
+
|
|
229
|
+
|
|
161
230
|
__all__ = [
|
|
162
231
|
"CustomBaseSettings",
|
|
232
|
+
"HashableBaseSettings",
|
|
163
233
|
"JsonConfigSectionSettingsSource",
|
|
164
234
|
"TomlConfigSectionSettingsSource",
|
|
165
235
|
"YamlConfigSectionSettingsSource",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|