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 CHANGED
@@ -15,4 +15,4 @@ __all__ = [
15
15
  "print_configuration",
16
16
  ]
17
17
 
18
- __version__ = "0.2.4"
18
+ __version__ = "0.4.0"
@@ -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
- envs: dict[str, str] | None = None,
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
- The initialization adds environment variables and parses dynamic values.
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
- self = self if envs is None else self.add_envs(envs, prefix=env_prefix) # noqa: PLW0642
61
- return self.parse_dynamic(extra_dynamic)
62
-
63
- def with_model(self, model: type[ModelT]) -> ModelT:
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": _find_pyproject_toml()}
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
- import builtins # noqa: PLC0415
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 _find_pyproject_toml(
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 _find_pyproject_toml(path.parent, _file_name=_file_name)
247
+ return find_pyproject_toml(path.parent, _file_name=_file_name)
245
248
 
246
249
 
247
250
  def _get_foreign_path() -> Path:
@@ -26,9 +26,14 @@ def loader_names() -> list[str]:
26
26
  return sorted(pyplugs.names(PACKAGE))
27
27
 
28
28
 
29
- def from_file(path: str | Path, loader: str | None = None) -> dict[str, Any]:
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: configaroo
3
- Version: 0.2.4
3
+ Version: 0.4.0
4
4
  Summary: Bouncy handling of configuration files
5
5
  Author-email: Geir Arne Hjelle <geirarne@gmail.com>
6
6
  Maintainer-email: Geir Arne Hjelle <geirarne@gmail.com>
@@ -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,,