Skip to content

Commit 09da8bf

Browse files
committed
fix: remove workarounds for generic validation
Obviated by pydantic/pydantic#10666, which does the Right Thing with instances of unparameterized generics.
1 parent 720e9ef commit 09da8bf

File tree

6 files changed

+17
-42
lines changed

6 files changed

+17
-42
lines changed

ampel/base/AmpelBaseModel.py

-16
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
# Last Modified Date: 05.01.2022
88
# Last Modified By: valery brinnel <[email protected]>
99

10-
import warnings
1110
from types import UnionType
1211
from typing import TYPE_CHECKING, Any, Union, get_args, get_origin
1312

@@ -50,21 +49,6 @@ def __init_subclass__(cls, *args, **kwargs) -> None:
5049
and NoneType in get_args(v)
5150
):
5251
setattr(cls, k, None)
53-
# add generic args to defaults if missing
54-
elif (
55-
k in cls.__dict__
56-
and safe_issubclass(v, AmpelBaseModel)
57-
and v.get_model_origin() is type(cls.__dict__[k])
58-
and v.get_model_args() and not cls.__dict__[k].get_model_args()
59-
):
60-
warnings.warn(
61-
DeprecationWarning(
62-
f"field {k} declared as {v}, but default has type {type(cls.__dict__[k])}"
63-
" Adding generic args to default, but this will be an error in the future."
64-
),
65-
stacklevel=1
66-
)
67-
setattr(cls, k, v.model_validate(cls.__dict__[k].model_dump()))
6852
super().__init_subclass__(*args, **kwargs)
6953

7054
@classmethod

ampel/base/AmpelUnit.py

+2-18
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@
77
# Last Modified Date: 09.01.2022
88
# Last Modified By: valery brinnel <[email protected]>
99

10-
import warnings
1110
from functools import partial
1211
from types import MemberDescriptorType, UnionType
1312
from typing import TYPE_CHECKING, Any, ClassVar, Union, get_args, get_origin
1413

1514
from pydantic import BaseModel, ValidationError, create_model
1615

17-
from ampel.base.AmpelBaseModel import AmpelBaseModel, safe_issubclass
16+
from ampel.base.AmpelBaseModel import AmpelBaseModel
1817
from ampel.secret.Secret import Secret
1918
from ampel.types import TRACELESS, Traceless
2019

@@ -72,22 +71,7 @@ def __init_subclass__(cls, *args, **kwargs) -> None:
7271
if k in cls._slot_defaults:
7372
joined_defaults[k] = cls._slot_defaults[k]
7473
continue
75-
# parameterized generic with unparameterized default
76-
if (
77-
safe_issubclass(v, AmpelBaseModel)
78-
and v.get_model_origin() is type(defs[k])
79-
and v.get_model_args() and not defs[k].get_model_args()
80-
):
81-
warnings.warn(
82-
DeprecationWarning(
83-
f"field {k} declared as {v}, but default has type {type(defs[k])}"
84-
" Adding generic args to default, but this will be an error in the future."
85-
),
86-
stacklevel=1
87-
)
88-
joined_defaults[k] = v.model_validate(defs[k].model_dump())
89-
else:
90-
joined_defaults[k] = base.__dict__[k]
74+
joined_defaults[k] = base.__dict__[k]
9175
# if None | with no default
9276
elif get_origin(v) in (Union, UnionType) and NoneType in get_args(v) and k not in joined_defaults:
9377
joined_defaults[k] = None

poetry.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ packages = [{include = "ampel"}]
1818

1919
[tool.poetry.dependencies]
2020
python = "^3.10"
21-
pydantic = "^2.7"
21+
pydantic = "^2.10"
2222
xxhash = "^3.0.0"
2323
PyYAML = "^6.0.0"
2424
ujson = "^5.1.0"

tests/test_AmpelUnit.py

-4
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ class Unit(AmpelUnit):
100100
}
101101

102102

103-
@pytest.mark.filterwarnings("ignore:field .* declared as:DeprecationWarning")
104103
def test_secret_without_type():
105104
class UnitWithSecret(AmpelUnit):
106105
secret: NamedSecret[str] = NamedSecret(label="foo")
@@ -109,9 +108,6 @@ class UnitWithSecret(AmpelUnit):
109108
other: Sequence[int] = [1]
110109

111110
assert UnitWithSecret().secret.get_model_args() == (str,)
112-
assert UnitWithSecret._defaults["secret"].get_model_args() == (
113-
str,
114-
), "parameteized "
115111

116112

117113
def test_slots():

tests/test_AmpelVault.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,20 @@ class HasSecret(AmpelBaseModel):
2828

2929

3030
def test_secret_validation() -> None:
31-
HasSecret(secret=NamedSecret[str](label="foo"))
31+
"""Secret fields can be initialized with and without type hints, but validate if fields are provided"""
32+
secret = HasSecret(secret=NamedSecret[str](label="foo", value="bar")).secret
33+
assert HasSecret(secret=NamedSecret(label="foo", value="bar")).secret == secret
34+
assert HasSecret(**{"secret": {"label": "foo", "value": "bar"}}).secret == secret # type: ignore[arg-type]
35+
# type parameter defaults to Any
36+
NamedSecret(label="foo", value=1)
37+
# validation fails with explicit type hint
3238
with pytest.raises(ValidationError):
33-
HasSecret(secret=NamedSecret(label="foo"))
39+
NamedSecret[str](label="foo", value=1) # type: ignore[arg-type]
40+
# validation succeeds with correct type hint
41+
int_secret = NamedSecret[int](label="foo", value=1)
42+
# but passing the value to a model field will fail
43+
with pytest.raises(ValidationError):
44+
HasSecret(secret=int_secret) # type: ignore[arg-type]
3445

3546

3647
def test_secret_resolution() -> None:

0 commit comments

Comments
 (0)