@typespec/http-client-python 0.3.1 → 0.3.3

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.
@@ -17,7 +17,7 @@ enable=useless-suppression
17
17
  # too-many-arguments: Due to the nature of the CLI many commands have large arguments set which reflect in large arguments set in corresponding methods.
18
18
  # too-many-lines: Due to code generation many files end up with too many lines.
19
19
  # Let's black deal with bad-continuation
20
- disable=useless-object-inheritance,missing-docstring,locally-disabled,fixme,cyclic-import,too-many-arguments,invalid-name,duplicate-code,too-few-public-methods,consider-using-f-string,super-with-arguments,redefined-builtin,import-outside-toplevel,client-suffix-needed,unnecessary-dunder-call,unnecessary-ellipsis,disallowed-name,consider-using-max-builtin,too-many-lines,parse-error,useless-suppression,unknown-option-value
20
+ disable=useless-object-inheritance,missing-docstring,locally-disabled,fixme,cyclic-import,too-many-arguments,invalid-name,duplicate-code,too-few-public-methods,consider-using-f-string,super-with-arguments,redefined-builtin,import-outside-toplevel,client-suffix-needed,unnecessary-dunder-call,unnecessary-ellipsis,disallowed-name,consider-using-max-builtin
21
21
 
22
22
  [FORMAT]
23
23
  max-line-length=120
@@ -37,6 +37,8 @@ def _single_dir_pylint(mod):
37
37
  "--evaluation=(max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention + info)/ statement) * 10)))",
38
38
  "--load-plugins=pylint_guidelines_checker",
39
39
  "--output-format=parseable",
40
+ "--recursive=y",
41
+ "--py-version=3.8",
40
42
  str(inner_class.absolute()),
41
43
  ]
42
44
  )
@@ -47,4 +49,8 @@ def _single_dir_pylint(mod):
47
49
 
48
50
 
49
51
  if __name__ == "__main__":
52
+ if os.name == "nt":
53
+ # Before https://github.com/microsoft/typespec/issues/4759 fixed, skip running Pylint for now on Windows
54
+ logging.info("Skip running Pylint on Windows for now")
55
+ sys.exit(0)
50
56
  run_check("pylint", _single_dir_pylint, "Pylint")
@@ -59,10 +59,9 @@ class BlackScriptPlugin(Plugin):
59
59
  except:
60
60
  _LOGGER.error("Error: failed to format %s", file)
61
61
  raise
62
- else:
63
- if len(file_content.splitlines()) > 1000:
64
- file_content = "# pylint: disable=too-many-lines\n" + file_content
65
- self.write_file(file, file_content)
62
+ if len(file_content.splitlines()) > 1000:
63
+ file_content = "# pylint: disable=too-many-lines\n" + file_content
64
+ self.write_file(file, file_content)
66
65
 
67
66
 
68
67
  if __name__ == "__main__":
@@ -354,7 +354,7 @@ class Config(_ClientConfigBase[ConfigGlobalParameterList]):
354
354
  """Model representing our Config type."""
355
355
 
356
356
  def pylint_disable(self) -> str:
357
- retval = add_to_pylint_disable("", "too-many-instance-attributes")
357
+ retval = add_to_pylint_disable("", "too-many-instance-attributes") if self.code_model.is_azure_flavor else ""
358
358
  if len(self.name) > NAME_LENGTH_LIMIT:
359
359
  retval = add_to_pylint_disable(retval, "name-too-long")
360
360
  return retval
@@ -236,8 +236,6 @@ class ModelType(BaseType): # pylint: disable=too-many-instance-attributes, too-
236
236
 
237
237
  def pylint_disable(self) -> str:
238
238
  retval: str = ""
239
- if len(self.properties) > 10:
240
- retval = add_to_pylint_disable(retval, "too-many-instance-attributes")
241
239
  if len(self.name) > NAME_LENGTH_LIMIT:
242
240
  retval = add_to_pylint_disable(retval, "name-too-long")
243
241
  return retval
@@ -142,11 +142,6 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
142
142
  if not async_mode and not self.is_overload and self.response_type_annotation(async_mode=False) == "None":
143
143
  # doesn't matter if it's async or not
