Skip to content

Commit 1d6104c

Browse files
committed
test: implement basic tests for FlatInitModel
1 parent 3fb6d7a commit 1d6104c

3 files changed

Lines changed: 325 additions & 0 deletions

File tree

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""Pytest entry point for for basic lupl.FlatInitModel test."""
2+
3+
from typing import Any, NamedTuple
4+
5+
from lupl import ConfigDict, FlatInitModel
6+
from pydantic import BaseModel
7+
import pytest
8+
9+
10+
class FlatInitTestParameter(NamedTuple):
11+
model: type[BaseModel]
12+
kwargs: dict[str, Any]
13+
expected: dict[str, Any]
14+
15+
16+
class DeeplyNestedModel1(BaseModel):
17+
z: int
18+
19+
20+
class NestedModel1(BaseModel):
21+
y: int
22+
deeply_nested: DeeplyNestedModel1
23+
24+
25+
class NestedModel2(NestedModel1):
26+
model_config = ConfigDict(model_bool="y")
27+
28+
29+
class NestedModel3(NestedModel1):
30+
model_config = ConfigDict(model_bool=lambda model: model.y < 0)
31+
32+
33+
class NestedModel4(NestedModel1):
34+
model_config = ConfigDict(model_bool={"y", "y2"})
35+
36+
y2: int = 0
37+
38+
39+
class Model1(BaseModel):
40+
x: int
41+
nested: NestedModel1
42+
43+
44+
class Model2(Model1):
45+
model_config = ConfigDict(extra="forbid")
46+
47+
48+
class Model3(Model1):
49+
x: int = 42
50+
51+
52+
class Model4(BaseModel):
53+
x: int
54+
nested: NestedModel2 | str = "default"
55+
56+
57+
class Model5(BaseModel):
58+
x: int
59+
nested: NestedModel3 | str = "default"
60+
61+
62+
class Model6(BaseModel):
63+
x: int
64+
nested: NestedModel4 | str = "default"
65+
66+
67+
class Model7(BaseModel):
68+
x: int
69+
nested: NestedModel1 | None = None
70+
71+
72+
class Model8(BaseModel):
73+
x: int
74+
nested: DeeplyNestedModel1 | None = None
75+
76+
77+
params: list[FlatInitTestParameter] = [
78+
FlatInitTestParameter(
79+
model=Model1,
80+
kwargs={"x": 1, "y": 2, "z": 3},
81+
expected={"x": 1, "nested": {"y": 2, "deeply_nested": {"z": 3}}},
82+
),
83+
FlatInitTestParameter(
84+
model=Model2,
85+
kwargs={"x": 1, "y": 2, "z": 3},
86+
expected={"x": 1, "nested": {"y": 2, "deeply_nested": {"z": 3}}},
87+
),
88+
FlatInitTestParameter(
89+
model=Model1,
90+
kwargs={"x": 1.0, "y": 2.0, "z": 3.0},
91+
expected={"x": 1, "nested": {"y": 2, "deeply_nested": {"z": 3}}},
92+
),
93+
FlatInitTestParameter(
94+
model=Model3,
95+
kwargs={"x": 1, "y": 2, "z": 3},
96+
expected={"x": 1, "nested": {"y": 2, "deeply_nested": {"z": 3}}},
97+
),
98+
FlatInitTestParameter(
99+
model=Model3,
100+
kwargs={"y": 2, "z": 3},
101+
expected={"x": 42, "nested": {"y": 2, "deeply_nested": {"z": 3}}},
102+
),
103+
FlatInitTestParameter(
104+
model=Model4,
105+
kwargs={"x": 1, "y": 2, "z": 3},
106+
expected={"x": 1, "nested": {"y": 2, "deeply_nested": {"z": 3}}},
107+
),
108+
FlatInitTestParameter(
109+
model=Model4,
110+
kwargs={"x": 1, "y": 0, "z": 3},
111+
expected={"x": 1, "nested": "default"},
112+
),
113+
FlatInitTestParameter(
114+
model=Model5,
115+
kwargs={"x": 1, "y": 0, "z": 3},
116+
expected={"x": 1, "nested": "default"},
117+
),
118+
FlatInitTestParameter(
119+
model=Model5,
120+
kwargs={"x": 1, "y": -2, "z": 3},
121+
expected={"x": 1, "nested": {"y": -2, "deeply_nested": {"z": 3}}},
122+
),
123+
FlatInitTestParameter(
124+
model=Model6,
125+
kwargs={"x": 1, "y": 2, "z": 3},
126+
expected={"x": 1, "nested": "default"},
127+
),
128+
FlatInitTestParameter(
129+
model=Model7,
130+
kwargs={"x": 1, "y": 2, "z": 3},
131+
expected={"x": 1, "nested": {"y": 2, "deeply_nested": {"z": 3}}},
132+
),
133+
FlatInitTestParameter(
134+
model=Model8,
135+
kwargs={"x": 1, "z": 3},
136+
expected={"x": 1, "nested": {"z": 3}},
137+
),
138+
FlatInitTestParameter(
139+
model=Model8,
140+
kwargs={"x": 1, "z": 0},
141+
expected={"x": 1, "nested": None},
142+
),
143+
]
144+
145+
146+
@pytest.mark.parametrize("param", params)
147+
def test_basic_flat_init_model(param):
148+
constructor = FlatInitModel(model=param.model)
149+
instance = constructor(**param.kwargs)
150+
151+
assert instance.model_dump() == param.expected
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Pytest entry point for lupl.FlatInitModel model_bool failure tests."""
2+
3+
from lupl import ConfigDict, FlatInitModel
4+
from pydantic import BaseModel
5+
import pytest
6+
7+
8+
class NestedModel1(BaseModel):
9+
model_config = ConfigDict(model_bool=["x"])
10+
11+
12+
class NestedModel2(BaseModel):
13+
model_config = ConfigDict(model_bool=object())
14+
15+
16+
class NestedModel3(BaseModel):
17+
model_config = ConfigDict(model_bool=None)
18+
19+
20+
class Model1(BaseModel):
21+
nested: NestedModel1 | None = None
22+
23+
24+
class Model2(BaseModel):
25+
nested: NestedModel2 | None = None
26+
27+
28+
class Model3(BaseModel):
29+
nested: NestedModel3 | None = None
30+
31+
32+
@pytest.mark.parametrize("model", [Model1, Model2, Model3])
33+
def test_flat_init_model_model_bool_fail(model):
34+
constructor = FlatInitModel(model=model)
35+
36+
with pytest.raises(ValueError):
37+
constructor()
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
"""Pytest entry point for lupl.FlatInitBase fail tests."""
2+
3+
from typing import Any, NamedTuple
4+
5+
from lupl import FlatInitModel
6+
from pydantic import BaseModel, ValidationError
7+
import pytest
8+
9+
10+
class FlatInitFailParameter(NamedTuple):
11+
model: type[BaseModel]
12+
kwargs: dict[str, Any]
13+
errors: list[dict[str, Any]]
14+
fail_fast: bool = True
15+
16+
17+
class DeeplyNestedModel(BaseModel):
18+
z: int
19+
20+
21+
class NestedModel(BaseModel):
22+
y: int
23+
deeply_nested: DeeplyNestedModel
24+
25+
26+
class Model(BaseModel):
27+
x: int
28+
nested: NestedModel
29+
30+
31+
class SimpleModel(BaseModel):
32+
x: int
33+
y: int
34+
35+
36+
params = [
37+
FlatInitFailParameter(
38+
model=Model,
39+
kwargs={"x": 1, "y": 2.1, "z": 3},
40+
errors=[
41+
{
42+
"type": "int_from_float",
43+
"loc": ("y",),
44+
"msg": "Input should be a valid integer, got a number with a fractional part",
45+
"input": 2.1,
46+
"url": "https://errors.pydantic.dev/2.12/v/int_from_float",
47+
}
48+
],
49+
),
50+
FlatInitFailParameter(
51+
model=Model,
52+
kwargs={"x": 1, "y": 2, "z": 3.1},
53+
errors=[
54+
{
55+
"type": "int_from_float",
56+
"loc": ("z",),
57+
"msg": "Input should be a valid integer, got a number with a fractional part",
58+
"input": 3.1,
59+
"url": "https://errors.pydantic.dev/2.12/v/int_from_float",
60+
}
61+
],
62+
),
63+
FlatInitFailParameter(
64+
model=Model,
65+
kwargs={"x": 1, "y": 2.1, "z": 3.1},
66+
errors=[
67+
{
68+
"type": "int_from_float",
69+
"loc": ("y",),
70+
"msg": "Input should be a valid integer, got a number with a fractional part",
71+
"input": 2.1,
72+
"url": "https://errors.pydantic.dev/2.12/v/int_from_float",
73+
}
74+
],
75+
fail_fast=True,
76+
),
77+
FlatInitFailParameter(
78+
model=Model,
79+
kwargs={"x": 1, "y": 2.1, "z": 3.1},
80+
errors=[
81+
{
82+
"type": "int_from_float",
83+
"loc": ("z",),
84+
"msg": "Input should be a valid integer, got a number with a fractional part",
85+
"input": 3.1,
86+
"url": "https://errors.pydantic.dev/2.12/v/int_from_float",
87+
}
88+
],
89+
fail_fast=False,
90+
),
91+
FlatInitFailParameter(
92+
model=SimpleModel,
93+
kwargs={"x": 1.1, "y": 2.1},
94+
errors=[
95+
{
96+
"type": "int_from_float",
97+
"loc": ("x",),
98+
"msg": "Input should be a valid integer, got a number with a fractional part",
99+
"input": 1.1,
100+
"url": "https://errors.pydantic.dev/2.12/v/int_from_float",
101+
},
102+
{
103+
"type": "int_from_float",
104+
"loc": ("y",),
105+
"msg": "Input should be a valid integer, got a number with a fractional part",
106+
"input": 2.1,
107+
"url": "https://errors.pydantic.dev/2.12/v/int_from_float",
108+
},
109+
],
110+
fail_fast=False,
111+
),
112+
FlatInitFailParameter(
113+
model=SimpleModel,
114+
kwargs={"x": 1.1, "y": 2.1},
115+
errors=[
116+
{
117+
"type": "int_from_float",
118+
"loc": ("x",),
119+
"msg": "Input should be a valid integer, got a number with a fractional part",
120+
"input": 1.1,
121+
"url": "https://errors.pydantic.dev/2.12/v/int_from_float",
122+
}
123+
],
124+
fail_fast=True,
125+
),
126+
]
127+
128+
129+
@pytest.mark.parametrize("param", params)
130+
def test_flat_init_model_validation_fail(param):
131+
constructor = FlatInitModel(model=param.model, fail_fast=param.fail_fast)
132+
133+
with pytest.raises(ValidationError) as excinfo:
134+
constructor(**param.kwargs)
135+
136+
errors = excinfo.value.errors()
137+
assert param.errors == errors

0 commit comments

Comments
 (0)