diff --git a/doc/changelog.rst b/doc/changelog.rst index 136b503..5914862 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -1,6 +1,13 @@ Changelog ========= +[0.6.5] - 2026-03-10 +-------------------- + +Fixed +^^^^^ +- Fix extension serialization crash when an extension is declared but not populated on a resource serialized outside of SCIM context (e.g. FastAPI ``response_model``). :pr:`131` + [0.6.4] - 2026-02-05 -------------------- diff --git a/scim2_models/resources/resource.py b/scim2_models/resources/resource.py index 254f314..3e50ccb 100644 --- a/scim2_models/resources/resource.py +++ b/scim2_models/resources/resource.py @@ -117,7 +117,11 @@ def _extension_serializer( For instance, attributes 'meta', 'id' or 'schemas' should not be dumped when the model is used as an extension for another model. """ + if value is None: + return None + partial_result = handler(value) + result = { attr_name: value for attr_name, value in partial_result.items() diff --git a/tests/test_resource_extension.py b/tests/test_resource_extension.py index 01983f5..a27d998 100644 --- a/tests/test_resource_extension.py +++ b/tests/test_resource_extension.py @@ -1,6 +1,7 @@ import datetime import pytest +from pydantic import TypeAdapter from scim2_models import URN from scim2_models import Context @@ -370,6 +371,14 @@ def test_class_getitem(): User[int] +def test_dump_resource_with_unset_extension(): + """Serialize a resource whose extension is declared but not populated.""" + user = User[EnterpriseUser](user_name="bjensen") + ta = TypeAdapter(User[EnterpriseUser]) + payload = ta.dump_python(user) + assert "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" not in payload + + def test_model_attribute_to_scim_attribute_error(): """Test error case where get_field_root_type returns None.""" from pydantic import Field