Skip to content

Commit 33f9763

Browse files
Update pydantic to v2.3 (#703)
This update is necessary to stay current with the latest pydantic version, rather than pinning the library to v1.9.0. However, it's worth noting that this is a temporary solution until Frequenz-SDK is updated to use Marshmallow instead of pydantic, which would require a higher level of effort. One important consideration is the dependency on typing-extensions>=4.6.1 introduced in pydantic v2.0. Additionally, there's a breaking change in pydantic v2, which disallows data type conversion if it results in a loss of precision. This is particularly relevant when converting a float to an int. Consequently, the `test_config.py` file has been updated to accommodate this change. Fixes #500
2 parents 88ad5a1 + c3dce99 commit 33f9763

File tree

3 files changed

+13
-9
lines changed

3 files changed

+13
-9
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ dependencies = [
3737
"networkx >= 2.8, < 4",
3838
"numpy >= 1.24.2, < 2",
3939
"protobuf >= 4.21.6, < 5",
40-
"pydantic >= 1.9, < 2",
40+
"pydantic >= 2.3, < 3",
4141
"tqdm >= 4.38.0, < 5",
42-
"typing_extensions >= 4.4.0, < 5",
42+
"typing_extensions >= 4.6.1, < 5",
4343
"watchfiles >= 0.15.0",
4444
]
4545
dynamic = ["version"]

src/frequenz/sdk/config/_config.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
"""Read and update config variables."""
55

6+
import json
67
import logging
78
from typing import Any, TypeVar
89

9-
# pylint not finding parse_raw_as is a false positive
10-
from pydantic import ValidationError, parse_raw_as # pylint: disable=no-name-in-module
10+
from pydantic import Strict, TypeAdapter, ValidationError
1111

1212
_logger = logging.getLogger(__name__)
1313

@@ -121,7 +121,11 @@ def get_as(self, key: str, expected_type: Any) -> Any:
121121
return value
122122

123123
try:
124-
parsed_value: Any = parse_raw_as(expected_type, value)
124+
obj = json.loads(value)
125+
metadata = getattr(expected_type, "__metadata__", (None,))[0]
126+
strict = metadata.strict if isinstance(metadata, Strict) else False
127+
adapter = TypeAdapter(expected_type)
128+
parsed_value = adapter.validate_python(obj, strict=strict)
125129
except (ValidationError, ValueError) as err:
126130
raise ValueError(
127131
f"Could not convert config variable: {key} = '{value}' "

tests/config/test_config.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,18 @@ def test_contains(self, conf_vars: dict[str, Any]) -> None:
9292
("logging_lvl", str, "DEBUG"),
9393
("var_int", int, 5),
9494
("var_int", StrictInt, 5),
95+
("var_int", StrictFloat, 5.0),
9596
("var_int", float, 5.0),
9697
("var_float", float, 3.14),
9798
("var_float", StrictFloat, 3.14),
98-
("var_float", int, 3),
9999
("var_bool", int, 1),
100100
("var_bool", float, 1.0),
101101
("var_bool", bool, True),
102102
("var1", bool, 1),
103103
("var_bool", StrictBool, True),
104104
("list_int", list[int], [1, 2, 3]),
105105
("list_int", list[StrictInt], [1, 2, 3]),
106-
("list_float", list[int], [1, 2, 3]),
106+
("list_int", list[StrictFloat], [1.0, 2.0, 3.0]),
107107
("list_int", list[float], [1.0, 2.0, 3.0]),
108108
("list_float", list[float], [1, 2.0, 3.5]),
109109
("list_non_strict_bool", list[bool], 2 * [False] + 2 * [True]),
@@ -124,12 +124,12 @@ def test_get_as_success(
124124
@pytest.mark.parametrize(
125125
"key, expected_type",
126126
[
127+
("var_float", int),
127128
("var_float", StrictInt),
128-
("var_int", StrictFloat),
129129
("var1", StrictBool),
130130
("list_float", list[StrictInt]),
131-
("list_int", list[StrictFloat]),
132131
("list_non_strict_bool", list[int]),
132+
("list_float", list[int]),
133133
],
134134
)
135135
def test_get_as_validation_error(

0 commit comments

Comments
 (0)