@autorest/python 6.29.1 → 6.31.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 (46) hide show
  1. package/autorest/m4reformatter/__init__.py +1 -1
  2. package/generator/build/lib/pygen/__init__.py +3 -3
  3. package/generator/build/lib/pygen/black.py +2 -2
  4. package/generator/build/lib/pygen/codegen/__init__.py +5 -7
  5. package/generator/build/lib/pygen/codegen/models/code_model.py +5 -5
  6. package/generator/build/lib/pygen/codegen/models/paging_operation.py +11 -2
  7. package/generator/build/lib/pygen/codegen/models/parameter.py +2 -1
  8. package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +2 -0
  9. package/generator/build/lib/pygen/codegen/models/response.py +1 -1
  10. package/generator/build/lib/pygen/codegen/serializers/__init__.py +18 -14
  11. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +47 -25
  12. package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +5 -2
  13. package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +1 -1
  14. package/generator/build/lib/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +6 -2
  15. package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +5 -5
  16. package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +3 -3
  17. package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +14 -5
  18. package/generator/build/lib/pygen/preprocess/__init__.py +10 -12
  19. package/generator/build/lib/pygen/preprocess/python_mappings.py +1 -1
  20. package/generator/build/lib/pygen/utils.py +5 -5
  21. package/generator/component-detection-pip-report.json +7 -6
  22. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  23. package/generator/pygen/__init__.py +3 -3
  24. package/generator/pygen/black.py +2 -2
  25. package/generator/pygen/codegen/__init__.py +5 -7
  26. package/generator/pygen/codegen/models/code_model.py +5 -5
  27. package/generator/pygen/codegen/models/paging_operation.py +11 -2
  28. package/generator/pygen/codegen/models/parameter.py +2 -1
  29. package/generator/pygen/codegen/models/request_builder_parameter.py +2 -0
  30. package/generator/pygen/codegen/models/response.py +1 -1
  31. package/generator/pygen/codegen/serializers/__init__.py +18 -14
  32. package/generator/pygen/codegen/serializers/builder_serializer.py +47 -25
  33. package/generator/pygen/codegen/serializers/general_serializer.py +5 -2
  34. package/generator/pygen/codegen/serializers/test_serializer.py +1 -1
  35. package/generator/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +6 -2
  36. package/generator/pygen/codegen/templates/packaging_templates/README.md.jinja2 +5 -5
  37. package/generator/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +3 -3
  38. package/generator/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +14 -5
  39. package/generator/pygen/preprocess/__init__.py +10 -12
  40. package/generator/pygen/preprocess/python_mappings.py +1 -1
  41. package/generator/pygen/utils.py +5 -5
  42. package/generator/pygen.egg-info/PKG-INFO +4 -3
  43. package/generator/pygen.egg-info/requires.txt +2 -2
  44. package/generator/setup.py +2 -2
  45. package/package.json +2 -2
  46. package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
@@ -551,7 +551,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
551
551
  def add_paging_information(self, group_name: str, operation: Dict[str, Any], yaml_data: Dict[str, Any]) -> None:
552
552
  operation["discriminator"] = "paging"
553
553
  operation["itemName"] = yaml_data["extensions"]["x-ms-pageable"].get("itemName", "value")
554
- operation["continuationTokenName"] = yaml_data["extensions"]["x-ms-pageable"].get("nextLinkName")
554
+ operation["nextLinkName"] = yaml_data["extensions"]["x-ms-pageable"].get("nextLinkName")
555
555
  returned_response_object = (
556
556
  operation["nextOperation"]["responses"][0] if operation.get("nextOperation") else operation["responses"][0]
557
557
  )
@@ -78,12 +78,12 @@ class YamlUpdatePlugin(Plugin):
78
78
  """A plugin that update the YAML as input."""
79
79
 
80
80
  def get_yaml(self) -> Dict[str, Any]:
81
- # cadl file doesn't have to be relative to output folder
82
- with open(self.options["cadl_file"], "r", encoding="utf-8-sig") as fd:
81
+ # tsp file doesn't have to be relative to output folder
82
+ with open(self.options["tsp_file"], "r", encoding="utf-8-sig") as fd:
83
83
  return yaml.safe_load(fd.read())
84
84
 
85
85
  def write_yaml(self, yaml_string: str) -> None:
