@typespec/http-client-python 0.27.1 → 0.28.0

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 (75) hide show
  1. package/dist/emitter/code-model.d.ts.map +1 -1
  2. package/dist/emitter/code-model.js +20 -15
  3. package/dist/emitter/code-model.js.map +1 -1
  4. package/dist/emitter/emitter.js +1 -1
  5. package/dist/emitter/emitter.js.map +1 -1
  6. package/dist/emitter/http.d.ts.map +1 -1
  7. package/dist/emitter/http.js +2 -3
  8. package/dist/emitter/http.js.map +1 -1
  9. package/emitter/src/code-model.ts +28 -21
  10. package/emitter/src/emitter.ts +1 -1
  11. package/emitter/src/http.ts +1 -4
  12. package/emitter/temp/tsconfig.tsbuildinfo +1 -1
  13. package/eng/scripts/ci/regenerate-common.ts +472 -0
  14. package/eng/scripts/ci/regenerate.ts +41 -437
  15. package/eng/scripts/setup/__pycache__/package_manager.cpython-311.pyc +0 -0
  16. package/eng/scripts/setup/__pycache__/venvtools.cpython-311.pyc +0 -0
  17. package/generator/build/lib/pygen/codegen/models/client.py +5 -5
  18. package/generator/build/lib/pygen/codegen/models/credential_types.py +1 -1
  19. package/generator/build/lib/pygen/codegen/models/enum_type.py +1 -1
  20. package/generator/build/lib/pygen/codegen/models/imports.py +2 -3
  21. package/generator/build/lib/pygen/codegen/models/lro_operation.py +1 -1
  22. package/generator/build/lib/pygen/codegen/models/model_type.py +2 -2
  23. package/generator/build/lib/pygen/codegen/models/operation.py +5 -5
  24. package/generator/build/lib/pygen/codegen/models/operation_group.py +1 -1
  25. package/generator/build/lib/pygen/codegen/models/paging_operation.py +2 -2
  26. package/generator/build/lib/pygen/codegen/models/primitive_types.py +1 -1
  27. package/generator/build/lib/pygen/codegen/models/request_builder.py +1 -1
  28. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +16 -7
  29. package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +4 -31
  30. package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +14 -4
  31. package/generator/build/lib/pygen/preprocess/__init__.py +9 -21
  32. package/generator/build/lib/pygen/preprocess/python_mappings.py +0 -2
  33. package/generator/component-detection-pip-report.json +5 -6
  34. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  35. package/generator/pygen/codegen/models/client.py +5 -5
  36. package/generator/pygen/codegen/models/credential_types.py +1 -1
  37. package/generator/pygen/codegen/models/enum_type.py +1 -1
  38. package/generator/pygen/codegen/models/imports.py +2 -3
  39. package/generator/pygen/codegen/models/lro_operation.py +1 -1
  40. package/generator/pygen/codegen/models/model_type.py +2 -2
  41. package/generator/pygen/codegen/models/operation.py +5 -5
  42. package/generator/pygen/codegen/models/operation_group.py +1 -1
  43. package/generator/pygen/codegen/models/paging_operation.py +2 -2
  44. package/generator/pygen/codegen/models/primitive_types.py +1 -1
  45. package/generator/pygen/codegen/models/request_builder.py +1 -1
  46. package/generator/pygen/codegen/serializers/builder_serializer.py +16 -7
  47. package/generator/pygen/codegen/serializers/import_serializer.py +4 -31
  48. package/generator/pygen/codegen/templates/model_base.py.jinja2 +14 -4
  49. package/generator/pygen/preprocess/__init__.py +9 -21
  50. package/generator/pygen/preprocess/python_mappings.py +0 -2
  51. package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_flatten_async.py +24 -2
  52. package/generator/test/azure/mock_api_tests/asynctests/test_azure_core_page_async.py +12 -0
  53. package/generator/test/azure/mock_api_tests/asynctests/test_special_words_async.py +6 -0
  54. package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_flatten.py +22 -2
  55. package/generator/test/azure/mock_api_tests/test_azure_core_page.py +11 -0
  56. package/generator/test/azure/mock_api_tests/test_clear_output_folder.py +9 -0
  57. package/generator/test/azure/mock_api_tests/test_special_words.py +5 -0
  58. package/generator/test/azure/requirements.txt +4 -1
  59. package/generator/test/generic_mock_api_tests/asynctests/test_authentication_async.py +13 -1
  60. package/generator/test/generic_mock_api_tests/asynctests/test_encode_bytes_async.py +6 -1
  61. package/generator/test/generic_mock_api_tests/asynctests/test_payload_xml_async.py +21 -0
  62. package/generator/test/generic_mock_api_tests/data/image.jpg +0 -0
  63. package/generator/test/generic_mock_api_tests/data/image.png +0 -0
  64. package/generator/test/generic_mock_api_tests/test_authentication.py +11 -1
  65. package/generator/test/generic_mock_api_tests/test_encode_bytes.py +6 -0
  66. package/generator/test/generic_mock_api_tests/test_payload_xml.py +19 -0
  67. package/generator/test/unbranded/mock_api_tests/asynctests/test_special_words_async.py +7 -0
  68. package/generator/test/unbranded/mock_api_tests/test_special_words.py +6 -0
  69. package/generator/test/unbranded/mock_api_tests/test_unbranded.py +9 -8
  70. package/generator/test/unbranded/requirements.txt +2 -1
  71. package/generator/test/unittests/test_enums.py +37 -0
  72. package/generator/test/unittests/test_model_base_serialization.py +161 -0
  73. package/generator/test/unittests/test_model_base_xml_serialization.py +244 -2
  74. package/generator/test/unittests/test_name_converter.py +0 -8
  75. package/package.json +39 -39
