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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.168.1
3
+ Version: 0.168.3
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=OrbMLBGcu3xLdMPQ4r4I_hMdXdAIG1S5Jw5pNJuMvfk,60
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=wwuvW12ZVhJfoAJoiQpVT8EDVyNm79H3cWJR7u-wMQo,5115
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.1.dist-info/METADATA,sha256=7jVdRmilyNEQ9D64FlUih9pQEMUGQwKz0SvvbkcKgr4,1699
97
- dycw_utilities-0.168.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
98
- dycw_utilities-0.168.1.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
99
- dycw_utilities-0.168.1.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
100
- dycw_utilities-0.168.1.dist-info/RECORD,,
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
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.168.1"
3
+ __version__ = "0.168.3"
@@ -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",