@typespec/http-client-python 0.21.0 → 0.23.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 (45) hide show
  1. package/dist/emitter/types.d.ts.map +1 -1
  2. package/dist/emitter/types.js +10 -1
  3. package/dist/emitter/types.js.map +1 -1
  4. package/emitter/src/types.ts +11 -1
  5. package/emitter/temp/tsconfig.tsbuildinfo +1 -1
  6. package/eng/scripts/ci/regenerate.ts +4 -0
  7. package/eng/scripts/setup/__pycache__/package_manager.cpython-311.pyc +0 -0
  8. package/eng/scripts/setup/__pycache__/venvtools.cpython-311.pyc +0 -0
  9. package/generator/build/lib/pygen/codegen/models/__init__.py +2 -0
  10. package/generator/build/lib/pygen/codegen/models/code_model.py +15 -0
  11. package/generator/build/lib/pygen/codegen/models/primitive_types.py +33 -0
  12. package/generator/build/lib/pygen/codegen/models/property.py +2 -0
  13. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +1 -2
  14. package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +29 -11
  15. package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +5 -0
  16. package/generator/build/lib/pygen/codegen/templates/macros.jinja2 +12 -5
  17. package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +92 -1
  18. package/generator/build/lib/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +3 -0
  19. package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +3 -0
  20. package/generator/build/lib/pygen/codegen/templates/utils.py.jinja2 +5 -4
  21. package/generator/build/lib/pygen/preprocess/__init__.py +23 -12
  22. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  23. package/generator/pygen/codegen/models/__init__.py +2 -0
  24. package/generator/pygen/codegen/models/code_model.py +15 -0
  25. package/generator/pygen/codegen/models/primitive_types.py +33 -0
  26. package/generator/pygen/codegen/models/property.py +2 -0
  27. package/generator/pygen/codegen/serializers/builder_serializer.py +1 -2
  28. package/generator/pygen/codegen/serializers/general_serializer.py +29 -11
  29. package/generator/pygen/codegen/serializers/model_serializer.py +5 -0
  30. package/generator/pygen/codegen/templates/macros.jinja2 +12 -5
  31. package/generator/pygen/codegen/templates/model_base.py.jinja2 +92 -1
  32. package/generator/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +3 -0
  33. package/generator/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +3 -0
  34. package/generator/pygen/codegen/templates/utils.py.jinja2 +5 -4
  35. package/generator/pygen/preprocess/__init__.py +23 -12
  36. package/generator/test/azure/mock_api_tests/test_model_base_flatten_compatibility.py +251 -0
  37. package/generator/test/azure/requirements.txt +3 -0
  38. package/generator/test/generic_mock_api_tests/asynctests/test_encode_array_async.py +43 -0
  39. package/generator/test/generic_mock_api_tests/asynctests/test_specs_documentation_async.py +60 -0
  40. package/generator/test/generic_mock_api_tests/test_encode_array.py +38 -0
  41. package/generator/test/generic_mock_api_tests/test_specs_documentation.py +52 -0
  42. package/generator/test/unbranded/requirements.txt +2 -0
  43. package/generator/test/unittests/test_model_base_serialization.py +264 -0
  44. package/generator/test/unittests/test_name_converter.py +1 -1
  45. package/package.json +33 -33