@@ -4743,3 +4743,164 @@ def test_dictionary_set_datetime():
4743
4743
  assert dict_ref1 is dict_ref2
4744
4744
  assert isinstance(dict_ref1["start"], datetime)
4745
4745
  assert isinstance(dict_ref2["start"], datetime)
4746
+
4747
+
4748
+ def test_eq_same_model_instances():
4749
+ """Two model instances with the same data should be equal."""
4750
+ model1 = BasicResource(
4751
+ platform_update_domain_count=5,
4752
+ platform_fault_domain_count=3,
4753
+ virtual_machines=[],
4754
+ )
4755
+ model2 = BasicResource(
4756
+ platform_update_domain_count=5,
4757
+ platform_fault_domain_count=3,
4758
+ virtual_machines=[],
4759
+ )
4760
+ assert model1 == model2
4761
+
4762
+
4763
+ def test_eq_different_model_data():
4764
+ """Two model instances with different data should not be equal."""
4765
+ model1 = BasicResource(
4766
+ platform_update_domain_count=5,
4767
+ platform_fault_domain_count=3,
4768
+ virtual_machines=[],
4769
+ )
4770
+ model2 = BasicResource(
4771
+ platform_update_domain_count=10,
4772
+ platform_fault_domain_count=3,
4773
+ virtual_machines=[],
4774
+ )
4775
+ assert model1 != model2
4776
+
4777
+
4778
+ def test_eq_model_constructed_from_dict():
4779
+ """A model created via kwargs and a model created from a dict should be equal."""
4780
+ dict_response = {
4781
+ "platformUpdateDomainCount": 5,
4782
+ "platformFaultDomainCount": 3,
4783
+ "virtualMachines": [],
4784
+ }
4785
+ model_from_kwargs = BasicResource(
4786
+ platform_update_domain_count=5,
4787
+ platform_fault_domain_count=3,
4788
+ virtual_machines=[],
4789
+ )
4790
+ model_from_dict = BasicResource(dict_response)
4791
+ assert model_from_kwargs == model_from_dict
4792
+
4793
+
4794
+ def test_eq_model_equal_to_plain_dict():
4795
+ """A model should be equal to a plain dict with matching data (backward compat)."""
4796
+ dict_response = {
4797
+ "platformUpdateDomainCount": 5,
4798
+ "platformFaultDomainCount": 3,
4799
+ "virtualMachines": [],
4800
+ }
4801
+ model = BasicResource(
4802
+ platform_update_domain_count=5,
4803
+ platform_fault_domain_count=3,
4804
+ virtual_machines=[],
4805
+ )
4806
+ assert model == dict_response
4807
+
4808
+
4809
+ def test_eq_model_not_equal_to_non_model_types():
4810
+ """A model should not be equal to strings, ints, None, or lists."""
4811
+ model = BasicResource(
4812
+ platform_update_domain_count=5,
4813
+ platform_fault_domain_count=3,
4814
+ virtual_machines=[],
4815
+ )
4816
+ assert model != "some string"
4817
+ assert model != 42
4818
+ assert model != None # noqa: E711
4819
+ assert model != []
4820
+ assert model != True # noqa: E712
4821
+
4822
+
4823
+ def test_eq_different_model_types_same_data():
4824
+ """Two different model types with the same underlying _data should be equal
4825
+ since isinstance checks against _MyMutableMapping, not the specific subclass."""
4826
+ model1 = Pet(name="test", species="dog")
4827
+
4828
+ class AnotherModel(Model):
4829
+ name: str = rest_field()
4830
+ species: str = rest_field()
4831
+
4832
+ @overload
4833
+ def __init__(self, *, name: str, species: str): ...
4834
+
4835
+ @overload
4836
+ def __init__(self, mapping: Mapping[str, Any], /): ...
4837
+
4838
+ def __init__(self, *args, **kwargs):
4839
+ super().__init__(*args, **kwargs)
4840
+
4841
+ model2 = AnotherModel(name="test", species="dog")
4842
+ assert model1 == model2
4843
+
4844
+
4845
+ def test_ne_is_inverse_of_eq():
4846
+ """__ne__ should return the inverse of __eq__."""
4847
+ model1 = BasicResource(
4848
+ platform_update_domain_count=5,
4849
+ platform_fault_domain_count=3,
4850
+ virtual_machines=[],
4851
+ )
4852
+ model2 = BasicResource(
4853
+ platform_update_domain_count=5,
4854
+ platform_fault_domain_count=3,
4855
+ virtual_machines=[],
4856
+ )
4857
+ model3 = BasicResource(
4858
+ platform_update_domain_count=10,
4859
+ platform_fault_domain_count=3,
4860
+ virtual_machines=[],
4861
+ )
4862
+ assert not (model1 != model2)
4863
+ assert model1 != model3
4864
+
4865
+
4866
+ def test_eq_nested_models():
4867
+ """Two models with identical nested model children should be equal."""
4868
+ model1 = OptionalModel(
4869
+ optional_str="hello",
4870
+ optional_time=datetime.time(11, 34, 56),
4871
+ optional_dict={
4872
+ "buddy": Pet(name="Buddy", species="Dog"),
4873
+ },
4874
+ optional_myself=OptionalModel(optional_str="inner"),
4875
+ )
4876
+ model2 = OptionalModel(
4877
+ optional_str="hello",
4878
+ optional_time=datetime.time(11, 34, 56),
4879
+ optional_dict={
4880
+ "buddy": Pet(name="Buddy", species="Dog"),
4881
+ },
4882
+ optional_myself=OptionalModel(optional_str="inner"),
4883
+ )
4884
+ assert model1 == model2
4885
+
4886
+ # Change the nested model's data — they should no longer be equal
4887
+ model2_different_inner = OptionalModel(
4888
+ optional_str="hello",
4889
+ optional_time=datetime.time(11, 34, 56),
4890
+ optional_dict={
4891
+ "buddy": Pet(name="Buddy", species="Dog"),
4892
+ },
4893
+ optional_myself=OptionalModel(optional_str="different"),
4894
+ )
4895
+ assert model1 != model2_different_inner
4896
+
4897
+ # Change the nested Pet — they should no longer be equal
4898
+ model2_different_pet = OptionalModel(
4899
+ optional_str="hello",
4900
+ optional_time=datetime.time(11, 34, 56),
4901
+ optional_dict={
4902
+ "buddy": Pet(name="Max", species="Cat"),
4903
+ },
4904
+ optional_myself=OptionalModel(optional_str="inner"),
4905
+ )
4906
+ assert model1 != model2_different_pet
@@ -4,7 +4,7 @@
4
4
  # ------------------------------------
