@@ -144,16 +144,42 @@ def handle_extension(resource: Resource, scim_name: str) -> tuple[BaseModel, str
144144 return resource , scim_name
145145
146146
147- def model_validate_from_dict (field_root_type : type [BaseModel ], value : dict ) -> Any :
148- """Workaround for some of the "special" requirements for MS Entra, mixing display and displayName in some cases."""
149- if (
150- "display" not in value
151- and "display" in field_root_type .model_fields
152- and "displayName" in value
153- ):
154- value ["display" ] = value ["displayName" ]
155- del value ["displayName" ]
156- return field_root_type .model_validate (value )
147+ def parse_value (field_root_type : type , value : Any ) -> Any :
148+ """Parse a PATCH value according to the target field root type."""
149+ if isinstance (value , dict ):
150+ if not hasattr (field_root_type , "model_fields" ):
151+ raise TypeError
152+
153+ # Work around mixed display/displayName payloads emitted by MS Entra.
154+ if (
155+ "display" not in value
156+ and "display" in field_root_type .model_fields
157+ and "displayName" in value
158+ ):
159+ value = value .copy ()
160+ value ["display" ] = value ["displayName" ]
161+ del value ["displayName" ]
162+ return field_root_type .model_validate (value )
163+
164+ if field_root_type is bool and isinstance (value , str ):
165+ return not value .lower () == "false"
166+
167+ if field_root_type is datetime .datetime and isinstance (value , str ):
168+ # ISO 8601 datetime format (notably with the Z suffix) are only supported from Python 3.11
169+ if sys .version_info < (3 , 11 ): # pragma: no cover
170+ return datetime .datetime .fromisoformat (re .sub (r"Z$" , "+00:00" , value ))
171+ return datetime .datetime .fromisoformat (value )
172+
173+ if field_root_type is EmailStr and isinstance (value , str ):
174+ return value
175+
176+ if hasattr (field_root_type , "model_fields" ):
177+ primary_value = get_by_alias (field_root_type , "value" , True )
178+ if primary_value is not None :
179+ return field_root_type (value = value )
180+ raise TypeError
181+
182+ return field_root_type (value )
157183
158184
159185def parse_new_value (model : BaseModel , attribute_name : str , value : Any ) -> Any :
@@ -164,31 +190,10 @@ def parse_new_value(model: BaseModel, attribute_name: str, value: Any) -> Any:
164190 """
165191 field_root_type = model .get_field_root_type (attribute_name )
166192 try :
167- if isinstance (value , dict ):
168- new_value = model_validate_from_dict (field_root_type , value )
169- elif isinstance (value , list ):
170- new_value = [model_validate_from_dict (field_root_type , v ) for v in value ]
193+ if isinstance (value , list ):
194+ new_value = [parse_value (field_root_type , v ) for v in value ]
171195 else :
172- if field_root_type is bool and isinstance (value , str ):
173- new_value = not value .lower () == "false"
174- elif field_root_type is datetime .datetime and isinstance (value , str ):
175- # ISO 8601 datetime format (notably with the Z suffix) are only supported from Python 3.11
176- if sys .version_info < (3 , 11 ): # pragma: no cover
177- new_value = datetime .datetime .fromisoformat (
178- re .sub (r"Z$" , "+00:00" , value )
179- )
180- else :
181- new_value = datetime .datetime .fromisoformat (value )
182- elif field_root_type is EmailStr and isinstance (value , str ):
183- new_value = value
184- elif hasattr (field_root_type , "model_fields" ):
185- primary_value = get_by_alias (field_root_type , "value" , True )
186- if primary_value is not None :
187- new_value = field_root_type (value = value )
188- else :
189- raise TypeError
190- else :
191- new_value = field_root_type (value )
196+ new_value = parse_value (field_root_type , value )
192197 except (AttributeError , TypeError , ValueError , ValidationError ) as e :
193198 raise InvalidValueException () from e
194199 return new_value
0 commit comments