@autorest/python 5.16.0 → 5.19.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 (96) hide show
  1. package/ChangeLog.md +79 -4
  2. package/README.md +30 -4
  3. package/autorest/__init__.py +1 -1
  4. package/autorest/codegen/__init__.py +55 -211
  5. package/autorest/codegen/models/__init__.py +116 -83
  6. package/autorest/codegen/models/base_builder.py +49 -88
  7. package/autorest/codegen/models/base_model.py +1 -1
  8. package/autorest/codegen/models/{base_schema.py → base_type.py} +61 -39
  9. package/autorest/codegen/models/client.py +165 -53
  10. package/autorest/codegen/models/code_model.py +122 -257
  11. package/autorest/codegen/models/combined_type.py +107 -0
  12. package/autorest/codegen/models/{constant_schema.py → constant_type.py} +49 -40
  13. package/autorest/codegen/models/credential_types.py +224 -0
  14. package/autorest/codegen/models/dictionary_type.py +131 -0
  15. package/autorest/codegen/models/enum_type.py +195 -0
  16. package/autorest/codegen/models/imports.py +80 -2
  17. package/autorest/codegen/models/list_type.py +149 -0
  18. package/autorest/codegen/models/lro_operation.py +79 -156
  19. package/autorest/codegen/models/lro_paging_operation.py +28 -11
  20. package/autorest/codegen/models/model_type.py +262 -0
  21. package/autorest/codegen/models/operation.py +331 -298
  22. package/autorest/codegen/models/operation_group.py +54 -91
  23. package/autorest/codegen/models/paging_operation.py +82 -123
  24. package/autorest/codegen/models/parameter.py +289 -396
  25. package/autorest/codegen/models/parameter_list.py +355 -360
  26. package/autorest/codegen/models/primitive_types.py +544 -0
  27. package/autorest/codegen/models/property.py +123 -139
  28. package/autorest/codegen/models/request_builder.py +130 -102
  29. package/autorest/codegen/models/request_builder_parameter.py +112 -100
  30. package/autorest/codegen/models/response.py +325 -0
  31. package/autorest/codegen/models/utils.py +12 -19
  32. package/autorest/codegen/serializers/__init__.py +55 -37
  33. package/autorest/codegen/serializers/builder_serializer.py +695 -1144
  34. package/autorest/codegen/serializers/client_serializer.py +92 -89
  35. package/autorest/codegen/serializers/general_serializer.py +15 -69
  36. package/autorest/codegen/serializers/import_serializer.py +7 -4
  37. package/autorest/codegen/serializers/metadata_serializer.py +15 -104
  38. package/autorest/codegen/serializers/model_base_serializer.py +49 -36
  39. package/autorest/codegen/serializers/model_generic_serializer.py +8 -6
  40. package/autorest/codegen/serializers/model_init_serializer.py +2 -4
  41. package/autorest/codegen/serializers/model_python3_serializer.py +22 -16
  42. package/autorest/codegen/serializers/operation_groups_serializer.py +7 -13
  43. package/autorest/codegen/serializers/parameter_serializer.py +174 -0
  44. package/autorest/codegen/serializers/request_builders_serializer.py +13 -30
  45. package/autorest/codegen/serializers/utils.py +0 -140
  46. package/autorest/codegen/templates/MANIFEST.in.jinja2 +1 -0
  47. package/autorest/codegen/templates/{service_client.py.jinja2 → client.py.jinja2} +10 -7
  48. package/autorest/codegen/templates/config.py.jinja2 +13 -13
  49. package/autorest/codegen/templates/enum.py.jinja2 +4 -4
  50. package/autorest/codegen/templates/enum_container.py.jinja2 +1 -1
  51. package/autorest/codegen/templates/init.py.jinja2 +2 -2
  52. package/autorest/codegen/templates/lro_operation.py.jinja2 +4 -1
  53. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +4 -1
  54. package/autorest/codegen/templates/metadata.json.jinja2 +33 -33
  55. package/autorest/codegen/templates/model.py.jinja2 +23 -24
  56. package/autorest/codegen/templates/model_container.py.jinja2 +2 -1
  57. package/autorest/codegen/templates/model_init.py.jinja2 +3 -5
  58. package/autorest/codegen/templates/operation.py.jinja2 +6 -8
  59. package/autorest/codegen/templates/operation_group.py.jinja2 +21 -8
  60. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +2 -2
  61. package/autorest/codegen/templates/operation_tools.jinja2 +11 -3
  62. package/autorest/codegen/templates/paging_operation.py.jinja2 +2 -2
  63. package/autorest/codegen/templates/request_builder.py.jinja2 +10 -15
  64. package/autorest/codegen/templates/request_builders.py.jinja2 +1 -1
  65. package/autorest/codegen/templates/serialization.py.jinja2 +2006 -0
  66. package/autorest/codegen/templates/setup.py.jinja2 +13 -3
  67. package/autorest/codegen/templates/vendor.py.jinja2 +11 -1
  68. package/autorest/jsonrpc/server.py +15 -3
  69. package/autorest/m4reformatter/__init__.py +1126 -0
  70. package/autorest/multiapi/models/client.py +12 -2
  71. package/autorest/multiapi/models/code_model.py +1 -1
  72. package/autorest/multiapi/serializers/__init__.py +18 -4
  73. package/autorest/multiapi/templates/multiapi_config.py.jinja2 +3 -3
  74. package/autorest/multiapi/templates/multiapi_init.py.jinja2 +2 -2
  75. package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +4 -4
  76. package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +9 -9
  77. package/autorest/postprocess/__init__.py +202 -0
  78. package/autorest/postprocess/get_all.py +19 -0
  79. package/autorest/postprocess/venvtools.py +73 -0
  80. package/autorest/preprocess/__init__.py +210 -0
  81. package/autorest/preprocess/helpers.py +54 -0
  82. package/autorest/{namer → preprocess}/python_mappings.py +21 -16
  83. package/package.json +2 -2
  84. package/autorest/codegen/models/credential_model.py +0 -55
  85. package/autorest/codegen/models/credential_schema.py +0 -95
  86. package/autorest/codegen/models/credential_schema_policy.py +0 -73
  87. package/autorest/codegen/models/dictionary_schema.py +0 -106
  88. package/autorest/codegen/models/enum_schema.py +0 -225
  89. package/autorest/codegen/models/list_schema.py +0 -135
  90. package/autorest/codegen/models/object_schema.py +0 -303
  91. package/autorest/codegen/models/primitive_schemas.py +0 -495
  92. package/autorest/codegen/models/request_builder_parameter_list.py +0 -249
  93. package/autorest/codegen/models/schema_request.py +0 -55
  94. package/autorest/codegen/models/schema_response.py +0 -141
  95. package/autorest/namer/__init__.py +0 -23
  96. package/autorest/namer/name_converter.py +0 -509
