Skip to content

Commit 9ed4030

Browse files
committed
Make load_config() accept a base_schema
This is necessary to use custom fields when loading configurations. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent 0642d3a commit 9ed4030

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

RELEASE_NOTES.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010

1111
## New Features
1212

13-
<!-- Here goes the main new features and examples or instructions on how to use them -->
13+
14+
- `frequenz.sdk.config.load_config()` can now use a base schema to customize even further how data is loaded.
1415

1516
## Bug Fixes
1617

src/frequenz/sdk/config/_util.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from collections.abc import Mapping
77
from typing import Any, TypeVar, cast
88

9+
from marshmallow import Schema
910
from marshmallow_dataclass import class_schema
1011

1112
T = TypeVar("T")
@@ -16,6 +17,7 @@ def load_config(
1617
cls: type[T],
1718
config: Mapping[str, Any],
1819
/,
20+
base_schema: type[Schema] | None = None,
1921
**marshmallow_load_kwargs: Any,
2022
) -> T:
2123
"""Load a configuration from a dictionary into an instance of a configuration class.
@@ -42,13 +44,16 @@ def load_config(
4244
Args:
4345
cls: The configuration class.
4446
config: The configuration dictionary.
47+
base_schema: An optional class to be used as a base schema for the configuration
48+
class. This allow using custom fields for example. Will be passed to
49+
[`marshmallow_dataclass.class_schema`][].
4550
**marshmallow_load_kwargs: Additional arguments to be passed to
4651
[`marshmallow.Schema.load`][].
4752
4853
Returns:
4954
The loaded configuration as an instance of the configuration class.
5055
"""
51-
instance = class_schema(cls)().load(config, **marshmallow_load_kwargs)
56+
instance = class_schema(cls, base_schema)().load(config, **marshmallow_load_kwargs)
5257
# We need to cast because `.load()` comes from marshmallow and doesn't know which
5358
# type is returned.
5459
return cast(T, instance)

tests/config/test_util.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,27 @@ def test_load_config_load_None() -> None:
3737
"""Test that load_config raises ValidationError if the configuration is None."""
3838
config: dict[str, Any] = {}
3939
with pytest.raises(marshmallow.ValidationError):
40-
_ = load_config(MmSimpleConfig, config.get("loggers", None))
40+
_ = load_config(SimpleConfig, config.get("loggers", None))
41+
42+
43+
def test_load_config_with_base_schema() -> None:
44+
"""Test that load_config loads a configuration using a base schema."""
45+
46+
class _MyBaseSchema(marshmallow.Schema):
47+
"""A base schema for testing."""
48+
49+
class Meta:
50+
"""Meta options for the schema."""
51+
52+
unknown = marshmallow.EXCLUDE
53+
54+
config: dict[str, Any] = {"name": "test", "value": 42, "extra": "extra"}
55+
56+
loaded_config = load_config(SimpleConfig, config, base_schema=_MyBaseSchema)
57+
assert loaded_config == SimpleConfig(name="test", value=42)
58+
59+
with pytest.raises(marshmallow.ValidationError):
60+
_ = load_config(SimpleConfig, config)
4161

4262

4363
def test_load_config_type_hints(mocker: MockerFixture) -> None:

0 commit comments

Comments
 (0)