configaroo 0.1.2__tar.gz → 0.2.0__tar.gz

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.
Files changed (23) hide show
  1. {configaroo-0.1.2 → configaroo-0.2.0}/PKG-INFO +1 -1
  2. {configaroo-0.1.2 → configaroo-0.2.0}/pyproject.toml +1 -1
  3. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo/__init__.py +1 -1
  4. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo/configuration.py +13 -14
  5. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo.egg-info/PKG-INFO +1 -1
  6. {configaroo-0.1.2 → configaroo-0.2.0}/tests/test_validation.py +18 -5
  7. {configaroo-0.1.2 → configaroo-0.2.0}/LICENSE +0 -0
  8. {configaroo-0.1.2 → configaroo-0.2.0}/README.md +0 -0
  9. {configaroo-0.1.2 → configaroo-0.2.0}/setup.cfg +0 -0
  10. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo/exceptions.py +0 -0
  11. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo/loaders/__init__.py +0 -0
  12. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo/loaders/json.py +0 -0
  13. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo/loaders/toml.py +0 -0
  14. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo/py.typed +0 -0
  15. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo.egg-info/SOURCES.txt +0 -0
  16. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo.egg-info/dependency_links.txt +0 -0
  17. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo.egg-info/requires.txt +0 -0
  18. {configaroo-0.1.2 → configaroo-0.2.0}/src/configaroo.egg-info/top_level.txt +0 -0
  19. {configaroo-0.1.2 → configaroo-0.2.0}/tests/test_configuration.py +0 -0
  20. {configaroo-0.1.2 → configaroo-0.2.0}/tests/test_environment.py +0 -0
  21. {configaroo-0.1.2 → configaroo-0.2.0}/tests/test_json.py +0 -0
  22. {configaroo-0.1.2 → configaroo-0.2.0}/tests/test_loaders.py +0 -0
  23. {configaroo-0.1.2 → configaroo-0.2.0}/tests/test_toml.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: configaroo
3
- Version: 0.1.2
3
+ Version: 0.2.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>
@@ -50,7 +50,7 @@ dev = [
50
50
  version = { attr = "configaroo.__version__" }
51
51
 
52
52
  [tool.bumpver]
53
- current_version = "v0.1.2"
53
+ current_version = "v0.2.0"
54
54
  version_pattern = "vMAJOR.MINOR.PATCH"
55
55
  commit_message = "bump version {old_version} -> {new_version}"
56
56
  tag_message = "{new_version}"
@@ -7,4 +7,4 @@ from configaroo.exceptions import ( # noqa
7
7
  UnsupportedLoaderError,
8
8
  )
9
9
 
10
- __version__ = "0.1.2"
10
+ __version__ = "0.2.0"
@@ -5,13 +5,15 @@ import os
5
5
  import re
6
6
  from collections import UserDict
7
7
  from pathlib import Path
8
- from typing import Any, Self, Type
8
+ from typing import Any, Self, Type, TypeVar
9
9
 
10
10
  from pydantic import BaseModel
11
11
 
12
12
  from configaroo import loaders
13
13
  from configaroo.exceptions import MissingEnvironmentVariableError
14
14
 
15
+ ModelT = TypeVar("ModelT", bound=BaseModel)
16
+
15
17
 
16
18
  class Configuration(UserDict):
17
19
  """A Configuration is a dict-like structure with some conveniences"""
@@ -24,12 +26,11 @@ class Configuration(UserDict):
24
26
  envs: dict[str, str] | None = None,
25
27
  env_prefix: str = "",
26
28
  extra_dynamic: dict[str, Any] | None = None,
27
- model: Type[BaseModel] | None = None,
28
29
  ) -> Self:
29
30
  """Read a Configuration from a file"""
30
31
  config_dict = loaders.from_file(file_path, loader=loader)
31
32
  return cls(config_dict).initialize(
32
- envs=envs, env_prefix=env_prefix, extra_dynamic=extra_dynamic, model=model
33
+ envs=envs, env_prefix=env_prefix, extra_dynamic=extra_dynamic
33
34
  )
34
35
 
35
36
  def initialize(
@@ -37,18 +38,17 @@ class Configuration(UserDict):
37
38
  envs: dict[str, str] | None = None,
38
39
  env_prefix: str = "",
39
40
  extra_dynamic: dict[str, Any] | None = None,
40
- model: Type[BaseModel] | None = None,
41
41
  ) -> Self:
