diff --git a/pyproject.toml b/pyproject.toml index 9820f9b..be9305c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,11 @@ classifiers = [ "Typing :: Typed", ] dynamic = ["version"] -dependencies = ["pydantic", "importlib_metadata; python_version<'3.8'"] +dependencies = [ + "pydantic", + "importlib_metadata; python_version<'3.8'", + "packaging", +] [tool.hatch.envs.default] dependencies = [ diff --git a/src/pydantic_compat/_shared.py b/src/pydantic_compat/_shared.py index 4760d33..7e4b9b6 100644 --- a/src/pydantic_compat/_shared.py +++ b/src/pydantic_compat/_shared.py @@ -5,8 +5,10 @@ import pydantic import pydantic.version +from packaging.version import Version -PYDANTIC2 = pydantic.version.VERSION.startswith("2") +PYDANTIC2 = Version(pydantic.version.VERSION) >= Version("2") +PYDANTIC2_10 = Version(pydantic.version.VERSION) >= Version("2.10") FIELD_KWARGS = { p.name for p in signature(pydantic.Field).parameters.values() diff --git a/src/pydantic_compat/_v1/__init__.py b/src/pydantic_compat/_v1/__init__.py index b966141..2f633d2 100644 --- a/src/pydantic_compat/_v1/__init__.py +++ b/src/pydantic_compat/_v1/__init__.py @@ -1,6 +1,7 @@ import pydantic.version +from packaging.version import Version -if not pydantic.version.VERSION.startswith("1"): # pragma: no cover +if Version(pydantic.version.VERSION) >= Version("2"): # pragma: no cover raise ImportError("pydantic_compat._v1 only supports pydantic v1.x") diff --git a/src/pydantic_compat/_v2/__init__.py b/src/pydantic_compat/_v2/__init__.py index d5235af..1b95b24 100644 --- a/src/pydantic_compat/_v2/__init__.py +++ b/src/pydantic_compat/_v2/__init__.py @@ -1,6 +1,7 @@ import pydantic.version +from packaging.version import Version -if int(pydantic.version.VERSION[0]) <= 1: # pragma: no cover +if Version(pydantic.version.VERSION) < Version("2"): # pragma: no cover raise ImportError("pydantic_compat._v2 only supports pydantic v2.x") from .decorators import root_validator as root_validator diff --git a/src/pydantic_compat/_v2/mixin.py b/src/pydantic_compat/_v2/mixin.py index 865a1ff..5a74364 100644 --- a/src/pydantic_compat/_v2/mixin.py +++ b/src/pydantic_compat/_v2/mixin.py @@ -5,7 +5,11 @@ from pydantic import BaseModel from pydantic._internal import _model_construction -from pydantic_compat._shared import V2_RENAMED_CONFIG_KEYS, check_mixin_order +from pydantic_compat._shared import ( + PYDANTIC2_10, + V2_RENAMED_CONFIG_KEYS, + check_mixin_order, +) if TYPE_CHECKING: from pydantic import ConfigDict @@ -93,7 +97,10 @@ def parse_raw(cls: type[Model], *args: Any, **kwargs: Any) -> Any: # this is needed in addition to the metaclass patch in __init_subclass__ @property def __fields__(self: Model) -> Dict[str, Any]: # noqa: UP006 - return self.model_fields + if PYDANTIC2_10: + return self.__class__.model_fields + else: + return self.model_fields @property def __fields_set__(self: Model) -> set[str]: diff --git a/tests/test_base_model.py b/tests/test_base_model.py index 2d8c402..ba060d7 100644 --- a/tests/test_base_model.py +++ b/tests/test_base_model.py @@ -4,6 +4,7 @@ import pytest from pydantic_compat import PYDANTIC2, PydanticCompatMixin +from pydantic_compat._shared import PYDANTIC2_10 class Model(PydanticCompatMixin, pydantic.BaseModel): @@ -64,7 +65,8 @@ def test_v1_attributes() -> None: def test_v2_attributes() -> None: m = Model() - assert "x" in m.model_fields + if not PYDANTIC2_10: + assert "x" in m.model_fields assert "x" in Model.model_fields assert "x" not in m.model_fields_set m.x = 2 diff --git a/tests/test_decorators.py b/tests/test_decorators.py index 1de0666..a749db1 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -120,9 +120,9 @@ def _validate_x_before(cls, v): return v @model_validator(mode="after") - def _validate_x_after(cls, v): - mock_after(v) - return v + def _validate_x_after(self): + mock_after() + return self # this also needs to work @model_validator(mode="after") @@ -133,6 +133,6 @@ def _validate_x_after_cm(cls, v): m = Model(x="2") mock_before.assert_called_once_with({"x": "2"}) - mock_after.assert_called_once_with(m) + mock_after.assert_called_once_with() mock_after_cm.assert_called_once_with(m) assert m.x == 2