@autorest/python 6.25.0 → 6.26.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.
Files changed (27) hide show
  1. package/README.md +0 -23
  2. package/autorest/jsonrpc/server.py +0 -3
  3. package/generator/MANIFEST.in +1 -0
  4. package/generator/pygen/black.py +3 -4
  5. package/generator/pygen/codegen/models/client.py +1 -1
  6. package/generator/pygen/codegen/models/model_type.py +0 -2
  7. package/generator/pygen/codegen/models/operation.py +0 -5
  8. package/generator/pygen/codegen/serializers/builder_serializer.py +3 -2
  9. package/generator/pygen/codegen/serializers/model_serializer.py +23 -5
  10. package/generator/pygen/codegen/serializers/operations_init_serializer.py +1 -1
  11. package/generator/pygen/codegen/templates/init.py.jinja2 +2 -2
  12. package/generator/pygen/codegen/templates/keywords.jinja2 +11 -3
  13. package/generator/pygen/codegen/templates/model_base.py.jinja2 +8 -8
  14. package/generator/pygen/codegen/templates/model_container.py.jinja2 +3 -0
  15. package/generator/pygen/codegen/templates/model_dpg.py.jinja2 +3 -3
  16. package/generator/pygen/codegen/templates/model_init.py.jinja2 +7 -2
  17. package/generator/pygen/codegen/templates/operations_folder_init.py.jinja2 +1 -1
  18. package/generator/pygen/codegen/templates/serialization.py.jinja2 +4 -5
  19. package/generator/pygen.egg-info/SOURCES.txt +44 -3
  20. package/generator/setup.py +1 -0
  21. package/package.json +2 -2
  22. package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
  23. package/scripts/eng/pylintrc +1 -1
  24. package/autorest/postprocess.py +0 -14
  25. package/generator/pygen/postprocess/__init__.py +0 -183
  26. package/generator/pygen/postprocess/get_all.py +0 -19
  27. package/generator/pygen/postprocess/venvtools.py +0 -75
package/README.md CHANGED
@@ -39,10 +39,6 @@ modelerfour:
39
39
  flatten-payloads: true
40
40
  ```
41
41
 
42
- ```yaml $(postprocess)
43
- allow-no-input: true
44
- ```
45
-
46
42
  ```yaml !$(multiapiscript) && !$(multiclientscript)
47
43
  pass-thru:
48
44
  - model-deduplicator
@@ -142,25 +138,6 @@ scope-black/emitter:
142
138
  output-artifact: python-files
143
139
  ```
144
140
 
145
- # Post-process customized code for mypy pipeline
146
-
147
- ```yaml $(postprocess)
148
- pipeline:
149
- python/postprocess:
150
- scope: postprocess
151
- output-artifact: python-files
152
-
153
- python/postprocess/emitter:
154
- input: postprocess
155
- scope: scope-postprocess/emitter
156
-
157
- scope-postprocess/emitter:
158
- input-artifact: python-files
159
- output-uri-expr: $key
160
-
161
- output-artifact: python-files
162
- ```
163
-
164
141
  # Multi Client pipeline
165
142
 
166
143
  ```yaml $(multiclientscript)
@@ -27,7 +27,6 @@ def GetPluginNames():
27
27
  "m4reformatter",
28
28
  "black",
29
29
  "multiapiscript",
30
- "postprocess",
31
30
  "multiclientscript",
32
31
  ]
33
32
 
@@ -52,8 +51,6 @@ def Process(plugin_name: str, session_id: str) -> bool:
52
51
  from ..m4reformatter import M4Reformatter as PluginToLoad # type: ignore
53
52
  elif plugin_name == "codegen":
54
53
  from ..codegen import CodeGeneratorAutorest as PluginToLoad # type: ignore
55
- elif plugin_name == "postprocess":
56
- from ..postprocess import PostProcessPluginAutorest as PluginToLoad # type: ignore
57
54
  elif plugin_name == "black":
58
55
  from ..black import BlackScriptPluginAutorest as PluginToLoad # type: ignore
59
56
  elif plugin_name == "multiapiscript":
@@ -0,0 +1 @@
1
+ recursive-include pygen/codegen/templates *.jinja2
@@ -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 ""
@@ -28,7 +28,7 @@ class OperationsInitSerializer:
28
28
  return "_operations" if self.code_model.options["combine_operation_files"] else operation_group.filename
29
29
 
