|
2 | 2 | from typing import Generic |
3 | 3 |
|
4 | 4 | from pydantic import Field |
| 5 | +from pydantic import FieldSerializationInfo |
| 6 | +from pydantic import SerializerFunctionWrapHandler |
5 | 7 | from pydantic import ValidationInfo |
6 | 8 | from pydantic import ValidatorFunctionWrapHandler |
| 9 | +from pydantic import field_serializer |
7 | 10 | from pydantic import model_validator |
8 | 11 | from pydantic_core import PydanticCustomError |
9 | 12 | from typing_extensions import Self |
10 | 13 |
|
11 | 14 | from ..context import Context |
12 | 15 | from ..path import URN |
| 16 | +from ..path import Path |
13 | 17 | from ..resources.resource import AnyResource |
| 18 | +from ..scim_object import ScimObject |
14 | 19 | from .message import Message |
15 | 20 | from .message import _GenericMessageMetaclass |
16 | 21 |
|
@@ -67,3 +72,96 @@ def check_results_number( |
67 | 72 | ) |
68 | 73 |
|
69 | 74 | return obj |
| 75 | + |
| 76 | + @field_serializer("resources", mode="wrap") |
| 77 | + def _serialize_resources( |
| 78 | + self, |
| 79 | + value: list[AnyResource] | None, |
| 80 | + handler: SerializerFunctionWrapHandler, |
| 81 | + info: FieldSerializationInfo, |
| 82 | + ) -> Any: |
| 83 | + """Apply attributes/excluded_attributes filtering to each embedded resource.""" |
| 84 | + if not value: |
| 85 | + return handler(value) |
| 86 | + |
| 87 | + attributes = info.context.get("scim_list_attributes") if info.context else None |
| 88 | + excluded_attributes = ( |
| 89 | + info.context.get("scim_list_excluded_attributes") if info.context else None |
| 90 | + ) |
| 91 | + |
| 92 | + if not attributes and not excluded_attributes: |
| 93 | + return handler(value) |
| 94 | + |
| 95 | + scim_ctx = info.context.get("scim") if info.context else None |
| 96 | + return [ |
| 97 | + resource.model_dump( |
| 98 | + scim_ctx=scim_ctx, |
| 99 | + attributes=attributes or None, |
| 100 | + excluded_attributes=excluded_attributes or None, |
| 101 | + ) |
| 102 | + for resource in value |
| 103 | + ] |
| 104 | + |
| 105 | + def _prepare_model_dump( |
| 106 | + self, |
| 107 | + scim_ctx: Context | None = Context.DEFAULT, |
| 108 | + attributes: list[str | Path[Any]] | None = None, |
| 109 | + excluded_attributes: list[str | Path[Any]] | None = None, |
| 110 | + **kwargs: Any, |
| 111 | + ) -> dict[str, Any]: |
| 112 | + kwargs = super()._prepare_model_dump(scim_ctx, **kwargs) |
| 113 | + if attributes: |
| 114 | + kwargs["context"]["scim_list_attributes"] = attributes |
| 115 | + if excluded_attributes: |
| 116 | + kwargs["context"]["scim_list_excluded_attributes"] = excluded_attributes |
| 117 | + return kwargs |
| 118 | + |
| 119 | + def model_dump( |
| 120 | + self, |
| 121 | + *args: Any, |
| 122 | + scim_ctx: Context | None = Context.DEFAULT, |
| 123 | + attributes: list[str | Path[Any]] | None = None, |
| 124 | + excluded_attributes: list[str | Path[Any]] | None = None, |
| 125 | + **kwargs: Any, |
| 126 | + ) -> dict[str, Any]: |
| 127 | + """Create a model representation that can be included in SCIM messages by using Pydantic :code:`BaseModel.model_dump`. |
| 128 | +
|
| 129 | + :param scim_ctx: If a SCIM context is passed, some default values of |
| 130 | + Pydantic :code:`BaseModel.model_dump` are tuned to generate valid SCIM |
| 131 | + messages. Pass :data:`None` to get the default Pydantic behavior. |
| 132 | + :param attributes: A multi-valued list of strings indicating the names of resource |
| 133 | + attributes to return in the response, overriding the set of attributes that |
| 134 | + would be returned by default. Invalid values are ignored. |
| 135 | + :param excluded_attributes: A multi-valued list of strings indicating the names of resource |
| 136 | + attributes to be removed from the default set of attributes to return. Invalid values are ignored. |
| 137 | + """ |
| 138 | + dump_kwargs = self._prepare_model_dump( |
| 139 | + scim_ctx, attributes, excluded_attributes, **kwargs |
| 140 | + ) |
| 141 | + if scim_ctx: |
| 142 | + dump_kwargs.setdefault("mode", "json") |
| 143 | + return super(ScimObject, self).model_dump(*args, **dump_kwargs) |
| 144 | + |
| 145 | + def model_dump_json( |
| 146 | + self, |
| 147 | + *args: Any, |
| 148 | + scim_ctx: Context | None = Context.DEFAULT, |
| 149 | + attributes: list[str | Path[Any]] | None = None, |
| 150 | + excluded_attributes: list[str | Path[Any]] | None = None, |
| 151 | + **kwargs: Any, |
| 152 | + ) -> str: |
| 153 | + """Create a JSON model representation that can be included in SCIM messages by using Pydantic :code:`BaseModel.model_dump_json`. |
| 154 | +
|
| 155 | + :param scim_ctx: If a SCIM context is passed, some default values of |
| 156 | + Pydantic :code:`BaseModel.model_dump` are tuned to generate valid SCIM |
| 157 | + messages. Pass :data:`None` to get the default Pydantic behavior. |
| 158 | + :param attributes: A multi-valued list of strings indicating the names of resource |
| 159 | + attributes to return in the response, overriding the set of attributes that |
| 160 | + would be returned by default. Invalid values are ignored. |
| 161 | + :param excluded_attributes: A multi-valued list of strings indicating the names of resource |
| 162 | + attributes to be removed from the default set of attributes to return. Invalid values are ignored. |
| 163 | + """ |
| 164 | + dump_kwargs = self._prepare_model_dump( |
| 165 | + scim_ctx, attributes, excluded_attributes, **kwargs |
| 166 | + ) |
| 167 | + return super(ScimObject, self).model_dump_json(*args, **dump_kwargs) |
0 commit comments