42
42
  """Initialize a configuration.
43
43
 
44
- The initialization adds environment variables, parses dynamic values,
45
- validates against a Pydantic model, and converts value types using the
46
- same model.
44
+ The initialization adds environment variables and parses dynamic values.
47
45
  """
48
46
  self = self if envs is None else self.add_envs(envs, prefix=env_prefix)
49
- self = self.parse_dynamic(extra_dynamic)
50
- self = self if model is None else self.validate(model).convert(model)
51
- return self
47
+ return self.parse_dynamic(extra_dynamic)
48
+
49
+ def with_model(self, model: Type[ModelT]) -> ModelT:
50
+ """Apply a pydantic model to a configuration."""
51
+ return self.validate_model(model).convert_model(model)
52
52
 
53
53
  def __getitem__(self, key: str) -> Any:
54
54
  """Make sure nested sections have type Configuration"""
@@ -129,15 +129,14 @@ class Configuration(UserDict):
129
129
  }
130
130
  )
131
131
 
132
- def validate(self, model: Type[BaseModel]) -> Self:
132
+ def validate_model(self, model: Type[BaseModel]) -> Self:
133
133
  """Validate the configuration against the given model."""
134
134
  model.model_validate(self.data)
135
135
  return self
136
136
 
137
- def convert(self, model: Type[BaseModel]) -> Self:
137
+ def convert_model(self, model: Type[ModelT]) -> ModelT:
138
138
  """Convert data types to match the given model"""
139
- cls = type(self)
140
- return cls(model(**self.data).model_dump())
139
+ return model(**self.data)
141
140
 
142
141
  def to_dict(self) -> dict[str, Any]:
143
142
  """Dump the configuration into a Python dictionary"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: configaroo
3
- Version: 0.1.2
3
+ Version: 0.2.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>
@@ -10,7 +10,7 @@ from configaroo import Configuration
10
10
 
11
11
  def test_can_validate(config, model):
12
12
  """Test that a configuration can be validated"""
13
- assert config.validate(model)
13
+ assert config.validate_model(model)
14
14
 
15
15
 
16
16
  def test_wrong_key_raises(model):
@@ -19,24 +19,37 @@ def test_wrong_key_raises(model):
19
19
  digit=4, nested={"pie": 3.14, "seven": 7}, path="files/config.toml"
20
20
  )
21
21
  with pytest.raises(pydantic.ValidationError):
22
- config.validate(model)
22
+ config.validate_model(model)
23
23
 
24
24
 
25
25
  def test_missing_key_raises(model):
26
26
  """Test that a missing key raises an error"""
27
27
  config = Configuration(nested={"pie": 3.14, "seven": 7}, path="files/config.toml")
28
28
  with pytest.raises(pydantic.ValidationError):
29
- config.validate(model)
29
+ config.validate_model(model)
30
30
 
31
31
 
32
32
  def test_extra_key_ok(config, model):
33
33
  """Test that an extra key raises when the model is strict"""
34
34
  updated_config = config | {"new_word": "cuckoo-bird"}
35
35
  with pytest.raises(pydantic.ValidationError):
36
- updated_config.validate(model)
36
+ updated_config.validate_model(model)
37
37
 
38
38
 
39
39
  def test_type_conversion(config, model):
40
- config_w_types = config.convert(model)
40
+ """Test that types can be converted based on the model"""
41
+ config_w_types = config.convert_model(model)
41
42
  assert isinstance(config.paths.relative, str)
42
43
  assert isinstance(config_w_types.paths.relative, Path)
44
+
45
+
46
+ def test_converted_model_is_pydantic(config, model):
47
+ """Test that the converted model is a BaseModel which helps with auto-complete"""
48
+ config_w_types = config.convert_model(model=model)
49
+ assert isinstance(config_w_types, pydantic.BaseModel)
50
+
51
+
52
+ def test_validate_and_convert(config, model):
53
+ config_w_model = config.with_model(model)
54
+ assert isinstance(config_w_model, pydantic.BaseModel)
55
+ assert isinstance(config_w_model.paths.relative, Path)
File without changes
File without changes
File without changes