30
30
  return [
31
- f"from .{_get_filename(og)} import {og.class_name}"
31
+ f"from .{_get_filename(og)} import {og.class_name} # type: ignore"
32
32
  for client in self.clients
33
33
  for og in client.operation_groups
34
34
  ]
@@ -1,10 +1,10 @@
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
- from .{{ client.filename }} import {{ client.name }}
7
+ from .{{ client.filename }} import {{ client.name }} # type: ignore
8
8
  {% endfor %}
9
9
  {% endif %}
10
10
  {% if not async_mode and code_model.options['package_version']%}
@@ -4,16 +4,24 @@
4
4
  {% set async_class = "Async" if async_mode else "" %}
5
5
  {% macro escape_str(s) %}'{{ s|replace("'", "\\'") }}'{% endmacro %}
6
6
  {% set kwargs_declaration = "**kwargs: Any" %}
7
- {% set extend_all = "__all__.extend([p for p in _patch_all if p not in __all__])" %}
7
+ {% set extend_all = "__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore" %}
8
8
  {% macro patch_imports(try_except=False) %}
9
9
  {% set indentation = " " if try_except else "" %}
10
10
  {% if try_except %}
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
- from ._patch import patch_sdk as _patch_sdk{% endmacro %}
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 %}
@@ -57,11 +57,11 @@
57
57
  {% for param_signature in serializer.init_line(model) %}
58
58
  {{ param_signature }}
59
59
  {% endfor %}
60
- ):
60
+ ) -> None:
61
61
  ...
62
62
 
63
63
  @overload
64
- def __init__(self, mapping: Mapping[str, Any]):
64
+ def __init__(self, mapping: Mapping[str, Any]) -> None:
65
65
  """
66
66
  :param mapping: raw JSON to initialize the model.
67
67
  :type mapping: Mapping[str, Any]
@@ -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,17 +1,22 @@
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
 
7
+ from .{{ code_model.models_filename }} import ( # type: ignore
6
8
  {% for schema in schemas %}
7
- from .{{ code_model.models_filename }} import {{ schema }}
9
+ {{ schema }},
8
10
  {% endfor %}
11
+ )
9
12
  {% endif %}
10
13
  {% if enums %}
11
14
 
15
+ from .{{ code_model.enums_filename }} import ( # type: ignore
12
16
  {% for enum in enums %}
13
- from .{{ code_model.enums_filename }} import {{ enum }}
17
+ {{ enum }},
14
18
  {% endfor %}
19
+ )
15
20
  {% endif %}
16
21
  {{ keywords.patch_imports() }}
17
22
  __all__ = [
@@ -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__ = [
@@ -226,7 +226,7 @@ except ImportError: # Python 2.7
226
226
  :param datetime.timedelta offset: offset in timedelta format
227
227
  """
228
228
 
229
- def __init__(self, offset):
229
+ def __init__(self, offset) -> None:
230
230
  self.__offset = offset
231
231
 
232
232
  def utcoffset(self, dt):
@@ -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:
@@ -598,7 +597,7 @@ class Serializer(object): # pylint: disable=too-many-public-methods
598
597
  "multiple": lambda x, y: x % y != 0,
599
598
  }
600
599
 