5
5
  import xml.etree.ElementTree as ET
6
6
 
7
- from typing import Literal
7
+ from typing import Literal, Optional
8
8
 
9
9
  from specialwords._utils.model_base import (
10
10
  _get_element,
@@ -165,7 +165,7 @@ class TestXmlDeserialization:
165
165
  _xml = {"name": "Data"}
166
166
 
167
167
  result = _deserialize_xml(XmlModel, basic_xml)
168
- assert result.age is None
168
+ assert result.age == []
169
169
 
170
170
  def test_list_wrapped_items_name_basic_types(self):
171
171
  """Test XML list and wrap, items is basic type and there is itemsName."""
@@ -515,6 +515,248 @@ class TestXmlDeserialization:
515
515
  assert isinstance(result.filter, CorrelationFilter)
516
516
  assert result.filter.correlation_id == 12
517
517
 
518
+ def test_enumeration_results(self):
519
+ """Test deserializing an Azure Blob Storage EnumerationResults XML payload."""
520
+ xml_payload = '<?xml version="1.0" encoding="utf-8"?><EnumerationResults ServiceEndpoint="https://service.blob.core.windows.net/" ContainerName="my-container-108f32e8"><Delimiter>/</Delimiter><Blobs /><NextMarker /></EnumerationResults>'
521
+
522
+ class EnumerationResults(Model):
523
+ service_endpoint: str = rest_field(
524
+ name="ServiceEndpoint", xml={"name": "ServiceEndpoint", "attribute": True}
525
+ )
526
+ container_name: str = rest_field(name="ContainerName", xml={"name": "ContainerName", "attribute": True})
527
+ delimiter: str = rest_field(name="Delimiter", xml={"name": "Delimiter"})
528
+ blobs: list[str] = rest_field(name="Blobs", xml={"name": "Blobs"})
529
+ next_marker: str = rest_field(name="NextMarker", xml={"name": "NextMarker"})
530
+
531
+ def __init__(self, *args, **kwargs):
532
+ super().__init__(*args, **kwargs)
533
+
534
+ _xml = {"name": "EnumerationResults"}
535
+
536
+ result = _deserialize_xml(EnumerationResults, xml_payload)
537
+
538
+ assert result.service_endpoint == "https://service.blob.core.windows.net/"
539
+ assert result.container_name == "my-container-108f32e8"
540
+ assert result.delimiter == "/"
541
+ assert result.blobs == []
542
+ assert result.next_marker == ""
543
+
544
+ def test_enumeration_results_nested_empty_list(self):
545
+ """Test deserializing XML where a container element holds a nested empty list (e.g. Blobs/BlobPrefixes)."""
546
+ xml_payload = '<?xml version="1.0" encoding="utf-8"?><EnumerationResults ServiceEndpoint="https://service.blob.core.windows.net/" ContainerName="my-container"><Delimiter>/</Delimiter><Blobs><BlobPrefixes /></Blobs><NextMarker /></EnumerationResults>'
547
+
548
+ class BlobPrefix(Model):
549
+ name: str = rest_field(name="Name", xml={"name": "Name"})
550
+
551
+ def __init__(self, *args, **kwargs):
552
+ super().__init__(*args, **kwargs)
553
+
554
+ _xml = {"name": "BlobPrefix"}
555
+
556
+ class BlobsSegment(Model):
557
+ blob_prefixes: list[BlobPrefix] = rest_field(
558
+ name="BlobPrefixes", xml={"name": "BlobPrefixes", "itemsName": "BlobPrefix"}
559
+ )
560
+
561
+ def __init__(self, *args, **kwargs):
562
+ super().__init__(*args, **kwargs)
563
+
564
+ _xml = {"name": "Blobs"}
565
+
566
+ class EnumerationResults(Model):
567
+ service_endpoint: str = rest_field(
568
+ name="ServiceEndpoint", xml={"name": "ServiceEndpoint", "attribute": True}
569
+ )
570
+ container_name: str = rest_field(name="ContainerName", xml={"name": "ContainerName", "attribute": True})
571
+ delimiter: str = rest_field(name="Delimiter", xml={"name": "Delimiter"})
572
+ blobs: BlobsSegment = rest_field(name="Blobs", xml={"name": "Blobs"})
573
+ next_marker: str = rest_field(name="NextMarker", xml={"name": "NextMarker"})
574
+
575
+ def __init__(self, *args, **kwargs):
576
+ super().__init__(*args, **kwargs)
577
+
578
+ _xml = {"name": "EnumerationResults"}
579
+
580
+ result = _deserialize_xml(EnumerationResults, xml_payload)
581
+
582
+ assert result.service_endpoint == "https://service.blob.core.windows.net/"
583
+ assert result.container_name == "my-container"
584
+ assert result.delimiter == "/"
585
+ assert result.blobs.blob_prefixes == []
586
+ assert result.next_marker == ""
587
+
588
+ def test_enumeration_results_azure_sdk_pattern(self):
589
+ """Test the real Azure SDK model pattern where BlobsSegment has two unwrapped list fields."""
590
+ # Both blob_prefixes and blob_items are unwrapped lists (items appear directly in <Blobs>).
591
+ # With <Blobs />, no matching children are found so both are None.
592
+ xml_payload = '<?xml version="1.0" encoding="utf-8"?><EnumerationResults ServiceEndpoint="https://service.blob.core.windows.net/" ContainerName="my-container"><Delimiter>/</Delimiter><Blobs /><NextMarker /></EnumerationResults>'
593
+
594
+ class BlobPrefix(Model):
595
+ name: str = rest_field(name="Name", xml={"name": "Name"})
596
+
597
+ def __init__(self, *args, **kwargs):
598
+ super().__init__(*args, **kwargs)
599
+
600
+ _xml = {"name": "BlobPrefix"}
601
+
602
+ class BlobItem(Model):
603
+ name: str = rest_field(name="Name", xml={"name": "Name"})
604
+
605
+ def __init__(self, *args, **kwargs):
606
+ super().__init__(*args, **kwargs)
607
+
608
+ _xml = {"name": "Blob"}
609
+
610
+ class BlobsSegment(Model):
611
+ blob_prefixes: list[BlobPrefix] = rest_field(
612
+ name="blob_prefixes", xml={"name": "BlobPrefix", "unwrapped": True}
613
+ )
614
+ blob_items: list[BlobItem] = rest_field(name="blob_items", xml={"name": "Blob", "unwrapped": True})
615
+
616
+ def __init__(self, *args, **kwargs):
617
+ super().__init__(*args, **kwargs)
618
+
619
+ _xml = {"name": "Blobs"}
620
+
621
+ class EnumerationResults(Model):
622
+ service_endpoint: str = rest_field(
623
+ name="ServiceEndpoint", xml={"name": "ServiceEndpoint", "attribute": True}
624
+ )
625
+ container_name: str = rest_field(name="ContainerName", xml={"name": "ContainerName", "attribute": True})
626
+ delimiter: str = rest_field(name="Delimiter", xml={"name": "Delimiter"})
627
+ blobs: BlobsSegment = rest_field(name="Blobs", xml={"name": "Blobs"})
628
+ next_marker: str = rest_field(name="NextMarker", xml={"name": "NextMarker"})
629
+
630
+ def __init__(self, *args, **kwargs):
631
+ super().__init__(*args, **kwargs)
632
+
633
+ _xml = {"name": "EnumerationResults"}
634
+
635
+ result = _deserialize_xml(EnumerationResults, xml_payload)
636
+
637
+ assert result.service_endpoint == "https://service.blob.core.windows.net/"
638
+ assert result.container_name == "my-container"
639
+ assert result.delimiter == "/"
640
+ assert isinstance(result.blobs, BlobsSegment)
641
+ # With <Blobs />, no <BlobPrefix> or <Blob> children exist → unwrapped non-optional lists default to []
642
+ assert result.blobs.blob_prefixes == []
643
+ assert result.blobs.blob_items == []
644
+ assert result.next_marker == ""
645
+
646
+ def test_enumeration_results_azure_sdk_pattern_optional(self):
647
+ """Test the Azure SDK pattern where unwrapped list fields are Optional[list[X]].
648
+
649
+ When the type is Optional[list[X]], empty unwrapped lists should stay None
650
+ (the element is absent, and None is a valid value for the optional type).
651
+ """
652
+ xml_payload = '<?xml version="1.0" encoding="utf-8"?><EnumerationResults ServiceEndpoint="https://service.blob.core.windows.net/" ContainerName="my-container"><Delimiter>/</Delimiter><Blobs /><NextMarker /></EnumerationResults>'
653
+
654
+ class BlobPrefix(Model):
655
+ name: str = rest_field(name="Name", xml={"name": "Name"})
656
+
657
+ def __init__(self, *args, **kwargs):
658
+ super().__init__(*args, **kwargs)
659
+
660
+ _xml = {"name": "BlobPrefix"}
661
+
662
+ class BlobItem(Model):
663
+ name: str = rest_field(name="Name", xml={"name": "Name"})
664
+
665
+ def __init__(self, *args, **kwargs):
666
+ super().__init__(*args, **kwargs)
667
+
668
+ _xml = {"name": "Blob"}
669
+
670
+ class BlobsSegment(Model):
671
+ blob_prefixes: Optional[list[BlobPrefix]] = rest_field(
672
+ name="blob_prefixes", xml={"name": "BlobPrefix", "unwrapped": True}
673
+ )
674
+ blob_items: Optional[list[BlobItem]] = rest_field(
675
+ name="blob_items", xml={"name": "Blob", "unwrapped": True}
676
+ )
677
+
678
+ def __init__(self, *args, **kwargs):
679
+ super().__init__(*args, **kwargs)
680
+
681
+ _xml = {"name": "Blobs"}
682
+
683
+ class EnumerationResults(Model):
684
+ service_endpoint: str = rest_field(
685
+ name="ServiceEndpoint", xml={"name": "ServiceEndpoint", "attribute": True}
686
+ )
687
+ container_name: str = rest_field(name="ContainerName", xml={"name": "ContainerName", "attribute": True})
688
+ delimiter: str = rest_field(name="Delimiter", xml={"name": "Delimiter"})
689
+ blobs: BlobsSegment = rest_field(name="Blobs", xml={"name": "Blobs"})
690
+ next_marker: str = rest_field(name="NextMarker", xml={"name": "NextMarker"})
691
+
692
+ def __init__(self, *args, **kwargs):
693
+ super().__init__(*args, **kwargs)
694
+
695
+ _xml = {"name": "EnumerationResults"}
696
+
697
+ result = _deserialize_xml(EnumerationResults, xml_payload)
698
+
699
+ assert result.service_endpoint == "https://service.blob.core.windows.net/"
700
+ assert result.container_name == "my-container"
701
+ assert result.delimiter == "/"
702
+ assert isinstance(result.blobs, BlobsSegment)
703
+ # With <Blobs />, no <BlobPrefix> or <Blob> children exist → Optional lists stay None
704
+ assert result.blobs.blob_prefixes is None
705
+ assert result.blobs.blob_items is None
706
+ assert result.next_marker == ""
707
+
708
+ def test_enumeration_results_blobs_unwrapped(self):
709
+ """Test what happens when the blobs field itself is declared with unwrapped=True."""
710
+ # When a non-list model field uses unwrapped=True, the matching XML elements are collected
711
+ # as a list and stored as-is (the field receives a list of ET.Element objects).
712
+ xml_payload = '<?xml version="1.0" encoding="utf-8"?><EnumerationResults ServiceEndpoint="https://service.blob.core.windows.net/" ContainerName="my-container"><Delimiter>/</Delimiter><Blobs /><NextMarker /></EnumerationResults>'
713
+
714
+ class BlobPrefix(Model):
715
+ name: str = rest_field(name="Name", xml={"name": "Name"})
716
+
717
+ def __init__(self, *args, **kwargs):
718
+ super().__init__(*args, **kwargs)
719
+
720
+ _xml = {"name": "BlobPrefix"}
721
+
722
+ class BlobsSegment(Model):
723
+ blob_prefixes: list[BlobPrefix] = rest_field(
724
+ name="BlobPrefixes", xml={"name": "BlobPrefixes", "itemsName": "BlobPrefix"}
725
+ )
726
+
727
+ def __init__(self, *args, **kwargs):
728
+ super().__init__(*args, **kwargs)
729
+
730
+ _xml = {"name": "Blobs"}
731
+
732
+ class EnumerationResults(Model):
733
+ service_endpoint: str = rest_field(
734
+ name="ServiceEndpoint", xml={"name": "ServiceEndpoint", "attribute": True}
735
+ )
736
+ container_name: str = rest_field(name="ContainerName", xml={"name": "ContainerName", "attribute": True})
737
+ delimiter: str = rest_field(name="Delimiter", xml={"name": "Delimiter"})
738
+ # unwrapped=True on a model-typed field: the deserialization collects matching XML
739
+ # elements as a list (rather than deserializing them into the model).
740
+ blobs: BlobsSegment = rest_field(name="Blobs", xml={"name": "Blobs", "unwrapped": True})
741
+ next_marker: str = rest_field(name="NextMarker", xml={"name": "NextMarker"})
742
+
743
+ def __init__(self, *args, **kwargs):
744
+ super().__init__(*args, **kwargs)
745
+
746
+ _xml = {"name": "EnumerationResults"}
747
+
748
+ result = _deserialize_xml(EnumerationResults, xml_payload)
749
+
750
+ assert result.service_endpoint == "https://service.blob.core.windows.net/"
751
+ assert result.container_name == "my-container"
752
+ assert result.delimiter == "/"
753
+ # unwrapped=True on a model field collects matching elements; <Blobs /> is found so it
754
+ # returns a list containing the raw ET.Element instead of a deserialized BlobsSegment.
755
+ assert isinstance(result.blobs, list)
756
+ assert len(result.blobs) == 1
757
+ assert isinstance(result.blobs[0], ET.Element)
758
+ assert result.next_marker == ""
759
+
518
760
 
519
761
  class TestXmlSerialization:
520
762
  def test_basic(self):
@@ -33,11 +33,3 @@ def test_escaped_reserved_words():
33
33
  }
