@typespec/http-client-python 0.3.0 → 0.3.2

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.
@@ -1,7 +1,7 @@
1
1
  {% import 'keywords.jinja2' as keywords %}
2
2
  # coding=utf-8
3
3
  {{ code_model.options['license_header'] }}
4
-
4
+ {{ keywords.path_type_checking_imports() }}
5
5
  {% if clients %}
6
6
  {% for client in clients %}
7
7
  from .{{ client.filename }} import {{ client.name }}
@@ -17,3 +17,11 @@ except ImportError:
17
17
  _patch_all = []
18
18
  {% endif %}
19
19
  from ._patch import patch_sdk as _patch_sdk{% endmacro %}
20
+ {% macro path_type_checking_imports() %}
21
+ # pylint: disable=wrong-import-position
22
+
23
+ from typing import TYPE_CHECKING
24
+
25
+ if TYPE_CHECKING:
26
+ from ._patch import * # pylint: disable=unused-wildcard-import
27
+ {% endmacro %}
@@ -1,6 +1,7 @@
1
1
  {% import 'keywords.jinja2' as keywords %}
2
2
  # coding=utf-8
3
3
  {{ code_model.options['license_header'] }}
4
+ {{ keywords.path_type_checking_imports() }}
4
5
  {% if schemas %}
5
6
 
6
7
  {% for schema in schemas %}