86
- with open(self.options["cadl_file"], "w", encoding="utf-8-sig") as fd:
86
+ with open(self.options["tsp_file"], "w", encoding="utf-8-sig") as fd:
87
87
  fd.write(yaml_string)
88
88
 
89
89
  def process(self) -> bool:
@@ -77,6 +77,6 @@ class BlackScriptPlugin(Plugin):
77
77
 
78
78
 
79
79
  if __name__ == "__main__":
80
- # CADL pipeline will call this
81
- args, unknown_args = parse_args(need_cadl_file=False)
80
+ # TSP pipeline will call this
81
+ args, unknown_args = parse_args(need_tsp_file=False)
82
82
  BlackScriptPlugin(output_folder=args.output_folder, **unknown_args).process()
@@ -40,7 +40,6 @@ class OptionsRetriever:
40
40
  "generate-test": False,
41
41
  "from-typespec": False,
42
42
  "emit-cross-language-definition-file": False,
43
- "enable-typespec-namespace": False,
44
43
  }
45
44
 
46
45
  @property
@@ -79,7 +78,7 @@ class OptionsRetriever:
79
78
  @property
80
79
  def _models_mode_default(self) -> str:
81
80
  models_mode_default = "none" if self.low_level_client or self.version_tolerant else "msrest"
82
- if self.options.get("cadl_file") is not None:
81
+ if self.options.get("tsp_file") is not None:
83
82
  models_mode_default = "dpg"
84
83
  return models_mode_default
85
84
 
@@ -317,13 +316,12 @@ class CodeGenerator(Plugin):
317
316
  "flavor",
318
317
  "company_name",
319
318
  "emit_cross_language_definition_file",
320
- "enable_typespec_namespace",
321
319
  ]
322
320
  return {f: getattr(self.options_retriever, f) for f in flags}
323
321
 
324
322
  def get_yaml(self) -> Dict[str, Any]:
325
- # cadl file doesn't have to be relative to output folder
326
- with open(self.options["cadl_file"], "r", encoding="utf-8-sig") as fd:
323
+ # tsp file doesn't have to be relative to output folder
324
+ with open(self.options["tsp_file"], "r", encoding="utf-8-sig") as fd:
327
325
  return yaml.safe_load(fd.read())
328
326
 
329
327
  def get_serializer(self, code_model: CodeModel):
@@ -350,10 +348,10 @@ class CodeGenerator(Plugin):
350
348
 
351
349
 
352
350
  if __name__ == "__main__":
353
- # CADL pipeline will call this
351
+ # TSP pipeline will call this
354
352
  parsed_args, unknown_args = parse_args()
355
353
  CodeGenerator(
356
354
  output_folder=parsed_args.output_folder,
357
- cadl_file=parsed_args.cadl_file,
355
+ tsp_file=parsed_args.tsp_file,
358
356
  **unknown_args,
359
357
  ).process()
@@ -145,12 +145,8 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
145
145
  return result
146
146
  return f"{result}{module_name}" if result.endswith(".") else f"{result}.{module_name}"
147
147
 
148
- @property
149
- def need_unique_model_alias(self) -> bool:
150
- return self.has_subnamespace and self.options["enable_typespec_namespace"]
151
-
152
148
  def get_unique_models_alias(self, serialize_namespace: str, imported_namespace: str) -> str:
153
- if not self.need_unique_model_alias:
149
+ if not self.has_subnamespace:
154
150
  return "_models"