34
34
  for name in expected_conversion_parameter:
35
35
  assert pad_reserved_words(name, pad_type=PadType.PARAMETER) == expected_conversion_parameter[name]
36
-
37
- expected_conversion_enum = {
38
- "self": "self",
39
- "mro": "mro_enum",
40
- "continuation_token": "continuation_token",
41
- }
42
- for name in expected_conversion_enum:
43
- assert pad_reserved_words(name, pad_type=PadType.ENUM_VALUE) == expected_conversion_enum[name]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/http-client-python",
3
- "version": "0.27.1",
3
+ "version": "0.28.0",
4
4
  "author": "Microsoft Corporation",
5
5
  "description": "TypeSpec emitter for Python SDKs",
6
6
  "homepage": "https://typespec.io",
@@ -54,55 +54,55 @@
54
54
  "emitter"
55
55
  ],
56
56
  "peerDependencies": {
57
- "@azure-tools/typespec-autorest": ">=0.65.0 <1.0.0",
58
- "@azure-tools/typespec-azure-core": ">=0.65.0 <1.0.0",
59
- "@azure-tools/typespec-azure-resource-manager": ">=0.65.0 <1.0.0",
60
- "@azure-tools/typespec-azure-rulesets": ">=0.65.0 <1.0.0",
61
- "@azure-tools/typespec-client-generator-core": ">=0.65.0 <1.0.0",
62
- "@typespec/compiler": "^1.9.0",
63
- "@typespec/http": "^1.9.0",
64
- "@typespec/openapi": "^1.9.0",
65
- "@typespec/rest": ">=0.79.0 <1.0.0",
66
- "@typespec/versioning": ">=0.79.0 <1.0.0",
67
- "@typespec/events": ">=0.79.0 <1.0.0",
68
- "@typespec/sse": ">=0.79.0 <1.0.0",
69
- "@typespec/streams": ">=0.79.0 <1.0.0",
70
- "@typespec/xml": ">=0.79.0 <1.0.0"
57
+ "@azure-tools/typespec-autorest": ">=0.66.0 <1.0.0",
58
+ "@azure-tools/typespec-azure-core": ">=0.66.0 <1.0.0",
59
+ "@azure-tools/typespec-azure-resource-manager": ">=0.66.0 <1.0.0",
60
+ "@azure-tools/typespec-azure-rulesets": ">=0.65.1 <1.0.0",
61
+ "@azure-tools/typespec-client-generator-core": ">=0.66.1 <1.0.0",
62
+ "@typespec/compiler": "^1.10.0",
63
+ "@typespec/http": "^1.10.0",
64
+ "@typespec/openapi": "^1.10.0",
65
+ "@typespec/rest": ">=0.80.0 <1.0.0",
66
+ "@typespec/versioning": ">=0.80.0 <1.0.0",
67
+ "@typespec/events": ">=0.80.0 <1.0.0",
68
+ "@typespec/sse": ">=0.80.0 <1.0.0",
69
+ "@typespec/streams": ">=0.80.0 <1.0.0",
70
+ "@typespec/xml": ">=0.80.0 <1.0.0"
71
71
  },