@@ -0,0 +1,251 @@
1
+ # ------------------------------------
2
+ # Copyright (c) Microsoft Corporation.
3
+ # Licensed under the MIT License.
4
+ # ------------------------------------
5
+ import datetime
6
+ from typing import (
7
+ Any,
8
+ Mapping,
9
+ Optional,
10
+ overload,
11
+ )
12
+
13
+ from specs.azure.clientgenerator.core.flattenproperty._utils.model_base import (
14
+ Model,
15
+ rest_field,
16
+ )
17
+ from azure.core.serialization import attribute_list
18
+
19
+
20
+ class ModelProperty(Model):
21
+ """This is a test model."""
22
+
23
+ value: str = rest_field()
24
+ """Required."""
25
+
26
+ @overload
27
+ def __init__(
28
+ self,
29
+ *,
30
+ value: str,
31
+ ) -> None: ...
32
+
33
+ @overload
34
+ def __init__(self, mapping: Mapping[str, Any]) -> None:
35
+ """
36
+ :param mapping: raw JSON to initialize the model.
37
+ :type mapping: Mapping[str, Any]
38
+ """
39
+
40
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
41
+ super().__init__(*args, **kwargs)
42
+
43
+
44
+ class ChildModel(Model):
45
+ """This is the child model to be flattened.
46
+
47
+ :ivar description: Required.
48
+ :vartype description: str
49
+ :ivar age: Required.
50
+ :vartype age: int
51
+ """
52
+
53
+ description: str = rest_field()
54
+ """Required."""
55
+ age: int = rest_field()
56
+ """Required."""
57
+ model_property: "ModelProperty" = rest_field(name="modelProperty")
58
+ """Required."""
59
+ datetime_default: datetime.datetime = rest_field(name="datetimeDefault")
60
+ datetime_rfc3339: datetime.datetime = rest_field(name="datetimeRfc3339", format="rfc3339")
61
+ datetime_rfc7231: datetime.datetime = rest_field(name="datetimeRfc7231", format="rfc7231")
62
+ datetime_unix_timestamp: datetime.datetime = rest_field(name="datetimeUnixTimestamp", format="unix-timestamp")
63
+
64
+ @overload
65
+ def __init__(
66
+ self,
67
+ *,
68
+ description: str,
69
+ age: int,
70
+ model_property: "ModelProperty",
71
+ datetime_default: datetime.datetime,
72
+ datetime_rfc3339: datetime.datetime,
73
+ datetime_rfc7231: datetime.datetime,
74
+ datetime_unix_timestamp: datetime.datetime,
75
+ ) -> None: ...
76
+
77
+ @overload
78
+ def __init__(self, mapping: Mapping[str, Any]) -> None:
79
+ """
80
+ :param mapping: raw JSON to initialize the model.
81
+ :type mapping: Mapping[str, Any]
82
+ """
83
+
84
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
85
+ super().__init__(*args, **kwargs)
86
+
87
+
88
+ class FlattenModel(Model):
89
+ """This is the model with one level of flattening."""
90
+
91
+ name: str = rest_field()
92
+ """Required."""
93
+ properties: "ChildModel" = rest_field()
94
+ """Required."""
95
+
96
+ __flattened_items = [
97
+ "description",
98
+ "age",
99
+ "model_property",
100
+ "datetime_default",
101
+ "datetime_rfc3339",
102
+ "datetime_rfc7231",
103
+ "datetime_unix_timestamp",
104
+ ]
105
+
106
+ @overload
107
+ def __init__(
108
+ self,
109
+ *,
110
+ name: str,
111
+ properties: "ChildModel",
112
+ ) -> None: ...
113
+
114
+ @overload
115
+ def __init__(self, mapping: Mapping[str, Any]) -> None:
116
+ """
117
+ :param mapping: raw JSON to initialize the model.
118
+ :type mapping: Mapping[str, Any]
119
+ """
120
+
121
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
122
+ _flattened_input = {k: kwargs.pop(k) for k in kwargs.keys() & self.__flattened_items}
123
+ super().__init__(*args, **kwargs)
124
+ for k, v in _flattened_input.items():
125
+ setattr(self, k, v)
126
+
127
+ def __getattr__(self, name: str) -> Any:
128
+ if name in self.__flattened_items:
129
+ if self.properties is None:
130
+ return None
131
+ return getattr(self.properties, name)
132
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
133
+
134
+ def __setattr__(self, key: str, value: Any) -> None:
135
+ if key in self.__flattened_items:
136
+ if self.properties is None:
137
+ self.properties = self._attr_to_rest_field["properties"]._class_type()
138
+ setattr(self.properties, key, value)
139
+ else:
140
+ super().__setattr__(key, value)
141
+
142
+
143
+ def test_model_initialization():
144
+ model = FlattenModel(
145
+ name="test",
146
+ description="a description",
147
+ age=30,
148
+ model_property=ModelProperty(value="test value"),
149
+ datetime_default=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc),
150
+ datetime_rfc3339=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc),
151
+ datetime_rfc7231=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc),
152
+ datetime_unix_timestamp=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc),
153
+ )
154
+
155
+ assert model.name == "test"
156
+
157
+ assert model.description == "a description"
158
+ assert model.properties.description == "a description"
159
+
160
+ assert model.age == 30
161
+ assert model.properties.age == 30
162
+
163
+ assert model.model_property.value == "test value"
164
+ assert model.properties.model_property == ModelProperty(value="test value")
165
+ assert model.properties.model_property.value == "test value"
166
+
167
+ assert model.datetime_default == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc)
168
+ assert model.properties.datetime_default == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc)
169
+ assert model.properties["datetimeDefault"] == "2023-01-12T00:00:00Z"
170
+
171
+ assert model.datetime_rfc3339 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc)
172
+ assert model.properties.datetime_rfc3339 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc)
173
+ assert model.properties["datetimeRfc3339"] == "2023-01-12T00:00:00Z"
174
+
175
+ assert model.datetime_rfc7231 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc)
176
+ assert model.properties.datetime_rfc7231 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc)
177
+ assert model.properties["datetimeRfc7231"] == "Thu, 12 Jan 2023 00:00:00 GMT"
178
+
179
+ assert model.datetime_unix_timestamp == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc)
180
+ assert model.properties.datetime_unix_timestamp == datetime.datetime(
181
+ 2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc
182
+ )
183
+ assert model.properties["datetimeUnixTimestamp"] == 1673481600
184
+
185
+
186
+ class FlattenModelWithOptionalProperties(Model):
187
+ """This is the model with one level of flattening and optional properties."""
188
+
189
+ name: str = rest_field()
190
+ """Required."""
191
+ properties: Optional["ModelProperty"] = rest_field()
192
+ """Optional."""
193
+
194
+ __flattened_items = ["value"]
195
+
196
+ @overload
197
+ def __init__(
198
+ self,
199
+ *,
200
+ name: str,
201
+ properties: Optional["ModelProperty"],
202
+ ) -> None: ...
203
+
204
+ @overload
205
+ def __init__(self, mapping: Mapping[str, Any]) -> None:
206
+ """
207
+ :param mapping: raw JSON to initialize the model.
208
+ :type mapping: Mapping[str, Any]
209
+ """
210
+
211
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
212
+ _flattened_input = {k: kwargs.pop(k) for k in kwargs.keys() & self.__flattened_items}
213
+ super().__init__(*args, **kwargs)
214
+ for k, v in _flattened_input.items():
215
+ setattr(self, k, v)
216
+
217
+ def __getattr__(self, name: str) -> Any:
218
+ if name in self.__flattened_items:
219
+ if self.properties is None:
220
+ return None
221
+ return getattr(self.properties, name)
222
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
223
+
224
+ def __setattr__(self, key: str, value: Any) -> None:
225
+ if key in self.__flattened_items:
226
+ if self.properties is None:
227
+ self.properties = self._attr_to_rest_field["properties"]._class_type()
228
+ setattr(self.properties, key, value)
229
+ else:
230
+ super().__setattr__(key, value)
231
+
232
+
233
+ def test_model_with_optional_properties_initialization():
234
+ model = FlattenModelWithOptionalProperties(
235
+ name="test",
236
+ value="test value",
237
+ )
238
+
239
+ assert model.name == "test"
240
+
241
+ assert model.value == "test value"
242
+ assert model.properties.value == "test value"
243
+
244
+
245
+ def test_model_with_optional_properties_attribute_list():
246
+ model = FlattenModelWithOptionalProperties(
247
+ name="test",
248
+ )
249
+
250
+ attrs = attribute_list(model)
251
+ assert sorted(attrs) == sorted(["name", "value"])
@@ -14,6 +14,7 @@ azure-mgmt-core==1.6.0
14
14
  -e ./generated/azure-client-generator-core-usage
