From f65aa31eaaeaba963bf2cf10f833d8d7c2272de5 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Tue, 26 Mar 2024 10:05:48 +0100 Subject: [PATCH 1/2] :arrow_up: [#2279] Upgrade pydantic to 2.6.4 task: https://taiga.maykinmedia.nl/project/open-inwoner/issue/2279 --- requirements/base.txt | 7 ++++++- requirements/ci.txt | 13 ++++++++++++- requirements/dev.txt | 13 ++++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/requirements/base.txt b/requirements/base.txt index 3d5746d504..8f9a486442 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -8,6 +8,8 @@ aldryn-apphooks-config==0.7.0 # via -r requirements/base.in amqp==5.1.1 # via kombu +annotated-types==0.6.0 + # via pydantic ape-pie==0.1.0 # via zgw-consumers asgiref==3.7.2 @@ -413,8 +415,10 @@ psycopg2==2.9.9 # via -r requirements/base.in pycparser==2.20 # via cffi -pydantic[email]==1.10.14 +pydantic[email]==2.6.4 # via -r requirements/base.in +pydantic-core==2.16.3 + # via pydantic pydyf==0.1.2 # via weasyprint pyee==11.0.1 @@ -506,6 +510,7 @@ typing-extensions==4.10.0 # via # -r requirements/base.in # pydantic + # pydantic-core # pyee # xsdata uritemplate==4.1.1 diff --git a/requirements/ci.txt b/requirements/ci.txt index 2c3f02038d..6adcb072c1 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -13,6 +13,11 @@ amqp==5.1.1 # -c requirements/base.txt # -r requirements/base.txt # kombu +annotated-types==0.6.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # pydantic ape-pie==0.1.0 # via # -c requirements/base.txt @@ -760,7 +765,12 @@ pycparser==2.20 # -c requirements/base.txt # -r requirements/base.txt # cffi -pydantic[email]==1.10.14 +pydantic[email]==2.6.4 + # via + # -c requirements/base.txt + # -r requirements/base.txt + # pydantic +pydantic-core==2.16.3 # via # -c requirements/base.txt # -r requirements/base.txt @@ -931,6 +941,7 @@ typing-extensions==4.10.0 # -r requirements/base.txt # polyfactory # pydantic + # pydantic-core # pyee # xsdata uritemplate==4.1.1 diff --git a/requirements/dev.txt b/requirements/dev.txt index 949a18cdea..e0cd031b38 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -15,6 +15,11 @@ amqp==5.1.1 # -c requirements/ci.txt # -r requirements/ci.txt # kombu +annotated-types==0.6.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # pydantic ape-pie==0.1.0 # via # -c requirements/ci.txt @@ -889,7 +894,12 @@ pycparser==2.20 # -c requirements/ci.txt # -r requirements/ci.txt # cffi -pydantic[email]==1.10.14 +pydantic[email]==2.6.4 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # pydantic +pydantic-core==2.16.3 # via # -c requirements/ci.txt # -r requirements/ci.txt @@ -1119,6 +1129,7 @@ typing-extensions==4.10.0 # -r requirements/ci.txt # polyfactory # pydantic + # pydantic-core # pyee # xsdata uritemplate==4.1.1 From 739a7acd3e75fcbf24d1b2700d800869259e1815 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Tue, 26 Mar 2024 10:51:32 +0100 Subject: [PATCH 2/2] :alien: [#2279] Fix compatibility with pydantic v2 task: https://taiga.maykinmedia.nl/project/open-inwoner/issue/2279 --- src/open_inwoner/laposta/api_models.py | 8 +------ src/open_inwoner/qmatic/client.py | 5 +---- src/open_inwoner/utils/api.py | 31 ++++++++++++-------------- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/src/open_inwoner/laposta/api_models.py b/src/open_inwoner/laposta/api_models.py index 6eab7e0c0b..bfb2ae6636 100644 --- a/src/open_inwoner/laposta/api_models.py +++ b/src/open_inwoner/laposta/api_models.py @@ -25,11 +25,8 @@ class LapostaList(JSONEncoderMixin, BaseModel): account_id: str members: Members - class Config(JSONEncoderMixin.Config): - pass - -class UserData(BaseModel): +class UserData(JSONEncoderMixin, BaseModel): ip: IPvAnyAddress email: EmailStr source_url: HttpUrl | None @@ -46,6 +43,3 @@ class Member(JSONEncoderMixin, BaseModel): ip: IPvAnyAddress source_url: HttpUrl | Literal[""] | None = None custom_fields: dict | None = None - - class Config(JSONEncoderMixin.Config): - pass diff --git a/src/open_inwoner/qmatic/client.py b/src/open_inwoner/qmatic/client.py index bc7f0cfc2b..5e62208e99 100644 --- a/src/open_inwoner/qmatic/client.py +++ b/src/open_inwoner/qmatic/client.py @@ -66,7 +66,7 @@ class BranchDetail(BaseModel): class Appointment(JSONEncoderMixin, BaseModel): - url: str | None + url: str | None = None services: list[QmaticService] title: str start: datetime @@ -77,9 +77,6 @@ class Appointment(JSONEncoderMixin, BaseModel): branch: BranchDetail notes: str | None - class Config(JSONEncoderMixin.Config): - pass - class NoServiceConfigured(RuntimeError): pass diff --git a/src/open_inwoner/utils/api.py b/src/open_inwoner/utils/api.py index a3ec7ced4b..015e014843 100644 --- a/src/open_inwoner/utils/api.py +++ b/src/open_inwoner/utils/api.py @@ -4,6 +4,7 @@ from typing import Any import requests +from pydantic_core import Url logger = logging.getLogger(__name__) @@ -31,23 +32,19 @@ def get_json_response(response: requests.Response) -> dict | None: class JSONEncoderMixin: - """ - Mixin for `pydantic.BaseModel` to make `BaseModel.dict()` produce JSON serialized data - """ - - # To make `BaseModel.dict()` produce JSON serialized data, i.e. for usage in tests - # in tandem with `requests_mock`, we cast the data using the configured JSON encoders - # Source: https://github.com/pydantic/pydantic/issues/1409#issuecomment-1381655025 - def _iter(self, **kwargs): - for key, value in super()._iter(**kwargs): - yield key, self.__config__.json_encoders.get(type(value), lambda v: v)( - value - ) - - class Config: - json_encoders = { - # We need to specify a serializable format for datetimes and IPv4Addresses, otherwise - # `BaseModel.dict()` will complain about certain types not being JSON serializable + def model_dump(self, **kwargs): + """ + To make `BaseModel.model_dump()` produce JSON serialized data, i.e. for usage in tests + in tandem with `requests_mock`, we cast the data using the configured JSON encoders + Source: https://github.com/pydantic/pydantic/issues/1409#issuecomment-1130601015 + """ + json_encoders: dict = { datetime: lambda dt: dt.isoformat(sep=" "), IPv4Address: str, + Url: str, } + result = super().model_dump(**kwargs) + for key, value in result.items(): + if mapping_func := json_encoders.get(type(value)): + result[key] = mapping_func(value) + return result