Skip to content

Commit c89735f

Browse files
committed
Merge branch 'master' into feat/GEOLIB-219-Force-Pydantic-v2
2 parents 7d8c896 + d07e708 commit c89735f

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

geolib/models/base_model.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,12 @@
1313
from typing import List, Optional, Type, Union
1414

1515
import requests
16-
from pydantic import DirectoryPath, FilePath, HttpUrl, conlist
16+
from pydantic import DirectoryPath, FilePath, HttpUrl, ValidationError, conlist
1717

1818
from geolib._compat import IS_PYDANTIC_V2
1919

2020
if IS_PYDANTIC_V2:
21-
from pydantic import ValidationError
22-
else:
23-
from pydantic.error_wrappers import ValidationError
21+
from pydantic import SerializeAsAny
2422

2523
from requests.auth import HTTPBasicAuth
2624

@@ -37,7 +35,18 @@
3735

3836
class BaseModel(BaseDataClass, abc.ABC):
3937
filename: Optional[Path] = None
40-
datastructure: Optional[BaseModelStructure] = None
38+
if IS_PYDANTIC_V2:
39+
datastructure: Optional[SerializeAsAny[BaseModelStructure]] = None
40+
else:
41+
datastructure: Optional[BaseModelStructure] = None
42+
"""
43+
This is the base class for all models in GEOLib.
44+
45+
Note that `datastructure` is a `SerializeAsAny` type, which means that
46+
the inheriting class is serialized according to its own definition (duck-typing).
47+
This is needed since Pydantic v2 as the default behavior has changed:
48+
https://docs.pydantic.dev/latest/concepts/serialization/#subclass-instances-for-fields-of-basemodel-dataclasses-typeddict
49+
"""
4150

4251
def execute(self, timeout_in_seconds: int = meta.timeout) -> "BaseModel":
4352
"""Execute a Model and wait for `timeout` seconds.

tests/models/test_base_model.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from fastapi.testclient import TestClient
77
from teamcity import is_running_under_teamcity
88

9+
from geolib._compat import IS_PYDANTIC_V2
910
from geolib.models import BaseDataClass, DSettlementModel
1011
from geolib.models.base_model import BaseModel, BaseModelList, MetaData
1112
from geolib.models.dfoundations.dfoundations_model import DFoundationsModel
@@ -104,6 +105,27 @@ def test_basemodellist_execute(self, model, filename, modelname):
104105
assert len(output.errors) == 1
105106
assert fn in output.errors[-1]
106107

108+
@pytest.mark.unittest
109+
def test_serialize_modellist(self):
110+
# 1. Set initial test data.
111+
a = DSettlementModel(filename="a.txt")
112+
b = DSettlementModel(filename="b.txt")
113+
ml = BaseModelList(models=[a, b])
114+
115+
# 2. Define test action.
116+
if IS_PYDANTIC_V2:
117+
_dump = ml.model_dump()
118+
else:
119+
_dump = ml.dict()
120+
121+
# 3. Verify final expectations.
122+
if IS_PYDANTIC_V2:
123+
assert _dump.get("models") == [a.model_dump(), b.model_dump()]
124+
else:
125+
assert _dump.get("models") == [a.dict(), b.dict()]
126+
for _model in _dump.get("models"):
127+
assert _model["datastructure"]
128+
107129
@pytest.mark.acceptance
108130
@only_teamcity
109131
@mock.patch("geolib.models.base_model.requests.post", side_effect=client.post)
@@ -120,7 +142,6 @@ def test_basemodellist_execute(self, model, filename, modelname):
120142
(DFoundationsModel, "bm1-1a.foi", "dfoundations/benchmarks"),
121143
],
122144
)
123-
@pytest.mark.skip(reason="Failing after pydantic 2 update. Cause of failure should be investigated in more detail.")
124145
def test_basemodellist_execute_remote(self, _, __, model, filename, modelname):
125146
# Setup models
126147
a = model()
@@ -170,6 +191,7 @@ def test_basemodel_execute_remote(self, _, __, model, filename, modelname):
170191
model = modelinstance.execute_remote("/") # no url is needed with the TestClient
171192
assert model.output
172193

194+
173195
class TestBool:
174196
@pytest.mark.unittest
175197
def test_init(self):

0 commit comments

Comments
 (0)