dycw-utilities 0.132.0__py3-none-any.whl → 0.132.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.132.0
3
+ Version: 0.132.2
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=rp9t0gUqAH2TAe2FasaswzrPMlJ2l6RH0WIc6dPt-DM,60
1
+ utilities/__init__.py,sha256=RYydFF7hiCzHBA5ftJVJGt--0UCdLtJbhMfwLLE87tk,60
2
2
  utilities/aiolimiter.py,sha256=mD0wEiqMgwpty4XTbawFpnkkmJS6R4JRsVXFUaoitSU,628
3
3
  utilities/altair.py,sha256=HeZBVUocjkrTNwwKrClppsIqgNFF-ykv05HfZSoHYno,9104
4
4
  utilities/asyncio.py,sha256=USWMMrHqPVRr20vlIn_n5JLimyqa-5xLhuqDYWJed8A,37586
@@ -78,18 +78,18 @@ utilities/text.py,sha256=ymBFlP_cA8OgNnZRVNs7FAh7OG8HxE6YkiLEMZv5g_A,11297
78
78
  utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
79
79
  utilities/timer.py,sha256=oYqRQ-G-DMOOHB6a4yP5-PJDVimLnbNkMnkOj_jUmFg,2474
80
80
  utilities/traceback.py,sha256=i-790AQbTrDA8MiYyOcYPFpm48I558VR_kL_7x4ypfY,8503
81
- utilities/typed_settings.py,sha256=zUA0_CmVJT5rwrm3e-dZO83OdPXEel4NfVK24NAD5Vk,1779
81
+ utilities/typed_settings.py,sha256=DqJsJjSit9wd_OA3KyMDpx2zatKIi5QhuARI9TPl3rk,3701
82
82
  utilities/types.py,sha256=fuJQiVjKYKL9g3F5H7oW_98Xm1-R5Xq4t4kU-aHxW0M,18826
83
83
  utilities/typing.py,sha256=kVWK6ciV8T0MKxnFQcMSEr_XlRisspH5aBTTosMUh30,13872
84
84
  utilities/tzdata.py,sha256=fgNVj66yUbCSI_-vrRVzSD3gtf-L_8IEJEPjP_Jel5Y,266
85
- utilities/tzlocal.py,sha256=xbBBzVIUKMk8AkhuIp1qxGRNBioIa5I09dpeoBnIOOU,662
85
+ utilities/tzlocal.py,sha256=KyCXEgCTjqGFx-389JdTuhMRUaT06U1RCMdWoED-qro,728
86
86
  utilities/uuid.py,sha256=jJTFxz-CWgltqNuzmythB7iEQ-Q1mCwPevUfKthZT3c,611
87
87
  utilities/version.py,sha256=ufhJMmI6KPs1-3wBI71aj5wCukd3sP_m11usLe88DNA,5117
88
88
  utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
89
89
  utilities/whenever.py,sha256=tArX9unVEKhRYdvbUFa83e4hrzdtMKKCEN4QWTaYd8c,19524
90
90
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
91
91
  utilities/zoneinfo.py,sha256=oEH-nL3t4h9uawyZqWDtNtDAl6M-CLpLYGI_nI6DulM,1971
92
- dycw_utilities-0.132.0.dist-info/METADATA,sha256=uup-06B--FHZD8qwwZxSe2XuXJvBLf6F5QPidKDvHCg,1584
93
- dycw_utilities-0.132.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
- dycw_utilities-0.132.0.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
- dycw_utilities-0.132.0.dist-info/RECORD,,
92
+ dycw_utilities-0.132.2.dist-info/METADATA,sha256=w5I6ev0jGeLsqltZGkzBTijkicnDJObi8fINbNUcYI4,1584
93
+ dycw_utilities-0.132.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
+ dycw_utilities-0.132.2.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
+ dycw_utilities-0.132.2.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.132.0"
3
+ __version__ = "0.132.2"
@@ -1,8 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from dataclasses import dataclass
4
+ from ipaddress import IPv4Address, IPv6Address
5
+ from pathlib import Path
6
+ from re import search
3
7
  from typing import TYPE_CHECKING, Any, TypeVar, override
4
8
 
9
+ import typed_settings
10
+ from typed_settings import EnvLoader, FileLoader, find
5
11
  from typed_settings.converters import TSConverter
