Skip to content

Commit

Permalink
Update to pydantic v2 and fix deprecated API usage. (#28)
Browse files Browse the repository at this point in the history
This fixes lots of deprecration warnings in CI builds and ultimately for
users as well. From now on, we will require `pydantic>=2` as we now use
their new API.

NB: I've piggy-backed removing the deprecated usage of
`datetime.utcnow()` as well. This only affects our tests though.
  • Loading branch information
daniel-k authored Nov 30, 2023
1 parent 36667fd commit abb3023
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 30 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ dynamic = [
dependencies = [
"httpx",
"pandas>=2",
"pydantic",
"pydantic>=2",
]
[project.optional-dependencies]
docs = [
Expand Down
4 changes: 2 additions & 2 deletions src/enlyze/api_clients/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def get_paginated(
while True:
response_body = self.get(url, params=params, **kwargs)
try:
paginated_response = self.PaginatedResponseModel.parse_obj(
paginated_response = self.PaginatedResponseModel.model_validate(
response_body
)
except ValidationError as e:
Expand All @@ -203,7 +203,7 @@ def get_paginated(

for elem in page_data:
try:
yield model.parse_obj(elem)
yield model.model_validate(elem)
except ValidationError as e:
raise EnlyzeError(
f"ENLYZE platform API returned an unparsable {model.__name__} "
Expand Down
6 changes: 3 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
hypothesis.settings.load_profile(os.getenv("HYPOTHESIS_PROFILE", "default"))

datetime_today_until_now_strategy = st.datetimes(
min_value=datetime.utcnow().replace(hour=0),
max_value=datetime.utcnow(),
min_value=datetime.now().replace(hour=0),
max_value=datetime.now(),
timezones=st.just(timezone.utc),
)

datetime_before_today_strategy = st.datetimes(
max_value=datetime.utcnow().replace(hour=0),
max_value=datetime.now().replace(hour=0),
min_value=datetime(1970, 1, 1, 12, 0, 0),
timezones=st.just(timezone.utc),
)
Expand Down
2 changes: 1 addition & 1 deletion tests/enlyze/api_clients/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@pytest.fixture
def string_model():
with patch(
"enlyze.api_clients.base.ApiBaseModel.parse_obj",
"enlyze.api_clients.base.ApiBaseModel.model_validate",
side_effect=lambda o: str(o),
):
yield ApiBaseModel
Expand Down
10 changes: 5 additions & 5 deletions tests/enlyze/api_clients/production_runs/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ def test_timeseries_api_get_paginated_single_page(
production_runs_client, string_model, paginated_response_no_next_page
):
expected_data = [
string_model.parse_obj(e) for e in paginated_response_no_next_page.data
string_model.model_validate(e) for e in paginated_response_no_next_page.data
]
respx.get("").respond(json=paginated_response_no_next_page.dict())
respx.get("").respond(json=paginated_response_no_next_page.model_dump())
assert list(production_runs_client.get_paginated("", string_model)) == expected_data


Expand All @@ -98,20 +98,20 @@ def test_timeseries_api_get_paginated_multi_page(
paginated_response_no_next_page,
):
expected_data = [
string_model.parse_obj(e)
string_model.model_validate(e)
for e in [
*paginated_response_no_next_page.data,
*paginated_response_with_next_page.data,
]
]
next_cursor = paginated_response_with_next_page.metadata.next_cursor
respx.get("", params=f"cursor={next_cursor}").respond(
200, json=paginated_response_no_next_page.dict()
200, json=paginated_response_no_next_page.model_dump()
)
respx.get("").mock(
side_effect=lambda request: httpx.Response(
200,
json=paginated_response_with_next_page.dict(),
json=paginated_response_with_next_page.model_dump(),
)
)

Expand Down
20 changes: 11 additions & 9 deletions tests/enlyze/api_clients/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,13 @@ def test_get_paginated_single_page(
endpoint = "https://irrelevant-url.com"
params = {"params": {"param1": "value1"}}
expected_data = [
string_model.parse_obj(e) for e in paginated_response_no_next_page.data
string_model.model_validate(e) for e in paginated_response_no_next_page.data
]

mock_has_more = base_client._has_more
mock_has_more.return_value = False
route = respx.get(endpoint, params=params).respond(
200, json=paginated_response_no_next_page.dict()
200, json=paginated_response_no_next_page.model_dump()
)

data = list(base_client.get_paginated(endpoint, ApiBaseModel, params=params))
Expand All @@ -172,7 +172,7 @@ def test_get_paginated_multi_page(
endpoint = "https://irrelevant-url.com"
initial_params = {"irrelevant": "values"}
expected_data = [
string_model.parse_obj(e)
string_model.model_validate(e)
for e in [
*paginated_response_with_next_page.data,
*paginated_response_no_next_page.data,
Expand All @@ -187,8 +187,8 @@ def test_get_paginated_multi_page(

route = respx.get(endpoint)
route.side_effect = [
httpx.Response(200, json=paginated_response_with_next_page.dict()),
httpx.Response(200, json=paginated_response_no_next_page.dict()),
httpx.Response(200, json=paginated_response_with_next_page.model_dump()),
httpx.Response(200, json=paginated_response_no_next_page.model_dump()),
]

data = list(
Expand Down Expand Up @@ -239,8 +239,8 @@ def test_get_paginated_raises_enlyze_error(
):
# most straightforward way to raise a pydantic.ValidationError
# https://github.com/pydantic/pydantic/discussions/6459
string_model.parse_obj.side_effect = lambda _: Metadata()
respx.get("").respond(200, json=paginated_response_no_next_page.dict())
string_model.model_validate.side_effect = lambda _: Metadata()
respx.get("").respond(200, json=paginated_response_no_next_page.model_dump())

with pytest.raises(EnlyzeError, match="ENLYZE platform API returned an unparsable"):
next(base_client.get_paginated("", string_model))
Expand All @@ -255,13 +255,15 @@ def test_get_paginated_transform_paginated_data(
_transform_paginated_data_integers
)
expected_data = [
string_model.parse_obj(e)
string_model.model_validate(e)
for e in _transform_paginated_data_integers(
paginated_response_no_next_page.data
)
]

route = respx.get("").respond(200, json=paginated_response_no_next_page.dict())
route = respx.get("").respond(
200, json=paginated_response_no_next_page.model_dump()
)

data = list(base_client.get_paginated("", ApiBaseModel))

Expand Down
16 changes: 9 additions & 7 deletions tests/enlyze/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class PaginatedTimeseriesApiResponse(httpx.Response):
def __init__(self, data, next=None) -> None:
super().__init__(
status_code=HTTPStatus.OK,
text=_PaginatedTimeseriesResponse(data=data, next=next).json(),
text=_PaginatedTimeseriesResponse(data=data, next=next).model_dump_json(),
headers=MOCK_RESPONSE_HEADERS,
)

Expand All @@ -111,7 +111,7 @@ def __init__(self, data, has_more=False, next_cursor=None) -> None:
has_more=has_more,
next_cursor=next_cursor,
),
).json(),
).model_dump_json(),
headers=MOCK_RESPONSE_HEADERS,
)

Expand Down Expand Up @@ -242,7 +242,7 @@ def test_get_timeseries(
data=timeseries_api_models.TimeseriesData(
columns=["time", str(variable.uuid)],
records=records[1:],
).dict()
).model_dump()
)
)

Expand All @@ -251,7 +251,7 @@ def test_get_timeseries(
data=timeseries_api_models.TimeseriesData(
columns=["time", str(variable.uuid)],
records=records[:1],
).dict(),
).model_dump(),
next=str(request.url.join("?offset=1")),
)
)
Expand Down Expand Up @@ -285,7 +285,7 @@ def test_get_timeseries(
"data",
[
{},
timeseries_api_models.TimeseriesData(columns=[], records=[]).dict(),
timeseries_api_models.TimeseriesData(columns=[], records=[]).model_dump(),
],
)
@pytest.mark.parametrize(
Expand Down Expand Up @@ -383,7 +383,7 @@ def test_get_timeseries_raises_api_returned_no_timestamps(
data=timeseries_api_models.TimeseriesData(
columns=["something but not time"],
records=[],
).dict()
).model_dump()
)
)
with pytest.raises(EnlyzeError, match="didn't return timestamps"):
Expand Down Expand Up @@ -433,7 +433,9 @@ def test_get_production_runs(
PaginatedTimeseriesApiResponse(data=[site])
)
production_runs_api_mock.get("production-runs").mock(
PaginatedProductionRunsApiResponse(data=[p.dict() for p in production_runs])
PaginatedProductionRunsApiResponse(
data=[p.model_dump() for p in production_runs]
)
)

result = client.get_production_runs(
Expand Down
4 changes: 2 additions & 2 deletions tests/enlyze/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

@given(
dt=st.datetimes(
max_value=datetime.utcnow(),
max_value=datetime.now(),
timezones=st.timezones(),
)
)
Expand All @@ -38,7 +38,7 @@ def test_ensure_datetime_aware(dt):

@given(
dt=st.datetimes(
max_value=datetime.utcnow(),
max_value=datetime.now(),
timezones=st.timezones(),
)
)
Expand Down

0 comments on commit abb3023

Please sign in to comment.