44{% endif %}
55# pylint: disable=protected-access, broad-except
66
7+ import contextvars
78import copy
89import calendar
910import decimal
@@ -656,41 +657,32 @@ def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typin
656657 if rf._is_multipart_file_input:
657658 return value
658659 if rf._is_model:
659- return _deserialize(rf._type, value)
660+ if _is_model(value):
661+ return value
662+ return _deserialize_public(rf._type, value)
660663 if isinstance(value, ET.Element):
661664 value = _deserialize(rf._type, value)
662665 return _serialize(value, rf._format)
663666
664667
665- def _clone_wire_value(value: typing.Any) -> typing.Any:
666- if isinstance(value, list):
667- return [_clone_wire_value(entry) for entry in value]
668- if isinstance(value, dict):
669- return {key: _clone_wire_value(entry) for key, entry in value.items()}
670- if isinstance(value, set):
671- return {_clone_wire_value(entry) for entry in value}
672- if isinstance(value, tuple):
673- return tuple(_clone_wire_value(entry) for entry in value)
674- return value
675-
676-
677668def _create_public_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typing.Any:
678- if rf and rf._is_model:
679- value = _clone_wire_value(value)
680669 return _create_value(rf, value)
681670
682671
683- class _OwnedWireValue:
684- __slots__ = ("value",)
685-
686- def __init__(self, value: typing.Mapping[str, typing.Any]) -> None:
687- self.value = value
672+ _WIRE_VALUE = contextvars.ContextVar("_WIRE_VALUE", default=None)
673+ _DESERIALIZING_PUBLIC_VALUE = contextvars.ContextVar("_DESERIALIZING_PUBLIC_VALUE", default=False)
688674
689675
690676def _construct_from_wire(cls: type, data: typing.Any) -> typing.Any:
691- # ET.Element payloads are passed through as-is; JSON payloads are wrapped in
692- # _OwnedWireValue so the constructed model takes zero-copy ownership of the wire data.
693- return cls(data) if isinstance(data, ET.Element) else cls(_OwnedWireValue(data))
677+ token = _WIRE_VALUE.set(data)
678+ try:
679+ return cls(data)
680+ finally:
681+ _WIRE_VALUE.reset(token)
682+
683+
684+ def _construct_model(cls: type, data: typing.Any) -> typing.Any:
685+ return cls(data) if _DESERIALIZING_PUBLIC_VALUE.get() else _construct_from_wire(cls, data)
694686
695687
696688def _create_value_from_wire(rf: typing.Optional["_RestField"], value: typing.Any) -> typing.Any:
@@ -707,7 +699,7 @@ def _create_value_from_wire(rf: typing.Optional["_RestField"], value: typing.Any
707699 :rtype: any
708700 """
709701 if not rf:
710- return _serialize( value, None)
702+ return value
711703 if rf._is_multipart_file_input:
712704 return value
713705 if rf._is_model:
@@ -890,6 +882,12 @@ def _extract_xml_model_type(rf_type):
890882 return None
891883
892884
885+ def _deserialize_xml_model(model_cls, value):
886+ if isinstance(value, list):
887+ return value
888+ return model_cls._deserialize(value, [])
889+
890+
893891def _build_xml_field_plan( # pylint: disable=docstring-missing-return, docstring-missing-rtype, unused-variable
894892 cls, attr_to_rest_field: dict
895893) -> list:
@@ -926,7 +924,7 @@ def _build_xml_field_plan( # pylint: disable=docstring-missing-return, docstrin
926924 if deser is None and rf._type is not None:
927925 model_cls = _extract_xml_model_type(rf._type)
928926 if model_cls is not None:
929- deser = model_cls
927+ deser = functools.partial(_deserialize_xml_model, model_cls)
930928
931929 if prop_meta.get("attribute", False):
932930 plan.append((rf._rest_name, xml_name, 1, deser, rf._type, is_optional, None))
@@ -967,11 +965,7 @@ class Model(_MyMutableMapping):
967965 else:
968966 rest_field_by_rest_name = self._rest_field_by_rest_name
969967 mapping = args[0]
970- if isinstance(mapping, _OwnedWireValue):
971- mapping = mapping.value
972- create_value = _create_value_from_wire
973- else:
974- create_value = _create_public_value
968+ create_value = _create_value_from_wire if _WIRE_VALUE.get() is mapping else _create_public_value
975969 dict_to_pass.update(
976970 {
977971 k: create_value(rest_field_by_rest_name.get(k), v)
@@ -1171,10 +1165,10 @@ class Model(_MyMutableMapping):
11711165 @classmethod
11721166 def _deserialize(cls, data, exist_discriminators):
11731167 if not hasattr(cls, "__mapping__"):
1174- return _construct_from_wire (cls, data)
1168+ return _construct_model (cls, data)
11751169 discriminator = cls._get_discriminator(exist_discriminators)
11761170 if discriminator is None:
1177- return _construct_from_wire (cls, data)
1171+ return _construct_model (cls, data)
11781172 exist_discriminators.append(discriminator._rest_name)
11791173 if isinstance(data, ET.Element):
11801174 model_meta = getattr(cls, "_xml", {})
@@ -1317,7 +1311,7 @@ def _deserialize_primitive_sequence(
13171311 """Deserialize a homogeneous sequence of scalars.
13181312
13191313 Plain ``list``/``tuple``/``set`` inputs are converted with ``map(builtin, obj)``, falling
1320- back to a per-element conversion that returns the raw entry when it cannot be converted.
1314+ back to the generic per-element deserializer when an entry cannot be converted directly .
13211315 Any other shape (encoded ``str``, ``ET.Element``, ...) is delegated to
13221316 :func:`_deserialize_sequence`.
13231317
@@ -1335,6 +1329,8 @@ def _deserialize_primitive_sequence(
13351329 if obj is None:
13361330 return obj
13371331 if isinstance(obj, (list, tuple, set)):
1332+ if obj and isinstance(next(iter(obj)), ET.Element):
1333+ return _deserialize_sequence(deserializer, module, obj)
13381334 try:
13391335 return type(obj)(map(builtin, obj))
13401336 except (TypeError, ValueError):
@@ -1345,7 +1341,7 @@ def _deserialize_primitive_sequence(
13451341 try:
13461342 return builtin(entry)
13471343 except (TypeError, ValueError):
1348- return entry
1344+ return _deserialize(deserializer, entry, module)
13491345
13501346 return type(obj)(_lenient(entry) for entry in obj)
13511347 return _deserialize_sequence(deserializer, module, obj)
@@ -1498,10 +1494,15 @@ def _resolve_deserialize_callable_from_annotation( # pylint: disable=too-many-r
14981494 pass
14991495 return obj
15001496
1501- if get_deserializer(annotation, rf):
1502- return functools.partial(_deserialize_default, get_deserializer(annotation, rf))
1497+ deserializer = get_deserializer(annotation, rf)
1498+ {% if code_model .has_external_type %}
1499+ if deserializer is TYPE_HANDLER_REGISTRY.get_deserializer(annotation):
1500+ def _deserialize_external_default(obj):
1501+ return _deserialize_default(TYPE_HANDLER_REGISTRY.get_deserializer(annotation) or annotation, obj)
15031502
1504- return functools.partial(_deserialize_default, annotation)
1503+ return _deserialize_external_default
1504+ {% endif %}
1505+ return functools.partial(_deserialize_default, deserializer or annotation)
15051506
15061507
15071508def _deserialize_with_callable(
@@ -1557,6 +1558,17 @@ def _deserialize(
15571558 return _deserialize_with_callable(deserializer, value)
15581559
15591560
1561+ def _deserialize_public(
1562+ deserializer: typing.Any,
1563+ value: typing.Any,
1564+ ) -> typing.Any:
1565+ token = _DESERIALIZING_PUBLIC_VALUE.set(True)
1566+ try:
1567+ return _deserialize(deserializer, value)
1568+ finally:
1569+ _DESERIALIZING_PUBLIC_VALUE.reset(token)
1570+
1571+
15601572def _failsafe_deserialize(
15611573 deserializer: typing.Any,
15621574 response: HttpResponse,
@@ -1686,7 +1698,7 @@ class _RestField:
16861698 return
16871699 if self._is_model:
16881700 if not _is_model(value):
1689- value = _deserialize (self._type, value)
1701+ value = _deserialize_public (self._type, value)
16901702 obj.__setitem__(self._rest_name, value)
16911703 return
16921704 obj.__setitem__(self._rest_name, _serialize(value, self._format))
0 commit comments