@autorest/python 6.19.0 → 6.20.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 (36) hide show
  1. package/generator/pygen/black.py +2 -3
  2. package/generator/pygen/codegen/models/combined_type.py +1 -1
  3. package/generator/pygen/codegen/models/credential_types.py +7 -14
  4. package/generator/pygen/codegen/models/enum_type.py +1 -1
  5. package/generator/pygen/codegen/models/lro_operation.py +0 -1
  6. package/generator/pygen/codegen/models/lro_paging_operation.py +1 -1
  7. package/generator/pygen/codegen/models/model_type.py +5 -7
  8. package/generator/pygen/codegen/models/paging_operation.py +0 -1
  9. package/generator/pygen/codegen/models/parameter_list.py +2 -5
  10. package/generator/pygen/codegen/models/primitive_types.py +9 -3
  11. package/generator/pygen/codegen/serializers/__init__.py +1 -1
  12. package/generator/pygen/codegen/serializers/builder_serializer.py +10 -11
  13. package/generator/pygen/codegen/serializers/general_serializer.py +2 -1
  14. package/generator/pygen/codegen/serializers/sample_serializer.py +1 -3
  15. package/generator/pygen/codegen/templates/model_base.py.jinja2 +6 -0
  16. package/generator/pygen/m2r.py +1 -1
  17. package/generator/pygen/postprocess/__init__.py +2 -2
  18. package/generator/pygen/postprocess/venvtools.py +1 -3
  19. package/generator/pygen/preprocess/__init__.py +1 -1
  20. package/generator/pygen/utils.py +1 -3
  21. package/generator/setup.py +1 -1
  22. package/package.json +8 -5
  23. package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
  24. package/scripts/copy-generator.ts +24 -0
  25. package/scripts/eng/format.ts +5 -0
  26. package/scripts/eng/lint.ts +75 -0
  27. package/scripts/eng/mypy.ini +38 -0
  28. package/scripts/eng/pylintrc +58 -0
  29. package/scripts/eng/pyrightconfig.json +6 -0
  30. package/scripts/eng/regenerate.ts +298 -0
  31. package/scripts/{run-tests.ts → eng/run-tests.ts} +10 -11
  32. package/scripts/eng/utils.ts +38 -0
  33. package/scripts/mypy.ini +38 -0
  34. package/scripts/run-python3.ts +25 -0
  35. package/scripts/system-requirements.ts +253 -0
  36. package/scripts/copy-generator.js +0 -19
