configaroo 0.2.4__py3-none-any.whl → 0.4.0__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.
- configaroo/__init__.py +1 -1
- configaroo/configuration.py +35 -32
- configaroo/loaders/__init__.py +6 -1
- {configaroo-0.2.4.dist-info → configaroo-0.4.0.dist-info}/METADATA +1 -1
- configaroo-0.4.0.dist-info/RECORD +12 -0
- configaroo-0.2.4.dist-info/RECORD +0 -12
- {configaroo-0.2.4.dist-info → configaroo-0.4.0.dist-info}/WHEEL +0 -0
- {configaroo-0.2.4.dist-info → configaroo-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {configaroo-0.2.4.dist-info → configaroo-0.4.0.dist-info}/top_level.txt +0 -0
configaroo/__init__.py
CHANGED
configaroo/configuration.py
CHANGED
@@ -36,33 +36,20 @@ class Configuration(UserDict[str, Any]):
|
|
36
36
|
def from_file(
|
37
37
|
cls,
|
38
38
|
file_path: str | Path,
|
39
|
+
*,
|
39
40
|
loader: str | None = None,
|
40
|
-
|
41
|
-
env_prefix: str = "",
|
42
|
-
extra_dynamic: dict[str, Any] | None = None,
|
41
|
+
not_exist_ok: bool = False,
|
43
42
|
) -> Self:
|
44
|
-
"""Read a Configuration from a file.
|
45
|
-
config_dict = loaders.from_file(file_path, loader=loader)
|
46
|
-
return cls(config_dict).initialize(
|
47
|
-
envs=envs, env_prefix=env_prefix, extra_dynamic=extra_dynamic
|
48
|
-
)
|
49
|
-
|
50
|
-
def initialize(
|
51
|
-
self,
|
52
|
-
envs: dict[str, str] | None = None,
|
53
|
-
env_prefix: str = "",
|
54
|
-
extra_dynamic: dict[str, Any] | None = None,
|
55
|
-
) -> Self:
|
56
|
-
"""Initialize a configuration.
|
43
|
+
"""Read a Configuration from a file.
|
57
44
|
|
58
|
-
|
45
|
+
If not_exist_ok is True, then a missing file returns an empty
|
46
|
+
configuration. This may be useful if the configuration is potentially
|
47
|
+
populated by environment variables.
|
59
48
|
"""
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
"""Apply a pydantic model to a configuration."""
|
65
|
-
return self.validate_model(model).convert_model(model)
|
49
|
+
config_dict = loaders.from_file(
|
50
|
+
file_path, loader=loader, not_exist_ok=not_exist_ok
|
51
|
+
)
|
52
|
+
return cls(config_dict)
|
66
53
|
|
67
54
|
def __getitem__(self, key: str) -> Any: # noqa: ANN401
|
68
55
|
"""Make sure nested sections have type Configuration."""
|
@@ -112,8 +99,22 @@ class Configuration(UserDict[str, Any]):
|
|
112
99
|
cls = type(self)
|
113
100
|
return self | {prefix: cls(self.setdefault(prefix, {})).add(rest, value)}
|
114
101
|
|
115
|
-
def add_envs(self, envs: dict[str, str], prefix: str = "") -> Self:
|
116
|
-
"""Add environment variables to configuration.
|
102
|
+
def add_envs(self, envs: dict[str, str] | None = None, prefix: str = "") -> Self:
|
103
|
+
"""Add environment variables to configuration.
|
104
|
+
|
105
|
+
If you don't specify which environment variables to read, you'll
|
106
|
+
automatically add any that matches a top-level value of the
|
107
|
+
configuration.
|
108
|
+
"""
|
109
|
+
if envs is None:
|
110
|
+
# Automatically add top-level configuration items
|
111
|
+
envs = {
|
112
|
+
re.sub(r"\W", "_", key).upper(): key
|
113
|
+
for key, value in self.data.items()
|
114
|
+
if isinstance(value, str | int | float)
|
115
|
+
}
|
116
|
+
|
117
|
+
# Read environment variables
|
117
118
|
for env, key in envs.items():
|
118
119
|
env_key = f"{prefix}{env}"
|
119
120
|
if env_value := os.getenv(env_key):
|
@@ -129,7 +130,7 @@ class Configuration(UserDict[str, Any]):
|
|
129
130
|
cls = type(self)
|
130
131
|
variables = (
|
131
132
|
(self.to_flat_dict() if _include_self else {})
|
132
|
-
| {"project_path":
|
133
|
+
| {"project_path": find_pyproject_toml()}
|
133
134
|
| ({} if extra is None else extra)
|
134
135
|
)
|
135
136
|
parsed = cls(
|
@@ -158,6 +159,10 @@ class Configuration(UserDict[str, Any]):
|
|
158
159
|
"""Convert data types to match the given model."""
|
159
160
|
return model(**self.data)
|
160
161
|
|
162
|
+
def with_model(self, model: type[ModelT]) -> ModelT:
|
163
|
+
"""Apply a pydantic model to a configuration."""
|
164
|
+
return self.validate_model(model).convert_model(model)
|
165
|
+
|
161
166
|
def to_dict(self) -> dict[str, Any]:
|
162
167
|
"""Dump the configuration into a Python dictionary."""
|
163
168
|
return {
|
@@ -196,16 +201,14 @@ def print_configuration(config: Configuration | BaseModel, indent: int = 4) -> N
|
|
196
201
|
)
|
197
202
|
|
198
203
|
|
199
|
-
def _get_rich_print() -> Callable[[str], None]:
|
204
|
+
def _get_rich_print() -> Callable[[str], None]: # pragma: no cover
|
200
205
|
"""Initialize a Rich console if Rich is installed, otherwise use built-in print."""
|
201
206
|
try:
|
202
207
|
from rich.console import Console # noqa: PLC0415
|
203
208
|
|
204
209
|
return Console().print
|
205
210
|
except ImportError:
|
206
|
-
|
207
|
-
|
208
|
-
return builtins.print
|
211
|
+
return print
|
209
212
|
|
210
213
|
|
211
214
|
def _print_dict_as_tree(
|
@@ -228,7 +231,7 @@ def _print_dict_as_tree(
|
|
228
231
|
_print(" " * current_indent + f"- {key}: {value!r}")
|
229
232
|
|
230
233
|
|
231
|
-
def
|
234
|
+
def find_pyproject_toml(
|
232
235
|
path: Path | None = None, _file_name: str = "pyproject.toml"
|
233
236
|
) -> Path:
|
234
237
|
"""Find a directory that contains a pyproject.toml file.
|
@@ -241,7 +244,7 @@ def _find_pyproject_toml(
|
|
241
244
|
if (path / _file_name).exists() or path == path.parent:
|
242
245
|
return path.resolve()
|
243
246
|
|
244
|
-
return
|
247
|
+
return find_pyproject_toml(path.parent, _file_name=_file_name)
|
245
248
|
|
246
249
|
|
247
250
|
def _get_foreign_path() -> Path:
|
configaroo/loaders/__init__.py
CHANGED
@@ -26,9 +26,14 @@ def loader_names() -> list[str]:
|
|
26
26
|
return sorted(pyplugs.names(PACKAGE))
|
27
27
|
|
28
28
|
|
29
|
-
def from_file(
|
29
|
+
def from_file(
|
30
|
+
path: str | Path, *, loader: str | None = None, not_exist_ok: bool = False
|
31
|
+
) -> dict[str, Any]:
|
30
32
|
"""Load a file using a loader defined by the suffix if necessary."""
|
31
33
|
path = Path(path)
|
34
|
+
if not path.exists() and not_exist_ok:
|
35
|
+
return {}
|
36
|
+
|
32
37
|
loader = path.suffix.lstrip(".") if loader is None else loader
|
33
38
|
try:
|
34
39
|
return load(loader, path=path)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
configaroo/__init__.py,sha256=zlCtdtE7UWy7SWKYq_NfGX0uUvO8l5-xRj1mB1Bn3Ac,412
|
2
|
+
configaroo/configuration.py,sha256=hMo9INlvD3OwjYeK0PJpun8T8x6wfAl8t1ZM2_EaqvY,9823
|
3
|
+
configaroo/exceptions.py,sha256=GfLf3CLfHStiQjvdS7ZAtrKF9gmGL_8biFLayue6J0M,772
|
4
|
+
configaroo/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
configaroo/loaders/__init__.py,sha256=XQrFwCMWzQ71ykaZFPmYysDz12y_elPqxWhUMQCsq3s,1076
|
6
|
+
configaroo/loaders/json.py,sha256=fT2Lg4hPM2BuwqrDsP7bcJlepAdmEh2iKU-YVK4KmIA,306
|
7
|
+
configaroo/loaders/toml.py,sha256=jw9U78Lf-GMA8QmGIM8xMBqOhPaa8ITSMAhhN1ZNyng,256
|
8
|
+
configaroo-0.4.0.dist-info/licenses/LICENSE,sha256=rdeT6Y5bm0MUaERso7HRWpPj37Y1RD5li2lIQaMNJjc,1090
|
9
|
+
configaroo-0.4.0.dist-info/METADATA,sha256=6527XCdJ8w6eo3v693VifE-AzR1ZUw4tCGeSEXAomUs,2672
|
10
|
+
configaroo-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
11
|
+
configaroo-0.4.0.dist-info/top_level.txt,sha256=JVYICl1cWSjvSOZuZMYm976z9lnZaWtHVRSt373QCxg,11
|
12
|
+
configaroo-0.4.0.dist-info/RECORD,,
|
@@ -1,12 +0,0 @@
|
|
1
|
-
configaroo/__init__.py,sha256=OcTq-Fj19iymbgbNPYt5euEv1C4bw1vPxZ5OQTnej7A,412
|
2
|
-
configaroo/configuration.py,sha256=1wkwPEkpqbwphh7YUmQWkVRpzUu6CIJWCZq5hZHylco,9729
|
3
|
-
configaroo/exceptions.py,sha256=GfLf3CLfHStiQjvdS7ZAtrKF9gmGL_8biFLayue6J0M,772
|
4
|
-
configaroo/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
configaroo/loaders/__init__.py,sha256=l2pHeD9PJ3ZQA5xUCq9nfFqw2YhAHLeTe50wvhMmTYA,977
|
6
|
-
configaroo/loaders/json.py,sha256=fT2Lg4hPM2BuwqrDsP7bcJlepAdmEh2iKU-YVK4KmIA,306
|
7
|
-
configaroo/loaders/toml.py,sha256=jw9U78Lf-GMA8QmGIM8xMBqOhPaa8ITSMAhhN1ZNyng,256
|
8
|
-
configaroo-0.2.4.dist-info/licenses/LICENSE,sha256=rdeT6Y5bm0MUaERso7HRWpPj37Y1RD5li2lIQaMNJjc,1090
|
9
|
-
configaroo-0.2.4.dist-info/METADATA,sha256=0BOSHrCgGd3qoMAzyqDf5loteaUivWpFwbjA0yb32ck,2672
|
10
|
-
configaroo-0.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
11
|
-
configaroo-0.2.4.dist-info/top_level.txt,sha256=JVYICl1cWSjvSOZuZMYm976z9lnZaWtHVRSt373QCxg,11
|
12
|
-
configaroo-0.2.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|