azure-quantum 3.5.1.dev1__py3-none-any.whl → 3.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. azure/quantum/_client/__init__.py +2 -2
  2. azure/quantum/_client/_client.py +18 -57
  3. azure/quantum/_client/_configuration.py +13 -22
  4. azure/quantum/_client/_patch.py +7 -6
  5. azure/quantum/_client/_utils/__init__.py +6 -0
  6. azure/quantum/_client/{_model_base.py → _utils/model_base.py} +210 -45
  7. azure/quantum/_client/{_serialization.py → _utils/serialization.py} +74 -151
  8. azure/quantum/_client/_validation.py +66 -0
  9. azure/quantum/_client/_version.py +1 -1
  10. azure/quantum/_client/aio/__init__.py +29 -0
  11. azure/quantum/_client/aio/_client.py +110 -0
  12. azure/quantum/_client/aio/_configuration.py +75 -0
  13. azure/quantum/_client/aio/_patch.py +21 -0
  14. azure/quantum/_client/aio/operations/__init__.py +25 -0
  15. azure/quantum/_client/aio/operations/_operations.py +1988 -0
  16. azure/quantum/_client/aio/operations/_patch.py +21 -0
  17. azure/quantum/_client/models/__init__.py +8 -4
  18. azure/quantum/_client/models/_enums.py +28 -23
  19. azure/quantum/_client/models/_models.py +198 -106
  20. azure/quantum/_client/models/_patch.py +7 -6
  21. azure/quantum/_client/operations/__init__.py +2 -12
  22. azure/quantum/_client/operations/_operations.py +900 -715
  23. azure/quantum/_client/operations/_patch.py +7 -6
  24. azure/quantum/_constants.py +5 -0
  25. azure/quantum/_mgmt_client.py +18 -8
  26. azure/quantum/_workspace_connection_params.py +27 -2
  27. azure/quantum/job/base_job.py +8 -0
  28. azure/quantum/job/job.py +1 -1
  29. azure/quantum/job/session.py +11 -0
  30. azure/quantum/target/target.py +5 -1
  31. azure/quantum/target/target_factory.py +14 -7
  32. azure/quantum/version.py +1 -1
  33. azure/quantum/workspace.py +35 -31
  34. {azure_quantum-3.5.1.dev1.dist-info → azure_quantum-3.6.0.dist-info}/METADATA +1 -1
  35. azure_quantum-3.6.0.dist-info/RECORD +74 -0
  36. azure_quantum-3.5.1.dev1.dist-info/RECORD +0 -65
  37. {azure_quantum-3.5.1.dev1.dist-info → azure_quantum-3.6.0.dist-info}/WHEEL +0 -0
  38. {azure_quantum-3.5.1.dev1.dist-info → azure_quantum-3.6.0.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,10 @@
1
- # pylint: disable=too-many-lines
1
+ # pylint: disable=line-too-long,useless-suppression,too-many-lines
2
2
  # coding=utf-8
3
3
  # --------------------------------------------------------------------------
4
4
  # Copyright (c) Microsoft Corporation. All rights reserved.
5
- # Licensed under the MIT License. See License.txt in the project root for
6
- # license information.
5
+ # Licensed under the MIT License. See License.txt in the project root for license information.
6
+ # Code generated by Microsoft (R) Python Code Generator.
7
+ # Changes may cause incorrect behavior and will be lost if the code is regenerated.
7
8
  # --------------------------------------------------------------------------
8
9
  # pylint: disable=protected-access, broad-except
9
10
 
@@ -21,17 +22,14 @@ import email.utils
21
22
  from datetime import datetime, date, time, timedelta, timezone
22
23
  from json import JSONEncoder
23
24
  import xml.etree.ElementTree as ET
25
+ from collections.abc import MutableMapping
24
26
  from typing_extensions import Self
25
27
  import isodate
26
28
  from azure.core.exceptions import DeserializationError
27
29
  from azure.core import CaseInsensitiveEnumMeta
28
30
  from azure.core.pipeline import PipelineResponse
29
31
  from azure.core.serialization import _Null
30
-
31
- if sys.version_info >= (3, 9):
32
- from collections.abc import MutableMapping
33
- else:
34
- from typing import MutableMapping
32
+ from azure.core.rest import HttpResponse
35
33
 
36
34
  _LOGGER = logging.getLogger(__name__)
37
35
 
@@ -173,6 +171,21 @@ _VALID_RFC7231 = re.compile(
173
171
  r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT"
174
172
  )
175
173
 
174
+ _ARRAY_ENCODE_MAPPING = {
175
+ "pipeDelimited": "|",
176
+ "spaceDelimited": " ",
177
+ "commaDelimited": ",",
178
+ "newlineDelimited": "\n",
179
+ }
180
+
181
+
182
+ def _deserialize_array_encoded(delimit: str, attr):
183
+ if isinstance(attr, str):
184
+ if attr == "":
185
+ return []
186
+ return attr.split(delimit)
187
+ return attr
188
+
176
189
 
177
190
  def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime:
178
191
  """Deserialize ISO-8601 formatted string into Datetime object.
@@ -317,6 +330,8 @@ _DESERIALIZE_MAPPING_WITHFORMAT = {
317
330
  def get_deserializer(annotation: typing.Any, rf: typing.Optional["_RestField"] = None):
318
331
  if annotation is int and rf and rf._format == "str":
319
332
  return _deserialize_int_as_str
333
+ if annotation is str and rf and rf._format in _ARRAY_ENCODE_MAPPING:
334
+ return functools.partial(_deserialize_array_encoded, _ARRAY_ENCODE_MAPPING[rf._format])
320
335
  if rf and rf._format:
321
336
  return _DESERIALIZE_MAPPING_WITHFORMAT.get(rf._format)
322
337
  return _DESERIALIZE_MAPPING.get(annotation) # pyright: ignore
@@ -347,17 +362,47 @@ def _get_model(module_name: str, model_name: str):
347
362
  _UNSET = object()
348
363
 
349
364
 
350
- class _MyMutableMapping(MutableMapping[str, typing.Any]): # pylint: disable=unsubscriptable-object
351
- def __init__(self, data: typing.Dict[str, typing.Any]) -> None:
365
+ class _MyMutableMapping(MutableMapping[str, typing.Any]):
366
+ def __init__(self, data: dict[str, typing.Any]) -> None:
352
367
  self._data = data
353
368
 
354
369
  def __contains__(self, key: typing.Any) -> bool:
355
370
  return key in self._data
356
371
 
357
372
  def __getitem__(self, key: str) -> typing.Any:
373
+ # If this key has been deserialized (for mutable types), we need to handle serialization
374
+ if hasattr(self, "_attr_to_rest_field"):
375
+ cache_attr = f"_deserialized_{key}"
376
+ if hasattr(self, cache_attr):
377
+ rf = _get_rest_field(getattr(self, "_attr_to_rest_field"), key)
378
+ if rf:
379
+ value = self._data.get(key)
380
+ if isinstance(value, (dict, list, set)):
381
+ # For mutable types, serialize and return
382
+ # But also update _data with serialized form and clear flag
383
+ # so mutations via this returned value affect _data
384
+ serialized = _serialize(value, rf._format)
385
+ # If serialized form is same type (no transformation needed),
386
+ # return _data directly so mutations work
387
+ if isinstance(serialized, type(value)) and serialized == value:
388
+ return self._data.get(key)
389
+ # Otherwise return serialized copy and clear flag
390
+ try:
391
+ object.__delattr__(self, cache_attr)
392
+ except AttributeError:
393
+ pass
394
+ # Store serialized form back
395
+ self._data[key] = serialized
396
+ return serialized
358
397
  return self._data.__getitem__(key)
359
398
 
360
399
  def __setitem__(self, key: str, value: typing.Any) -> None:
400
+ # Clear any cached deserialized value when setting through dictionary access
401
+ cache_attr = f"_deserialized_{key}"
402
+ try:
403
+ object.__delattr__(self, cache_attr)
404
+ except AttributeError:
405
+ pass
361
406
  self._data.__setitem__(key, value)
362
407
 
363
408
  def __delitem__(self, key: str) -> None:
@@ -373,50 +418,97 @@ class _MyMutableMapping(MutableMapping[str, typing.Any]): # pylint: disable=uns
373
418
  return not self.__eq__(other)
374
419
 
375
420
  def keys(self) -> typing.KeysView[str]:
421
+ """
422
+ :returns: a set-like object providing a view on D's keys
423
+ :rtype: ~typing.KeysView
424
+ """
376
425
  return self._data.keys()
377
426
 
378
427
  def values(self) -> typing.ValuesView[typing.Any]:
428
+ """
429
+ :returns: an object providing a view on D's values
430
+ :rtype: ~typing.ValuesView
431
+ """
379
432
  return self._data.values()
380
433
 
381
434
  def items(self) -> typing.ItemsView[str, typing.Any]:
435
+ """
436
+ :returns: set-like object providing a view on D's items
437
+ :rtype: ~typing.ItemsView
438
+ """
382
439
  return self._data.items()
383
440
 
384
441
  def get(self, key: str, default: typing.Any = None) -> typing.Any:
442
+ """
443
+ Get the value for key if key is in the dictionary, else default.
444
+ :param str key: The key to look up.
445
+ :param any default: The value to return if key is not in the dictionary. Defaults to None
446
+ :returns: D[k] if k in D, else d.
447
+ :rtype: any
448
+ """
385
449
  try:
386
450
  return self[key]
387
451
  except KeyError:
388
452
  return default
389
453
 
390
454
  @typing.overload
391
- def pop(self, key: str) -> typing.Any: ...
455
+ def pop(self, key: str) -> typing.Any: ... # pylint: disable=arguments-differ
392
456
 
393
457
  @typing.overload
394
- def pop(self, key: str, default: _T) -> _T: ...
458
+ def pop(self, key: str, default: _T) -> _T: ... # pylint: disable=signature-differs
395
459
 
396
460
  @typing.overload
397
- def pop(self, key: str, default: typing.Any) -> typing.Any: ...
461
+ def pop(self, key: str, default: typing.Any) -> typing.Any: ... # pylint: disable=signature-differs
398
462
 
399
463
  def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
464
+ """
465
+ Removes specified key and return the corresponding value.
466
+ :param str key: The key to pop.
467
+ :param any default: The value to return if key is not in the dictionary
468
+ :returns: The value corresponding to the key.
469
+ :rtype: any
470
+ :raises KeyError: If key is not found and default is not given.
471
+ """
400
472
  if default is _UNSET:
401
473
  return self._data.pop(key)
402
474
  return self._data.pop(key, default)
403
475
 
404
- def popitem(self) -> typing.Tuple[str, typing.Any]:
476
+ def popitem(self) -> tuple[str, typing.Any]:
477
+ """
478
+ Removes and returns some (key, value) pair
479
+ :returns: The (key, value) pair.
480
+ :rtype: tuple
481
+ :raises KeyError: if D is empty.
482
+ """
405
483
  return self._data.popitem()
406
484
 
407
485
  def clear(self) -> None:
486
+ """
487
+ Remove all items from D.
488
+ """
408
489
  self._data.clear()
409
490
 
410
- def update(self, *args: typing.Any, **kwargs: typing.Any) -> None:
491
+ def update(self, *args: typing.Any, **kwargs: typing.Any) -> None: # pylint: disable=arguments-differ
492
+ """
493
+ Updates D from mapping/iterable E and F.
494
+ :param any args: Either a mapping object or an iterable of key-value pairs.
495
+ """
411
496
  self._data.update(*args, **kwargs)
412
497
 
413
498
  @typing.overload
414
499
  def setdefault(self, key: str, default: None = None) -> None: ...
415
500
 
416
501
  @typing.overload
417
- def setdefault(self, key: str, default: typing.Any) -> typing.Any: ...
502
+ def setdefault(self, key: str, default: typing.Any) -> typing.Any: ... # pylint: disable=signature-differs
418
503
 
419
504
  def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
505
+ """
506
+ Same as calling D.get(k, d), and setting D[k]=d if k not found
507
+ :param str key: The key to look up.
508
+ :param any default: The value to set if key is not in the dictionary
509
+ :returns: D[k] if k in D, else d.
510
+ :rtype: any
511
+ """
420
512
  if default is _UNSET:
421
513
  return self._data.setdefault(key)
422
514
  return self._data.setdefault(key, default)
@@ -438,6 +530,8 @@ def _is_model(obj: typing.Any) -> bool:
438
530
 
439
531
  def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-many-return-statements
440
532
  if isinstance(o, list):
533
+ if format in _ARRAY_ENCODE_MAPPING and all(isinstance(x, str) for x in o):
534
+ return _ARRAY_ENCODE_MAPPING[format].join(o)
441
535
  return [_serialize(x, format) for x in o]
442
536
  if isinstance(o, dict):
443
537
  return {k: _serialize(v, format) for k, v in o.items()}
@@ -469,9 +563,7 @@ def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-m
469
563
  return o
470
564
 
471
565
 
472
- def _get_rest_field(
473
- attr_to_rest_field: typing.Dict[str, "_RestField"], rest_name: str
474
- ) -> typing.Optional["_RestField"]:
566
+ def _get_rest_field(attr_to_rest_field: dict[str, "_RestField"], rest_name: str) -> typing.Optional["_RestField"]:
475
567
  try:
476
568
  return next(rf for rf in attr_to_rest_field.values() if rf._rest_name == rest_name)
477
569
  except StopIteration:
@@ -494,7 +586,7 @@ class Model(_MyMutableMapping):
494
586
  _is_model = True
495
587
  # label whether current class's _attr_to_rest_field has been calculated
496
588
  # could not see _attr_to_rest_field directly because subclass inherits it from parent class
497
- _calculated: typing.Set[str] = set()
589
+ _calculated: set[str] = set()
498
590
 
499
591
  def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None:
500
592
  class_name = self.__class__.__name__
@@ -579,7 +671,7 @@ class Model(_MyMutableMapping):
579
671
  # we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping',
580
672
  # 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object'
581
673
  mros = cls.__mro__[:-9][::-1] # ignore parents, and reverse the mro order
582
- attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property
674
+ attr_to_rest_field: dict[str, _RestField] = { # map attribute name to rest_field property
583
675
  k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type")
584
676
  }
585
677
  annotations = {
@@ -594,10 +686,10 @@ class Model(_MyMutableMapping):
594
686
  rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None))
595
687
  if not rf._rest_name_input:
596
688
  rf._rest_name_input = attr
597
- cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items())
689
+ cls._attr_to_rest_field: dict[str, _RestField] = dict(attr_to_rest_field.items())
598
690
  cls._calculated.add(f"{cls.__module__}.{cls.__qualname__}")
599
691
 
600
- return super().__new__(cls) # pylint: disable=no-value-for-parameter
692
+ return super().__new__(cls)
601
693
 
602
694
  def __init_subclass__(cls, discriminator: typing.Optional[str] = None) -> None:
603
695
  for base in cls.__bases__:
@@ -633,10 +725,10 @@ class Model(_MyMutableMapping):
633
725
  discriminator_value = data.find(xml_name).text # pyright: ignore
634
726
  else:
635
727
  discriminator_value = data.get(discriminator._rest_name)
636
- mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore
728
+ mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore # pylint: disable=no-member
637
729
  return mapped_cls._deserialize(data, exist_discriminators)
638
730
 
639
- def as_dict(self, *, exclude_readonly: bool = False) -> typing.Dict[str, typing.Any]:
731
+ def as_dict(self, *, exclude_readonly: bool = False) -> dict[str, typing.Any]:
640
732
  """Return a dict that can be turned into json using json.dump.
641
733
 
642
734
  :keyword bool exclude_readonly: Whether to remove the readonly properties.
@@ -696,7 +788,7 @@ def _deserialize_with_union(deserializers, obj):
696
788
  def _deserialize_dict(
697
789
  value_deserializer: typing.Optional[typing.Callable],
698
790
  module: typing.Optional[str],
699
- obj: typing.Dict[typing.Any, typing.Any],
791
+ obj: dict[typing.Any, typing.Any],
700
792
  ):
701
793
  if obj is None:
702
794
  return obj
@@ -706,7 +798,7 @@ def _deserialize_dict(
706
798
 
707
799
 
708
800
  def _deserialize_multiple_sequence(
709
- entry_deserializers: typing.List[typing.Optional[typing.Callable]],
801
+ entry_deserializers: list[typing.Optional[typing.Callable]],
710
802
  module: typing.Optional[str],
711
803
  obj,
712
804
  ):
@@ -724,17 +816,28 @@ def _deserialize_sequence(
724
816
  return obj
725
817
  if isinstance(obj, ET.Element):
726
818
  obj = list(obj)
819
+ try:
820
+ if (
821
+ isinstance(obj, str)
822
+ and isinstance(deserializer, functools.partial)
823
+ and isinstance(deserializer.args[0], functools.partial)
824
+ and deserializer.args[0].func == _deserialize_array_encoded # pylint: disable=comparison-with-callable
825
+ ):
826
+ # encoded string may be deserialized to sequence
827
+ return deserializer(obj)
828
+ except: # pylint: disable=bare-except
829
+ pass
727
830
  return type(obj)(_deserialize(deserializer, entry, module) for entry in obj)
728
831
 
729
832
 
730
- def _sorted_annotations(types: typing.List[typing.Any]) -> typing.List[typing.Any]:
833
+ def _sorted_annotations(types: list[typing.Any]) -> list[typing.Any]:
731
834
  return sorted(
732
835
  types,
733
836
  key=lambda x: hasattr(x, "__name__") and x.__name__.lower() in ("str", "float", "int", "bool"),
734
837
  )
735
838
 
736
839
 
737
- def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-branches
840
+ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-statements, too-many-branches
738
841
  annotation: typing.Any,
739
842
  module: typing.Optional[str],
740
843
  rf: typing.Optional["_RestField"] = None,
@@ -799,7 +902,10 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur
799
902
  return functools.partial(_deserialize_with_union, deserializers)
800
903
 
801
904
  try:
802
- if annotation._name == "Dict": # pyright: ignore
905
+ annotation_name = (
906
+ annotation.__name__ if hasattr(annotation, "__name__") else annotation._name # pyright: ignore
907
+ )
908
+ if annotation_name.lower() == "dict":
803
909
  value_deserializer = _get_deserialize_callable_from_annotation(
804
910
  annotation.__args__[1], module, rf # pyright: ignore
805
911
  )
@@ -812,7 +918,10 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur
812
918
  except (AttributeError, IndexError):
813
919
  pass
814
920
  try:
815
- if annotation._name in ["List", "Set", "Tuple", "Sequence"]: # pyright: ignore
921
+ annotation_name = (
922
+ annotation.__name__ if hasattr(annotation, "__name__") else annotation._name # pyright: ignore
923
+ )
924
+ if annotation_name.lower() in ["list", "set", "tuple", "sequence"]:
816
925
  if len(annotation.__args__) > 1: # pyright: ignore
817
926
  entry_deserializers = [
818
927
  _get_deserialize_callable_from_annotation(dt, module, rf)
@@ -894,6 +1003,35 @@ def _deserialize(
894
1003
  return _deserialize_with_callable(deserializer, value)
895
1004
 
896
1005
 
1006
+ def _failsafe_deserialize(
1007
+ deserializer: typing.Any,
1008
+ response: HttpResponse,
1009
+ module: typing.Optional[str] = None,
1010
+ rf: typing.Optional["_RestField"] = None,
1011
+ format: typing.Optional[str] = None,
1012
+ ) -> typing.Any:
1013
+ try:
1014
+ return _deserialize(deserializer, response.json(), module, rf, format)
1015
+ except DeserializationError:
1016
+ _LOGGER.warning(
1017
+ "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True
1018
+ )
1019
+ return None
1020
+
1021
+
1022
+ def _failsafe_deserialize_xml(
1023
+ deserializer: typing.Any,
1024
+ response: HttpResponse,
1025
+ ) -> typing.Any:
1026
+ try:
1027
+ return _deserialize_xml(deserializer, response.text())
1028
+ except DeserializationError:
1029
+ _LOGGER.warning(
1030
+ "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True
1031
+ )
1032
+ return None
1033
+
1034
+
897
1035
  class _RestField:
898
1036
  def __init__(
899
1037
  self,
@@ -901,11 +1039,11 @@ class _RestField:
901
1039
  name: typing.Optional[str] = None,
902
1040
  type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin
903
1041
  is_discriminator: bool = False,
904
- visibility: typing.Optional[typing.List[str]] = None,
1042
+ visibility: typing.Optional[list[str]] = None,
905
1043
  default: typing.Any = _UNSET,
906
1044
  format: typing.Optional[str] = None,
907
1045
  is_multipart_file_input: bool = False,
908
- xml: typing.Optional[typing.Dict[str, typing.Any]] = None,
1046
+ xml: typing.Optional[dict[str, typing.Any]] = None,
909
1047
  ):
910
1048
  self._type = type
911
1049
  self._rest_name_input = name
@@ -920,7 +1058,11 @@ class _RestField:
920
1058
 
921
1059
  @property
922
1060
  def _class_type(self) -> typing.Any:
923
- return getattr(self._type, "args", [None])[0]
1061
+ result = getattr(self._type, "args", [None])[0]
1062
+ # type may be wrapped by nested functools.partial so we need to check for that
1063
+ if isinstance(result, functools.partial):
1064
+ return getattr(result, "args", [None])[0]
1065
+ return result
924
1066
 
925
1067
  @property
926
1068
  def _rest_name(self) -> str:
@@ -931,14 +1073,37 @@ class _RestField:
931
1073
  def __get__(self, obj: Model, type=None): # pylint: disable=redefined-builtin
932
1074
  # by this point, type and rest_name will have a value bc we default
933
1075
  # them in __new__ of the Model class
934
- item = obj.get(self._rest_name)
1076
+ # Use _data.get() directly to avoid triggering __getitem__ which clears the cache
1077
+ item = obj._data.get(self._rest_name)
935
1078
  if item is None:
936
1079
  return item
937
1080
  if self._is_model:
938
1081
  return item
939
- return _deserialize(self._type, _serialize(item, self._format), rf=self)
1082
+
1083
+ # For mutable types, we want mutations to directly affect _data
1084
+ # Check if we've already deserialized this value
1085
+ cache_attr = f"_deserialized_{self._rest_name}"
1086
+ if hasattr(obj, cache_attr):
1087
+ # Return the value from _data directly (it's been deserialized in place)
1088
+ return obj._data.get(self._rest_name)
1089
+
1090
+ deserialized = _deserialize(self._type, _serialize(item, self._format), rf=self)
1091
+
1092
+ # For mutable types, store the deserialized value back in _data
1093
+ # so mutations directly affect _data
1094
+ if isinstance(deserialized, (dict, list, set)):
1095
+ obj._data[self._rest_name] = deserialized
1096
+ object.__setattr__(obj, cache_attr, True) # Mark as deserialized
1097
+ return deserialized
1098
+
1099
+ return deserialized
940
1100
 
941
1101
  def __set__(self, obj: Model, value) -> None:
1102
+ # Clear the cached deserialized object when setting a new value
1103
+ cache_attr = f"_deserialized_{self._rest_name}"
1104
+ if hasattr(obj, cache_attr):
1105
+ object.__delattr__(obj, cache_attr)
1106
+
942
1107
  if value is None:
943
1108
  # we want to wipe out entries if users set attr to None
944
1109
  try:
@@ -963,11 +1128,11 @@ def rest_field(
963
1128
  *,
964
1129
  name: typing.Optional[str] = None,
965
1130
  type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin
966
- visibility: typing.Optional[typing.List[str]] = None,
1131
+ visibility: typing.Optional[list[str]] = None,
967
1132
  default: typing.Any = _UNSET,
968
1133
  format: typing.Optional[str] = None,
969
1134
  is_multipart_file_input: bool = False,
970
- xml: typing.Optional[typing.Dict[str, typing.Any]] = None,
1135
+ xml: typing.Optional[dict[str, typing.Any]] = None,
971
1136
  ) -> typing.Any:
972
1137
  return _RestField(
973
1138
  name=name,
@@ -984,8 +1149,8 @@ def rest_discriminator(
984
1149
  *,
985
1150
  name: typing.Optional[str] = None,
986
1151
  type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin
987
- visibility: typing.Optional[typing.List[str]] = None,
988
- xml: typing.Optional[typing.Dict[str, typing.Any]] = None,
1152
+ visibility: typing.Optional[list[str]] = None,
1153
+ xml: typing.Optional[dict[str, typing.Any]] = None,
989
1154
  ) -> typing.Any:
990
1155
  return _RestField(name=name, type=type, is_discriminator=True, visibility=visibility, xml=xml)
991
1156
 
@@ -1004,9 +1169,9 @@ def serialize_xml(model: Model, exclude_readonly: bool = False) -> str:
1004
1169
  def _get_element(
1005
1170
  o: typing.Any,
1006
1171
  exclude_readonly: bool = False,
1007
- parent_meta: typing.Optional[typing.Dict[str, typing.Any]] = None,
1172
+ parent_meta: typing.Optional[dict[str, typing.Any]] = None,
1008
1173
  wrapped_element: typing.Optional[ET.Element] = None,
1009
- ) -> typing.Union[ET.Element, typing.List[ET.Element]]:
1174
+ ) -> typing.Union[ET.Element, list[ET.Element]]:
1010
1175
  if _is_model(o):
1011
1176
  model_meta = getattr(o, "_xml", {})
1012
1177
 
@@ -1095,7 +1260,7 @@ def _get_element(
1095
1260
  def _get_wrapped_element(
1096
1261
  v: typing.Any,
1097
1262
  exclude_readonly: bool,
1098
- meta: typing.Optional[typing.Dict[str, typing.Any]],
1263
+ meta: typing.Optional[dict[str, typing.Any]],
1099
1264
  ) -> ET.Element:
1100
1265
  wrapped_element = _create_xml_element(
1101
1266
  meta.get("name") if meta else None, meta.get("prefix") if meta else None, meta.get("ns") if meta else None
@@ -1138,7 +1303,7 @@ def _deserialize_xml(
1138
1303
  def _convert_element(e: ET.Element):
1139
1304
  # dict case
1140
1305
  if len(e.attrib) > 0 or len({child.tag for child in e}) > 1:
1141
- dict_result: typing.Dict[str, typing.Any] = {}
1306
+ dict_result: dict[str, typing.Any] = {}
1142
1307
  for child in e:
1143
1308
  if dict_result.get(child.tag) is not None:
1144
1309
  if isinstance(dict_result[child.tag], list):
@@ -1151,7 +1316,7 @@ def _convert_element(e: ET.Element):
1151
1316
  return dict_result
1152
1317
  # array case
1153
1318
  if len(e) > 0:
1154
- array_result: typing.List[typing.Any] = []
1319
+ array_result: list[typing.Any] = []
1155
1320
  for child in e:
1156
1321
  array_result.append(_convert_element(child))
1157
1322
  return array_result