@azure-tools/typespec-python 0.27.1 → 0.29.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 (56) hide show
  1. package/dist/scripts/regenerate.d.ts +2 -0
  2. package/dist/scripts/regenerate.d.ts.map +1 -0
  3. package/dist/scripts/regenerate.js +258 -0
  4. package/dist/scripts/regenerate.js.map +1 -0
  5. package/dist/scripts/run-python3.d.ts +2 -0
  6. package/dist/scripts/run-python3.d.ts.map +1 -0
  7. package/dist/scripts/run-python3.js +23 -0
  8. package/dist/scripts/run-python3.js.map +1 -0
  9. package/dist/scripts/run-tests.d.ts +2 -0
  10. package/dist/scripts/run-tests.d.ts.map +1 -0
  11. package/dist/scripts/run-tests.js +50 -0
  12. package/dist/scripts/run-tests.js.map +1 -0
  13. package/dist/scripts/system-requirements.d.ts +17 -0
  14. package/dist/scripts/system-requirements.d.ts.map +1 -0
  15. package/{scripts/system-requirements.cjs → dist/scripts/system-requirements.js} +80 -97
  16. package/dist/scripts/system-requirements.js.map +1 -0
  17. package/dist/src/code-model.d.ts.map +1 -1
  18. package/dist/src/code-model.js +29 -41
  19. package/dist/src/code-model.js.map +1 -1
  20. package/dist/src/emitter.js +1 -1
  21. package/dist/src/emitter.js.map +1 -1
  22. package/dist/src/external-process.js +1 -1
  23. package/dist/src/external-process.js.map +1 -1
  24. package/dist/src/http.d.ts.map +1 -1
  25. package/dist/src/http.js +32 -17
  26. package/dist/src/http.js.map +1 -1
  27. package/dist/src/types.d.ts +9 -2
  28. package/dist/src/types.d.ts.map +1 -1
  29. package/dist/src/types.js +56 -3
  30. package/dist/src/types.js.map +1 -1
  31. package/dist/src/utils.d.ts +1 -1
  32. package/dist/src/utils.d.ts.map +1 -1
  33. package/dist/src/utils.js +6 -8
  34. package/dist/src/utils.js.map +1 -1
  35. package/generator/pygen/codegen/models/__init__.py +2 -0
  36. package/generator/pygen/codegen/models/base.py +1 -1
  37. package/generator/pygen/codegen/models/code_model.py +2 -4
  38. package/generator/pygen/codegen/models/model_type.py +1 -2
  39. package/generator/pygen/codegen/models/operation.py +13 -16
  40. package/generator/pygen/codegen/models/parameter.py +6 -0
  41. package/generator/pygen/codegen/models/primitive_types.py +26 -0
  42. package/generator/pygen/codegen/models/property.py +1 -9
  43. package/generator/pygen/codegen/serializers/__init__.py +1 -1
  44. package/generator/pygen/codegen/serializers/builder_serializer.py +2 -2
  45. package/generator/pygen/codegen/serializers/general_serializer.py +0 -1
  46. package/generator/pygen/codegen/serializers/model_serializer.py +2 -0
  47. package/generator/pygen/codegen/serializers/sample_serializer.py +19 -12
  48. package/generator/pygen/codegen/templates/model_base.py.jinja2 +24 -18
  49. package/generator/pygen/codegen/templates/vendor.py.jinja2 +0 -2
  50. package/package.json +33 -39
  51. package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
  52. package/scripts/regenerate.ts +285 -0
  53. package/scripts/run-python3.ts +25 -0
  54. package/scripts/run-tests.ts +57 -0
  55. package/scripts/system-requirements.ts +253 -0
  56. package/scripts/run-python3.cjs +0 -22
@@ -489,6 +489,9 @@ def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typin
489
489
 
490
490
  class Model(_MyMutableMapping):
491
491
  _is_model = True
492
+ # label whether current class's _attr_to_rest_field has been calculated
493
+ # could not see _attr_to_rest_field directly because subclass inherits it from parent class
494
+ _calculated: typing.Set[str] = set()
492
495
 