72
72
  "dependencies": {
73
73
  "js-yaml": "~4.1.0",
74
74
  "marked": "^15.0.6",
75
75
  "pyodide": "0.26.2",
76
76
  "semver": "~7.6.2",
77
- "tsx": "~4.19.1"
77
+ "tsx": "^4.21.0"
78
78
  },
79
79
  "devDependencies": {
80
- "@azure-tools/typespec-autorest": "~0.65.0",
81
- "@azure-tools/typespec-azure-core": "~0.65.0",
82
- "@azure-tools/typespec-azure-resource-manager": "~0.65.0",
83
- "@azure-tools/typespec-azure-rulesets": "~0.65.0",
84
- "@azure-tools/typespec-client-generator-core": "~0.65.0",
85
- "@azure-tools/azure-http-specs": "0.1.0-alpha.37",
86
- "@typespec/compiler": "^1.9.0",
87
- "@typespec/http": "^1.9.0",
88
- "@typespec/openapi": "^1.9.0",
89
- "@typespec/rest": "~0.79.0",
90
- "@typespec/versioning": "~0.79.0",
91
- "@typespec/events": "~0.79.0",
92
- "@typespec/spector": "0.1.0-alpha.23",
93
- "@typespec/spec-api": "0.1.0-alpha.12",
94
- "@typespec/sse": "~0.79.0",
95
- "@typespec/streams": "~0.79.0",
96
- "@typespec/xml": "~0.79.0",
97
- "@typespec/http-specs": "0.1.0-alpha.32",
80
+ "@azure-tools/typespec-autorest": "~0.66.0",
81
+ "@azure-tools/typespec-azure-core": "~0.66.0",
82
+ "@azure-tools/typespec-azure-resource-manager": "~0.66.0",
83
+ "@azure-tools/typespec-azure-rulesets": "~0.65.1",
84
+ "@azure-tools/typespec-client-generator-core": "~0.66.1",
85
+ "@azure-tools/azure-http-specs": "0.1.0-alpha.38",
86
+ "@typespec/compiler": "^1.10.0",
87
+ "@typespec/http": "^1.10.0",
88
+ "@typespec/openapi": "^1.10.0",
89
+ "@typespec/rest": "~0.80.0",
90
+ "@typespec/versioning": "~0.80.0",
91
+ "@typespec/events": "~0.80.0",
92
+ "@typespec/spector": "0.1.0-alpha.24",
93
+ "@typespec/spec-api": "0.1.0-alpha.13",
94
+ "@typespec/sse": "~0.80.0",
95
+ "@typespec/streams": "~0.80.0",
96
+ "@typespec/xml": "~0.80.0",
97
+ "@typespec/http-specs": "0.1.0-alpha.34",
98
98
  "@types/js-yaml": "~4.0.5",
99
- "@types/node": "~24.1.0",
99
+ "@types/node": "~25.0.2",
100
100
  "@types/semver": "7.5.8",
101
101
  "c8": "^10.1.3",
102
102
  "chalk": "5.3.0",
103
- "rimraf": "~6.0.1",
104
- "typescript": "~5.8.2",
105
- "typescript-eslint": "^8.21.0",
106
- "vitest": "^3.1.2"
103
+ "rimraf": "~6.1.2",
104
+ "typescript": "~5.9.2",
105
+ "typescript-eslint": "^8.49.0",
106
+ "vitest": "^4.0.15"
107
107
  }
108
108
  }