144
144
  retval = add_to_pylint_disable(retval, "inconsistent-return-statements")
145
- try:
146
- if any(is_internal(r.type) for r in self.responses) or is_internal(self.parameters.body_parameter.type):
147
- retval = add_to_pylint_disable(retval, "protected-access")
148
- except ValueError:
149
- pass
150
145
  if len(self.name) > NAME_LENGTH_LIMIT:
151
146
  retval = add_to_pylint_disable(retval, "name-too-long")
152
147
  return retval
@@ -553,11 +553,12 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
553
553
  type_ignore = self.async_mode and builder.group_name == "" # is in a mixin
554
554
  if builder.stream_value is True and not self.code_model.options["version_tolerant"]:
555
555
  retval.append("_decompress = kwargs.pop('decompress', True)")
556
+ pylint_disable = " # pylint: disable=protected-access" if self.code_model.is_azure_flavor else ""
556
557
  retval.extend(
557
558
  [
558
559
  f"_stream = {builder.stream_value}",
559
560
  f"pipeline_response: PipelineResponse = {self._call_method}self._client.{self.pipeline_name}.run( "
560
- + f"{'# type: ignore' if type_ignore else ''} # pylint: disable=protected-access",
561
+ + f"{'# type: ignore' if type_ignore else ''}{pylint_disable}",
561
562
  " _request,",
562
563
  " stream=_stream,",
563
564
  " **kwargs",
@@ -599,7 +600,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
599
600
  retval.append(f" params_added_on={dict(params_added_on)},")
600
601
  if retval:
601
602
  retval_str = "\n".join(retval)
602
- return f"@api_version_validation(\n{retval_str}\n){builder.pylint_disable(self.async_mode)}"
603
+ return f"@api_version_validation(\n{retval_str}\n)"
603
604
  return ""
604
605
 
605
606
  def pop_kwargs_from_signature(self, builder: OperationType) -> List[str]:
@@ -110,16 +110,22 @@ class _ModelSerializer(BaseSerializer, ABC):
110
110
  def need_init(self, model: ModelType) -> bool:
111
111
  return (not model.internal) and bool(self.init_line(model) or model.discriminator)
112
112
 
113
- def pylint_disable(self, model: ModelType) -> str:
113
+ def pylint_disable_items(self, model: ModelType) -> List[str]:
114
114
  if model.flattened_property or self.initialize_properties(model):
115
- return ""
115
+ return [""]
116
116
  if any(p for p in model.properties if p.is_discriminator and model.discriminator_value):
117
- return ""
117
+ return [""]
118
118
  if model.parents and any(
119
119
  "=" in prop for parent in model.parents for prop in self.init_line(parent) if self.need_init(parent)
120
120
  ):
121
- return ""
122
- return " # pylint: disable=useless-super-delegation"
121
+ return [""]
122
+ return ["useless-super-delegation"]
123
+
124
+ def pylint_disable(self, model: ModelType) -> str:
125
+ return " # pylint: disable=" + ", ".join(self.pylint_disable_items(model))
126
+
127
+ def global_pylint_disables(self) -> str:
128
+ return ""
123
129
 
124
130
 
125
131
  class MsrestModelSerializer(_ModelSerializer):
@@ -315,3 +321,15 @@ class DpgModelSerializer(_ModelSerializer):
315
321
  properties_to_pass_to_super.append(f"{prop.client_name}={prop.get_declaration()}")
316
322
  properties_to_pass_to_super.append("**kwargs")
317
323
  return ", ".join(properties_to_pass_to_super)
324
+
325
+ def global_pylint_disables(self) -> str:
326
+ result = []
327
+ for model in self.code_model.model_types:
328
+ if self.need_init(model):
329
+ for item in self.pylint_disable_items(model):
330
+ if item:
331
+ result.append(item)
332
+ final_result = set(result)
333
+ if final_result:
334
+ return "# pylint: disable=" + ", ".join(final_result)
335
+ return ""
@@ -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 }}
@@ -11,9 +11,17 @@
11
11
  try:
12
12
  {% endif %}
13
13
  {{ indentation }}from ._patch import __all__ as _patch_all
14
- {{ indentation }}from ._patch import * # pylint: disable=unused-wildcard-import
14
+ {{ indentation }}from ._patch import *
15
15
  {% if try_except %}