12
+ from typed_settings.loaders import TomlFormat
6
13
  from whenever import (
7
14
  Date,
8
15
  DateDelta,
@@ -13,13 +20,23 @@ from whenever import (
13
20
  ZonedDateTime,
14
21
  )
15
22
 
23
+ from utilities.iterables import always_iterable
24
+
16
25
  if TYPE_CHECKING:
17
26
  from collections.abc import Callable
18
27
 
28
+ from typed_settings.loaders import Loader
29
+ from typed_settings.processors import Processor
30
+
31
+ from utilities.types import MaybeIterable, PathLike
32
+
19
33
 
20
34
  _T = TypeVar("_T")
21
35
 
22
36
 
37
+ ##
38
+
39
+
23
40
  class ExtendedTSConverter(TSConverter):
24
41
  """An extension of the TSConverter for custom types."""
25
42
 
@@ -35,6 +52,8 @@ class ExtendedTSConverter(TSConverter):
35
52
  (Date, Date.parse_common_iso),
36
53
  (DateDelta, DateDelta.parse_common_iso),
37
54
  (DateTimeDelta, DateTimeDelta.parse_common_iso),
55
+ (IPv4Address, IPv4Address),
56
+ (IPv6Address, IPv6Address),
38
57
  (PlainDateTime, PlainDateTime.parse_common_iso),
39
58
  (Time, Time.parse_common_iso),
40
59
  (TimeDelta, TimeDelta.parse_common_iso),
@@ -58,4 +77,48 @@ def _make_converter(
58
77
  return hook
59
78
 
60
79
 
61
- __all__ = ["ExtendedTSConverter"]
80
+ ##
81
+
82
+ _BASE_DIR: Path = Path()
83
+
84
+
85
+ def load_settings(
86
+ cls: type[_T],
87
+ app_name: str,
88
+ /,
89
+ *,
90
+ filenames: MaybeIterable[str] = "settings.toml",
91
+ start_dir: PathLike | None = None,
92
+ loaders: MaybeIterable[Loader] | None = None,
93
+ processors: MaybeIterable[Processor] = (),
94
+ base_dir: Path = _BASE_DIR,
95
+ ) -> _T:
96
+ if not search(r"^[A-Za-z]+(?:_[A-Za-z]+)*$", app_name):
97
+ raise LoadSettingsError(appname=app_name)
98
+ filenames_use = list(always_iterable(filenames))
99
+ start_dir_use = None if start_dir is None else Path(start_dir)
100
+ files = [find(filename, start_dir=start_dir_use) for filename in filenames_use]
101
+ file_loader = FileLoader(formats={"*.toml": TomlFormat(app_name)}, files=files)
102
+ env_loader = EnvLoader(f"{app_name.upper()}__", nested_delimiter="__")
103
+ loaders_use: list[Loader] = [file_loader, env_loader]
104
+ if loaders is not None:
105
+ loaders_use.extend(always_iterable(loaders))
106
+ return typed_settings.load_settings(
107
+ cls,
108
+ loaders_use,
109
+ processors=list(always_iterable(processors)),
110
+ converter=ExtendedTSConverter(),
111
+ base_dir=base_dir,
112
+ )
113
+
114
+
115
+ @dataclass(kw_only=True, slots=True)
116
+ class LoadSettingsError(Exception):
117
+ appname: str
118
+
119
+ @override
120
+ def __str__(self) -> str:
121
+ return f"Invalid app name; got {self.appname!r}"
122
+
123
+
124
+ __all__ = ["ExtendedTSConverter", "LoadSettingsError", "load_settings"]
utilities/tzlocal.py CHANGED
@@ -1,13 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from logging import getLogger
4
- from typing import TYPE_CHECKING
4
+ from typing import TYPE_CHECKING, cast
5
5
 
6
6
  from tzlocal import get_localzone
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from zoneinfo import ZoneInfo
10
10
 
11
+ from utilities.types import TimeZone
12
+
11
13
 
12
14
  def get_local_time_zone() -> ZoneInfo:
13
15
  """Get the local time zone, with the logging disabled."""
@@ -20,7 +22,7 @@ def get_local_time_zone() -> ZoneInfo:
20
22
 
21
23
 
22
24
  LOCAL_TIME_ZONE = get_local_time_zone()
23
- LOCAL_TIME_ZONE_NAME = LOCAL_TIME_ZONE.key
25
+ LOCAL_TIME_ZONE_NAME = cast("TimeZone", LOCAL_TIME_ZONE.key)
24
26
 
25
27
 
26
28
  __all__ = ["LOCAL_TIME_ZONE", "LOCAL_TIME_ZONE_NAME", "get_local_time_zone"]