15
15
  -e ./generated/azure-client-generator-core-override
16
16
  -e ./generated/azure-client-generator-core-client-location
17
+ -e ./generated/azure-client-generator-core-alternate-type
17
18
  -e ./generated/azure-client-generator-core-next-link-verb
18
19
  -e ./generated/azure-core-basic
19
20
  -e ./generated/azure-core-scalar
@@ -51,8 +52,10 @@ azure-mgmt-core==1.6.0
51
52
  -e ./generated/authentication-oauth2
52
53
  -e ./generated/authentication-union
53
54
  -e ./generated/setuppy-authentication-union
55
+ -e ./generated/specs-documentation
54
56
  -e ./generated/encode-duration
55
57
  -e ./generated/encode-numeric
58
+ -e ./generated/encode-array
56
59
  -e ./generated/parameters-basic
57
60
  -e ./generated/parameters-collection-format
58
61
  -e ./generated/parameters-path
@@ -0,0 +1,43 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+
7
+ import pytest
8
+ from encode.array.aio import ArrayClient
9
+ from encode.array import models
10
+
11
+
12
+ @pytest.fixture
13
+ async def client():
14
+ async with ArrayClient() as client:
15
+ yield client
16
+
17
+
18
+ @pytest.mark.asyncio
19
+ async def test_comma_delimited(client: ArrayClient):
20
+ body = models.CommaDelimitedArrayProperty(value=["blue", "red", "green"])
21
+ result = await client.property.comma_delimited(body)
22
+ assert result.value == ["blue", "red", "green"]
23
+
24
+
25
+ @pytest.mark.asyncio
26
+ async def test_space_delimited(client: ArrayClient):
27
+ body = models.SpaceDelimitedArrayProperty(value=["blue", "red", "green"])
28
+ result = await client.property.space_delimited(body)
29
+ assert result.value == ["blue", "red", "green"]
30
+
31
+
32
+ @pytest.mark.asyncio
33
+ async def test_pipe_delimited(client: ArrayClient):
34
+ body = models.PipeDelimitedArrayProperty(value=["blue", "red", "green"])
35
+ result = await client.property.pipe_delimited(body)
36
+ assert result.value == ["blue", "red", "green"]
37
+
38
+
39
+ @pytest.mark.asyncio
40
+ async def test_newline_delimited(client: ArrayClient):
41
+ body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"])
42
+ result = await client.property.newline_delimited(body)
43
+ assert result.value == ["blue", "red", "green"]
@@ -0,0 +1,60 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+
7
+ import pytest
8
+ from specs.documentation.aio import DocumentationClient
9
+ from specs.documentation import models
10
+
11
+
12
+ @pytest.fixture
13
+ async def client():
14
+ async with DocumentationClient(endpoint="http://localhost:3000") as client:
15
+ yield client
16
+
17
+
18
+ class TestLists:
19
+ @pytest.mark.asyncio
20
+ async def test_bullet_points_op(self, client: DocumentationClient):
21
+ # GET /documentation/lists/bullet-points/op
22
+ # Expected: 204 No Content
23
+ await client.lists.bullet_points_op()
24
+
25
+ @pytest.mark.skip(reason="https://github.com/microsoft/typespec/issues/9173")
26
+ @pytest.mark.asyncio
27
+ async def test_bullet_points_model(self, client: DocumentationClient):
28
+ # POST /documentation/lists/bullet-points/model
29
+ # Expected request body: {"prop": "Simple"}
30
+ # Expected: 200 OK
31
+ await client.lists.bullet_points_model(input=models.BulletPointsModel(prop="Simple"))
32
+
33
+ # Also test with JSON
34
+ await client.lists.bullet_points_model(body={"input": {"prop": "Simple"}})
35
+
36
+ @pytest.mark.asyncio
37
+ async def test_numbered(self, client: DocumentationClient):
38
+ # GET /documentation/lists/numbered
39
+ # Expected: 204 No Content
40
+ await client.lists.numbered()
41
+
42
+
43
+ class TestTextFormatting:
44
+ @pytest.mark.asyncio
45
+ async def test_bold_text(self, client: DocumentationClient):
46
+ # GET /documentation/text-formatting/bold
47
+ # Expected: 204 No Content
48
+ await client.text_formatting.bold_text()
49
+
50
+ @pytest.mark.asyncio
51
+ async def test_italic_text(self, client: DocumentationClient):
52
+ # GET /documentation/text-formatting/italic
53
+ # Expected: 204 No Content
54
+ await client.text_formatting.italic_text()
55
+
56
+ @pytest.mark.asyncio
57
+ async def test_combined_formatting(self, client: DocumentationClient):
58
+ # GET /documentation/text-formatting/combined
59
+ # Expected: 204 No Content
60
+ await client.text_formatting.combined_formatting()
@@ -0,0 +1,38 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+
7
+ import pytest
8
+ from encode.array import ArrayClient, models
9
+
10
+
11
+ @pytest.fixture
12
+ def client():
13
+ with ArrayClient() as client:
14
+ yield client
15
+
16
+
17
+ def test_comma_delimited(client: ArrayClient):
18
+ body = models.CommaDelimitedArrayProperty(value=["blue", "red", "green"])
19
+ result = client.property.comma_delimited(body)
20
+ assert result.value == ["blue", "red", "green"]
21
+
22
+
23
+ def test_space_delimited(client: ArrayClient):
24
+ body = models.SpaceDelimitedArrayProperty(value=["blue", "red", "green"])
25
+ result = client.property.space_delimited(body)
26
+ assert result.value == ["blue", "red", "green"]
27
+
28
+
29
+ def test_pipe_delimited(client: ArrayClient):
30
+ body = models.PipeDelimitedArrayProperty(value=["blue", "red", "green"])
31
+ result = client.property.pipe_delimited(body)
32
+ assert result.value == ["blue", "red", "green"]
33
+
34
+
35
+ def test_newline_delimited(client: ArrayClient):
36
+ body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"])
37
+ result = client.property.newline_delimited(body)
38
+ assert result.value == ["blue", "red", "green"]
@@ -0,0 +1,52 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+
7
+ import pytest
8
+ from specs.documentation import DocumentationClient, models
9
+
10
+
11
+ @pytest.fixture
12
+ def client():
13
+ with DocumentationClient(endpoint="http://localhost:3000") as client:
14
+ yield client
15
+
16
+
17
+ class TestLists:
18
+ def test_bullet_points_op(self, client: DocumentationClient):
19
+ # GET /documentation/lists/bullet-points/op
20
+ # Expected: 204 No Content
21
+ client.lists.bullet_points_op()
22
+
23
+ @pytest.mark.skip(reason="https://github.com/microsoft/typespec/issues/9173")
24
+ def test_bullet_points_model(self, client: DocumentationClient):
25
+ # POST /documentation/lists/bullet-points/model
26
+ # Expected: 200 OK
27
+ client.lists.bullet_points_model(input=models.BulletPointsModel(prop="Simple"))
28
+
29
+ # Also test with JSON
30
+ client.lists.bullet_points_model(body={"input": {"prop": "Simple"}})
31
+
32
+ def test_numbered(self, client: DocumentationClient):
33
+ # GET /documentation/lists/numbered
34
+ # Expected: 204 No Content
35
+ client.lists.numbered()
36
+
37
+
38
+ class TestTextFormatting:
39
+ def test_bold_text(self, client: DocumentationClient):
40
+ # GET /documentation/text-formatting/bold
41
+ # Expected: 204 No Content
42
+ client.text_formatting.bold_text()
43
+
44
+ def test_italic_text(self, client: DocumentationClient):
45
+ # GET /documentation/text-formatting/italic
46
+ # Expected: 204 No Content
47
+ client.text_formatting.italic_text()
48
+
49
+ def test_combined_formatting(self, client: DocumentationClient):
50
+ # GET /documentation/text-formatting/combined
51
+ # Expected: 204 No Content
52
+ client.text_formatting.combined_formatting()
@@ -7,8 +7,10 @@
7
7
  -e ./generated/authentication-oauth2
8
8
  -e ./generated/authentication-union
9
9
  -e ./generated/setuppy-authentication-union
10
+ -e ./generated/specs-documentation
10
11
  -e ./generated/encode-duration
11
12
  -e ./generated/encode-numeric
13
+ -e ./generated/encode-array
12
14
  -e ./generated/parameters-basic
13
15
  -e ./generated/parameters-collection-format
14
16
  -e ./generated/parameters-path