@@ -5,9 +5,10 @@
5
5
  # --------------------------------------------------------------------------
6
6
  import sys
7
7
  import json
8
+ import re
8
9
  from typing import Any, Dict, List
9
10
  from pathlib import Path
10
- from .imports import FileImport
11
+ from .imports import FileImport, TypingSection, ImportType
11
12
 
12
13
 
13
14
  def _extract_version(metadata_json: Dict[str, Any], version_path: Path) -> str:
@@ -43,9 +44,18 @@ class Client:
43
44
 
44
45
  def imports(self, async_mode: bool) -> FileImport:
45
46
  imports_to_load = "async_imports" if async_mode else "sync_imports"
46
- return FileImport(
47
+ file_import = FileImport(
47
48
  json.loads(self.default_version_metadata["client"][imports_to_load])
48
49
  )
50
+ local_imports = file_import.imports.get(TypingSection.REGULAR, {}).get(
51
+ ImportType.LOCAL, {}
52
+ )
53
+ for key in local_imports:
54
+ if re.search("^\\.*_serialization$", key):
55
+ relative_path = ".." if async_mode else "."
56
+ local_imports[f"{relative_path}_serialization"] = local_imports.pop(key)
57
+ break
58
+ return file_import
49
59
 
50
60
  @property
51
61
  def parameterized_host_template_to_api_version(self) -> Dict[str, List[str]]:
@@ -34,7 +34,7 @@ class CodeModel: # pylint: disable=too-many-instance-attributes
34
34
  self.azure_arm = default_version_metadata["client"]["azure_arm"]
35
35
  self.default_version_metadata = default_version_metadata
36
36
  self.version_path_to_metadata = version_path_to_metadata
37
- self.service_client = Client(
37
+ self.client = Client(
38
38
  self.azure_arm, default_version_metadata, version_path_to_metadata
39
39
  )
40
40
  self.config = Config(default_version_metadata)
@@ -18,7 +18,7 @@ __all__ = [
18
18
 
19
19
  _FILE_TO_TEMPLATE = {
20
20
  "init": "multiapi_init.py.jinja2",
21
- "service_client": "multiapi_service_client.py.jinja2",
21
+ "client": "multiapi_service_client.py.jinja2",
22
22
  "config": "multiapi_config.py.jinja2",
23
23
  "models": "multiapi_models.py.jinja2",
24
24
  "operations_mixin": "multiapi_operations_mixin.py.jinja2",
@@ -58,11 +58,11 @@ class MultiAPISerializer(object):
58
58
 
59
59
  # serialize service client file
60
60
  imports = FileImportSerializer(
61
- code_model.service_client.imports(async_mode), is_python3_file=async_mode
61
+ code_model.client.imports(async_mode), is_python3_file=async_mode
62
62
  )
63
63
  self._autorestapi.write_file(
64
- _get_file_path(code_model.service_client.filename, async_mode),
65
- _render_template("service_client", imports=imports),
64
+ _get_file_path(code_model.client.filename, async_mode),
65
+ _render_template("client", imports=imports),
66
66
  )
67
67
 
68
68
  # serialize config file
@@ -115,3 +115,17 @@ class MultiAPISerializer(object):
115
115
  )
116
116
 
117
117
  self._autorestapi.write_file(Path("py.typed"), "# Marker file for PEP 561.")
118
+
119
+ if not code_model.client.client_side_validation:
120
+ codegen_env = Environment(
121
+ loader=PackageLoader("autorest.codegen", "templates"),
122
+ keep_trailing_newline=True,
123
+ line_statement_prefix="##",
124
+ line_comment_prefix="###",
125
+ trim_blocks=True,
126
+ lstrip_blocks=True,
127
+ )
128
+ self._autorestapi.write_file(
129
+ Path("_serialization.py"),
130
+ codegen_env.get_template("serialization.py.jinja2").render(),
131
+ )
@@ -28,8 +28,8 @@ def __init__(
28
28
  # --------------------------------------------------------------------------
29
29
  {{ imports }}
30
30
 
31
- class {{ code_model.service_client.name }}Configuration(Configuration):
32
- """Configuration for {{ code_model.service_client.name }}.
31
+ class {{ code_model.client.name }}Configuration(Configuration):
32
+ """Configuration for {{ code_model.client.name }}.
33
33
 
34
34
  Note that all parameters used to create this instance are saved as instance
35
35
  attributes.
@@ -52,7 +52,7 @@ class {{ code_model.service_client.name }}Configuration(Configuration):
52
52
  raise ValueError("Parameter '{{ parameter.name }}' must not be None.")
53
53
  {% endif %}
54
54
  {% endfor %}
55
- super({{ code_model.service_client.name }}Configuration, self).__init__(**kwargs)
55
+ super({{ code_model.client.name }}Configuration, self).__init__(**kwargs)
56
56
 
57
57
  {% for parameter in code_model.global_parameters.parameters %}
58
58
  self.{{ parameter.name }} = {{ parameter.name }}
@@ -6,8 +6,8 @@
6
6
  # Changes may cause incorrect behavior and will be lost if the code is regenerated.
7
7
  # --------------------------------------------------------------------------
8
8
 
9
- from .{{ code_model.service_client.filename }} import {{ code_model.service_client.name }}
10
- __all__ = ['{{ code_model.service_client.name }}']
9
+ from .{{ code_model.client.filename }} import {{ code_model.client.name }}
10
+ __all__ = ['{{ code_model.client.name }}']
11
11
  {% if not async_mode %}
12
12
 
13
13
  try:
@@ -8,13 +8,13 @@
8
8
  # Changes may cause incorrect behavior and will be lost if the code is
9
9
  # regenerated.
10
10
  # --------------------------------------------------------------------------
11
- from msrest import Serializer, Deserializer
11
+ from {{ ".." if async_mode else "." }}_serialization import Serializer, Deserializer
12
12
  {% if imports %}
13
13
  {{ imports }}
14
14
  {% endif %}
15
15
 
16
16
 
17
- class {{ code_model.service_client.name }}OperationsMixin(object):
17
+ class {{ code_model.client.name }}OperationsMixin(object):
18
18
  {% for mixin_operation in code_model.operation_mixin_group.mixin_operations %}
19
19
 
20
20
  {{ mixin_operation.signature(async_mode) | indent }} {{ mixin_operation.description(async_mode) | indent(8) }}
@@ -22,7 +22,7 @@ class {{ code_model.service_client.name }}OperationsMixin(object):
22
22
  {% for api in mixin_operation.available_apis|sort %}
23
23
  {% set if_statement = "if" if loop.first else "elif" %}
24
24
  {{ if_statement }} api_version == '{{ code_model.mod_to_api_version[api] }}':
25
- from {{ ".." if async_mode else "." }}{{ api }}{{ ".aio" if async_mode else "" }}.operations import {{ code_model.service_client.name }}OperationsMixin as OperationClass
25
+ from {{ ".." if async_mode else "." }}{{ api }}{{ ".aio" if async_mode else "" }}.operations import {{ code_model.client.name }}OperationsMixin as OperationClass
26
26
  {% endfor %}
27
27
  else:
28
28
  raise ValueError("API version {} does not have operation '{{ mixin_operation.name }}'".format(api_version))
@@ -30,7 +30,7 @@ class {{ code_model.service_client.name }}OperationsMixin(object):
30
30
  mixin_instance._client = self._client
31
31
  mixin_instance._config = self._config
32
32
  mixin_instance._serialize = Serializer(self._models_dict(api_version))
33
- {% if not code_model.service_client.client_side_validation %}
33
+ {% if not code_model.client.client_side_validation %}
34
34
  mixin_instance._serialize.client_side_validation = False
35
35
  {% endif %}
36
36
  mixin_instance._deserialize = Deserializer(self._models_dict(api_version))
@@ -43,8 +43,8 @@ class _SDKClient(object):
43
43
  """
44
44
  pass
45
45
 
46
- class {{ code_model.service_client.name }}({% if code_model.operation_mixin_group.mixin_operations %}{{ code_model.service_client.name }}OperationsMixin, {% endif %}MultiApiClientMixin, _SDKClient):
47
- """{{ code_model.service_client.description }}
46
+ class {{ code_model.client.name }}({% if code_model.operation_mixin_group.mixin_operations %}{{ code_model.client.name }}OperationsMixin, {% endif %}MultiApiClientMixin, _SDKClient):
47
+ """{{ code_model.client.description }}
48
48
 
49
49
  This ready contains multiple API versions, to help you deal with all of the Azure clouds
50
50
  (Azure Stack, Azure Government, Azure China, etc.).
@@ -64,13 +64,13 @@ class {{ code_model.service_client.name }}({% if code_model.operation_mixin_grou
64
64
  :param {{ parameter.name }}: {{ parameter.description(async_mode) }}
65
65
  :type {{ parameter.name }}: {{ parameter.docstring_type(async_mode) }}
66
66
  {% endfor %}
67
- {% if code_model.service_client.has_lro_operations %}
67
+ {% if code_model.client.has_lro_operations %}
68
68
  :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present.
69
69
  {% endif %}
70
70
  """
71
71
 
72
72
  DEFAULT_API_VERSION = '{{ code_model.mod_to_api_version[code_model.default_api_version] }}'
73
- _PROFILE_TAG = "{{ code_model.module_name }}.{{ code_model.service_client.name }}"
73
+ _PROFILE_TAG = "{{ code_model.module_name }}.{{ code_model.client.name }}"
74
74
  LATEST_PROFILE = ProfileDefinition({
75
75
  _PROFILE_TAG: {
76
76
  None: DEFAULT_API_VERSION,
@@ -82,8 +82,8 @@ class {{ code_model.service_client.name }}({% if code_model.operation_mixin_grou
82
82
  )
83
83
 
84
84
  {{ method_signature()|indent }}
85
- {% if not code_model.service_client.host_value %}
86
- {% for parameterized_host_template, api_versions in code_model.service_client.parameterized_host_template_to_api_version|dictsort %}
85
+ {% if not code_model.client.host_value %}
86
+ {% for parameterized_host_template, api_versions in code_model.client.parameterized_host_template_to_api_version|dictsort %}
87
87
  {% set if_statement = "if" if loop.first else "elif" %}
88
88
  {{ if_statement ~ " api_version == '" ~ api_versions|join("' or api_version == '") ~ "'" }}:
89
89
  base_url = {{ parameterized_host_template }}
@@ -91,9 +91,9 @@ class {{ code_model.service_client.name }}({% if code_model.operation_mixin_grou
91
91
  else:
92
92
  raise ValueError("API version {} is not available".format(api_version))
93
93
  {% endif %}
94
- self._config = {{ code_model.service_client.name }}Configuration({{ code_model.global_parameters.call }}{{ ", " if code_model.global_parameters.call }}**kwargs)
95
- self._client = {{ async_prefix }}{{ code_model.service_client.pipeline_client }}(base_url=base_url, config=self._config, **kwargs)
96
- super({{ code_model.service_client.name }}, self).__init__(
94
+ self._config = {{ code_model.client.name }}Configuration({{ code_model.global_parameters.call }}{{ ", " if code_model.global_parameters.call }}**kwargs)
95
+ self._client = {{ async_prefix }}{{ code_model.client.pipeline_client }}(base_url=base_url, config=self._config, **kwargs)
96
+ super({{ code_model.client.name }}, self).__init__(
97
97
  api_version=api_version,
98
98
  profile=profile
99
99
  )
@@ -0,0 +1,202 @@
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
+ from typing import Tuple
7
+ from pathlib import Path
8
+ import os
9
+ import shutil
10
+ from venv import EnvBuilder
11
+ import black
12
+ from .venvtools import ExtendedEnvBuilder, python_run
13
+
14
+ from .. import Plugin
15
+
16
+ _BLACK_MODE = black.Mode()
17
+ _BLACK_MODE.line_length = 120
18
+
19
+
20
+ def format_file(file: Path, file_content: str) -> str:
21
+ if not file.suffix == ".py":
22
+ return file_content
23
+ try:
24
+ file_content = black.format_file_contents(
25
+ file_content, fast=True, mode=_BLACK_MODE
26
+ )
27
+ except black.NothingChanged:
28
+ pass
29
+ return file_content
30
+
31
+
32
+ class PostProcessPlugin(Plugin):
33
+ def __init__(self, autorestapi):
34
+ super().__init__(autorestapi)
35
+ output_folder_uri = self._autorestapi.get_value("outputFolderUri")
36
+ if output_folder_uri.startswith("file:"):
37
+ output_folder_uri = output_folder_uri[5:]
38
+ if os.name == "nt" and output_folder_uri.startswith("///"):
39
+ output_folder_uri = output_folder_uri[3:]
40
+ self.output_folder = Path(output_folder_uri) # path to where the setup.py is
41
+ self.setup_venv()
42
+
43
+ # set up the venv
44
+ # base folder is where the code starts, i.e. where we
45
+ self.base_folder, self.namespace = self.get_namespace(self.output_folder, "")
46
+
47
+ def setup_venv(self):
48
+ venv_path = self.output_folder / Path(".temp_folder") / Path("temp_venv")
49
+
50
+ if venv_path.exists():
51
+ env_builder = EnvBuilder(with_pip=True)
52
+ self.venv_context = env_builder.ensure_directories(venv_path)
53
+ else:
54
+ env_builder = ExtendedEnvBuilder(with_pip=True)
55
+ env_builder.create(venv_path)
56
+ self.venv_context = env_builder.context
57
+ python_run(
58
+ self.venv_context,
59
+ "pip",
60
+ ["install", "-e", str(self.output_folder)],
61
+ directory=self.output_folder,
62
+ )
63
+
64
+ def get_namespace(self, dir: Path, namespace: str) -> Tuple[Path, str]:
65
+ try:
66
+ init_file = next(d for d in dir.iterdir() if d.name == "__init__.py")
67
+ # we don't care about pkgutil inits, we skip over them
68
+ file_content = self._autorestapi.read_file(
69
+ init_file.relative_to(self.output_folder)
70
+ )
71
+ if not "pkgutil" in file_content:
72
+ return dir, namespace
73
+ except StopIteration:
74
+ pass
75
+
76
+ try:
77
+ # first, see if we can get a folder that has the same name as the current output folder
78
+ start = self.output_folder.stem.split("-")[0]
79
+ next_dir = next(d for d in dir.iterdir() if d.is_dir() and d.name == start)
80
+ except StopIteration:
81
+ invalid_start_chars = [".", "_"]
82
+ invalid_dirs = [
83
+ "swagger",
84
+ "out",
85
+ "tests",
86
+ "samples",
87
+ ]
88
+
89
+ next_dir = next(
90
+ d
91
+ for d in dir.iterdir()
92
+ if d.is_dir()
93
+ and not str(d).endswith("egg-info")
94
+ and d.name[0] not in invalid_start_chars
95
+ and d.name not in invalid_dirs
96
+ )
97
+
98
+ namespace = f"{namespace}.{next_dir.name}" if namespace else next_dir.name
99
+ return self.get_namespace(next_dir, namespace)
100
+
101
+ def process(self) -> bool:
102
+ folders = [
103
+ f
104
+ for f in self.base_folder.glob("**/*")
105
+ if f.is_dir() and not f.stem.startswith("__")
106
+ ]
107
+ # will always have the root
108
+ self.fix_imports_in_init(
109
+ generated_file_name="_client",
110
+ folder_path=self.base_folder,
111
+ namespace=self.namespace,
112
+ )
113
+ try:
114
+ aio_folder = next(f for f in folders if f.stem == "aio")
115
+ self.fix_imports_in_init(
116
+ generated_file_name="_client",
117
+ folder_path=aio_folder,
118
+ namespace=f"{self.namespace}.aio",
119
+ )
120
+ except StopIteration:
121
+ pass
122
+
123
+ try:
124
+ models_folder = next(f for f in folders if f.stem == "models")
125
+ self.fix_imports_in_init(
126
+ generated_file_name="_models",
127
+ folder_path=models_folder,
128
+ namespace=f"{self.namespace}.models",
129
+ )
130
+ except StopIteration:
131
+ pass
132
+ operations_folders = [
133
+ f for f in folders if f.stem in ["operations", "_operations"]
134
+ ]
135
+ for operations_folder in operations_folders:
136
+ aio = ".aio" if operations_folder.parent.stem == "aio" else ""
137
+ self.fix_imports_in_init(
138
+ generated_file_name="_operations",
139
+ folder_path=operations_folder,
140
+ namespace=f"{self.namespace}{aio}.{operations_folder.stem}",
141
+ )
142
+ shutil.rmtree(f"{str(self.output_folder)}/.temp_folder")
143
+ return True
144
+
145
+ def fix_imports_in_init(
146
+ self, generated_file_name: str, folder_path: Path, namespace: str
147
+ ) -> None:
148
+ customized_objects_str = python_run(
149
+ self.venv_context,
150
+ command=[namespace, str(self.output_folder)],
151
+ module="get_all",
152
+ )
153
+
154
+ if not customized_objects_str:
155
+ return
156
+ customized_objects = {
157
+ k: None for k in customized_objects_str.split(",")
158
+ }.keys() # filter out duplicates
159
+ file = (folder_path / "__init__.py").relative_to(self.output_folder)
160
+ file_content = self._autorestapi.read_file(file)
161
+ added_objs = []
162
+ for obj in customized_objects:
163
+ if f" import {obj}\n" in file_content:
164
+ # means we're overriding a generated model
165
+ file_content = file_content.replace(
166
+ f"from .{generated_file_name} import {obj}\n",
167
+ f"from ._patch import {obj}\n",
168
+ )
169
+ else:
170
+ added_objs.append(obj)
171
+ file_content = file_content.replace(
172
+ "try:\n from ._patch import __all__ as _patch_all\n "
173
+ "from ._patch import * # type: ignore # pylint: disable=unused-wildcard-import"
174
+ "\nexcept ImportError:\n _patch_all = []",
175
+ "",
176
+ )
177
+ file_content = file_content.replace(
178
+ "from ._patch import __all__ as _patch_all", ""
179
+ )
180
+ file_content = file_content.replace(
181
+ "from ._patch import * # type: ignore # pylint: disable=unused-wildcard-import\n",
182
+ "",
183
+ )
184
+ file_content = file_content.replace(
185
+ "__all__.extend([p for p in _patch_all if p not in __all__])", ""
186
+ )
187
+ if added_objs:
188
+ # add import
189
+ patch_sdk_import = "from ._patch import patch_sdk as _patch_sdk"
190
+ imports = "\n".join([f"from ._patch import {obj}" for obj in added_objs])
191
+ if imports:
192
+ replacement = f"{imports}\n{patch_sdk_import}"
193
+ else:
194
+ replacement = patch_sdk_import
195
+ file_content = file_content.replace(patch_sdk_import, replacement)
196
+ # add to __all__
197
+ added_objs_all = "\n".join([f' "{obj}",' for obj in added_objs]) + "\n"
198
+ file_content = file_content.replace(
199
+ "__all__ = [", f"__all__ = [\n{added_objs_all}", 1
200
+ )
201
+ formatted_file = format_file(file, file_content)
202
+ self._autorestapi.write_file(file, formatted_file)
@@ -0,0 +1,19 @@
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
+ import sys
7
+ import importlib
8
+
9
+
10
+ def main(namespace):
11
+ sdk = importlib.import_module(namespace)
12
+ return sdk._patch.__all__ # pylint: disable=protected-access
13
+
14
+
15
+ if __name__ == "__main__":
16
+ patched = ",".join(main(sys.argv[1]))
17
+ output_folder = sys.argv[2]
18
+ with open(f"{output_folder}/.temp_folder/patched.txt", "w") as f:
19
+ f.write(patched)
@@ -0,0 +1,73 @@
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
+ from typing import Optional
7
+ import subprocess
8
+ import venv
9
+ import sys
10
+ from pathlib import Path
11
+
12
+
13
+ _ROOT_DIR = Path(__file__).parent
14
+
15
+
16
+ class ExtendedEnvBuilder(venv.EnvBuilder):
17
+ """An extended env builder which saves the context, to have access
18
+ easily to bin path and such.
19
+ """
20
+
21
+ def __init__(self, *args, **kwargs):
22
+ self.context = None
23
+ super(ExtendedEnvBuilder, self).__init__(*args, **kwargs)
24
+
25
+ def ensure_directories(self, env_dir):
26
+ self.context = super(ExtendedEnvBuilder, self).ensure_directories(env_dir)
27
+ return self.context
28
+
29
+
30
+ def create(
31
+ env_dir,
32
+ system_site_packages=False,
33
+ clear=False,
34
+ symlinks=False,
35
+ with_pip=False,
36
+ prompt=None,
37
+ ):
38
+ """Create a virtual environment in a directory."""
39
+ builder = ExtendedEnvBuilder(
40
+ system_site_packages=system_site_packages,
41
+ clear=clear,
42
+ symlinks=symlinks,
43
+ with_pip=with_pip,
44
+ prompt=prompt,
45
+ )
46
+ builder.create(env_dir)
47
+ return builder.context
48
+
49
+
50
+ def python_run( # pylint: disable=inconsistent-return-statements
51
+ venv_context, module, command, directory=_ROOT_DIR, *, error_ok=False
52
+ ) -> Optional[str]:
53
+ try:
54
+ cmd_line = [
55
+ venv_context.env_exe,
56
+ "-m",
57
+ module,
58
+ ] + command
59
+ print("Executing: {}".format(" ".join(cmd_line)))
60
+ subprocess.run(
61
+ cmd_line,
62
+ cwd=directory,
63
+ check=True,
64
+ stdout=False,
65
+ )
66
+ if module == "get_all":
67
+ with open(f"{command[1]}/.temp_folder/patched.txt", "r") as f:
68
+ return f.read()
69
+ except subprocess.CalledProcessError as err:
70
+ print(err)
71
+ if not error_ok:
72
+ sys.exit(1)
73
+ return None