601
- def __init__(self, classes: Optional[Mapping[str, type]] = None):
600
+ def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None:
602
601
  self.serialize_type = {
603
602
  "iso-8601": Serializer.serialize_iso,
604
603
  "rfc-1123": Serializer.serialize_rfc,
@@ -1452,7 +1451,7 @@ class Deserializer(object):
1452
1451
 
1453
1452
  valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?")
1454
1453
 
1455
- def __init__(self, classes: Optional[Mapping[str, type]] = None):
1454
+ def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None:
1456
1455
  self.deserialize_type = {
1457
1456
  "iso-8601": Deserializer.deserialize_iso,
1458
1457
  "rfc-1123": Deserializer.deserialize_rfc,
@@ -1,4 +1,5 @@
1
1
  LICENSE
2
+ MANIFEST.in
2
3
  README.md
3
4
  setup.py
4
5
  pygen/__init__.py
@@ -58,9 +59,49 @@ pygen/codegen/serializers/sample_serializer.py
58
59
  pygen/codegen/serializers/test_serializer.py
59
60
  pygen/codegen/serializers/types_serializer.py
60
61
  pygen/codegen/serializers/utils.py
61
- pygen/postprocess/__init__.py
62
- pygen/postprocess/get_all.py
63
- pygen/postprocess/venvtools.py
62
+ pygen/codegen/templates/client.py.jinja2
63
+ pygen/codegen/templates/client_container.py.jinja2
64
+ pygen/codegen/templates/config.py.jinja2
65
+ pygen/codegen/templates/config_container.py.jinja2
66
+ pygen/codegen/templates/conftest.py.jinja2
67
+ pygen/codegen/templates/enum.py.jinja2
68
+ pygen/codegen/templates/enum_container.py.jinja2
69
+ pygen/codegen/templates/init.py.jinja2
70
+ pygen/codegen/templates/keywords.jinja2
71
+ pygen/codegen/templates/lro_operation.py.jinja2
72
+ pygen/codegen/templates/lro_paging_operation.py.jinja2
73
+ pygen/codegen/templates/macros.jinja2
74
+ pygen/codegen/templates/metadata.json.jinja2
75
+ pygen/codegen/templates/model_base.py.jinja2
76
+ pygen/codegen/templates/model_container.py.jinja2
77
+ pygen/codegen/templates/model_dpg.py.jinja2
78
+ pygen/codegen/templates/model_init.py.jinja2
79
+ pygen/codegen/templates/model_msrest.py.jinja2
80
+ pygen/codegen/templates/operation.py.jinja2
81
+ pygen/codegen/templates/operation_group.py.jinja2
82
+ pygen/codegen/templates/operation_groups_container.py.jinja2
83
+ pygen/codegen/templates/operation_tools.jinja2
84
+ pygen/codegen/templates/operations_folder_init.py.jinja2
85
+ pygen/codegen/templates/paging_operation.py.jinja2
86
+ pygen/codegen/templates/patch.py.jinja2
87
+ pygen/codegen/templates/pkgutil_init.py.jinja2
88
+ pygen/codegen/templates/request_builder.py.jinja2
89
+ pygen/codegen/templates/request_builders.py.jinja2
90
+ pygen/codegen/templates/rest_init.py.jinja2
91
+ pygen/codegen/templates/sample.py.jinja2
92
+ pygen/codegen/templates/serialization.py.jinja2
93
+ pygen/codegen/templates/test.py.jinja2
94
+ pygen/codegen/templates/testpreparer.py.jinja2
95
+ pygen/codegen/templates/types.py.jinja2
96
+ pygen/codegen/templates/validation.py.jinja2
97
+ pygen/codegen/templates/vendor.py.jinja2
98
+ pygen/codegen/templates/version.py.jinja2
99
+ pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2
100
+ pygen/codegen/templates/packaging_templates/LICENSE.jinja2
101
+ pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2
102
+ pygen/codegen/templates/packaging_templates/README.md.jinja2
103
+ pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2
104
+ pygen/codegen/templates/packaging_templates/setup.py.jinja2
64
105
  pygen/preprocess/__init__.py
65
106
  pygen/preprocess/helpers.py
66
107
  pygen/preprocess/python_mappings.py
@@ -23,6 +23,7 @@ if not version:
23
23
  setup(
24
24
  name="pygen",
25
25
  version=version,
26
+ include_package_data=True,
26
27
  description="Core Library for Python Generation",
27
28
  long_description=open("README.md", "r").read(),
28
29
  long_description_content_type="text/markdown",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autorest/python",
3
- "version": "6.25.0",
3
+ "version": "6.26.1",
4
4
  "description": "The Python extension for generators in AutoRest.",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "devDependencies": {
27
27
  "@microsoft.azure/autorest.testserver": "^3.3.50",
28
- "@typespec/http-client-python": "0.2.0",
28
+ "@typespec/http-client-python": "0.3.4",
29
29
  "chalk": "5.3.0",
30
30
  "typescript": "~5.1.6"
31
31
  },
@@ -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,unknown-option-value
21
21
 
22
22
  [FORMAT]
23
23
  max-line-length=120
@@ -1,14 +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 Any, Dict
7
-
8
- from pygen.postprocess import PostProcessPlugin
9
- from . import PluginAutorest
10
-
11
-
12
- class PostProcessPluginAutorest(PostProcessPlugin, PluginAutorest):
13
- def get_options(self) -> Dict[str, Any]:
14
- return {"outputFolderUri": self._autorestapi.get_value("outputFolderUri")}
@@ -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