@@ -208,14 +208,18 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride]
208
208
else :
209
209
fields_values [name ] = field_get_default (field )
210
210
211
+ extra_field_type = _get_extra_fields_type (__cls )
212
+
211
213
_extra = {}
212
214
for key , value in values .items ():
213
215
if key not in model_fields :
216
+ parsed = construct_type (value = value , type_ = extra_field_type ) if extra_field_type is not None else value
217
+
214
218
if PYDANTIC_V2 :
215
- _extra [key ] = value
219
+ _extra [key ] = parsed
216
220
else :
217
221
_fields_set .add (key )
218
- fields_values [key ] = value
222
+ fields_values [key ] = parsed
219
223
220
224
object .__setattr__ (m , "__dict__" , fields_values )
221
225
@@ -370,6 +374,23 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object:
370
374
return construct_type (value = value , type_ = type_ , metadata = getattr (field , "metadata" , None ))
371
375
372
376
377
+ def _get_extra_fields_type (cls : type [pydantic .BaseModel ]) -> type | None :
378
+ if not PYDANTIC_V2 :
379
+ # TODO
380
+ return None
381
+
382
+ schema = cls .__pydantic_core_schema__
383
+ if schema ["type" ] == "model" :
384
+ fields = schema ["schema" ]
385
+ if fields ["type" ] == "model-fields" :
386
+ extras = fields .get ("extras_schema" )
387
+ if extras and "cls" in extras :
388
+ # mypy can't narrow the type
389
+ return extras ["cls" ] # type: ignore[no-any-return]
390
+
391
+ return None
392
+
393
+
373
394
def is_basemodel (type_ : type ) -> bool :
374
395
"""Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`"""
375
396
if is_union (type_ ):
0 commit comments