diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7fe2a80..ae09088 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,12 @@ Changelog ========= +2.13.1 (2024-10-03) +------------------- + +- multiple pydantic model validators bug fixed. + + 2.13.0 (2024-09-29) ------------------- diff --git a/pydantic_xml/serializers/factories/model.py b/pydantic_xml/serializers/factories/model.py index d07d5b7..494a06e 100644 --- a/pydantic_xml/serializers/factories/model.py +++ b/pydantic_xml/serializers/factories/model.py @@ -57,7 +57,7 @@ def from_core_schema(cls, schema: pcs.ModelSchema, ctx: Serializer.Context) -> ' model_cls = schema['cls'] fields_schema = schema['schema'] - if fields_schema['type'] == 'function-before': + while fields_schema['type'] == 'function-before': fields_schema = fields_schema['schema'] assert issubclass(model_cls, pxml.BaseXmlModel), "model class must be a BaseXmlModel subclass" diff --git a/pyproject.toml b/pyproject.toml index a40e3d5..e631e56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pydantic-xml" -version = "2.13.0" +version = "2.13.1" description = "pydantic xml extension" authors = ["Dmitry Pershin "] license = "Unlicense" diff --git a/tests/test_preprocessors.py b/tests/test_preprocessors.py index 42da317..efd13bf 100644 --- a/tests/test_preprocessors.py +++ b/tests/test_preprocessors.py @@ -1,8 +1,10 @@ -from typing import List +from typing import Any, Dict, List +import pydantic as pd +import pytest from helpers import assert_xml_equal -from pydantic_xml import BaseXmlModel, element, xml_field_serializer, xml_field_validator +from pydantic_xml import BaseXmlModel, attr, element, xml_field_serializer, xml_field_validator from pydantic_xml.element import XmlElementReader, XmlElementWriter @@ -54,3 +56,49 @@ def serialize_element(self, element: XmlElementWriter, value: List[int], field_n actual_xml = obj.to_xml() assert_xml_equal(actual_xml, expected_xml) + + +def test_pydantic_model_validator(): + class TestModel(BaseXmlModel, tag='model1'): + text: str + attr1: str = attr() + attr2: str = attr() + + @pd.model_validator(mode='before') + def validate_before_attr1(cls, values: Dict[str, Any]) -> Dict[str, Any]: + if values.get('attr1') != "expected attr value": + raise ValueError('attr1') + + return values + + @pd.model_validator(mode='before') + def validate_before_attr2(cls, values: Dict[str, Any]) -> Dict[str, Any]: + if values.get('attr2') != "expected attr value": + raise ValueError('attr2') + + return values + + @pd.model_validator(mode='after') + def validate_model(self) -> 'TestModel': + if self.text != "expected text value": + raise ValueError('text') + + return self + + xml = 'expected text value' + TestModel.from_xml(xml) + + xml = 'expected text value' + with pytest.raises(ValueError) as err: + TestModel.from_xml(xml) + assert err.value.errors()[0]['ctx']['orig'] == 'Value error, attr1' + + xml = 'expected text value' + with pytest.raises(ValueError) as err: + TestModel.from_xml(xml) + assert err.value.errors()[0]['ctx']['orig'] == 'Value error, attr2' + + xml = 'unexpected text value' + with pytest.raises(ValueError) as err: + TestModel.from_xml(xml) + assert err.value.errors()[0]['ctx']['orig'] == 'Value error, text'