155
151
  relative_path = self.get_relative_import_path(
156
152
  serialize_namespace, self.get_imported_namespace_for_model(imported_namespace)
@@ -406,3 +402,7 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
406
402
  @staticmethod
407
403
  def has_non_json_models(models: List[ModelType]) -> bool:
408
404
  return any(m for m in models if m.base != "json")
405
+
406
+ @property
407
+ def is_tsp(self) -> bool:
408
+ return self.options.get("tsp_file") is not None
@@ -58,6 +58,15 @@ class PagingOperationBase(OperationBase[PagingResponseType]):
58
58
  self.override_success_response_to_200 = override_success_response_to_200
59
59
  self.pager_sync: str = yaml_data.get("pagerSync") or f"{self.code_model.core_library}.paging.ItemPaged"
60
60
  self.pager_async: str = yaml_data.get("pagerAsync") or f"{self.code_model.core_library}.paging.AsyncItemPaged"
61
+ self.continuation_token: Dict[str, Any] = yaml_data.get("continuationToken", {})
62
+
63
+ @property
64
+ def has_continuation_token(self) -> bool:
65
+ return bool(self.continuation_token.get("input") and self.continuation_token.get("output"))
66
+
67
+ @property
68
+ def next_variable_name(self) -> str:
69
+ return "_continuation_token" if self.has_continuation_token else "next_link"
61
70
 
62
71
  def _get_attr_name(self, wire_name: str) -> str:
63
72
  response_type = self.responses[0].type
@@ -74,8 +83,8 @@ class PagingOperationBase(OperationBase[PagingResponseType]):
74
83
  return self.responses[0].get_pager(async_mode)
75
84
 
76
85
  @property
77
- def continuation_token_name(self) -> Optional[str]:
78
- wire_name = self.yaml_data.get("continuationTokenName")
86
+ def next_link_name(self) -> Optional[str]:
87
+ wire_name = self.yaml_data.get("nextLinkName")
79
88
  if not wire_name:
80
89
  # That's an ok scenario, it just means no next page possible
81
90
  return None
@@ -85,6 +85,7 @@ class _ParameterBase(BaseModel, abc.ABC): # pylint: disable=too-many-instance-a
85
85
  self.in_overload: bool = self.yaml_data.get("inOverload", False)
86
86
  self.default_to_unset_sentinel: bool = self.yaml_data.get("defaultToUnsetSentinel", False)
87
87
  self.hide_in_method: bool = self.yaml_data.get("hideInMethod", False)
88
+ self.is_continuation_token: bool = bool(self.yaml_data.get("isContinuationToken"))
88
89
 
89
90
  def get_declaration(self, value: Any = None) -> Any:
90
91
  return self.type.get_declaration(value)
@@ -314,7 +315,7 @@ class Parameter(_ParameterBase):
314
315
  def hide_in_operation_signature(self) -> bool:
315
316
  if self.code_model.options["version_tolerant"] and self.client_name == "maxpagesize":
316
317
  return True
317
- return False
318
+ return self.is_continuation_token
318
319
 
319
320
  @property
320
321
  def in_method_signature(self) -> bool:
@@ -112,4 +112,6 @@ class RequestBuilderParameter(Parameter):
112
112
  return f"_{self.client_name}"
113
113
  if self.implementation == "Client":
114
114
  return f"self._config.{self.client_name}"
115
+ if self.is_continuation_token:
116
+ return "_continuation_token"
115
117
  return self.client_name
@@ -63,7 +63,7 @@ class Response(BaseModel):
63
63
  def result_property(self) -> str:
64
64
  field = self.yaml_data.get("resultProperty")
65
65
  if field:
66
- return f'.get("{field}")'
66
+ return "".join([f'.get("{field}", {{}})' for field in field.split(".")])
67
67
  return ""
68
68
 
69
69
  def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
@@ -197,6 +197,8 @@ class JinjaSerializer(ReaderAndWriter):
197
197
  env = Environment(
198
198
  loader=PackageLoader("pygen.codegen", "templates/packaging_templates"),
199
199
  undefined=StrictUndefined,
200
+ trim_blocks=True,
201
+ lstrip_blocks=True,
200
202
  )
201
203
 
202
204
  package_files = _PACKAGE_FILES
@@ -460,21 +462,11 @@ class JinjaSerializer(ReaderAndWriter):
460
462
  metadata_serializer = MetadataSerializer(self.code_model, env, client_namespace=namespace)
461
463
  self.write_file(self.exec_path(namespace) / Path("_metadata.json"), metadata_serializer.serialize())
462
464
 
463
- @property
464
- def _namespace_from_package_name(self) -> str:
465
- return get_namespace_from_package_name(self.code_model.options["package_name"])
466
-
467
- def _name_space(self) -> str:
468
- if self.code_model.namespace.count(".") >= self._namespace_from_package_name.count("."):
469
- return self.code_model.namespace
470
-
471
- return self._namespace_from_package_name
472
-
473
465
  @property
474
466
  def exec_path_compensation(self) -> Path:
475
467
  """Assume the process is running in the root folder of the package. If not, we need the path compensation."""
476
468
  return (
477
- Path("../" * (self._name_space().count(".") + 1))
469
+ Path("../" * (self.code_model.namespace.count(".") + 1))
478
470
  if self.code_model.options["no_namespace_folders"]
479
471
  else Path(".")
480
472
  )
@@ -482,16 +474,28 @@ class JinjaSerializer(ReaderAndWriter):
482
474
  def exec_path_for_test_sample(self, namespace: str) -> Path:
483
475
  return self.exec_path_compensation / Path(*namespace.split("."))
484
476
 
477
+ # pylint: disable=line-too-long
485
478
  def exec_path(self, namespace: str) -> Path:
486
479
  if self.code_model.options["no_namespace_folders"] and not self.code_model.options["multiapi"]:
480
+ # when output folder contains parts different from the namespace, we fall back to current folder directly.
481
+ # (e.g. https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-callautomation/swagger/SWAGGER.md)
487
482
  return Path(".")
488
483
  return self.exec_path_compensation / Path(*namespace.split("."))
489
484
 
485
+ # pylint: disable=line-too-long
490
486
  @property
491
- def _additional_folder(self) -> Path:
487
+ def sample_additional_folder(self) -> Path:
488
+ # For special package, we need to additional folder when generate samples.
489
+ # For example, azure-mgmt-resource is combined by multiple modules, and each module is multiapi package.
490
+ # one of namespace is "azure.mgmt.resource.resources.v2020_01_01", then additional folder is "resources"
491
+ # so that we could avoid conflict when generate samples.
492
+ # python config: https://github.com/Azure/azure-rest-api-specs/blob/main/specification/resources/resource-manager/readme.python.md
493
+ # generated SDK: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/resources/azure-mgmt-resource/generated_samples
492
494
  namespace_config = get_namespace_config(self.code_model.namespace, self.code_model.options["multiapi"])
493
495
  num_of_namespace = namespace_config.count(".") + 1
494
- num_of_package_namespace = self._namespace_from_package_name.count(".") + 1
496
+ num_of_package_namespace = (
497
+ get_namespace_from_package_name(self.code_model.options["package_name"]).count(".") + 1
498
+ )
495
499
  if num_of_namespace > num_of_package_namespace:
496
500
  return Path("/".join(namespace_config.split(".")[num_of_package_namespace:]))
497
501
  return Path("")
@@ -514,7 +518,7 @@ class JinjaSerializer(ReaderAndWriter):
514
518
  file_name = to_snake_case(extract_sample_name(file)) + ".py"
515
519
  try:
516
520
  self.write_file(
517
- out_path / self._additional_folder / _sample_output_path(file) / file_name,
521
+ out_path / self.sample_additional_folder / _sample_output_path(file) / file_name,
518
522
  SampleSerializer(
519
523
  code_model=self.code_model,
520
524
  env=env,
@@ -630,7 +630,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
630
630
  operation_name=f"('{builder.name}')" if builder.group_name == "" else "",
631
631
  )
632
632
  for p in builder.parameters.parameters:
633
- if p.hide_in_operation_signature:
633
+ if p.hide_in_operation_signature and not p.is_continuation_token:
634
634
  kwargs.append(f'{p.client_name} = kwargs.pop("{p.client_name}", None)')
635
635
  cls_annotation = builder.cls_type_annotation(
636
636
  async_mode=self.async_mode, serialize_namespace=self.serialize_namespace
@@ -1001,9 +1001,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
1001
1001
  retval.extend(deserialize_code)
1002
1002
  return retval
1003
1003
 
1004
- def handle_error_response( # pylint: disable=too-many-statements, too-many-branches
1005
- self, builder: OperationType
1006
- ) -> List[str]:
1004
+ def handle_error_response(self, builder: OperationType) -> List[str]:
1007
1005
  async_await = "await " if self.async_mode else ""
1008
1006
  retval = [f"if response.status_code not in {str(builder.success_status_codes)}:"]
1009
1007
  response_read = [
@@ -1290,16 +1288,20 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
1290
1288
 
1291
1289
  def _prepare_request_callback(self, builder: PagingOperationType) -> List[str]:
1292
1290
  retval = self._initialize_overloads(builder)
1293
- retval.append("def prepare_request(next_link=None):")
1294
- retval.append(" if not next_link:")
1295
- retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])
1296
- retval.append("")
1297
- retval.append(" else:")
1298
- retval.extend([f" {line}" for line in self.call_next_link_request_builder(builder)])
1299
- if not builder.next_request_builder and self.code_model.is_legacy:
1300
- retval.append(' _request.method = "GET"')
1291
+ if builder.has_continuation_token:
1292
+ retval.append(f"def prepare_request({builder.next_variable_name}=None):")
1293
+ retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])
1301
1294
  else:
1295
+ retval.append("def prepare_request(next_link=None):")
1296
+ retval.append(" if not next_link:")
1297
+ retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])
1302
1298
  retval.append("")
1299
+ retval.append(" else:")
1300
+ retval.extend([f" {line}" for line in self.call_next_link_request_builder(builder)])
1301
+ if not builder.next_request_builder and self.code_model.is_legacy:
1302
+ retval.append(' _request.method = "GET"')
1303
+ else:
1304
+ retval.append("")
1303
1305
  retval.append(" return _request")
1304
1306
  return retval
1305
1307
 
@@ -1307,7 +1309,7 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
1307
1309
  def _function_def(self) -> str:
1308
1310
  return "def"
1309
1311
 
1310
- def _extract_data_callback(self, builder: PagingOperationType) -> List[str]:
1312
+ def _extract_data_callback(self, builder: PagingOperationType) -> List[str]: # pylint: disable=too-many-statements
1311
1313
  retval = [f"{'async ' if self.async_mode else ''}def extract_data(pipeline_response):"]
1312
1314
  response = builder.responses[0]
1313
1315
  deserialized = "pipeline_response.http_response.json()"
@@ -1328,7 +1330,13 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
1328
1330
  else:
1329
1331
  retval.append(f" deserialized = {deserialized}")
