@typespec/http-client-python 0.4.4 → 0.5.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/emitter.d.ts.map +1 -1
- package/dist/emitter/emitter.js +110 -24
- package/dist/emitter/emitter.js.map +1 -1
- package/dist/emitter/http.js +1 -1
- package/dist/emitter/http.js.map +1 -1
- package/dist/emitter/lib.d.ts +1 -0
- package/dist/emitter/lib.d.ts.map +1 -1
- package/dist/emitter/lib.js +1 -0
- package/dist/emitter/lib.js.map +1 -1
- package/dist/emitter/run-python3.d.ts +2 -0
- package/dist/emitter/run-python3.d.ts.map +1 -0
- package/dist/emitter/run-python3.js +19 -0
- package/dist/emitter/run-python3.js.map +1 -0
- package/dist/emitter/system-requirements.d.ts +17 -0
- package/dist/emitter/system-requirements.d.ts.map +1 -0
- package/dist/emitter/system-requirements.js +167 -0
- package/dist/emitter/system-requirements.js.map +1 -0
- package/emitter/src/emitter.ts +111 -23
- package/emitter/src/http.ts +1 -1
- package/emitter/src/lib.ts +2 -0
- package/emitter/src/run-python3.ts +20 -0
- package/emitter/src/system-requirements.ts +261 -0
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/Test-Packages.ps1 +1 -1
- package/eng/scripts/ci/regenerate.ts +20 -8
- package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
- package/eng/scripts/setup/build.ts +16 -0
- package/eng/scripts/setup/build_pygen_wheel.py +40 -0
- package/eng/scripts/setup/install.py +9 -8
- package/eng/scripts/setup/install.ts +12 -0
- package/eng/scripts/setup/prepare.py +3 -1
- package/eng/scripts/setup/prepare.ts +11 -0
- package/eng/scripts/setup/run-python3.ts +1 -6
- package/generator/build/lib/pygen/__init__.py +107 -0
- package/generator/build/lib/pygen/_version.py +7 -0
- package/generator/build/lib/pygen/black.py +71 -0
- package/generator/build/lib/pygen/codegen/__init__.py +357 -0
- package/generator/build/lib/pygen/codegen/_utils.py +17 -0
- package/generator/build/lib/pygen/codegen/models/__init__.py +204 -0
- package/generator/build/lib/pygen/codegen/models/base.py +186 -0
- package/generator/build/lib/pygen/codegen/models/base_builder.py +118 -0
- package/generator/build/lib/pygen/codegen/models/client.py +435 -0
- package/generator/build/lib/pygen/codegen/models/code_model.py +237 -0
- package/generator/build/lib/pygen/codegen/models/combined_type.py +149 -0
- package/generator/build/lib/pygen/codegen/models/constant_type.py +129 -0
- package/generator/build/lib/pygen/codegen/models/credential_types.py +214 -0
- package/generator/build/lib/pygen/codegen/models/dictionary_type.py +127 -0
- package/generator/build/lib/pygen/codegen/models/enum_type.py +238 -0
- package/generator/build/lib/pygen/codegen/models/imports.py +291 -0
- package/generator/build/lib/pygen/codegen/models/list_type.py +143 -0
- package/generator/build/lib/pygen/codegen/models/lro_operation.py +142 -0
- package/generator/build/lib/pygen/codegen/models/lro_paging_operation.py +32 -0
- package/generator/build/lib/pygen/codegen/models/model_type.py +357 -0
- package/generator/build/lib/pygen/codegen/models/operation.py +509 -0
- package/generator/build/lib/pygen/codegen/models/operation_group.py +184 -0
- package/generator/build/lib/pygen/codegen/models/paging_operation.py +155 -0
- package/generator/build/lib/pygen/codegen/models/parameter.py +412 -0
- package/generator/build/lib/pygen/codegen/models/parameter_list.py +387 -0
- package/generator/build/lib/pygen/codegen/models/primitive_types.py +659 -0
- package/generator/build/lib/pygen/codegen/models/property.py +170 -0
- package/generator/build/lib/pygen/codegen/models/request_builder.py +189 -0
- package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +115 -0
- package/generator/build/lib/pygen/codegen/models/response.py +348 -0
- package/generator/build/lib/pygen/codegen/models/utils.py +21 -0
- package/generator/build/lib/pygen/codegen/serializers/__init__.py +574 -0
- package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +21 -0
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +1533 -0
- package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +294 -0
- package/generator/build/lib/pygen/codegen/serializers/enum_serializer.py +15 -0
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +213 -0
- package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +126 -0
- package/generator/build/lib/pygen/codegen/serializers/metadata_serializer.py +198 -0
- package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +33 -0
- package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +335 -0
- package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
- package/generator/build/lib/pygen/codegen/serializers/operations_init_serializer.py +44 -0
- package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +221 -0
- package/generator/build/lib/pygen/codegen/serializers/patch_serializer.py +19 -0
- package/generator/build/lib/pygen/codegen/serializers/request_builders_serializer.py +52 -0
- package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +168 -0
- package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +292 -0
- package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +31 -0
- package/generator/build/lib/pygen/codegen/serializers/utils.py +68 -0
- package/generator/build/lib/pygen/codegen/templates/client.py.jinja2 +37 -0
- package/generator/build/lib/pygen/codegen/templates/client_container.py.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/config.py.jinja2 +73 -0
- package/generator/build/lib/pygen/codegen/templates/config_container.py.jinja2 +16 -0
- package/generator/build/lib/pygen/codegen/templates/conftest.py.jinja2 +28 -0
- package/generator/build/lib/pygen/codegen/templates/enum.py.jinja2 +13 -0
- package/generator/build/lib/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
- package/generator/build/lib/pygen/codegen/templates/init.py.jinja2 +24 -0
- package/generator/build/lib/pygen/codegen/templates/keywords.jinja2 +27 -0
- package/generator/build/lib/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
- package/generator/build/lib/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
- package/generator/build/lib/pygen/codegen/templates/macros.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/metadata.json.jinja2 +167 -0
- package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +1174 -0
- package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +15 -0
- package/generator/build/lib/pygen/codegen/templates/model_dpg.py.jinja2 +97 -0
- package/generator/build/lib/pygen/codegen/templates/model_init.py.jinja2 +33 -0
- package/generator/build/lib/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
- package/generator/build/lib/pygen/codegen/templates/operation.py.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
- package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +19 -0
- package/generator/build/lib/pygen/codegen/templates/operation_tools.jinja2 +81 -0
- package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
- package/generator/build/lib/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/patch.py.jinja2 +19 -0
- package/generator/build/lib/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
- package/generator/build/lib/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
- package/generator/build/lib/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
- package/generator/build/lib/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/sample.py.jinja2 +44 -0
- package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +2117 -0
- package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +50 -0
- package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
- package/generator/build/lib/pygen/codegen/templates/types.py.jinja2 +7 -0
- package/generator/build/lib/pygen/codegen/templates/validation.py.jinja2 +38 -0
- package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +96 -0
- package/generator/build/lib/pygen/codegen/templates/version.py.jinja2 +4 -0
- package/generator/build/lib/pygen/m2r.py +65 -0
- package/generator/build/lib/pygen/preprocess/__init__.py +515 -0
- package/generator/build/lib/pygen/preprocess/helpers.py +27 -0
- package/generator/build/lib/pygen/preprocess/python_mappings.py +226 -0
- package/generator/build/lib/pygen/utils.py +163 -0
- package/generator/component-detection-pip-report.json +134 -0
- package/generator/dev_requirements.txt +0 -1
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/codegen/__init__.py +4 -4
- package/generator/pygen.egg-info/PKG-INFO +7 -4
- package/generator/pygen.egg-info/requires.txt +7 -4
- package/generator/setup.py +7 -4
- package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_flatten_async.py +1 -1
- package/generator/test/{generic_mock_api_tests/asynctests/test_payload_pageable_async.py → azure/mock_api_tests/asynctests/test_azure_payload_pageable_async.py} +1 -1
- package/generator/test/azure/mock_api_tests/conftest.py +5 -4
- package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_flatten.py +1 -1
- package/generator/test/{generic_mock_api_tests/test_payload_pageable.py → azure/mock_api_tests/test_azure_payload_pageable.py} +1 -1
- package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/test_resiliency_srv_driven.py +4 -2
- package/generator/test/{generic_mock_api_tests/asynctests → azure/mock_api_tests}/test_resiliency_srv_driven_async.py +3 -2
- package/generator/test/azure/requirements.txt +9 -8
- package/generator/test/generic_mock_api_tests/conftest.py +9 -4
- package/generator/test/unbranded/mock_api_tests/conftest.py +4 -4
- package/generator/test/unbranded/mock_api_tests/test_unbranded.py +1 -1
- package/generator/test/unbranded/requirements.txt +1 -8
- package/package.json +10 -10
- package/generator/requirements.txt +0 -12
- /package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/asynctests/test_client_naming_async.py +0 -0
- /package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/asynctests/test_client_structure_async.py +0 -0
- /package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/test_client_naming.py +0 -0
- /package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/test_client_structure.py +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{% set prefix_lower = test.prefix|lower %}
|
|
2
|
+
{% set client_var = "self.client" if code_model.options["azure_arm"] else "client" %}
|
|
3
|
+
{% set async = "async " if test.is_async else "" %}
|
|
4
|
+
{% set async_suffix = "_async" if test.is_async else "" %}
|
|
5
|
+
# coding=utf-8
|
|
6
|
+
{{ code_model.options['license_header'] }}
|
|
7
|
+
import pytest
|
|
8
|
+
{{ imports }}
|
|
9
|
+
|
|
10
|
+
{% if code_model.options["azure_arm"] %}
|
|
11
|
+
AZURE_LOCATION = "eastus"
|
|
12
|
+
{% endif %}
|
|
13
|
+
|
|
14
|
+
@pytest.mark.skip("you may need to update the auto-generated test case before run it")
|
|
15
|
+
class {{ test.test_class_name }}({{ test.base_test_class_name }}):
|
|
16
|
+
{% if code_model.options["azure_arm"] %}
|
|
17
|
+
def setup_method(self, method):
|
|
18
|
+
{% if test.is_async %}
|
|
19
|
+
self.client = self.create_mgmt_client({{ test.client_name }}, is_async=True)
|
|
20
|
+
{% else %}
|
|
21
|
+
self.client = self.create_mgmt_client({{ test.client_name }})
|
|
22
|
+
{% endif %}
|
|
23
|
+
{% endif %}
|
|
24
|
+
{% for testcase in test.testcases %}
|
|
25
|
+
{% if code_model.options["azure_arm"] %}
|
|
26
|
+
@{{ test.preparer_name }}(location=AZURE_LOCATION)
|
|
27
|
+
{% else %}
|
|
28
|
+
@{{ test.preparer_name }}()
|
|
29
|
+
{% endif %}
|
|
30
|
+
@recorded_by_proxy{{ async_suffix }}
|
|
31
|
+
{% if code_model.options["azure_arm"] %}
|
|
32
|
+
{{ async }}def test_{{ testcase.name }}(self, resource_group):
|
|
33
|
+
{% else %}
|
|
34
|
+
{{ async }}def test_{{ testcase.name }}(self, {{ prefix_lower }}_endpoint):
|
|
35
|
+
{{ client_var }} = self.{{ test.create_client_name }}(endpoint={{ prefix_lower }}_endpoint)
|
|
36
|
+
{% endif %}
|
|
37
|
+
{{testcase.response }}{{ client_var }}{{ testcase.operation_group_prefix }}.{{ testcase.operation.name }}(
|
|
38
|
+
{% for key, value in testcase.params.items() %}
|
|
39
|
+
{% if code_model.options["azure_arm"] and key == "resource_group_name" %}
|
|
40
|
+
{{ key }}=resource_group.name,
|
|
41
|
+
{% else %}
|
|
42
|
+
{{ key }}={{ value|indent(12) }},
|
|
43
|
+
{% endif %}
|
|
44
|
+
{% endfor %}
|
|
45
|
+
){{ testcase.operation_suffix }}
|
|
46
|
+
{{ testcase.extra_operation }}
|
|
47
|
+
# please add some check logic here by yourself
|
|
48
|
+
# ...
|
|
49
|
+
|
|
50
|
+
{% endfor %}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
{{ code_model.options['license_header'] }}
|
|
3
|
+
{{ imports }}
|
|
4
|
+
|
|
5
|
+
{% for test_name in test_names %}
|
|
6
|
+
{% set extra_async = ", is_async=True" if test_name.is_async else ""%}
|
|
7
|
+
{% set prefix_lower = test_name.prefix|lower %}
|
|
8
|
+
class {{ test_name.base_test_class_name }}(AzureRecordedTestCase):
|
|
9
|
+
|
|
10
|
+
def {{ test_name.create_client_name }}(self, endpoint):
|
|
11
|
+
credential = self.get_credential({{ test_name.client_name }}{{ extra_async }})
|
|
12
|
+
return self.create_client_from_credential(
|
|
13
|
+
{{ test_name.client_name }},
|
|
14
|
+
credential=credential,
|
|
15
|
+
endpoint=endpoint,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
{% if not test_name.is_async %}
|
|
19
|
+
{{ test_name.preparer_name }} = functools.partial(
|
|
20
|
+
PowerShellPreparer,
|
|
21
|
+
"{{ prefix_lower }}",
|
|
22
|
+
{{ prefix_lower }}_endpoint="https://fake_{{ prefix_lower }}_endpoint.com"
|
|
23
|
+
)
|
|
24
|
+
{% endif %}
|
|
25
|
+
|
|
26
|
+
{% endfor %}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{{ code_model.options['license_header'] }}
|
|
2
|
+
import functools
|
|
3
|
+
|
|
4
|
+
def api_version_validation(**kwargs):
|
|
5
|
+
params_added_on = kwargs.pop("params_added_on", {})
|
|
6
|
+
method_added_on = kwargs.pop("method_added_on", "")
|
|
7
|
+
|
|
8
|
+
def decorator(func):
|
|
9
|
+
@functools.wraps(func)
|
|
10
|
+
def wrapper(*args, **kwargs):
|
|
11
|
+
try:
|
|
12
|
+
# this assumes the client has an _api_version attribute
|
|
13
|
+
client = args[0]
|
|
14
|
+
client_api_version = client._config.api_version # pylint: disable=protected-access
|
|
15
|
+
except AttributeError:
|
|
16
|
+
return func(*args, **kwargs)
|
|
17
|
+
|
|
18
|
+
if method_added_on > client_api_version:
|
|
19
|
+
raise ValueError(
|
|
20
|
+
f"'{func.__name__}' is not available in API version "
|
|
21
|
+
f"{client_api_version}. Pass service API version {method_added_on} or newer to your client."
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
unsupported = {
|
|
25
|
+
parameter: api_version
|
|
26
|
+
for api_version, parameters in params_added_on.items()
|
|
27
|
+
for parameter in parameters
|
|
28
|
+
if parameter in kwargs and api_version > client_api_version
|
|
29
|
+
}
|
|
30
|
+
if unsupported:
|
|
31
|
+
raise ValueError("".join([
|
|
32
|
+
f"'{param}' is not available in API version {client_api_version}. "
|
|
33
|
+
f"Use service API version {version} or newer.\n"
|
|
34
|
+
for param, version in unsupported.items()
|
|
35
|
+
]))
|
|
36
|
+
return func(*args, **kwargs)
|
|
37
|
+
return wrapper
|
|
38
|
+
return decorator
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{% import 'keywords.jinja2' as keywords with context %}
|
|
2
|
+
{{ code_model.options['license_header'] }}
|
|
3
|
+
|
|
4
|
+
{{ imports }}
|
|
5
|
+
|
|
6
|
+
{% if code_model.need_mixin_abc %}
|
|
7
|
+
{% for client in clients | selectattr("has_mixin") %}
|
|
8
|
+
{% set pylint_disable = "# pylint: disable=name-too-long" if (client.name | length) + ("MixinABC" | length) > 40 else "" %}
|
|
9
|
+
class {{ client.name }}MixinABC( {{ pylint_disable }}
|
|
10
|
+
ABC
|
|
11
|
+
):
|
|
12
|
+
"""DO NOT use this class. It is for internal typing use only."""
|
|
13
|
+
_client: "{{ keywords.async_class }}PipelineClient"
|
|
14
|
+
_config: {{ client.name }}Configuration
|
|
15
|
+
_serialize: "Serializer"
|
|
16
|
+
_deserialize: "Deserializer"
|
|
17
|
+
{% endfor %}
|
|
18
|
+
{% endif %}
|
|
19
|
+
{% if code_model.has_abstract_operations %}
|
|
20
|
+
|
|
21
|
+
def raise_if_not_implemented(cls, abstract_methods):
|
|
22
|
+
not_implemented = [f for f in abstract_methods if not callable(getattr(cls, f, None))]
|
|
23
|
+
if not_implemented:
|
|
24
|
+
raise NotImplementedError("The following methods on operation group '{}' are not implemented: '{}'."
|
|
25
|
+
" Please refer to https://aka.ms/azsdk/python/dpcodegen/python/customize to learn how to customize.".format(
|
|
26
|
+
cls.__name__, '\', \''.join(not_implemented))
|
|
27
|
+
)
|
|
28
|
+
{% endif %}
|
|
29
|
+
|
|
30
|
+
{% if code_model.has_etag %}
|
|
31
|
+
def quote_etag(etag: Optional[str]) -> Optional[str]:
|
|
32
|
+
if not etag or etag == "*":
|
|
33
|
+
return etag
|
|
34
|
+
if etag.startswith("W/"):
|
|
35
|
+
return etag
|
|
36
|
+
if etag.startswith('"') and etag.endswith('"'):
|
|
37
|
+
return etag
|
|
38
|
+
if etag.startswith("'") and etag.endswith("'"):
|
|
39
|
+
return etag
|
|
40
|
+
return '"' + etag + '"'
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]:
|
|
44
|
+
if match_condition == MatchConditions.IfNotModified:
|
|
45
|
+
if_match = quote_etag(etag) if etag else None
|
|
46
|
+
return if_match
|
|
47
|
+
if match_condition == MatchConditions.IfPresent:
|
|
48
|
+
return "*"
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]:
|
|
53
|
+
if match_condition == MatchConditions.IfModified:
|
|
54
|
+
if_none_match = quote_etag(etag) if etag else None
|
|
55
|
+
return if_none_match
|
|
56
|
+
if match_condition == MatchConditions.IfMissing:
|
|
57
|
+
return "*"
|
|
58
|
+
return None
|
|
59
|
+
{% endif %}
|
|
60
|
+
{% if code_model.has_form_data and code_model.options["models_mode"] == "dpg" and not async_mode %}
|
|
61
|
+
# file-like tuple could be `(filename, IO (or bytes))` or `(filename, IO (or bytes), content_type)`
|
|
62
|
+
FileContent = Union[str, bytes, IO[str], IO[bytes]]
|
|
63
|
+
|
|
64
|
+
FileType = Union[
|
|
65
|
+
# file (or bytes)
|
|
66
|
+
FileContent,
|
|
67
|
+
# (filename, file (or bytes))
|
|
68
|
+
Tuple[Optional[str], FileContent],
|
|
69
|
+
# (filename, file (or bytes), content_type)
|
|
70
|
+
Tuple[Optional[str], FileContent, Optional[str]],
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
def serialize_multipart_data_entry(data_entry: Any) -> Any:
|
|
74
|
+
if isinstance(data_entry, (list, tuple, dict, Model)):
|
|
75
|
+
return json.dumps(data_entry, cls=SdkJSONEncoder, exclude_readonly=True)
|
|
76
|
+
return data_entry
|
|
77
|
+
|
|
78
|
+
def prepare_multipart_form_data(
|
|
79
|
+
body: Mapping[str, Any], multipart_fields: List[str], data_fields: List[str]
|
|
80
|
+
) -> Tuple[List[FileType], Dict[str, Any]]:
|
|
81
|
+
files: List[FileType] = []
|
|
82
|
+
data: Dict[str, Any] = {}
|
|
83
|
+
for multipart_field in multipart_fields:
|
|
84
|
+
multipart_entry = body.get(multipart_field)
|
|
85
|
+
if isinstance(multipart_entry, list):
|
|
86
|
+
files.extend([(multipart_field, e) for e in multipart_entry ])
|
|
87
|
+
elif multipart_entry:
|
|
88
|
+
files.append((multipart_field, multipart_entry))
|
|
89
|
+
|
|
90
|
+
for data_field in data_fields:
|
|
91
|
+
data_entry = body.get(data_field)
|
|
92
|
+
if data_entry:
|
|
93
|
+
data[data_field] = serialize_multipart_data_entry(data_entry)
|
|
94
|
+
|
|
95
|
+
return files, data
|
|
96
|
+
{% endif %}
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
"""An MD to RST plugin.
|
|
7
|
+
"""
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Any, Dict, Set, Union
|
|
10
|
+
|
|
11
|
+
import m2r2
|
|
12
|
+
|
|
13
|
+
from . import YamlUpdatePlugin
|
|
14
|
+
from .utils import parse_args
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
_LOGGER = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GeneratorRenderer(m2r2.RestRenderer):
|
|
21
|
+
"""Redefine the concept of inline HTML in the renderer, we don't want to define a new format
|
|
22
|
+
in the description/summary.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def inline_html(self, html: str) -> str:
|
|
26
|
+
"""Do not render inline HTML with a role definition."""
|
|
27
|
+
return r"\ :code:`{}`".format(html)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class M2R(YamlUpdatePlugin):
|
|
31
|
+
"""A plugin to convert any description and summary from MD to RST."""
|
|
32
|
+
|
|
33
|
+
def update_yaml(self, yaml_data: Dict[str, Any]) -> None:
|
|
34
|
+
"""Convert in place the YAML str."""
|
|
35
|
+
self._convert_docstring_no_cycles(yaml_data, set())
|
|
36
|
+
|
|
37
|
+
def _convert_docstring_no_cycles(self, yaml_data: Union[Dict[str, Any], str], node_list: Set[int]) -> None:
|
|
38
|
+
"""Walk the YAML tree to convert MD to RST."""
|
|
39
|
+
if id(yaml_data) in node_list:
|
|
40
|
+
return
|
|
41
|
+
node_list.add(id(yaml_data))
|
|
42
|
+
|
|
43
|
+
if isinstance(yaml_data, list):
|
|
44
|
+
for elt in yaml_data:
|
|
45
|
+
self._convert_docstring_no_cycles(elt, node_list)
|
|
46
|
+
elif isinstance(yaml_data, dict):
|
|
47
|
+
for key, value in yaml_data.items():
|
|
48
|
+
if key in ["description", "summary"]:
|
|
49
|
+
yaml_data[key] = self.convert_to_rst(value)
|
|
50
|
+
continue
|
|
51
|
+
self._convert_docstring_no_cycles(value, node_list)
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def convert_to_rst(string_to_convert: str) -> str:
|
|
55
|
+
"""Convert that string from MD to RST."""
|
|
56
|
+
try:
|
|
57
|
+
return m2r2.convert(string_to_convert, renderer=GeneratorRenderer()).strip()
|
|
58
|
+
except Exception: # pylint: disable=broad-except
|
|
59
|
+
return string_to_convert
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
# CADL pipeline will call this
|
|
64
|
+
args, unknown_args = parse_args()
|
|
65
|
+
M2R(output_folder=args.output_folder, cadl_file=args.cadl_file, **unknown_args).process()
|