493
496
  def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None:
494
497
  class_name = self.__class__.__name__
@@ -521,24 +524,27 @@ class Model(_MyMutableMapping):
521
524
  return Model(self.__dict__)
522
525
 
523
526
  def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: # pylint: disable=unused-argument
524
- # we know the last three classes in mro are going to be 'Model', 'dict', and 'object'
525
- mros = cls.__mro__[:-3][::-1] # ignore model, dict, and object parents, and reverse the mro order
526
- attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property
527
- k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type")
528
- }
529
- annotations = {
530
- k: v
531
- for mro_class in mros
532
- if hasattr(mro_class, "__annotations__") # pylint: disable=no-member
533
- for k, v in mro_class.__annotations__.items() # pylint: disable=no-member
534
- }
535
- for attr, rf in attr_to_rest_field.items():
536
- rf._module = cls.__module__
537
- if not rf._type:
538
- rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None))
539
- if not rf._rest_name_input:
540
- rf._rest_name_input = attr
541
- cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items())
527
+ if f"{cls.__module__}.{cls.__qualname__}" not in cls._calculated:
528
+ # we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping',
529
+ # 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object'
530
+ mros = cls.__mro__[:-9][::-1] # ignore parents, and reverse the mro order
531
+ attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property
532
+ k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type")
533
+ }
534
+ annotations = {
535
+ k: v
536
+ for mro_class in mros
537
+ if hasattr(mro_class, "__annotations__") # pylint: disable=no-member
538
+ for k, v in mro_class.__annotations__.items() # pylint: disable=no-member
539
+ }
540
+ for attr, rf in attr_to_rest_field.items():
541
+ rf._module = cls.__module__
542
+ if not rf._type:
543
+ rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None))
544
+ if not rf._rest_name_input:
545
+ rf._rest_name_input = attr
546
+ cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items())
547
+ cls._calculated.add(f"{cls.__module__}.{cls.__qualname__}")
542
548
 
543
549
  return super().__new__(cls) # pylint: disable=no-value-for-parameter
544
550
 
@@ -70,8 +70,6 @@ FileType = Union[
70
70
  Tuple[Optional[str], FileContent, Optional[str]],
71
71
  ]
72
72
 
73
- FilesType = Union[Mapping[str, FileType], Sequence[Tuple[str, FileType]]]
74
-
75
73
  def serialize_multipart_data_entry(data_entry: Any) -> Any:
76
74
  if isinstance(data_entry, (list, tuple, dict, Model)):
77
75
  return json.dumps(data_entry, cls=SdkJSONEncoder, exclude_readonly=True)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-tools/typespec-python",
3
- "version": "0.27.1",
3
+ "version": "0.29.0",
4
4
  "author": "Microsoft Corporation",
5
5
  "description": "TypeSpec emitter for Python SDKs",
6
6
  "homepage": "https://github.com/Azure/autorest.python",
@@ -33,60 +33,54 @@
33
33
  "scripts/**"
34
34
  ],
35
35
  "peerDependencies": {
36
- "@azure-tools/typespec-azure-core": ">=0.44.0 <1.0.0",
37
- "@azure-tools/typespec-azure-resource-manager": ">=0.44.0 <1.0.0",
38
- "@azure-tools/typespec-autorest": ">=0.44.1 <1.0.0",
39
- "@azure-tools/typespec-client-generator-core": ">=0.44.3 <1.0.0",
40
- "@azure-tools/typespec-azure-rulesets": ">=0.44.0 <3.0.0",
41
- "@typespec/compiler": ">=0.58.1 <1.0.0",
42
- "@typespec/http": ">=0.58.0 <1.0.0",
43
- "@typespec/rest": ">=0.58.0 <1.0.0",
44
- "@typespec/versioning": ">=0.58.0 <1.0.0",
45
- "@typespec/openapi": ">=0.58.0 <1.0.0"
46
- },
47
- "dependenciesMeta": {
48
- "@azure-tools/typespec-client-generator-core": {
49
- "injected": true
50
- }
36
+ "@azure-tools/typespec-azure-core": ">=0.45.0 <1.0.0",
37
+ "@azure-tools/typespec-azure-resource-manager": ">=0.45.0 <1.0.0",
38
+ "@azure-tools/typespec-autorest": ">=0.45.0 <1.0.0",
39
+ "@azure-tools/typespec-client-generator-core": ">=0.45.1 <1.0.0",
40
+ "@azure-tools/typespec-azure-rulesets": ">=0.45.0 <3.0.0",
41
+ "@typespec/compiler": ">=0.59.1 <1.0.0",
42
+ "@typespec/http": ">=0.59.0 <1.0.0",
43
+ "@typespec/rest": ">=0.59.0 <1.0.0",
44
+ "@typespec/versioning": ">=0.59.0 <1.0.0",
45
+ "@typespec/openapi": ">=0.59.0 <1.0.0"
51
46
  },
