|
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,39 +175,37 @@ def fill_with_random_values( |
174 | 175 | path.set(obj, value, strict=False) |
175 | 176 |
|
176 | 177 | fix_primary_attributes(obj) |
177 | | - |
178 | | - # Ensure reference consistency for all complex sub-attributes |
179 | | - for field_name in type(obj).model_fields: |
180 | | - child = getattr(obj, field_name, None) |
181 | | - if child is not None: |
182 | | - fix_reference_values_in_value(child) |
| 178 | + fix_reference_values(obj) |
183 | 179 |
|
184 | 180 | return obj |
185 | 181 |
|
186 | 182 |
|
187 | | -def fix_reference_values_in_value(value: Any) -> Any: |
188 | | - """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. |
189 | 185 |
|
190 | | - For SCIM reference fields, correctly sets the value field to match |
191 | | - the ID extracted from the reference URL. Works with both single values |
192 | | - 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. |
193 | 189 | """ |
194 | | - if isinstance(value, list): |
195 | | - for item in value: |
196 | | - if ( |
197 | | - hasattr(item, "ref") |
198 | | - and hasattr(item, "value") |
199 | | - and getattr(item, "ref", None) |
200 | | - ): |
201 | | - item.value = item.ref.rsplit("/", 1)[-1] |
202 | | - elif ( |
203 | | - hasattr(value, "ref") |
204 | | - and hasattr(value, "value") |
205 | | - and getattr(value, "ref", None) |
206 | | - ): |
207 | | - 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 |
208 | 194 |
|
209 | | - 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] |
210 | 209 |
|
211 | 210 |
|
212 | 211 | def fix_primary_attributes(obj: Resource[Any]) -> None: |
|
0 commit comments