@@ -0,0 +1,58 @@
1
+ [MASTER]
2
+ py-version=3.8
3
+ ignore-patterns=test_*,conftest,setup
4
+ reports=no
5
+
6
+ # PYLINT DIRECTORY BLACKLIST.
7
+ ignore=_generated,samples,examples,test,tests,doc,.tox,generated_samples
8
+
9
+ [MESSAGES CONTROL]
10
+
11
+ # Add enable for useless disables
12
+ enable=useless-suppression
13
+
14
+ # For all codes, run 'pylint --list-msgs' or go to 'https://pylint.readthedocs.io/en/latest/reference_guide/features.html'
15
+ # locally-disabled: Warning locally suppressed using disable-msg
16
+ # cyclic-import: because of https://github.com/PyCQA/pylint/issues/850
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
+ # Let's black deal with bad-continuation
19
+ 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
20
+
21
+ [FORMAT]
22
+ max-line-length=120
23
+
24
+ [VARIABLES]
25
+ # Tells whether we should check for unused import in __init__ files.
26
+ init-import=yes
27
+
28
+ [DESIGN]
29
+ # Maximum number of locals for function / method body
30
+ max-locals=25
31
+ # Maximum number of branch for function / method body
32
+ max-branches=20
33
+ # Maximum number of instance attributes for class
34
+ max-attributes=10
35
+ # Maximum number of ancestors
36
+ max-parents=15
37
+
38
+ [SIMILARITIES]
39
+ min-similarity-lines=10
40
+
41
+ [BASIC]
42
+ # Naming hints based on PEP 8 (https://www.python.org/dev/peps/pep-0008/#naming-conventions).
43
+ # Consider these guidelines and not hard rules. Read PEP 8 for more details.
44
+
45
+ # The invalid-name checker must be **enabled** for these hints to be used.
46
+ include-naming-hint=yes
47
+
48
+ # keep short; underscores are discouraged
49
+ module-naming-style=snake_case
50
+ const-naming-style=UPPER_CASE
51
+ class-naming-style=PascalCase
52
+ class-attribute-naming-style=snake_case
53
+ attr-naming-style=snake_case
54
+ method-naming-style=snake_case
55
+ function-naming-style=snake_case
56
+ argument-naming-style=snake_case
57
+ variable-naming-style=snake_case
58
+ inlinevar-naming-style=snake_case
@@ -0,0 +1,6 @@
1
+ {
2
+ "reportUnnecessaryCast": "warning",
3
+ "reportTypeCommentUsage": true,
4
+ "reportMissingImports": false,
5
+ "pythonVersion": "3.8"
6
+ }
@@ -0,0 +1,298 @@
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, rmSync } 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
+ interface TspCommand {
17
+ outputDir: string;
18
+ command: string;
19
+ }
20
+
21
+ const EMITTER_OPTIONS: Record<string, Record<string, string> | Record<string, string>[]> = {
22
+ "resiliency/srv-driven/old.tsp": {
23
+ "package-name": "resiliency-srv-driven1",
24
+ "package-mode": "azure-dataplane",
25
+ "package-pprint-name": "ResiliencySrvDriven1",
26
+ },
27
+ "resiliency/srv-driven": {
28
+ "package-name": "resiliency-srv-driven2",
29
+ "package-mode": "azure-dataplane",
30
+ "package-pprint-name": "ResiliencySrvDriven2",
31
+ },
32
+ "authentication/http/custom": {
33
+ "package-name": "authentication-http-custom",
34
+ },
35
+ "authentication/union": {
36
+ "package-name": "authentication-union",
37
+ },
38
+ "type/array": {
39
+ "package-name": "typetest-array",
40
+ },
41
+ "type/dictionary": {
42
+ "package-name": "typetest-dictionary",
43
+ },
44
+ "type/enum/extensible": {
45
+ "package-name": "typetest-enum-extensible",
46
+ },
47
+ "type/enum/fixed": {
48
+ "package-name": "typetest-enum-fixed",
49
+ },
50
+ "type/model/empty": {
51
+ "package-name": "typetest-model-empty",
52
+ },
53
+ "type/model/flatten": {
54
+ "package-name": "typetest-model-flatten",
55
+ },
56
+ "type/model/inheritance/enum-discriminator": {
57
+ "package-name": "typetest-model-enumdiscriminator",
58
+ },
59
+ "type/model/inheritance/nested-discriminator": {
60
+ "package-name": "typetest-model-nesteddiscriminator",
61
+ },
62
+ "type/model/inheritance/not-discriminated": {
63
+ "package-name": "typetest-model-notdiscriminated",
64
+ },
65
+ "type/model/inheritance/single-discriminator": {
66
+ "package-name": "typetest-model-singlediscriminator",
67
+ },
68
+ "type/model/inheritance/recursive": {
69
+ "package-name": "typetest-model-recursive",
70
+ },
71
+ "type/model/usage": {
72
+ "package-name": "typetest-model-usage",
73
+ },
74
+ "type/model/visibility": [
75
+ { "package-name": "typetest-model-visibility" },
76
+ { "package-name": "headasbooleantrue", "head-as-boolean": "true" },
77
+ { "package-name": "headasbooleanfalse", "head-as-boolean": "false" },
78
+ ],
79
+ "type/property/nullable": {
80
+ "package-name": "typetest-property-nullable",
81
+ },
82
+ "type/property/optionality": {
83
+ "package-name": "typetest-property-optional",
84
+ },
85
+ "type/property/additional-properties": {
86
+ "package-name": "typetest-property-additionalproperties",
87
+ },
88
+ "type/scalar": {
89
+ "package-name": "typetest-scalar",
90
+ },
91
+ "type/property/value-types": {
92
+ "package-name": "typetest-property-valuetypes",
93
+ },
94
+ "type/union": {
95
+ "package-name": "typetest-union",
96
+ },
97
+ "azure/core/lro/rpc": {
98
+ "package-name": "azurecore-lro-rpc",
99
+ },
100
+ "client/structure/multi-client": {
101
+ "package-name": "client-structure-multiclient",
102
+ },
103
+ "client/structure/renamed-operation": {
104
+ "package-name": "client-structure-renamedoperation",
105
+ },
106
+ "client/structure/two-operation-group": {
107
+ "package-name": "client-structure-twooperationgroup",
108
+ },
109
+ "mgmt/sphere": [{ "package-name": "azure-mgmt-spheredpg" }],
110
+ };
111
+
112
+ function toPosix(dir: string): string {
113
+ return dir.replace(/\\/g, "/");
114
+ }
115
+
116
+ function getEmitterOption(spec: string): Record<string, string>[] {
117
+ const relativeSpec = toPosix(relative(CADL_RANCH_DIR, spec));
118
+ const key = relativeSpec.includes("resiliency/srv-driven/old.tsp") ? relativeSpec : dirname(relativeSpec);
119
+ const result = EMITTER_OPTIONS[key] || [{}];
120
+ return Array.isArray(result) ? result : [result];
121
+ }
122
+
123
+ // Function to execute CLI commands asynchronously
124
+ async function executeCommand(tspCommand: TspCommand): Promise<void> {
125
+ try {
126
+ rmSync(tspCommand.outputDir, { recursive: true, force: true });
127
+ } catch (error) {
128
+ console.error(`rm error: ${error}`);
129
+ }
130
+ try {
131
+ console.log(`exec: ${tspCommand.command}`);
132
+ const { stdout, stderr } = await exec(tspCommand.command);
133
+ if (stdout) console.log(`stdout: ${stdout}`);
134
+ if (stderr) console.error(`stderr: ${stderr}`);
135
+ } catch (error) {
136
+ console.error(`exec error: ${error}`);
137
+ throw error;
138
+ }
139
+ }
140
+
141
+ interface RegenerateFlagsInput {
142
+ flavor?: "azure" | "unbranded";
143
+ debug?: boolean;
144
+ name?: string;
145
+ }
146
+
147
+ interface RegenerateFlags {
148
+ flavor: "azure" | "unbranded";
149
+ debug: boolean;
150
+ name?: string;
151
+ }
152
+
153
+ const SpecialFlags: Record<string, Record<string, any>> = {
154
+ azure: {
155
+ "generate-test": true,
156
+ "generate-sample": true,
157
+ },
158
+ };
159
+
160
+ async function getSubdirectories(baseDir: string, flags: RegenerateFlags): Promise<string[]> {
161
+ const subdirectories: string[] = [];
162
+
163
+ async function searchDir(currentDir: string) {
164
+ const items = await promises.readdir(currentDir, { withFileTypes: true });
165
+
166
+ const promisesArray = items.map(async (item) => {
167
+ const subDirPath = join(currentDir, item.name);
168
+ if (item.isDirectory()) {
169
+ const mainTspPath = join(subDirPath, "main.tsp");
170
+ const clientTspPath = join(subDirPath, "client.tsp");
171
+
172
+ const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath));
173
+ if (flags.flavor === "unbranded" && mainTspRelativePath.includes("azure")) return;
174
+
175
+ // after xml support, remove this check
176
+ if (mainTspRelativePath.includes("xml")) return;
177
+
178
+ // after fix test generation for nested operation group, remove this check
179
+ if (mainTspRelativePath.includes("client-operation-group")) return;
180
+
181
+ const hasMainTsp = await promises
182
+ .access(mainTspPath)
183
+ .then(() => true)
184
+ .catch(() => false);
185
+ const hasClientTsp = await promises
186
+ .access(clientTspPath)
187
+ .then(() => true)
188
+ .catch(() => false);
189
+
190
+ if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) {
191
+ if (mainTspRelativePath.includes("resiliency/srv-driven")) {
192
+ subdirectories.push(resolve(subDirPath, "old.tsp"));
193
+ }
194
+ if (hasClientTsp) {
195
+ subdirectories.push(resolve(subDirPath, "client.tsp"));
196
+ } else if (hasMainTsp) {
197
+ subdirectories.push(resolve(subDirPath, "main.tsp"));
198
+ }
199
+ }
200
+
201
+ // Recursively search in the subdirectory
202
+ await searchDir(subDirPath);
203
+ }
204
+ });
205
+
206
+ await Promise.all(promisesArray);
207
+ }
208
+
209
+ await searchDir(baseDir);
210
+ return subdirectories;
211
+ }
212
+
213
+ function defaultPackageName(spec: string): string {
214
+ return toPosix(relative(CADL_RANCH_DIR, dirname(spec)))
215
+ .replace(/\//g, "-")
216
+ .toLowerCase();
217
+ }
218
+
219
+ interface EmitterConfig {
220
+ optionsStr: string;
221
+ outputDir: string;
222
+ }
223
+
224
+ function addOptions(spec: string, generatedFolder: string, flags: RegenerateFlags): EmitterConfig[] {
225
+ const emitterConfigs: EmitterConfig[] = [];
226
+ for (const config of getEmitterOption(spec)) {
227
+ const options: Record<string, string> = { ...config };
228
+ options["flavor"] = flags.flavor;
229
+ for (const [k, v] of Object.entries(SpecialFlags[flags.flavor] ?? {})) {
230
+ options[k] = v;
231
+ }
232
+ if (options["emitter-output-dir"] === undefined) {
233
+ const packageName = options["package-name"] || defaultPackageName(spec);
234
+ options["emitter-output-dir"] = toPosix(`${generatedFolder}/test/${flags.flavor}/generated/${packageName}`);
235
+ }
236
+ if (flags.debug) {
237
+ options["debug"] = "true";
238
+ }
239
+ if (flags.flavor === "unbranded") {
240
+ options["company-name"] = "Unbranded";
241
+ }
242
+ options["examples-dir"] = toPosix(join(dirname(spec), "examples"));
243
+ const configs = Object.entries(options).flatMap(([k, v]) => {
244
+ return `--option @azure-tools/typespec-python.${k}=${v}`;
245
+ });
246
+ emitterConfigs.push({
247
+ optionsStr: configs.join(" "),
248
+ outputDir: options["emitter-output-dir"],
249
+ });
250
+ }
251
+ return emitterConfigs;
252
+ }
253
+ function _getCmdList(spec: string, flags: RegenerateFlags): TspCommand[] {
254
+ return addOptions(spec, PLUGIN_DIR, flags).map((option) => {
255
+ return {
256
+ outputDir: option.outputDir,
257
+ command: `tsp compile ${spec} --emit=${toPosix(PLUGIN_DIR)} ${option.optionsStr}`,
258
+ };
259
+ });
260
+ }
261
+
262
+ async function regenerate(flags: RegenerateFlagsInput): Promise<void> {
263
+ if (flags.flavor === undefined) {
264
+ await regenerate({ ...flags, flavor: "azure" });
265
+ await regenerate({ ...flags, flavor: "unbranded" });
266
+ } else {
267
+ const flagsResolved = { debug: false, flavor: flags.flavor, ...flags };
268
+ const CADL_RANCH_DIR = resolve(PLUGIN_DIR, "node_modules/@azure-tools/cadl-ranch-specs/http");
269
+ const subdirectories = await getSubdirectories(CADL_RANCH_DIR, flagsResolved);
270
+ const cmdList: TspCommand[] = subdirectories.flatMap((subdirectory) =>
271
+ _getCmdList(subdirectory, flagsResolved),
272
+ );
273
+ const PromiseCommands = cmdList.map((tspCommand) => executeCommand(tspCommand));
274
+ await Promise.all(PromiseCommands);
275
+ }
276
+ }
277
+
278
+ // PARSE INPUT ARGUMENTS
279
+ const argv = yargs(hideBin(process.argv))
280
+ .option("flavor", {
281
+ type: "string",
282
+ choices: ["azure", "unbranded"],
283
+ description: "Specify the flavor",
284
+ })
285
+ .option("debug", {
286
+ alias: "d",
287
+ type: "boolean",
288
+ description: "Debug mode",
289
+ })
290
+ .option("name", {
291
+ alias: "n",
292
+ type: "string",
293
+ description: "Specify filename if you only want to generate a subset",
294
+ }).argv;
295
+
296
+ regenerate(argv as RegenerateFlags)
297
+ .then(() => console.log("Regeneration successful"))
298
+ .catch((error) => console.error(`Regeneration failed: ${error.message}`));
@@ -4,28 +4,27 @@ import { readFileSync } from "fs";
4
4
  import { join } from "path";
5
5
  import yargs from "yargs";
6
6
  import { hideBin } from "yargs/helpers";
7
+ import { fileURLToPath } from "url";
7
8
 
8
9
  interface Arguments {
10
+ validFolders: string[];
9
11
  folder?: string;
10
12
  command?: string;
11
13
  }
12
14
 
13
- const validFolders = [
14
- "azure/legacy",
15
- "azure/version-tolerant",
16
- "vanilla/legacy",
17
- "vanilla/version-tolerant",
18
- "dpg/version-tolerant",
19
- ];
20
-
21
15
  const validCommands = ["ci", "lint", "mypy", "pyright", "apiview"];
22
16
 
23
17
  // Parse command-line arguments using yargs
24
18
  const argv = yargs(hideBin(process.argv))
19
+ .option("validFolders", {
20
+ alias: "vf",
21
+ describe: "Specify the valid folders",
22
+ type: "array",
23
+ default: ["azure", "unbranded"],
24
+ })
25
25
  .option("folder", {
26
26
  alias: "f",
27
27
  describe: "Specify the folder to use",
28
- choices: validFolders,
29
28
  type: "string",
30
29
  })
31
30
  .option("command", {
@@ -35,7 +34,7 @@ const argv = yargs(hideBin(process.argv))
35
34
  type: "string",
36
35
  }).argv as Arguments;
37
36
 
38
- const foldersToProcess = argv.folder ? [argv.folder] : validFolders;
37
+ const foldersToProcess = argv.folder ? [argv.folder] : argv.validFolders;
39
38
 
40
39
  const commandToRun = argv.command || "all";
41
40
 
@@ -45,7 +44,7 @@ function getCommand(command: string, folder: string) {
45
44
  }
46
45
 
47
46
  function sectionExistsInToxIni(command: string, folder: string): boolean {
48
- const toxIniPath = join(__dirname, `../test/${folder}/tox.ini`);
47
+ const toxIniPath = join(fileURLToPath(import.meta.url), `../../../test/${folder}/tox.ini`);
49
48
  const toxIniContent = readFileSync(toxIniPath, "utf-8");
50
49
  const sectionHeader = `[testenv:${command}]`;
51
50
  return toxIniContent.includes(sectionHeader);
@@ -0,0 +1,38 @@
1
+ /* eslint-disable no-console */
2
+ import { exec } from "child_process";
3
+ import process from "process";
4
+ import { existsSync } from "fs";
5
+ import { dirname, join } from "path";
6
+ import { fileURLToPath } from "url";
7
+ import chalk from "chalk";
8
+
9
+ // execute the command
10
+ export function executeCommand(command: string, prettyName: string) {
11
+ exec(command, (error, stdout, stderr) => {
12
+ if (error) {
13
+ console.error(chalk.red(`Error executing ${command}(stdout): ${stdout}`));
14
+ console.error(chalk.red(`Error executing ${command}{stderr}: ${stderr}`));
15
+ process.exit(1);
16
+ }
17
+ if (stderr) {
18
+ // Process stderr output
19
+ console.log(chalk.yellow(`${command}:\n${stderr}`));
20
+ return;
21
+ }
22
+ console.log(chalk.green(`${prettyName} passed`));
23
+ });
24
+ }
25
+
26
+ // Function to run a command and log the output
27
+ export function runCommand(command: string, prettyName: string) {
28
+ let pythonPath = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "venv/");
29
+ if (existsSync(join(pythonPath, "bin"))) {
30
+ pythonPath = join(pythonPath, "bin", "python");
31
+ } else if (existsSync(join(pythonPath, "Scripts"))) {
32
+ pythonPath = join(pythonPath, "Scripts", "python");
33
+ } else {
34
+ throw new Error(pythonPath);
35
+ }
36
+ command = `${pythonPath} -m ${command}`;
37
+ executeCommand(command, prettyName);
38
+ }
@@ -0,0 +1,38 @@
1
+ # global configurations
2
+ [mypy]
3
+ python_version = 3.8
4
+
5
+
6
+ # module level configuratiohns
7
+ [mypy-jsonrpc.*]
8
+ ignore_missing_imports = True
9
+
10
+ [mypy-ptvsd.*]
11
+ ignore_missing_imports = True
12
+
13
+ [mypy-debugpy.*]
14
+ ignore_missing_imports = True
15
+
16
+ [mypy-m2r2.*]
17
+ ignore_missing_imports = True
18
+
19
+ [mypy-autorest.common.utils.*]
20
+ ignore_missing_imports = True
21
+
22
+ [mypy-autorest.common.python_mappings.*]
23
+ ignore_missing_imports = True
24
+
25
+ [mypy-pygen.codegen.models.*]
26
+ ignore_missing_imports = True
27
+
28
+ [mypy-setuptools]
29
+ ignore_missing_imports = True
30
+
31
+ [mypy-*._patch]
32
+ ignore_missing_imports = True
33
+
34
+ [mypy-pygen.*]
35
+ ignore_missing_imports = True
36
+
37
+ [mypy-yaml.*]
38
+ ignore_missing_imports = True
@@ -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
+ });