52
47
  "dependencies": {
53
48
  "js-yaml": "~4.1.0",
54
- "@typespec/openapi3": "~0.58.0",
55
- "@autorest/system-requirements": "~1.0.2",
56
- "fs-extra": "~11.2.0",
57
- "semver": "~7.6.2"
49
+ "@typespec/openapi3": "~0.59.0",
50
+ "semver": "~7.6.2",
51
+ "tsx": "4.17.0"
58
52
  },
59
53
  "devDependencies": {
60
- "@azure-tools/typespec-azure-resource-manager": "~0.44.0",
61
- "@azure-tools/typespec-autorest": "~0.44.1",
62
- "@azure-tools/cadl-ranch-expect": "~0.14.1",
63
- "@azure-tools/cadl-ranch-specs": "~0.34.5",
54
+ "@azure-tools/typespec-azure-resource-manager": "~0.45.0",
55
+ "@azure-tools/typespec-autorest": "~0.45.0",
56
+ "@azure-tools/cadl-ranch-expect": "~0.15.1",
57
+ "@azure-tools/cadl-ranch-specs": "~0.35.4",
64
58
  "@types/js-yaml": "~4.0.5",
65
- "@types/mocha": "~10.0.1",
66
59
  "@types/node": "^18.16.3",
60
+ "@types/yargs": "17.0.32",
61
+ "@types/semver": "7.5.8",
67
62
  "@typespec/eslint-config-typespec": "~0.55.0",
68
- "@typespec/openapi": "~0.58.0",
63
+ "@typespec/openapi": "~0.59.0",
69
64
  "c8": "~7.13.0",
70
- "eslint": "^8.57.0",
71
- "mocha": "~10.2.0",
72
65
  "rimraf": "~5.0.0",
73
66
  "typescript": "~5.1.3",
74
- "@azure-tools/typespec-azure-core": "~0.44.0",
75
- "@azure-tools/typespec-client-generator-core": "~0.44.3",
76
- "@typespec/compiler": "~0.58.1",
77
- "@typespec/http": "~0.58.0",
78
- "@typespec/rest": "~0.58.0",
79
- "@typespec/versioning": "~0.58.0",
80
- "@azure-tools/typespec-azure-rulesets": "0.44.0"
67
+ "@azure-tools/typespec-azure-core": "~0.45.0",
68
+ "@azure-tools/typespec-client-generator-core": "0.45.1",
69
+ "@typespec/compiler": "~0.59.1",
70
+ "@typespec/http": "~0.59.0",
71
+ "@typespec/rest": "~0.59.0",
72
+ "@typespec/versioning": "~0.59.0",
73
+ "@azure-tools/typespec-azure-rulesets": "0.45.0",
74
+ "yargs": "~17.2.1"
81
75
  },