1330
1332
  item_name = builder.item_name
1331
- access = f".{item_name}" if self.code_model.options["models_mode"] == "msrest" else f'["{item_name}"]'
1333
+ if self.code_model.options["models_mode"] == "msrest":
1334
+ access = f".{item_name}"
1335
+ else:
1336
+ item_name_array = item_name.split(".")
1337
+ access = (
1338
+ "".join([f'.get("{i}", {{}})' for i in item_name_array[:-1]]) + f'.get("{item_name_array[-1]}", [])'
1339
+ )
1332
1340
  list_of_elem_deserialized = ""
1333
1341
  if self.code_model.options["models_mode"] == "dpg":
1334
1342
  item_type = builder.item_type.type_annotation(
@@ -1341,20 +1349,34 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
1341
1349
  retval.append(" if cls:")
1342
1350
  retval.append(" list_of_elem = cls(list_of_elem) # type: ignore")
1343
1351
 
1344
- continuation_token_name = builder.continuation_token_name
1345
- if not continuation_token_name:
1346
- cont_token_property = "None"
1347
- elif self.code_model.options["models_mode"] == "msrest":
1348
- cont_token_property = f"deserialized.{continuation_token_name} or None"
1352
+ if builder.has_continuation_token:
1353
+ location = builder.continuation_token.get("output", {}).get("location")
1354
+ wire_name = builder.continuation_token.get("output", {}).get("wireName") or ""
1355
+ if location == "header":
1356
+ cont_token_property = f'pipeline_response.http_response.headers.get("{wire_name}") or None'
1357
+ else:
1358
+ wire_name_array = wire_name.split(".")
1359
+ wire_name_call = (
1360
+ "".join([f'.get("{i}", {{}})' for i in wire_name_array[:-1]]) + f'.get("{wire_name_array[-1]}")'
1361
+ )
1362
+ cont_token_property = f"deserialized{wire_name_call} or None"
1349
1363
  else:
1350
- cont_token_property = f'deserialized.get("{continuation_token_name}") or None'
1364
+ next_link_name = builder.next_link_name
1365
+ if not next_link_name:
1366
+ cont_token_property = "None"
1367
+ elif self.code_model.options["models_mode"] == "msrest":
1368
+ cont_token_property = f"deserialized.{next_link_name} or None"
1369
+ else:
1370
+ cont_token_property = f'deserialized.get("{next_link_name}") or None'
1351
1371
  list_type = "AsyncList" if self.async_mode else "iter"
1352
1372
  retval.append(f" return {cont_token_property}, {list_type}(list_of_elem)")
1353
1373
  return retval
1354
1374
 
1355
1375
  def _get_next_callback(self, builder: PagingOperationType) -> List[str]:
1356
- retval = [f"{'async ' if self.async_mode else ''}def get_next(next_link=None):"]
1357
- retval.append(" _request = prepare_request(next_link)")
1376
+ retval = [
1377
+ f"{'async ' if self.async_mode else ''}def get_next({builder.next_variable_name}=None):" # pylint: disable=line-too-long
1378
+ ]
1379
+ retval.append(f" _request = prepare_request({builder.next_variable_name})")
1358
1380
  retval.append("")
1359
1381
  retval.extend([f" {l}" for l in self.make_pipeline_call(builder)])
1360
1382
  retval.append(" response = pipeline_response.http_response")
@@ -1506,10 +1528,10 @@ class LROPagingOperationSerializer(
1506
1528
 
1507
1529
  def get_long_running_output(self, builder: LROPagingOperation) -> List[str]:
1508
1530
  retval = ["def get_long_running_output(pipeline_response):"]
1509
- retval.append(f" {self._function_def} internal_get_next(next_link=None):")
1510
- retval.append(" if next_link is None:")
1531
+ retval.append(f" {self._function_def} internal_get_next({builder.next_variable_name}=None):")
1532
+ retval.append(f" if {builder.next_variable_name} is None:")
1511
1533
  retval.append(" return pipeline_response")
1512
- retval.append(f" return {self._call_method}get_next(next_link)")
1534
+ retval.append(f" return {self._call_method}get_next({builder.next_variable_name})")
1513
1535
  retval.append("")
1514
1536
  retval.append(f" return {builder.get_pager(self.async_mode)}(")
1515
1537
  retval.append(" internal_get_next, extract_data")
@@ -28,7 +28,11 @@ class GeneralSerializer(BaseSerializer):
28
28
 
29
29
  def serialize_package_file(self, template_name: str, **kwargs: Any) -> str:
30
30
  template = self.env.get_template(template_name)
31
- package_parts = (self.code_model.options["package_name"] or "").split("-")[:-1]
31
+ package_parts = (
32
+ self.code_model.namespace.split(".")[:-1]
33
+ if self.code_model.is_tsp
34
+ else (self.code_model.options["package_name"] or "").split("-")[:-1]
35
+ )
32
36
  token_credential = any(
33
37
  c for c in self.code_model.clients if isinstance(getattr(c.credential, "type", None), TokenCredentialType)
34
38
  )
@@ -44,7 +48,6 @@ class GeneralSerializer(BaseSerializer):
44
48
  "pkgutil_names": [".".join(package_parts[: i + 1]) for i in range(len(package_parts))],
45
49
  "init_names": ["/".join(package_parts[: i + 1]) + "/__init__.py" for i in range(len(package_parts))],
46
50
  "client_name": self.code_model.clients[0].name,
47
- "namespace": self.code_model.namespace,
48
51
  }
49
52
  params.update(self.code_model.options)
50
53
  params.update(kwargs)
@@ -19,7 +19,7 @@ from ..models import (
19
19
  CombinedType,
20
20
  FileImport,
21
21
  )
22
- from .utils import get_namespace_from_package_name, json_dumps_template
22
+ from .utils import json_dumps_template
23
23
 
24
24
 
25
25
  def is_lro(operation_type: str) -> bool:
@@ -1,8 +1,12 @@
1
1
  include *.md
2
2
  include LICENSE
3
+ {% if code_model.is_tsp %}
4
+ include {{ code_model.namespace.replace('.', '/') }}/py.typed
5
+ {% else %}
3
6
  include {{ package_name.replace('-', '/') }}/py.typed
7
+ {% endif %}
4
8
  recursive-include tests *.py
5
9
  recursive-include samples *.py *.md
6
- {%- for init_name in init_names %}
10
+ {% for init_name in init_names %}
7
11
  include {{ init_name }}
8
- {%- endfor %}
12
+ {% endfor %}
@@ -1,5 +1,5 @@
1
1
  {% if code_model.is_azure_flavor %}
2
- {% if package_mode == "mgmtplane" -%}
2
+ {% if package_mode == "mgmtplane" %}
3
3
  # Microsoft Azure SDK for Python
4
4
 
5
5
  This is the Microsoft {{package_pprint_name}} Client Library.
@@ -40,7 +40,7 @@ python -m pip install {{ package_name }}
40
40
  - You need an [Azure subscription][azure_sub] to use this package.
41
41
  - An existing {{ package_pprint_name }} instance.
42
42
 
43
- {%- if token_credential %}
43
+ {% if token_credential %}
44
44
  #### Create with an Azure Active Directory Credential
45
45
  To use an [Azure Active Directory (AAD) token credential][authenticate_with_token],
46
46
  provide an instance of the desired credential type obtained from the
@@ -57,7 +57,7 @@ Set the values of the client ID, tenant ID, and client secret of the AAD applica
57
57
  Use the returned token credential to authenticate the client:
58
58
 
59
59
  ```python
60
- >>> from {{ namespace }} import {{ client_name }}
60
+ >>> from {{ code_model.namespace }} import {{ client_name }}
61
61
  >>> from azure.identity import DefaultAzureCredential
62
62
  >>> client = {{ client_name }}(endpoint='<endpoint>', credential=DefaultAzureCredential())
63
63
  ```
@@ -65,7 +65,7 @@ Use the returned token credential to authenticate the client:
65
65
  ## Examples
66
66
 
67
67
  ```python
68
- >>> from {{ namespace }} import {{ client_name }}
68
+ >>> from {{ code_model.namespace }} import {{ client_name }}
69
69
  >>> from azure.identity import DefaultAzureCredential
70
70
  >>> from {{ code_model.core_library }}.exceptions import HttpResponseError
71
71
 
@@ -76,7 +76,7 @@ Use the returned token credential to authenticate the client:
76
76
  print('service responds error: {}'.format(e.response.json()))
77
77
 
78
78
  ```
79
- {%- endif %}
79
+ {% endif %}
80
80
 
81
81
  ## Contributing
82
82
 
@@ -1,9 +1,9 @@
1
1
  -e ../../../tools/azure-sdk-tools
2
2
  ../../core/azure-core
3
- {% if token_credential -%}
3
+ {% if token_credential %}
4
4
  ../../identity/azure-identity
5
5
  {% endif -%}
6
- {% if azure_arm -%}
6
+ {% if azure_arm %}
7
7
  ../../core/azure-mgmt-core
8
- {% endif -%}
8
+ {% endif %}
9
9
  aiohttp
@@ -2,19 +2,27 @@
2
2
  {{ license_header }}
3
3
  # coding: utf-8
4
4
  {% if package_mode %}
5
+
5
6
  import os
6
7
  import re
7
- {% endif -%}
8
+ {% endif %}
8
9
  from setuptools import setup, find_packages
9
10
 
10
11
  {% set package_name = package_name or code_model.clients[0].name %}
11
12
 
12
13
  PACKAGE_NAME = "{{ package_name|lower }}"
13
- {% if package_mode -%}
14
+ {% if package_mode %}
14
15
  PACKAGE_PPRINT_NAME = "{{ package_pprint_name }}"
16
+ {% if code_model.is_tsp %}
17
+ PACKAGE_NAMESPACE = "{{ code_model.namespace|lower }}"
18
+
19
+ # a.b.c => a/b/c
20
+ package_folder_path = PACKAGE_NAMESPACE.replace(".", "/")
21
+ {% else %}
15
22
 
16
23
  # a-b-c => a/b/c
17
24
  package_folder_path = PACKAGE_NAME.replace("-", "/")
25
+ {% endif %}
18
26
 
19
27
  # Version extraction inspired from 'requests'
20
28
  with open(os.path.join(package_folder_path, "_version.py"), "r") as fd:
@@ -33,7 +41,8 @@ version = "{{ package_version }}"
33
41
  {% set long_description = code_model.description %}
34
42
  {% set author_email = "" %}
35
43
  {% set url = "" %}
36
- {% endif -%}
44
+ {% endif %}
45
+
37
46
 
38
47
  setup(
39
48
  name=PACKAGE_NAME,
@@ -70,9 +79,9 @@ setup(
70
79
  {% if pkgutil_names %}
71
80
  # Exclude packages that will be covered by PEP420 or nspkg
72
81
  {% endif %}
73
- {%- for pkgutil_name in pkgutil_names %}
82
+ {% for pkgutil_name in pkgutil_names %}
74
83
  "{{ pkgutil_name }}",
75
- {%- endfor %}
84
+ {% endfor %}
76
85
  ]
77
86
  ),
78
87
  include_package_data=True,
@@ -14,7 +14,7 @@ from .helpers import (
14
14
  pad_builtin_namespaces,
15
15
  pad_special_chars,
16
16
  )
17
- from .python_mappings import CADL_RESERVED_WORDS, RESERVED_WORDS, PadType
17
+ from .python_mappings import TSP_RESERVED_WORDS, RESERVED_WORDS, PadType
18
18
 
19
19
  from .. import YamlUpdatePlugin
20
20
  from ..utils import (
@@ -182,11 +182,11 @@ class PreProcessPlugin(YamlUpdatePlugin):
182
182
 
183
183
  @property
184
184
  def models_mode(self) -> Optional[str]:
185
- return self.options.get("models-mode", "dpg" if self.is_cadl else None)
185
+ return self.options.get("models-mode", "dpg" if self.is_tsp else None)
186
186
 
187
187
  @property
188
- def is_cadl(self) -> bool:
189
- return self.options.get("cadl_file", False)
188
+ def is_tsp(self) -> bool:
189
+ return self.options.get("tsp_file", False)
190
190
 
191
191
  def add_body_param_type(
192
192
  self,
@@ -197,9 +197,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
197
197
  if ( # pylint: disable=too-many-boolean-expressions
198
198
  body_parameter
199
199
  and body_parameter["type"]["type"] in ("model", "dict", "list")
200
- and (
201
- has_json_content_type(body_parameter) or (self.is_cadl and has_multi_part_content_type(body_parameter))
202
- )
200
+ and (has_json_content_type(body_parameter) or (self.is_tsp and has_multi_part_content_type(body_parameter)))
203
201
  and not body_parameter["type"].get("xmlMetadata")
204
202
  and not any(t for t in ["flattened", "groupedBy"] if body_parameter.get(t))
205
203
  ):
@@ -210,7 +208,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
210
208
  "types": [body_parameter["type"]],
211
209
  }
212
210
  # don't add binary overload for multipart content type
213
- if not (self.is_cadl and has_multi_part_content_type(body_parameter)):
211
+ if not (self.is_tsp and has_multi_part_content_type(body_parameter)):
214
212
  body_parameter["type"]["types"].append(KNOWN_TYPES["binary"])
215
213
 
216
214
  if origin_type == "model" and is_dpg_model and self.models_mode == "dpg":
@@ -223,8 +221,8 @@ class PreProcessPlugin(YamlUpdatePlugin):
223
221
  # we'll pass in empty operation groups sometime etc.
224
222
  return name
225
223
 
226
- if self.is_cadl:
227
- reserved_words = {k: (v + CADL_RESERVED_WORDS.get(k, [])) for k, v in RESERVED_WORDS.items()}
224
+ if self.is_tsp:
225
+ reserved_words = {k: (v + TSP_RESERVED_WORDS.get(k, [])) for k, v in RESERVED_WORDS.items()}
228
226
  else:
229
227
  reserved_words = RESERVED_WORDS
230
228
  name = pad_special_chars(name)
@@ -506,6 +504,6 @@ class PreProcessPlugin(YamlUpdatePlugin):
506
504
 
507
505
 
508
506
  if __name__ == "__main__":
509
- # CADL pipeline will call this
507
+ # TSP pipeline will call this
510
508
  args, unknown_args = parse_args()
511
- PreProcessPlugin(output_folder=args.output_folder, cadl_file=args.cadl_file, **unknown_args).process()
509
+ PreProcessPlugin(output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args).process()
@@ -185,7 +185,7 @@ RESERVED_WORDS = {
185
185
  PadType.OPERATION_GROUP: [*_always_reserved],
186
186
  }
187
187
 
188
- CADL_RESERVED_WORDS = {
188
+ TSP_RESERVED_WORDS = {
189
189
  PadType.PARAMETER: ["stream"],
190
190
  PadType.PROPERTY: RESERVED_MODEL_PROPERTIES,
191
191
  }
@@ -44,7 +44,7 @@ def to_snake_case(name: str) -> str:
44
44
 
45
45
 
46
46
  def parse_args(
47
- need_cadl_file: bool = True,
47
+ need_tsp_file: bool = True,
48
48
  ) -> Tuple[argparse.Namespace, Dict[str, Any]]:
49
49
  parser = argparse.ArgumentParser(
50
50
  description="Run mypy against target folder. Add a local custom plugin to the path prior to execution. "
@@ -56,10 +56,10 @@ def parse_args(
56
56
  required=True,
57
57
  )
58
58
  parser.add_argument(
59
- "--cadl-file",
60
- dest="cadl_file",
61
- help="Serialized cadl file",
62
- required=need_cadl_file,
59
+ "--tsp-file",
60
+ dest="tsp_file",
61
+ help="Serialized tsp file",
62
+ required=need_tsp_file,
63
63
  )
64
64
  parser.add_argument(
65
65
  "--debug",