diff --git a/doc/changelog.rst b/doc/changelog.rst index 624524f..e521b5c 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -7,6 +7,7 @@ Changelog Fixed ^^^^^ - :class:`~scim2_models.ListResponse` pydantic discriminator issue introduced with pydantic 2.9.0. #75 +- Extension payloads are not required on response contexts. #77 [0.2.1] - 2024-09-06 -------------------- diff --git a/scim2_models/attributes.py b/scim2_models/attributes.py index 7c665aa..3334165 100644 --- a/scim2_models/attributes.py +++ b/scim2_models/attributes.py @@ -85,7 +85,8 @@ def validate_attribute_urn( return f"{schema}:{attribute_base}" -def contains_attribute_or_subattributes(attribute_urns: List[str], attribute_urn): +def contains_attribute_or_subattributes(attribute_urns: List[str], attribute_urn: str): return attribute_urn in attribute_urns or any( - item.startswith(f"{attribute_urn}.") for item in attribute_urns + item.startswith(f"{attribute_urn}.") or item.startswith(f"{attribute_urn}:") + for item in attribute_urns ) diff --git a/scim2_models/base.py b/scim2_models/base.py index 04fccaf..3814870 100644 --- a/scim2_models/base.py +++ b/scim2_models/base.py @@ -700,7 +700,10 @@ def get_attribute_urn(self, field_name: str) -> str: """ main_schema = self.model_fields["schemas"].default[0] alias = self.model_fields[field_name].serialization_alias or field_name - return f"{main_schema}:{alias}" + + # if alias contains a ':' this is an extension urn + full_urn = alias if ":" in alias else f"{main_schema}:{alias}" + return full_urn class ComplexAttribute(BaseModel): diff --git a/scim2_models/rfc7643/resource.py b/scim2_models/rfc7643/resource.py index 643143a..fe87007 100644 --- a/scim2_models/rfc7643/resource.py +++ b/scim2_models/rfc7643/resource.py @@ -136,7 +136,6 @@ def __new__(cls, name, bases, attrs, **kwargs): schema = extension.model_fields["schemas"].default[0] attrs.setdefault("__annotations__", {})[extension.__name__] = Annotated[ Optional[extension], - Returned.always, WrapSerializer(extension_serializer), ] attrs[extension.__name__] = Field( diff --git a/tests/test_resource_extension.py b/tests/test_resource_extension.py index 33373ea..ea7bcb3 100644 --- a/tests/test_resource_extension.py +++ b/tests/test_resource_extension.py @@ -257,3 +257,27 @@ def test_extensions_schemas(): ], "userName": "foobar", } + + +def test_validate_items_without_extension(): + """A model with an optional extension should be able to validate a payload + without an extension payload. + + https://github.com/yaal-coop/scim2-models/issues/77 + """ + + payload = { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], + "id": "new-user", + "userName": "new-user@example.com", + "meta": { + "resourceType": "User", + "created": "2010-01-23T04:56:22Z", + "lastModified": "2011-05-13T04:42:34Z", + "version": 'W\\/"3694e05e9dff590"', + "location": "http://localhost:46459/Users/new-user", + }, + } + User[EnterpriseUser].model_validate( + payload, scim_ctx=Context.RESOURCE_CREATION_RESPONSE + )