82
76
  "scripts": {
83
- "clean": "rimraf ./dist ./temp",
77
+ "clean": "rimraf ./dist ./temp ./venv ./node_modules",
84
78
  "build": "tsc -p .",
85
79
  "watch": "tsc -p . --watch",
86
- "test": "mocha",
87
- "test-official": "c8 mocha --forbid-only",
88
80
  "lint": "eslint . --ext .ts --max-warnings=0",
89
81
  "lint:fix": "eslint . --fix --ext .ts",
90
- "install": "node ./scripts/run-python3.cjs ./scripts/install.py"
82
+ "install": "tsx ./scripts/run-python3.ts ./scripts/install.py",
83
+ "regenerate": "tsx ./scripts/regenerate.ts",
84
+ "test": "tsx ./scripts/run-tests.ts"
91
85
  }
92
86
  }
@@ -0,0 +1,285 @@
1
+ /* eslint-disable no-console */
2
+ import { exec as execCallback } from "child_process";
3
+ import { promisify } from "util";
4
+ import yargs from "yargs";
5
+ import { hideBin } from "yargs/helpers";
6
+ import { dirname, join, relative, resolve } from "path";
7
+ import { promises } from "fs";
8
+ import { fileURLToPath } from "url";
9
+
10
+ // Promisify the exec function
11
+ const exec = promisify(execCallback);
12
+
13
+ // Get the directory of the current file
14
+ const PLUGIN_DIR = resolve(fileURLToPath(import.meta.url), "../../");
15
+ const CADL_RANCH_DIR = resolve(PLUGIN_DIR, "node_modules/@azure-tools/cadl-ranch-specs/http");
16
+
17
+ const EMITTER_OPTIONS: Record<string, Record<string, string> | Record<string, string>[]> = {
18
+ "resiliency/srv-driven/old.tsp": {
19
+ "package-name": "resiliency-srv-driven1",
20
+ "package-mode": "azure-dataplane",
21
+ "package-pprint-name": "ResiliencySrvDriven1",
22
+ },
23
+ "resiliency/srv-driven": {
24
+ "package-name": "resiliency-srv-driven2",
25
+ "package-mode": "azure-dataplane",
26
+ "package-pprint-name": "ResiliencySrvDriven2",
27
+ },
28
+ "authentication/http/custom": {
29
+ "package-name": "authentication-http-custom",
30
+ },
31
+ "authentication/union": {
32
+ "package-name": "authentication-union",
33
+ },
34
+ "type/array": {
35
+ "package-name": "typetest-array",
36
+ },
37
+ "type/dictionary": {
38
+ "package-name": "typetest-dictionary",
39
+ },
40
+ "type/enum/extensible": {
41
+ "package-name": "typetest-enum-extensible",
42
+ },
43
+ "type/enum/fixed": {
44
+ "package-name": "typetest-enum-fixed",
45
+ },
46
+ "type/model/empty": {
47
+ "package-name": "typetest-model-empty",
48
+ },
49
+ "type/model/flatten": {
50
+ "package-name": "typetest-model-flatten",
51
+ },
52
+ "type/model/inheritance/enum-discriminator": {
53
+ "package-name": "typetest-model-enumdiscriminator",
54
+ },
55
+ "type/model/inheritance/nested-discriminator": {
56
+ "package-name": "typetest-model-nesteddiscriminator",
57
+ },
58
+ "type/model/inheritance/not-discriminated": {
59
+ "package-name": "typetest-model-notdiscriminated",
60
+ },
61
+ "type/model/inheritance/single-discriminator": {
62
+ "package-name": "typetest-model-singlediscriminator",
63
+ },
64
+ "type/model/inheritance/recursive": {
65
+ "package-name": "typetest-model-recursive",
66
+ },
67
+ "type/model/usage": {
68
+ "package-name": "typetest-model-usage",
69
+ },
70
+ "type/model/visibility": [
71
+ { "package-name": "typetest-model-visibility" },
72
+ { "package-name": "headasbooleantrue", "head-as-boolean": "true" },
73
+ { "package-name": "headasbooleanfalse", "head-as-boolean": "false" },
74
+ ],
75
+ "type/property/nullable": {
76
+ "package-name": "typetest-property-nullable",
77
+ },
78
+ "type/property/optionality": {
79
+ "package-name": "typetest-property-optional",
80
+ },
81
+ "type/property/additional-properties": {
82
+ "package-name": "typetest-property-additionalproperties",
83
+ },
84
+ "type/scalar": {
85
+ "package-name": "typetest-scalar",
86
+ },
87
+ "type/property/value-types": {
88
+ "package-name": "typetest-property-valuetypes",
89
+ },
90
+ "type/union": {
91
+ "package-name": "typetest-union",
92
+ },
93
+ "azure/core/lro/rpc": {
94
+ "package-name": "azurecore-lro-rpc",
95
+ },
96
+ "client/structure/multi-client": {
97
+ "package-name": "client-structure-multiclient",
98
+ },
99
+ "client/structure/renamed-operation": {
100
+ "package-name": "client-structure-renamedoperation",
101
+ },
102
+ "client/structure/two-operation-group": {
103
+ "package-name": "client-structure-twooperationgroup",
104
+ },
105
+ "mgmt/sphere": [{ "package-name": "azure-mgmt-spheredpg" }],
106
+ };
107
+
108
+ function toPosix(dir: string): string {
109
+ return dir.replace(/\\/g, "/");
110
+ }
111
+
112
+ function getEmitterOption(spec: string): Record<string, string>[] {
113
+ const relativeSpec = toPosix(relative(CADL_RANCH_DIR, spec));
114
+ const key = relativeSpec.includes("resiliency/srv-driven/old.tsp") ? relativeSpec : dirname(relativeSpec);
115
+ const result = EMITTER_OPTIONS[key] || [{}];
116
+ return Array.isArray(result) ? result : [result];
117
+ }
118
+
119
+ // Function to execute CLI commands asynchronously
120
+ async function executeCommand(command: string): Promise<void> {
121
+ try {
122
+ const { stdout, stderr } = await exec(command);
123
+ if (stdout) console.log(`stdout: ${stdout}`);
124
+ if (stderr) console.error(`stderr: ${stderr}`);
125
+ } catch (error) {
126
+ console.error(`exec error: ${error}`);
127
+ throw error;
128
+ }
129
+ }
130
+
131
+ interface RegenerateFlagsInput {
132
+ flavor?: "azure" | "unbranded";
133
+ debug?: boolean;
134
+ name?: string;
135
+ }
136
+
137
+ interface RegenerateFlags {
138
+ flavor: "azure" | "unbranded";
139
+ debug: boolean;
140
+ name?: string;
141
+ }
142
+
143
+ const SpecialFlags: Record<string, Record<string, any>> = {
144
+ azure: {
145
+ "generate-test": true,
146
+ "generate-sample": true,
147
+ },
148
+ };
149
+
150
+ async function getSubdirectories(baseDir: string, flags: RegenerateFlags): Promise<string[]> {
151
+ const subdirectories: string[] = [];
152
+
153
+ async function searchDir(currentDir: string) {
154
+ const items = await promises.readdir(currentDir, { withFileTypes: true });
155
+
156
+ const promisesArray = items.map(async (item) => {
157
+ const subDirPath = join(currentDir, item.name);
158
+ if (item.isDirectory()) {
159
+ const mainTspPath = join(subDirPath, "main.tsp");
160
+ const clientTspPath = join(subDirPath, "client.tsp");
161
+
162
+ const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath));
163
+ if (flags.flavor === "unbranded" && mainTspRelativePath.includes("azure")) return;
164
+
165
+ // after xml support, remove this check
166
+ if (mainTspRelativePath.includes("xml")) return;
167
+
168
+ // after fix test generation for nested operation group, remove this check
169
+ if (mainTspRelativePath.includes("client-operation-group")) return;
170
+
171
+ const hasMainTsp = await promises
172
+ .access(mainTspPath)
173
+ .then(() => true)
174
+ .catch(() => false);
175
+ const hasClientTsp = await promises
176
+ .access(clientTspPath)
177
+ .then(() => true)
178
+ .catch(() => false);
179
+
180
+ if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) {
181
+ if (mainTspRelativePath.includes("resiliency/srv-driven")) {
182
+ subdirectories.push(resolve(subDirPath, "old.tsp"));
183
+ }
184
+ if (hasClientTsp) {
185
+ subdirectories.push(resolve(subDirPath, "client.tsp"));
186
+ } else if (hasMainTsp) {
187
+ subdirectories.push(resolve(subDirPath, "main.tsp"));
188
+ }
189
+ }
190
+
191
+ // Recursively search in the subdirectory
192
+ await searchDir(subDirPath);
193
+ }
194
+ });
195
+
196
+ await Promise.all(promisesArray);
197
+ }
198
+
199
+ await searchDir(baseDir);
200
+ return subdirectories;
201
+ }
202
+
203
+ function defaultPackageName(spec: string): string {
204
+ return toPosix(relative(CADL_RANCH_DIR, dirname(spec)))
205
+ .replace(/\//g, "-")
206
+ .toLowerCase();
207
+ }
208
+
209
+ function addOptions(spec: string, generatedFolder: string, flags: RegenerateFlags): string[] {
210
+ const emitterConfigs: string[] = [];
211
+ for (const config of getEmitterOption(spec)) {
212
+ const options: Record<string, string> = { ...config };
213
+ options["flavor"] = flags.flavor;
214
+ for (const [k, v] of Object.entries(SpecialFlags[flags.flavor] ?? {})) {
215
+ options[k] = v;
216
+ }
217
+ if (options["emitter-output-dir"] === undefined) {
218
+ const packageName = options["package-name"] || defaultPackageName(spec);
219
+ options["emitter-output-dir"] = toPosix(`${generatedFolder}/test/${flags.flavor}/generated/${packageName}`);
220
+ }
221
+ if (flags.debug) {
222
+ options["debug"] = "true";
223
+ }
224
+ if (flags.flavor === "unbranded") {
225
+ options["company-name"] = "Unbranded";
226
+ }
227
+ options["examples-directory"] = toPosix(join(dirname(spec), "examples"));
228
+ const configs = Object.entries(options).flatMap(([k, v]) => {
229
+ return `--option @azure-tools/typespec-python.${k}=${v}`;
230
+ });
231
+ emitterConfigs.push(configs.join(" "));
232
+ }
233
+ return emitterConfigs;
234
+ }
235
+
236
+ async function _regenerateSingle(spec: string, flags: RegenerateFlags): Promise<void> {
237
+ // Perform some asynchronous operation here
238
+ const options = addOptions(spec, PLUGIN_DIR, flags);
239
+ const commandPromises = options.map((option) => {
240
+ const command = `tsp compile ${spec} --emit=${toPosix(PLUGIN_DIR)} ${option}`;
241
+ console.log(command);
242
+ return executeCommand(command);
243
+ });
244
+ await Promise.all(commandPromises);
245
+ }
246
+
247
+ async function regenerate(flags: RegenerateFlagsInput): Promise<boolean> {
248
+ if (flags.flavor === undefined) {
249
+ const azureGeneration = await regenerate({ ...flags, flavor: "azure" });
250
+ const unbrandedGeneration = await regenerate({ ...flags, flavor: "unbranded" });
251
+ return azureGeneration && unbrandedGeneration;
252
+ } else {
253
+ const flagsResolved = { debug: false, flavor: flags.flavor, ...flags };
254
+ const CADL_RANCH_DIR = resolve(PLUGIN_DIR, "node_modules/@azure-tools/cadl-ranch-specs/http");
255
+ const subdirectories = await getSubdirectories(CADL_RANCH_DIR, flagsResolved);
256
+ const promises = subdirectories.map(async (subdirectory) => {
257
+ // Perform additional asynchronous operations on each subdirectory here
258
+ await _regenerateSingle(subdirectory, flagsResolved);
259
+ });
260
+ await Promise.all(promises);
261
+ return true;
262
+ }
263
+ }
264
+
265
+ // PARSE INPUT ARGUMENTS
266
+ const argv = yargs(hideBin(process.argv))
267
+ .option("flavor", {
268
+ type: "string",
269
+ choices: ["azure", "unbranded"],
270
+ description: "Specify the flavor",
271
+ })
272
+ .option("debug", {
273
+ alias: "d",
274
+ type: "boolean",
275
+ description: "Debug mode",
276
+ })
277
+ .option("name", {
278
+ alias: "n",
279
+ type: "string",
280
+ description: "Specify filename if you only want to generate a subset",
281
+ }).argv;
282
+
283
+ regenerate(argv as RegenerateFlags)
284
+ .then(() => console.log("Regeneration successful"))
285
+ .catch((error) => console.error(`Regeneration failed: ${error.message}`));
@@ -0,0 +1,25 @@
1
+ // This script wraps logic in @azure-tools/extension to resolve
2
+ // the path to Python 3 so that a Python script file can be run
3
+ // from an npm script in package.json. It uses the same Python 3
4
+ // path resolution algorithm as AutoRest so that the behavior
5
+ // is fully consistent (and also supports AUTOREST_PYTHON_EXE).
6
+ //
7
+ // Invoke it like so: "tsx run-python3.ts script.py"
8
+
9
+ import cp from "child_process";
10
+ import { patchPythonPath } from "./system-requirements.js";
11
+
12
+ async function runPython3(...args: string[]) {
13
+ const command = await patchPythonPath(["python", ...args], {
14
+ version: ">=3.8",
15
+ environmentVariable: "AUTOREST_PYTHON_EXE",
16
+ });
17
+ cp.execSync(command.join(" "), {
18
+ stdio: [0, 1, 2],
19
+ });
20
+ }
21
+
22
+ runPython3(...process.argv.slice(2)).catch((err) => {
23
+ console.error(err.toString()); // eslint-disable-line no-console
24
+ process.exit(1);
25
+ });
@@ -0,0 +1,57 @@
1
+ /* eslint-disable no-console */
2
+ import { execSync } from "child_process";
3
+ import yargs from "yargs";
4
+ import { hideBin } from "yargs/helpers";
5
+
6
+ interface Arguments {
7
+ folder?: string;
8
+ command?: string;
9
+ }
10
+
11
+ const validFolders = ["azure", "unbranded"];
12
+
13
+ const validCommands = ["ci", "lint", "mypy", "pyright", "apiview"];
14
+
15
+ // Parse command-line arguments using yargs
16
+ const argv = yargs(hideBin(process.argv))
17
+ .option("folder", {
18
+ alias: "f",
19
+ describe: "Specify the folder to use",
20
+ choices: validFolders,
21
+ type: "string",
22
+ })
23
+ .option("command", {
24
+ alias: "c",
25
+ describe: "Specify the command to run",
26
+ choices: validCommands,
27
+ type: "string",
28
+ }).argv as Arguments;
29
+
30
+ const foldersToProcess = argv.folder ? [argv.folder] : validFolders;
31
+
32
+ const commandToRun = argv.command || "all";
33
+
34
+ function getCommand(command: string, folder: string) {
35
+ if (!validCommands.includes(command)) throw new Error(`Unknown command '${command}'.`);
36
+ return `FOLDER=${folder} tox -c ./test/${folder}/tox.ini -e ${command}`;
37
+ }
38
+
39
+ foldersToProcess.forEach((folder) => {
40
+ try {
41
+ if (commandToRun === "all") {
42
+ for (const key of validCommands) {
43
+ console.log(`Running ${key} for folder ${folder}...`);
44
+ execSync(getCommand(key, folder), { stdio: "inherit" });
45
+ }
46
+ } else if (getCommand(commandToRun, folder)) {
47
+ console.log(`Running ${commandToRun} for folder ${folder}...`);
48
+ execSync(getCommand(commandToRun, folder), { stdio: "inherit" });
49
+ } else {
50
+ console.error(`Error: Unknown command '${commandToRun}'.`);
51
+ process.exit(1);
52
+ }
53
+ } catch (error) {
54
+ console.error(`Error executing command for folder ${folder}: ${(error as Error).message}`);
55
+ process.exit(1);
56
+ }
57
+ });