@typespec/http-client-python 0.27.2 → 0.28.1
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.
- package/dist/emitter/code-model.d.ts.map +1 -1
- package/dist/emitter/code-model.js +2 -1
- package/dist/emitter/code-model.js.map +1 -1
- package/dist/emitter/emitter.js +1 -1
- package/dist/emitter/emitter.js.map +1 -1
- package/dist/emitter/http.d.ts.map +1 -1
- package/dist/emitter/http.js +2 -13
- package/dist/emitter/http.js.map +1 -1
- package/emitter/src/code-model.ts +2 -1
- package/emitter/src/emitter.ts +1 -1
- package/emitter/src/http.ts +1 -13
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/Build-Packages.ps1 +1 -1
- package/eng/scripts/setup/__pycache__/package_manager.cpython-311.pyc +0 -0
- package/eng/scripts/setup/__pycache__/venvtools.cpython-311.pyc +0 -0
- package/eng/scripts/setup/package_manager.py +2 -2
- package/generator/build/lib/pygen/codegen/models/parameter.py +10 -4
- package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +6 -2
- package/generator/build/lib/pygen/preprocess/__init__.py +9 -21
- package/generator/build/lib/pygen/preprocess/python_mappings.py +0 -2
- package/generator/component-detection-pip-report.json +5 -6
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/codegen/models/parameter.py +10 -4
- package/generator/pygen/codegen/templates/model_base.py.jinja2 +6 -2
- package/generator/pygen/preprocess/__init__.py +9 -21
- package/generator/pygen/preprocess/python_mappings.py +0 -2
- package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_flatten_async.py +24 -2
- package/generator/test/azure/mock_api_tests/asynctests/test_client_naming_async.py +5 -5
- package/generator/test/azure/mock_api_tests/asynctests/test_client_structure_async.py +13 -11
- package/generator/test/azure/mock_api_tests/asynctests/test_client_structure_clientoperationgroup_async.py +6 -4
- package/generator/test/azure/mock_api_tests/asynctests/test_special_words_async.py +6 -0
- package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_flatten.py +22 -2
- package/generator/test/azure/mock_api_tests/test_client_naming.py +5 -5
- package/generator/test/azure/mock_api_tests/test_client_structure.py +12 -9
- package/generator/test/azure/mock_api_tests/test_client_structure_clientoperationgroup.py +7 -4
- package/generator/test/azure/mock_api_tests/test_special_words.py +5 -0
- package/generator/test/azure/requirements.txt +0 -1
- package/generator/test/generic_mock_api_tests/asynctests/test_authentication_async.py +13 -1
- package/generator/test/generic_mock_api_tests/asynctests/test_payload_pageable_async.py +7 -0
- package/generator/test/generic_mock_api_tests/asynctests/test_payload_xml_async.py +1 -0
- package/generator/test/generic_mock_api_tests/test_authentication.py +11 -1
- package/generator/test/generic_mock_api_tests/test_payload_pageable.py +6 -0
- package/generator/test/generic_mock_api_tests/test_payload_xml.py +1 -0
- package/generator/test/unbranded/mock_api_tests/asynctests/test_special_words_async.py +7 -0
- package/generator/test/unbranded/mock_api_tests/test_special_words.py +6 -0
- package/generator/test/unittests/test_enums.py +37 -0
- package/generator/test/unittests/test_model_base_xml_serialization.py +244 -2
- package/generator/test/unittests/test_name_converter.py +0 -8
- package/package.json +33 -33
- package/generator/test/azure/mock_api_tests/asynctests/test_azure_resource_manager_multi_service_older_versions_async.py +0 -111
- package/generator/test/azure/mock_api_tests/test_azure_resource_manager_multi_service_older_versions.py +0 -107
|
@@ -56,3 +56,8 @@ def test_model_properties_dict_methods(client: SpecialWordsClient):
|
|
|
56
56
|
|
|
57
57
|
def test_model_properties_with_list(client: SpecialWordsClient):
|
|
58
58
|
client.model_properties.with_list(models.ModelWithList(list="ok"))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_extensible_strings(client: SpecialWordsClient):
|
|
62
|
+
for enum_value in models.ExtensibleString:
|
|
63
|
+
assert enum_value == client.extensible_strings.put_extensible_string_value(body=enum_value)
|
|
@@ -40,7 +40,6 @@ azure-mgmt-core==1.6.0
|
|
|
40
40
|
-e ./generated/azure-resource-manager-resources
|
|
41
41
|
-e ./generated/azure-resource-manager-method-subscription-id
|
|
42
42
|
-e ./generated/azure-resource-manager-multi-service
|
|
43
|
-
-e ./generated/azure-resource-manager-multi-service-older-versions
|
|
44
43
|
-e ./generated/azure-resource-manager-multi-service-shared-models
|
|
45
44
|
-e ./generated/azure-versioning-previewversion
|
|
46
45
|
-e ./generated/client-namespace
|
|
@@ -9,7 +9,7 @@ from authentication.http.custom.aio import CustomClient
|
|
|
9
9
|
from authentication.oauth2.aio import OAuth2Client
|
|
10
10
|
from authentication.union.aio import UnionClient
|
|
11
11
|
from setuppy.authentication.union.aio import UnionClient as SetuppyUnionClient
|
|
12
|
-
|
|
12
|
+
from authentication.noauth.union.aio import UnionClient as NoauthUnionClient
|
|
13
13
|
|
|
14
14
|
# Utilities functions
|
|
15
15
|
|
|
@@ -113,6 +113,18 @@ async def test_union_tokenvalid(oauth2_client, union_client_type):
|
|
|
113
113
|
await client.valid_token(enforce_https=False)
|
|
114
114
|
|
|
115
115
|
|
|
116
|
+
@pytest.mark.asyncio
|
|
117
|
+
async def test_noauth_union_valid_no_auth():
|
|
118
|
+
client = NoauthUnionClient()
|
|
119
|
+
await client.valid_no_auth()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@pytest.mark.asyncio
|
|
123
|
+
async def test_noauth_union_valid_token(oauth2_client):
|
|
124
|
+
client = oauth2_client(NoauthUnionClient)
|
|
125
|
+
await client.valid_token(enforce_https=False)
|
|
126
|
+
|
|
127
|
+
|
|
116
128
|
@pytest.mark.asyncio
|
|
117
129
|
async def test_http_custom_valid(http_custom_client):
|
|
118
130
|
client = http_custom_client()
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
import pytest
|
|
7
7
|
from payload.pageable.aio import PageableClient
|
|
8
|
+
from payload.pageable.serverdrivenpagination.alternateinitialverb.models import Filter
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
@pytest.fixture
|
|
@@ -125,3 +126,9 @@ async def test_xml_pagination_list_with_continuation(client: PageableClient):
|
|
|
125
126
|
async def test_xml_pagination_list_with_next_link(client: PageableClient):
|
|
126
127
|
result = [p async for p in client.xml_pagination.list_with_next_link()]
|
|
127
128
|
assert_result(result)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@pytest.mark.asyncio
|
|
132
|
+
async def test_alternate_initial_verb_post(client: PageableClient):
|
|
133
|
+
result = [p async for p in client.server_driven_pagination.alternate_initial_verb.post(Filter(filter="foo eq bar"))]
|
|
134
|
+
assert_result(result)
|
|
@@ -138,6 +138,7 @@ async def test_model_with_datetime(client: XmlClient):
|
|
|
138
138
|
result = await client.model_with_datetime_value.get()
|
|
139
139
|
assert result.rfc3339 == model.rfc3339
|
|
140
140
|
assert result.rfc7231 == model.rfc7231
|
|
141
|
+
await client.model_with_datetime_value.put(model)
|
|
141
142
|
|
|
142
143
|
|
|
143
144
|
@pytest.mark.asyncio
|
|
@@ -8,9 +8,9 @@ from authentication.apikey import ApiKeyClient
|
|
|
8
8
|
from authentication.oauth2 import OAuth2Client
|
|
9
9
|
from authentication.union import UnionClient
|
|
10
10
|
from setuppy.authentication.union import UnionClient as SetuppyUnionClient
|
|
11
|
+
from authentication.noauth.union import UnionClient as NoauthUnionClient
|
|
11
12
|
from authentication.http.custom import CustomClient
|
|
12
13
|
|
|
13
|
-
|
|
14
14
|
# Utilities functions
|
|
15
15
|
|
|
16
16
|
|
|
@@ -107,6 +107,16 @@ def test_union_tokenvalid(oauth2_client, union_client_type):
|
|
|
107
107
|
client.valid_token(enforce_https=False)
|
|
108
108
|
|
|
109
109
|
|
|
110
|
+
def test_noauth_union_valid_no_auth():
|
|
111
|
+
client = NoauthUnionClient()
|
|
112
|
+
client.valid_no_auth()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_noauth_union_valid_token(oauth2_client):
|
|
116
|
+
client = oauth2_client(NoauthUnionClient)
|
|
117
|
+
client.valid_token(enforce_https=False)
|
|
118
|
+
|
|
119
|
+
|
|
110
120
|
def test_http_custom_valid(http_custom_client):
|
|
111
121
|
client = http_custom_client()
|
|
112
122
|
client.valid()
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
import pytest
|
|
7
7
|
from payload.pageable import PageableClient
|
|
8
|
+
from payload.pageable.serverdrivenpagination.alternateinitialverb.models import Filter
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
@pytest.fixture
|
|
@@ -91,3 +92,8 @@ def test_xml_pagination_list_with_continuation(client: PageableClient):
|
|
|
91
92
|
def test_xml_pagination_list_with_next_link(client: PageableClient):
|
|
92
93
|
result = list(client.xml_pagination.list_with_next_link())
|
|
93
94
|
assert_result(result)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_alternate_initial_verb_post(client: PageableClient):
|
|
98
|
+
result = list(client.server_driven_pagination.alternate_initial_verb.post(Filter(filter="foo eq bar")))
|
|
99
|
+
assert_result(result)
|
|
@@ -124,6 +124,7 @@ def test_model_with_datetime(client: XmlClient):
|
|
|
124
124
|
result = client.model_with_datetime_value.get()
|
|
125
125
|
assert result.rfc3339 == model.rfc3339
|
|
126
126
|
assert result.rfc7231 == model.rfc7231
|
|
127
|
+
client.model_with_datetime_value.put(model)
|
|
127
128
|
|
|
128
129
|
|
|
129
130
|
def test_xml_error_value(client: XmlClient, core_library):
|
|
@@ -7,6 +7,7 @@ import pytest
|
|
|
7
7
|
from specialwords.aio import SpecialWordsClient
|
|
8
8
|
from specialwords.models import models
|
|
9
9
|
from specialwords.modelproperties import models as model_properties_models
|
|
10
|
+
from specialwords.extensiblestrings import models as extensible_strings_models
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@pytest.fixture
|
|
@@ -64,3 +65,9 @@ async def test_model_properties_dict_methods(client: SpecialWordsClient):
|
|
|
64
65
|
@pytest.mark.asyncio
|
|
65
66
|
async def test_model_properties_with_list(client: SpecialWordsClient):
|
|
66
67
|
await client.model_properties.with_list(model_properties_models.ModelWithList(list="ok"))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@pytest.mark.asyncio
|
|
71
|
+
async def test_extensible_strings(client: SpecialWordsClient):
|
|
72
|
+
for enum_value in extensible_strings_models.ExtensibleString:
|
|
73
|
+
assert enum_value == await client.extensible_strings.put_extensible_string_value(body=enum_value)
|
|
@@ -7,6 +7,7 @@ import pytest
|
|
|
7
7
|
from specialwords import SpecialWordsClient
|
|
8
8
|
from specialwords.models import models
|
|
9
9
|
from specialwords.modelproperties import models as model_properties_models
|
|
10
|
+
from specialwords.extensiblestrings import models as extensible_strings_models
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@pytest.fixture
|
|
@@ -58,3 +59,8 @@ def test_model_properties_dict_methods(client: SpecialWordsClient):
|
|
|
58
59
|
|
|
59
60
|
def test_model_properties_with_list(client: SpecialWordsClient):
|
|
60
61
|
client.model_properties.with_list(model_properties_models.ModelWithList(list="ok"))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_extensible_strings(client: SpecialWordsClient):
|
|
65
|
+
for enum_value in extensible_strings_models.ExtensibleString:
|
|
66
|
+
assert enum_value == client.extensible_strings.put_extensible_string_value(body=enum_value)
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
from enum import Enum, EnumMeta
|
|
7
|
+
from specialwords.extensiblestrings import models as extensible_strings_models
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class _CaseInsensitiveEnumMeta(EnumMeta):
|
|
@@ -50,3 +51,39 @@ def test_find():
|
|
|
50
51
|
def test_join():
|
|
51
52
|
assert EnumsWithCallableNames.JOIN == "join"
|
|
52
53
|
assert callable(EnumsWithCallableNames.join)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_extensible_strings_enum_with_special_words():
|
|
57
|
+
assert extensible_strings_models.ExtensibleString.AND == "and"
|
|
58
|
+
assert extensible_strings_models.ExtensibleString.AS == "as"
|
|
59
|
+
assert extensible_strings_models.ExtensibleString.ASSERT == "assert"
|
|
60
|
+
assert extensible_strings_models.ExtensibleString.ASYNC == "async"
|
|
61
|
+
assert extensible_strings_models.ExtensibleString.AWAIT == "await"
|
|
62
|
+
assert extensible_strings_models.ExtensibleString.BREAK == "break"
|
|
63
|
+
assert extensible_strings_models.ExtensibleString.CLASS == "class"
|
|
64
|
+
assert extensible_strings_models.ExtensibleString.CONSTRUCTOR == "constructor"
|
|
65
|
+
assert extensible_strings_models.ExtensibleString.CONTINUE == "continue"
|
|
66
|
+
assert extensible_strings_models.ExtensibleString.DEF == "def"
|
|
67
|
+
assert extensible_strings_models.ExtensibleString.DEL == "del"
|
|
68
|
+
assert extensible_strings_models.ExtensibleString.ELIF == "elif"
|
|
69
|
+
assert extensible_strings_models.ExtensibleString.ELSE == "else"
|
|
70
|
+
assert extensible_strings_models.ExtensibleString.EXCEPT == "except"
|
|
71
|
+
assert extensible_strings_models.ExtensibleString.EXEC == "exec"
|
|
72
|
+
assert extensible_strings_models.ExtensibleString.FINALLY == "finally"
|
|
73
|
+
assert extensible_strings_models.ExtensibleString.FOR == "for"
|
|
74
|
+
assert extensible_strings_models.ExtensibleString.FROM == "from"
|
|
75
|
+
assert extensible_strings_models.ExtensibleString.GLOBAL == "global"
|
|
76
|
+
assert extensible_strings_models.ExtensibleString.IF == "if"
|
|
77
|
+
assert extensible_strings_models.ExtensibleString.IMPORT == "import"
|
|
78
|
+
assert extensible_strings_models.ExtensibleString.IN == "in"
|
|
79
|
+
assert extensible_strings_models.ExtensibleString.IS == "is"
|
|
80
|
+
assert extensible_strings_models.ExtensibleString.LAMBDA == "lambda"
|
|
81
|
+
assert extensible_strings_models.ExtensibleString.NOT == "not"
|
|
82
|
+
assert extensible_strings_models.ExtensibleString.OR == "or"
|
|
83
|
+
assert extensible_strings_models.ExtensibleString.PASS == "pass"
|
|
84
|
+
assert extensible_strings_models.ExtensibleString.RAISE == "raise"
|
|
85
|
+
assert extensible_strings_models.ExtensibleString.RETURN == "return"
|
|
86
|
+
assert extensible_strings_models.ExtensibleString.TRY == "try"
|
|
87
|
+
assert extensible_strings_models.ExtensibleString.WHILE == "while"
|
|
88
|
+
assert extensible_strings_models.ExtensibleString.WITH == "with"
|
|
89
|
+
assert extensible_strings_models.ExtensibleString.YIELD == "yield"
|
|
@@ -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
|
|
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.
|
|
3
|
+
"version": "0.28.1",
|
|
4
4
|
"author": "Microsoft Corporation",
|
|
5
5
|
"description": "TypeSpec emitter for Python SDKs",
|
|
6
6
|
"homepage": "https://typespec.io",
|
|
@@ -54,20 +54,20 @@
|
|
|
54
54
|
"emitter"
|
|
55
55
|
],
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@azure-tools/typespec-autorest": ">=0.
|
|
58
|
-
"@azure-tools/typespec-azure-core": ">=0.
|
|
59
|
-
"@azure-tools/typespec-azure-resource-manager": ">=0.
|
|
60
|
-
"@azure-tools/typespec-azure-rulesets": ">=0.
|
|
61
|
-
"@azure-tools/typespec-client-generator-core": ">=0.
|
|
62
|
-
"@typespec/compiler": "^1.
|
|
63
|
-
"@typespec/http": "^1.
|
|
64
|
-
"@typespec/openapi": "^1.
|
|
65
|
-
"@typespec/rest": ">=0.
|
|
66
|
-
"@typespec/versioning": ">=0.
|
|
67
|
-
"@typespec/events": ">=0.
|
|
68
|
-
"@typespec/sse": ">=0.
|
|
69
|
-
"@typespec/streams": ">=0.
|
|
70
|
-
"@typespec/xml": ">=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.66.0 <1.0.0",
|
|
61
|
+
"@azure-tools/typespec-client-generator-core": ">=0.66.3 <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",
|
|
@@ -77,24 +77,24 @@
|
|
|
77
77
|
"tsx": "^4.21.0"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@azure-tools/typespec-autorest": "~0.
|
|
81
|
-
"@azure-tools/typespec-azure-core": "~0.
|
|
82
|
-
"@azure-tools/typespec-azure-resource-manager": "~0.
|
|
83
|
-
"@azure-tools/typespec-azure-rulesets": "~0.
|
|
84
|
-
"@azure-tools/typespec-client-generator-core": "~0.
|
|
85
|
-
"@azure-tools/azure-http-specs": "0.1.0-alpha.
|
|
86
|
-
"@typespec/compiler": "^1.
|
|
87
|
-
"@typespec/http": "^1.
|
|
88
|
-
"@typespec/openapi": "^1.
|
|
89
|
-
"@typespec/rest": "~0.
|
|
90
|
-
"@typespec/versioning": "~0.
|
|
91
|
-
"@typespec/events": "~0.
|
|
92
|
-
"@typespec/spector": "0.1.0-alpha.
|
|
93
|
-
"@typespec/spec-api": "0.1.0-alpha.
|
|
94
|
-
"@typespec/sse": "~0.
|
|
95
|
-
"@typespec/streams": "~0.
|
|
96
|
-
"@typespec/xml": "~0.
|
|
97
|
-
"@typespec/http-specs": "0.1.0-alpha.
|
|
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.66.0",
|
|
84
|
+
"@azure-tools/typespec-client-generator-core": "~0.66.3",
|
|
85
|
+
"@azure-tools/azure-http-specs": "0.1.0-alpha.39-dev.4",
|
|
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.14-dev.1",
|
|
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.35",
|
|
98
98
|
"@types/js-yaml": "~4.0.5",
|
|
99
99
|
"@types/node": "~25.0.2",
|
|
100
100
|
"@types/semver": "7.5.8",
|