|
7 | 7 | from typing import Any |
8 | 8 |
|
9 | 9 | from pydantic import Base64Bytes |
| 10 | +from pydantic import BaseModel |
10 | 11 | from scim2_models import ComplexAttribute |
11 | 12 | from scim2_models import Extension |
12 | 13 | from scim2_models import Mutability |
@@ -134,7 +135,7 @@ def generate_random_value( |
134 | 135 | if path.is_multivalued: |
135 | 136 | value = [value] |
136 | 137 |
|
137 | | - return fix_reference_values_in_value(value) |
| 138 | + return value |
138 | 139 |
|
139 | 140 |
|
140 | 141 | def fill_with_random_values( |
@@ -174,33 +175,37 @@ def fill_with_random_values( |
174 | 175 | path.set(obj, value, strict=False) |
175 | 176 |
|
176 | 177 | fix_primary_attributes(obj) |
| 178 | + fix_reference_values(obj) |
177 | 179 |
|
178 | 180 | return obj |
179 | 181 |
|
180 | 182 |
|
181 | | -def fix_reference_values_in_value(value: Any) -> Any: |
182 | | - """Fix reference values in any value to extract IDs from reference URLs. |
| 183 | +def fix_reference_values(obj: BaseModel) -> None: |
| 184 | + """Recursively fix ref/value consistency on an object and its children. |
183 | 185 |
|
184 | | - For SCIM reference fields, correctly sets the value field to match |
185 | | - the ID extracted from the reference URL. Works with both single values |
186 | | - and lists containing reference objects. |
| 186 | + Walks the object tree and ensures that for any object with both |
| 187 | + ``ref`` and ``value`` attributes, ``value`` matches the last segment |
| 188 | + of the ``ref`` URL. |
187 | 189 | """ |
188 | | - if isinstance(value, list): |
189 | | - for item in value: |
190 | | - if ( |
191 | | - hasattr(item, "ref") |
192 | | - and hasattr(item, "value") |
193 | | - and getattr(item, "ref", None) |
194 | | - ): |
195 | | - item.value = item.ref.rsplit("/", 1)[-1] |
196 | | - elif ( |
197 | | - hasattr(value, "ref") |
198 | | - and hasattr(value, "value") |
199 | | - and getattr(value, "ref", None) |
200 | | - ): |
201 | | - value.value = value.ref.rsplit("/", 1)[-1] |
| 190 | + for field_name in type(obj).model_fields: |
| 191 | + child = getattr(obj, field_name, None) |
| 192 | + if child is None: |
| 193 | + continue |
202 | 194 |
|
203 | | - return value |
| 195 | + if isinstance(child, list): |
| 196 | + for item in child: |
| 197 | + _fix_ref_value(item) |
| 198 | + if isinstance(item, BaseModel): |
| 199 | + fix_reference_values(item) |
| 200 | + elif isinstance(child, BaseModel): |
| 201 | + _fix_ref_value(child) |
| 202 | + fix_reference_values(child) |
| 203 | + |
| 204 | + |
| 205 | +def _fix_ref_value(obj: Any) -> None: |
| 206 | + """Set ``value`` to the last segment of ``ref`` if both attributes exist.""" |
| 207 | + if hasattr(obj, "ref") and hasattr(obj, "value") and getattr(obj, "ref", None): |
| 208 | + obj.value = obj.ref.rsplit("/", 1)[-1] |
204 | 209 |
|
205 | 210 |
|
206 | 211 | def fix_primary_attributes(obj: Resource[Any]) -> None: |
|
0 commit comments