16
16
  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 %}
@@ -4,7 +4,7 @@
4
4
  # Licensed under the MIT License. See License.txt in the project root for
5
5
  # license information.
6
6
  # --------------------------------------------------------------------------
7
- # pylint: disable=protected-access, arguments-differ, signature-differs, broad-except, too-many-lines
7
+ # pylint: disable=protected-access, broad-except
8
8
 
9
9
  import copy
10
10
  import calendar
@@ -573,7 +573,7 @@ class Model(_MyMutableMapping):
573
573
  def copy(self) -> "Model":
574
574
  return Model(self.__dict__)
575
575
 
576
- def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: # pylint: disable=unused-argument
576
+ def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self:
577
577
  if f"{cls.__module__}.{cls.__qualname__}" not in cls._calculated:
578
578
  # we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping',
579
579
  # 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object'
@@ -584,8 +584,8 @@ class Model(_MyMutableMapping):
584
584
  annotations = {
585
585
  k: v
586
586
  for mro_class in mros
587
- if hasattr(mro_class, "__annotations__") # pylint: disable=no-member
588
- for k, v in mro_class.__annotations__.items() # pylint: disable=no-member
587
+ if hasattr(mro_class, "__annotations__")
588
+ for k, v in mro_class.__annotations__.items()
589
589
  }
590
590
  for attr, rf in attr_to_rest_field.items():
591
591
  rf._module = cls.__module__
@@ -600,8 +600,8 @@ class Model(_MyMutableMapping):
600
600
 
601
601
  def __init_subclass__(cls, discriminator: typing.Optional[str] = None) -> None:
602
602
  for base in cls.__bases__:
603
- if hasattr(base, "__mapping__"): # pylint: disable=no-member
604
- base.__mapping__[discriminator or cls.__name__] = cls # type: ignore # pylint: disable=no-member
603
+ if hasattr(base, "__mapping__"):
604
+ base.__mapping__[discriminator or cls.__name__] = cls # type: ignore
605
605
 
606
606
  @classmethod
607
607
  def _get_discriminator(cls, exist_discriminators) -> typing.Optional["_RestField"]:
@@ -612,7 +612,7 @@ class Model(_MyMutableMapping):
612
612
 
613
613
  @classmethod
614
614
  def _deserialize(cls, data, exist_discriminators):
615
- if not hasattr(cls, "__mapping__"): # pylint: disable=no-member
615
+ if not hasattr(cls, "__mapping__"):
616
616
  return cls(data)
617
617
  discriminator = cls._get_discriminator(exist_discriminators)
618
618
  if discriminator is None:
@@ -632,7 +632,7 @@ class Model(_MyMutableMapping):
632
632
  discriminator_value = data.find(xml_name).text # pyright: ignore
633
633
  else:
634
634
  discriminator_value = data.get(discriminator._rest_name)
635
- mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore # pylint: disable=no-member
635
+ mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore
636
636
  return mapped_cls._deserialize(data, exist_discriminators)
637
637
 
638
638
  def as_dict(self, *, exclude_readonly: bool = False) -> typing.Dict[str, typing.Any]:
@@ -1,6 +1,9 @@
1
1
  {% import 'operation_tools.jinja2' as op_tools %}
2
2
  # coding=utf-8
3
3
  {{ code_model.options['license_header'] }}
4
+ {% if serializer.global_pylint_disables() %}
5
+ {{ serializer.global_pylint_disables() }}
6
+ {% endif %}
4
7
 
5
8
  {{ imports }}
6
9
  {% for model in code_model.model_types %}
@@ -70,7 +70,7 @@
70
70
  {% endif %}
71
71
  {% set initialize_properties = serializer.initialize_properties(model) %}
72
72
  {% if serializer.need_init(model) or initialize_properties %}
73
- def __init__(self, *args: Any, **kwargs: Any) -> None:{{ '# pylint: disable=useless-super-delegation' if not initialize_properties else '' }}
73
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
74
74
  {% for line in serializer.super_call(model) %}
75
75
  {{ line }}
76
76
  {% endfor %}
@@ -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__ = [
@@ -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.1",
3
+ "version": "0.3.3",
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