@@ -3,7 +3,7 @@
3
3
  {# actual template starts here #}
4
4
  # coding=utf-8
5
5
  {{ code_model.options['license_header'] }}
6
-
6
+ {{ keywords.path_type_checking_imports() }}
7
7
  {{ op_tools.serialize(operation_group_imports()) }}
8
8
  {{ keywords.patch_imports() }}
9
9
  __all__ = [
@@ -506,7 +506,6 @@ class Model(object):
506
506
  def _classify(cls, response, objects):
507
507
  """Check the class _subtype_map for any child classes.
508
508
  We want to ignore any inherited _subtype_maps.
509
- Remove the polymorphic key from the initial data.
510
509
 
511
510
  :param dict response: The initial data
512
511
  :param dict objects: The class objects
@@ -518,7 +517,7 @@ class Model(object):
518
517
 
519
518
  if not isinstance(response, ET.Element):
520
519
  rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1]
521
- subtype_value = response.pop(rest_api_response_key, None) or response.pop(subtype_key, None)
520
+ subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None)
522
521
  else:
523
522
  subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response)
524
523
  if subtype_value:
@@ -102,9 +102,6 @@ pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2
102
102
  pygen/codegen/templates/packaging_templates/README.md.jinja2
103
103
  pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2
104
104
  pygen/codegen/templates/packaging_templates/setup.py.jinja2
105
- pygen/postprocess/__init__.py
106
- pygen/postprocess/get_all.py
107
- pygen/postprocess/venvtools.py
108
105
  pygen/preprocess/__init__.py
109
106
  pygen/preprocess/helpers.py
110
107
  pygen/preprocess/python_mappings.py
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/http-client-python",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "author": "Microsoft Corporation",
5
5
  "description": "TypeSpec emitter for Python SDKs",
6
6
  "homepage": "https://typespec.io",
@@ -1,183 +0,0 @@
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, Any
7
- from pathlib import Path
8
- import os
9
- import shutil
10
- from venv import EnvBuilder
11
- import black
12
- from black.report import NothingChanged
13
- from .venvtools import ExtendedEnvBuilder, python_run
14
-
15
- from .. import Plugin
16
-
17
- _BLACK_MODE = black.Mode() # pyright: ignore [reportPrivateImportUsage]
18
- _BLACK_MODE.line_length = 120
19
-
20
-
21
- def format_file(file: Path, file_content: str) -> str:
22
- if not file.suffix == ".py":
23
- return file_content
24
- try:
25
- file_content = black.format_file_contents(file_content, fast=True, mode=_BLACK_MODE)
26
- except NothingChanged:
27
- pass
28
- return file_content
29
-
30
-
31
- class PostProcessPlugin(Plugin):
32
- def __init__(self, **kwargs: Any):
33
- super().__init__(**kwargs)
34
- output_folder_uri = self.options["outputFolderUri"]
35
- if output_folder_uri.startswith("file:"):
36
- output_folder_uri = output_folder_uri[5:]
37
- if os.name == "nt" and output_folder_uri.startswith("///"):
38
- output_folder_uri = output_folder_uri[3:]
39
- self.output_folder = Path(output_folder_uri) # path to where the setup.py is
40
- self.setup_venv()
41
-
42
- # set up the venv
43
- # base folder is where the code starts, i.e. where we
44
- self.base_folder, self.namespace = self.get_namespace(self.output_folder, "")
45
-
46
- def setup_venv(self):
47
- venv_path = self.output_folder / Path(".temp_folder") / Path("temp_venv")
48
-
49
- if venv_path.exists():
50
- env_builder = EnvBuilder(with_pip=True)
51
- self.venv_context = env_builder.ensure_directories(venv_path)
52
- else:
53
- env_builder = ExtendedEnvBuilder(with_pip=True, upgrade_deps=True)
54
- env_builder.create(venv_path)
55
- self.venv_context = env_builder.context
56
- python_run(
57
- self.venv_context,
58
- "pip",
59
- ["install", "-e", str(self.output_folder)],
60
- directory=self.output_folder,
61
- )
62
-
63
- def get_namespace(self, dir: Path, namespace: str) -> Tuple[Path, str]:
64
- try:
65
- init_file = next(d for d in dir.iterdir() if d.name == "__init__.py")
66
- # we don't care about pkgutil inits, we skip over them
67
- file_content = self.read_file(init_file.relative_to(self.output_folder))
68
- if "pkgutil" not in file_content:
69
- return dir, namespace
70
- except StopIteration:
71
- pass
72
-
73
- try:
74
- # first, see if we can get a folder that has the same name as the current output folder
75
- start = self.output_folder.stem.split("-")[0]
76
- next_dir = next(d for d in dir.iterdir() if d.is_dir() and d.name == start)
77
- except StopIteration:
78
- invalid_start_chars = [".", "_"]
79
- invalid_dirs = [
80
- "swagger",
81
- "out",
82
- "tests",
83
- "samples",
84
- ]
85
-
86
- next_dir = next(
87
- d
88
- for d in dir.iterdir()
89
- if d.is_dir()
90
- and not str(d).endswith("egg-info")
91
- and d.name[0] not in invalid_start_chars
92
- and d.name not in invalid_dirs
93
- )
94
-
95
- namespace = f"{namespace}.{next_dir.name}" if namespace else next_dir.name
96
- return self.get_namespace(next_dir, namespace)
97
-
98
- def process(self) -> bool:
99
- folders = [f for f in self.base_folder.glob("**/*") if f.is_dir() and not f.stem.startswith("__")]
100
- # will always have the root
101
- self.fix_imports_in_init(
102
- generated_file_name="_client",
103
- folder_path=self.base_folder,
104
- namespace=self.namespace,
105
- )
106
- try:
107
- aio_folder = next(f for f in folders if f.stem == "aio")
108
- self.fix_imports_in_init(
109
- generated_file_name="_client",
110
- folder_path=aio_folder,
111
- namespace=f"{self.namespace}.aio",
112
- )
113
- except StopIteration:
114
- pass
115
-
116
- try:
117
- models_folder = next(f for f in folders if f.stem == "models")
118
- self.fix_imports_in_init(
119
- generated_file_name="_models",
120
- folder_path=models_folder,
121
- namespace=f"{self.namespace}.models",
122
- )
123
- except StopIteration:
124
- pass
125
- operations_folders = [f for f in folders if f.stem in ["operations", "_operations"]]
126
- for operations_folder in operations_folders:
127
- sub_namespace = ".".join(str(operations_folder.relative_to(self.base_folder)).split(os.sep))
128
- self.fix_imports_in_init(
129
- generated_file_name="_operations",
130
- folder_path=operations_folder,
131
- namespace=f"{self.namespace}.{sub_namespace}",
132
- )
133
- shutil.rmtree(f"{str(self.output_folder)}/.temp_folder")
134
- return True
135
-
136
- def fix_imports_in_init(self, generated_file_name: str, folder_path: Path, namespace: str) -> None:
137
- customized_objects_str = python_run(
138
- self.venv_context,
139
- command=[namespace, str(self.output_folder)],
140
- module="get_all",
141
- )
142
-
143
- if not customized_objects_str:
144
- return
145
- customized_objects = {k: None for k in customized_objects_str.split(",")}.keys() # filter out duplicates
146
- file = (folder_path / "__init__.py").relative_to(self.output_folder)
147
- file_content = self.read_file(file).replace("\r\n", "\n")
148
- added_objs = []
149
- for obj in customized_objects:
150
- if f" import {obj}\n" in file_content:
151
- # means we're overriding a generated model
152
- file_content = file_content.replace(
153
- f"from .{generated_file_name} import {obj}\n",
154
- f"from ._patch import {obj}\n",
155
- )
156
- else:
157
- added_objs.append(obj)
158
- file_content = file_content.replace(
159
- "try:\n from ._patch import __all__ as _patch_all\n "
160
- "from ._patch import * # pylint: disable=unused-wildcard-import"
161
- "\nexcept ImportError:\n _patch_all = []",
162
- "",
163
- )
164
- file_content = file_content.replace("from ._patch import __all__ as _patch_all", "")
165
- file_content = file_content.replace(
166
- "from ._patch import * # pylint: disable=unused-wildcard-import\n",
167
- "",
168
- )
169
- file_content = file_content.replace("__all__.extend([p for p in _patch_all if p not in __all__])", "")
170
- if added_objs:
171
- # add import
172
- patch_sdk_import = "from ._patch import patch_sdk as _patch_sdk"
173
- imports = "\n".join([f"from ._patch import {obj}" for obj in added_objs])
174
- if imports:
175
- replacement = f"{imports}\n{patch_sdk_import}"
176
- else:
177
- replacement = patch_sdk_import
178
- file_content = file_content.replace(patch_sdk_import, replacement)
179
- # add to __all__
180
- added_objs_all = "\n".join([f' "{obj}",' for obj in added_objs]) + "\n"
181
- file_content = file_content.replace("__all__ = [", f"__all__ = [\n{added_objs_all}", 1)
182
- formatted_file = format_file(file, file_content)
183
- self.write_file(file, formatted_file)
@@ -1,19 +0,0 @@
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", encoding="utf-8-sig") as f:
19
- f.write(patched)
@@ -1,75 +0,0 @@
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
- if sys.version_info < (3, 9, 0):
24
- # Not supported on Python 3.8, and we don't need it
25
- kwargs.pop("upgrade_deps", None)
26
- super().__init__(*args, **kwargs)
27
-
28
- def ensure_directories(self, env_dir):
29
- self.context = super(ExtendedEnvBuilder, self).ensure_directories(env_dir)
30
- return self.context
31
-
32
-
33
- def create(
34
- env_dir,
35
- system_site_packages=False,
36
- clear=False,
37
- symlinks=False,
38
- with_pip=False,
39
- prompt=None,
40
- upgrade_deps=False,
41
- ):
42
- """Create a virtual environment in a directory."""
43
- builder = ExtendedEnvBuilder(
44
- system_site_packages=system_site_packages,
45
- clear=clear,
46
- symlinks=symlinks,
47
- with_pip=with_pip,
48
- prompt=prompt,
49
- upgrade_deps=upgrade_deps,
50
- )
51
- builder.create(env_dir)
52
- return builder.context
53
-
54
-
55
- def python_run(venv_context, module, command, directory=_ROOT_DIR) -> Optional[str]:
56
- try:
57
- cmd_line = [
58
- venv_context.env_exe,
59
- "-m",
60
- module,
61
- ] + command
62
- print("Executing: {}".format(" ".join(cmd_line)))
63
- subprocess.run(
64
- cmd_line,
65
- cwd=directory,
66
- check=True,
67
- stdout=False,
68
- )
69
- if module == "get_all":
70
- with open(f"{command[1]}/.temp_folder/patched.txt", "r", encoding="utf-8-sig") as f:
71
- return f.read()
72
- except subprocess.CalledProcessError as err:
73
- print(err)
74
- sys.exit(1)
75
- return None