@typespec/http-client-python 0.7.0 → 0.8.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.
- package/dist/emitter/code-model.js +6 -6
- package/dist/emitter/code-model.js.map +1 -1
- package/dist/emitter/emitter.d.ts.map +1 -1
- package/dist/emitter/emitter.js +97 -59
- package/dist/emitter/emitter.js.map +1 -1
- package/dist/emitter/external-process.js +3 -3
- package/dist/emitter/external-process.js.map +1 -1
- package/dist/emitter/http.d.ts.map +1 -1
- package/dist/emitter/http.js +81 -23
- package/dist/emitter/http.js.map +1 -1
- package/dist/emitter/lib.d.ts +37 -1
- package/dist/emitter/lib.d.ts.map +1 -1
- package/dist/emitter/lib.js +24 -0
- package/dist/emitter/lib.js.map +1 -1
- package/dist/emitter/types.d.ts.map +1 -1
- package/dist/emitter/types.js +6 -4
- package/dist/emitter/types.js.map +1 -1
- package/dist/emitter/utils.d.ts +5 -2
- package/dist/emitter/utils.d.ts.map +1 -1
- package/dist/emitter/utils.js +99 -2
- package/dist/emitter/utils.js.map +1 -1
- package/emitter/src/code-model.ts +8 -8
- package/emitter/src/emitter.ts +101 -58
- package/emitter/src/external-process.ts +3 -3
- package/emitter/src/http.ts +113 -26
- package/emitter/src/lib.ts +24 -0
- package/emitter/src/types.ts +7 -4
- package/emitter/src/utils.ts +118 -1
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/emitter/test/utils.test.ts +6 -1
- package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
- package/eng/scripts/setup/run_tsp.py +4 -5
- package/generator/build/lib/pygen/__init__.py +3 -3
- package/generator/build/lib/pygen/black.py +2 -2
- package/generator/build/lib/pygen/codegen/__init__.py +5 -5
- package/generator/build/lib/pygen/codegen/models/paging_operation.py +11 -2
- package/generator/build/lib/pygen/codegen/models/parameter.py +2 -1
- package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +2 -0
- package/generator/build/lib/pygen/codegen/models/response.py +1 -1
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +47 -25
- package/generator/build/lib/pygen/preprocess/__init__.py +10 -12
- package/generator/build/lib/pygen/preprocess/python_mappings.py +1 -1
- package/generator/build/lib/pygen/utils.py +5 -5
- package/generator/component-detection-pip-report.json +7 -6
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/__init__.py +3 -3
- package/generator/pygen/black.py +2 -2
- package/generator/pygen/codegen/__init__.py +5 -5
- package/generator/pygen/codegen/models/paging_operation.py +11 -2
- package/generator/pygen/codegen/models/parameter.py +2 -1
- package/generator/pygen/codegen/models/request_builder_parameter.py +2 -0
- package/generator/pygen/codegen/models/response.py +1 -1
- package/generator/pygen/codegen/serializers/builder_serializer.py +47 -25
- package/generator/pygen/preprocess/__init__.py +10 -12
- package/generator/pygen/preprocess/python_mappings.py +1 -1
- package/generator/pygen/utils.py +5 -5
- package/generator/pygen.egg-info/PKG-INFO +0 -1
- package/generator/pygen.egg-info/SOURCES.txt +0 -1
- package/generator/pygen.egg-info/requires.txt +0 -1
- package/generator/setup.py +0 -1
- package/generator/test/generic_mock_api_tests/asynctests/test_payload_pageable_async.py +75 -0
- package/generator/test/generic_mock_api_tests/test_payload_pageable.py +54 -0
- package/package.json +2 -1
- package/generator/build/lib/pygen/m2r.py +0 -65
- package/generator/pygen/m2r.py +0 -65
- package/generator/test/generic_mock_api_tests/unittests/test_m2r.py +0 -10
- package/generator/test/unbranded/mock_api_tests/cadl-ranch-config.yaml +0 -27
package/emitter/src/emitter.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { saveCodeModelAsYaml } from "./external-process.js";
|
|
|
16
16
|
import { PythonEmitterOptions, PythonSdkContext, reportDiagnostic } from "./lib.js";
|
|
17
17
|
import { runPython3 } from "./run-python3.js";
|
|
18
18
|
import { disableGenerationMap, simpleTypesMap, typesMap } from "./types.js";
|
|
19
|
-
import { removeUnderscoresFromNamespace } from "./utils.js";
|
|
19
|
+
import { md2Rst, removeUnderscoresFromNamespace } from "./utils.js";
|
|
20
20
|
|
|
21
21
|
export function getModelsMode(context: SdkContext): "dpg" | "none" {
|
|
22
22
|
const specifiedModelsMode = context.emitContext.options["models-mode"];
|
|
@@ -80,6 +80,44 @@ async function createPythonSdkContext<TServiceOperation extends SdkServiceOperat
|
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
function walkThroughNodes(yamlMap: Record<string, any>): Record<string, any> {
|
|
84
|
+
const stack = [yamlMap];
|
|
85
|
+
const seen = new WeakSet();
|
|
86
|
+
|
|
87
|
+
while (stack.length > 0) {
|
|
88
|
+
const current = stack.pop();
|
|
89
|
+
|
|
90
|
+
if (seen.has(current!)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (current !== undefined && current !== null) {
|
|
94
|
+
seen.add(current);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (Array.isArray(current)) {
|
|
98
|
+
for (let i = 0; i < current.length; i++) {
|
|
99
|
+
if (current[i] !== undefined && typeof current[i] === "object") {
|
|
100
|
+
stack.push(current[i]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
for (const key in current) {
|
|
105
|
+
if (key === "description" || key === "summary") {
|
|
106
|
+
if (current[key] !== undefined) {
|
|
107
|
+
current[key] = md2Rst(current[key]);
|
|
108
|
+
}
|
|
109
|
+
} else if (Array.isArray(current[key])) {
|
|
110
|
+
stack.push(current[key]);
|
|
111
|
+
} else if (current[key] !== undefined && typeof current[key] === "object") {
|
|
112
|
+
stack.push(current[key]);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return yamlMap;
|
|
119
|
+
}
|
|
120
|
+
|
|
83
121
|
function cleanAllCache() {
|
|
84
122
|
typesMap.clear();
|
|
85
123
|
simpleTypesMap.clear();
|
|
@@ -87,6 +125,23 @@ function cleanAllCache() {
|
|
|
87
125
|
}
|
|
88
126
|
|
|
89
127
|
export async function $onEmit(context: EmitContext<PythonEmitterOptions>) {
|
|
128
|
+
try {
|
|
129
|
+
await onEmitMain(context);
|
|
130
|
+
} catch (error: any) {
|
|
131
|
+
const errStackStart =
|
|
132
|
+
"========================================= error stack start ================================================";
|
|
133
|
+
const errStackEnd =
|
|
134
|
+
"========================================= error stack end ================================================";
|
|
135
|
+
const errStack = error.stack ? `\n${errStackStart}\n${error.stack}\n${errStackEnd}` : "";
|
|
136
|
+
reportDiagnostic(context.program, {
|
|
137
|
+
code: "unknown-error",
|
|
138
|
+
target: NoTarget,
|
|
139
|
+
format: { stack: errStack },
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function onEmitMain(context: EmitContext<PythonEmitterOptions>) {
|
|
90
145
|
// clean all cache to make sure emitter could work in watch mode
|
|
91
146
|
cleanAllCache();
|
|
92
147
|
|
|
@@ -103,7 +158,10 @@ export async function $onEmit(context: EmitContext<PythonEmitterOptions>) {
|
|
|
103
158
|
});
|
|
104
159
|
return;
|
|
105
160
|
}
|
|
106
|
-
|
|
161
|
+
|
|
162
|
+
const parsedYamlMap = walkThroughNodes(yamlMap);
|
|
163
|
+
|
|
164
|
+
const yamlPath = await saveCodeModelAsYaml("python-yaml-path", parsedYamlMap);
|
|
107
165
|
const resolvedOptions = sdkContext.emitContext.options;
|
|
108
166
|
const commandArgs: Record<string, string> = {};
|
|
109
167
|
if (resolvedOptions["packaging-files-config"]) {
|
|
@@ -147,70 +205,55 @@ export async function $onEmit(context: EmitContext<PythonEmitterOptions>) {
|
|
|
147
205
|
}
|
|
148
206
|
}
|
|
149
207
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const pythonCode = `
|
|
208
|
+
if (resolvedOptions["use-pyodide"]) {
|
|
209
|
+
// here we run with pyodide
|
|
210
|
+
const pyodide = await setupPyodideCall(root);
|
|
211
|
+
// create the output folder if not exists
|
|
212
|
+
if (!fs.existsSync(outputDir)) {
|
|
213
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
214
|
+
}
|
|
215
|
+
// mount output folder to pyodide
|
|
216
|
+
pyodide.FS.mkdirTree("/output");
|
|
217
|
+
pyodide.FS.mount(pyodide.FS.filesystems.NODEFS, { root: outputDir }, "/output");
|
|
218
|
+
// mount yaml file to pyodide
|
|
219
|
+
pyodide.FS.mkdirTree("/yaml");
|
|
220
|
+
pyodide.FS.mount(pyodide.FS.filesystems.NODEFS, { root: path.dirname(yamlPath) }, "/yaml");
|
|
221
|
+
const globals = pyodide.toPy({
|
|
222
|
+
outputFolder: "/output",
|
|
223
|
+
yamlFile: `/yaml/${path.basename(yamlPath)}`,
|
|
224
|
+
commandArgs,
|
|
225
|
+
});
|
|
226
|
+
const pythonCode = `
|
|
170
227
|
async def main():
|
|
171
228
|
import warnings
|
|
172
229
|
with warnings.catch_warnings():
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
preprocess.PreProcessPlugin(output_folder=outputFolder, cadl_file=yamlFile, **commandArgs).process()
|
|
177
|
-
codegen.CodeGenerator(output_folder=outputFolder, cadl_file=yamlFile, **commandArgs).process()
|
|
230
|
+
from pygen import preprocess, codegen, black
|
|
231
|
+
preprocess.PreProcessPlugin(output_folder=outputFolder, tsp_file=yamlFile, **commandArgs).process()
|
|
232
|
+
codegen.CodeGenerator(output_folder=outputFolder, tsp_file=yamlFile, **commandArgs).process()
|
|
178
233
|
black.BlackScriptPlugin(output_folder=outputFolder, **commandArgs).process()
|
|
179
234
|
|
|
180
235
|
await main()`;
|
|
181
|
-
|
|
236
|
+
await pyodide.runPythonAsync(pythonCode, { globals });
|
|
237
|
+
} else {
|
|
238
|
+
// here we run with native python
|
|
239
|
+
let venvPath = path.join(root, "venv");
|
|
240
|
+
if (fs.existsSync(path.join(venvPath, "bin"))) {
|
|
241
|
+
venvPath = path.join(venvPath, "bin", "python");
|
|
242
|
+
} else if (fs.existsSync(path.join(venvPath, "Scripts"))) {
|
|
243
|
+
venvPath = path.join(venvPath, "Scripts", "python.exe");
|
|
182
244
|
} else {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
} else if (fs.existsSync(path.join(venvPath, "Scripts"))) {
|
|
188
|
-
venvPath = path.join(venvPath, "Scripts", "python.exe");
|
|
189
|
-
} else {
|
|
190
|
-
reportDiagnostic(program, {
|
|
191
|
-
code: "pyodide-flag-conflict",
|
|
192
|
-
target: NoTarget,
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
commandArgs["output-folder"] = outputDir;
|
|
196
|
-
commandArgs["cadl-file"] = yamlPath;
|
|
197
|
-
const commandFlags = Object.entries(commandArgs)
|
|
198
|
-
.map(([key, value]) => `--${key}=${value}`)
|
|
199
|
-
.join(" ");
|
|
200
|
-
const command = `${venvPath} ${root}/eng/scripts/setup/run_tsp.py ${commandFlags}`;
|
|
201
|
-
execSync(command, { stdio: [process.stdin, process.stdout] });
|
|
245
|
+
reportDiagnostic(program, {
|
|
246
|
+
code: "pyodide-flag-conflict",
|
|
247
|
+
target: NoTarget,
|
|
248
|
+
});
|
|
202
249
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
"
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
code: "unknown-error",
|
|
211
|
-
target: NoTarget,
|
|
212
|
-
format: { stack: errStack },
|
|
213
|
-
});
|
|
250
|
+
commandArgs["output-folder"] = outputDir;
|
|
251
|
+
commandArgs["tsp-file"] = yamlPath;
|
|
252
|
+
const commandFlags = Object.entries(commandArgs)
|
|
253
|
+
.map(([key, value]) => `--${key}=${value}`)
|
|
254
|
+
.join(" ");
|
|
255
|
+
const command = `${venvPath} ${root}/eng/scripts/setup/run_tsp.py ${commandFlags}`;
|
|
256
|
+
execSync(command, { stdio: [process.stdin, process.stdout] });
|
|
214
257
|
}
|
|
215
258
|
}
|
|
216
259
|
}
|
|
@@ -5,10 +5,10 @@ import { mkdir, writeFile } from "fs/promises";
|
|
|
5
5
|
import jsyaml from "js-yaml";
|
|
6
6
|
import os from "os";
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const tspCodeGenTempDir = joinPaths(os.tmpdir(), "tsp-codegen");
|
|
9
9
|
|
|
10
10
|
export function createTempPath(extension: string, prefix: string = "") {
|
|
11
|
-
return joinPaths(
|
|
11
|
+
return joinPaths(tspCodeGenTempDir, prefix + randomUUID() + extension);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -18,7 +18,7 @@ export function createTempPath(extension: string, prefix: string = "") {
|
|
|
18
18
|
* @return the absolute path to the created codemodel.
|
|
19
19
|
*/
|
|
20
20
|
export async function saveCodeModelAsYaml(name: string, codemodel: unknown): Promise<string> {
|
|
21
|
-
await mkdir(
|
|
21
|
+
await mkdir(tspCodeGenTempDir, { recursive: true });
|
|
22
22
|
const filename = createTempPath(".yaml", name);
|
|
23
23
|
const yamlStr = jsyaml.dump(codemodel);
|
|
24
24
|
await writeFile(filename, yamlStr);
|
package/emitter/src/http.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { NoTarget } from "@typespec/compiler";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
SdkBasicServiceMethod,
|
|
3
|
-
SdkBodyModelPropertyType,
|
|
4
5
|
SdkBodyParameter,
|
|
5
6
|
SdkClientType,
|
|
6
7
|
SdkHeaderParameter,
|
|
@@ -10,16 +11,16 @@ import {
|
|
|
10
11
|
SdkHttpResponse,
|
|
11
12
|
SdkLroPagingServiceMethod,
|
|
12
13
|
SdkLroServiceMethod,
|
|
14
|
+
SdkModelPropertyType,
|
|
13
15
|
SdkPagingServiceMethod,
|
|
14
16
|
SdkPathParameter,
|
|
15
17
|
SdkQueryParameter,
|
|
16
18
|
SdkServiceMethod,
|
|
17
19
|
SdkServiceResponseHeader,
|
|
18
|
-
SdkType,
|
|
19
20
|
UsageFlags,
|
|
20
21
|
} from "@azure-tools/typespec-client-generator-core";
|
|
21
22
|
import { HttpStatusCodeRange } from "@typespec/http";
|
|
22
|
-
import { PythonSdkContext } from "./lib.js";
|
|
23
|
+
import { PythonSdkContext, reportDiagnostic } from "./lib.js";
|
|
23
24
|
import { KnownTypes, getType } from "./types.js";
|
|
24
25
|
import {
|
|
25
26
|
camelToSnakeCase,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
getImplementation,
|
|
30
31
|
isAbstract,
|
|
31
32
|
isAzureCoreErrorResponse,
|
|
33
|
+
isContinuationToken,
|
|
32
34
|
} from "./utils.js";
|
|
33
35
|
|
|
34
36
|
function isContentTypeParameter(parameter: SdkHeaderParameter) {
|
|
@@ -96,6 +98,88 @@ function addLroInformation(
|
|
|
96
98
|
};
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
function getWireNameFromPropertySegments(segments: SdkModelPropertyType[]): string | undefined {
|
|
102
|
+
if (segments[0].kind === "property") {
|
|
103
|
+
return segments
|
|
104
|
+
.filter((s) => s.kind === "property")
|
|
105
|
+
.map((s) => s.serializationOptions.json?.name ?? "")
|
|
106
|
+
.join(".");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function getWireNameWithDiagnostics(
|
|
113
|
+
context: PythonSdkContext<SdkHttpOperation>,
|
|
114
|
+
segments: SdkModelPropertyType[] | undefined,
|
|
115
|
+
code: "invalid-paging-items" | "invalid-next-link" | "invalid-lro-result",
|
|
116
|
+
method?: SdkServiceMethod<SdkHttpOperation>,
|
|
117
|
+
): string | undefined {
|
|
118
|
+
if (segments && segments.length > 0) {
|
|
119
|
+
const result = getWireNameFromPropertySegments(segments);
|
|
120
|
+
if (result) {
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
const operationId = method ? method.name : "";
|
|
124
|
+
reportDiagnostic(context.program, {
|
|
125
|
+
code: code,
|
|
126
|
+
target: NoTarget,
|
|
127
|
+
format: { operationId: operationId },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function buildContinuationToken(
|
|
135
|
+
context: PythonSdkContext<SdkHttpOperation>,
|
|
136
|
+
method: SdkPagingServiceMethod<SdkHttpOperation> | SdkLroPagingServiceMethod<SdkHttpOperation>,
|
|
137
|
+
segments: SdkModelPropertyType[],
|
|
138
|
+
input: boolean = true,
|
|
139
|
+
): Record<string, any> {
|
|
140
|
+
if (segments[0].kind === "property") {
|
|
141
|
+
const wireName = getWireNameFromPropertySegments(segments);
|
|
142
|
+
if (wireName) {
|
|
143
|
+
return { wireName, location: "body" };
|
|
144
|
+
}
|
|
145
|
+
} else if (input) {
|
|
146
|
+
for (const parameter of method.operation.parameters) {
|
|
147
|
+
if (isContinuationToken(parameter, method)) {
|
|
148
|
+
return { wireName: parameter.serializedName, location: parameter.kind };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
for (const response of method.operation.responses) {
|
|
153
|
+
for (const header of response.headers) {
|
|
154
|
+
if (isContinuationToken(header, method, false)) {
|
|
155
|
+
return { wireName: header.serializedName, location: "header" };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
reportDiagnostic(context.program, {
|
|
161
|
+
code: "invalid-continuation-token",
|
|
162
|
+
target: NoTarget,
|
|
163
|
+
format: { operationId: method.name, direction: input ? "request" : "response" },
|
|
164
|
+
});
|
|
165
|
+
return {};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function buildAllContinuationToken(
|
|
169
|
+
context: PythonSdkContext<SdkHttpOperation>,
|
|
170
|
+
method: SdkPagingServiceMethod<SdkHttpOperation> | SdkLroPagingServiceMethod<SdkHttpOperation>,
|
|
171
|
+
): Record<string, any> {
|
|
172
|
+
const parameterSegments = method.pagingMetadata.continuationTokenParameterSegments ?? [];
|
|
173
|
+
const responseSegments = method.pagingMetadata.continuationTokenResponseSegments ?? [];
|
|
174
|
+
if (parameterSegments.length > 0 && responseSegments.length > 0) {
|
|
175
|
+
return {
|
|
176
|
+
input: buildContinuationToken(context, method, parameterSegments),
|
|
177
|
+
output: buildContinuationToken(context, method, responseSegments, false),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {};
|
|
181
|
+
}
|
|
182
|
+
|
|
99
183
|
function addPagingInformation(
|
|
100
184
|
context: PythonSdkContext<SdkHttpOperation>,
|
|
101
185
|
rootClient: SdkClientType<SdkHttpOperation>,
|
|
@@ -109,13 +193,17 @@ function addPagingInformation(
|
|
|
109
193
|
}
|
|
110
194
|
const itemType = getType(context, method.response.type!);
|
|
111
195
|
const base = emitHttpOperation(context, rootClient, operationGroupName, method.operation, method);
|
|
112
|
-
const itemName =
|
|
113
|
-
|
|
114
|
-
method.response.
|
|
196
|
+
const itemName = getWireNameWithDiagnostics(
|
|
197
|
+
context,
|
|
198
|
+
method.response.resultSegments,
|
|
199
|
+
"invalid-paging-items",
|
|
200
|
+
method,
|
|
115
201
|
);
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
method.
|
|
202
|
+
const nextLinkName = getWireNameWithDiagnostics(
|
|
203
|
+
context,
|
|
204
|
+
method.pagingMetadata.nextLinkSegments,
|
|
205
|
+
"invalid-next-link",
|
|
206
|
+
method,
|
|
119
207
|
);
|
|
120
208
|
base.responses.forEach((resp: Record<string, any>) => {
|
|
121
209
|
resp.type = itemType;
|
|
@@ -126,23 +214,14 @@ function addPagingInformation(
|
|
|
126
214
|
discriminator: "paging",
|
|
127
215
|
exposeStreamKeyword: false,
|
|
128
216
|
itemName,
|
|
129
|
-
|
|
217
|
+
nextLinkName,
|
|
130
218
|
itemType,
|
|
131
219
|
description: method.doc ?? "",
|
|
132
220
|
summary: method.summary,
|
|
221
|
+
continuationToken: buildAllContinuationToken(context, method),
|
|
133
222
|
};
|
|
134
223
|
}
|
|
135
224
|
|
|
136
|
-
function getPropertyWireName(type: SdkType | undefined, path?: string) {
|
|
137
|
-
if (!path || !type || type.kind !== "model") return path;
|
|
138
|
-
for (const property of type.properties) {
|
|
139
|
-
if (property.name === path) {
|
|
140
|
-
return (property as SdkBodyModelPropertyType).serializedName;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return path;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
225
|
export function emitLroHttpMethod(
|
|
147
226
|
context: PythonSdkContext<SdkHttpOperation>,
|
|
148
227
|
rootClient: SdkClientType<SdkHttpOperation>,
|
|
@@ -192,7 +271,7 @@ function emitHttpOperation(
|
|
|
192
271
|
const result = {
|
|
193
272
|
url: operation.path,
|
|
194
273
|
method: operation.verb.toUpperCase(),
|
|
195
|
-
parameters: emitHttpParameters(context, rootClient, operation),
|
|
274
|
+
parameters: emitHttpParameters(context, rootClient, operation, method),
|
|
196
275
|
bodyParameter: emitHttpBodyParameter(context, operation.bodyParam),
|
|
197
276
|
responses,
|
|
198
277
|
exceptions,
|
|
@@ -277,8 +356,9 @@ function emitHttpPathParameter(
|
|
|
277
356
|
function emitHttpHeaderParameter(
|
|
278
357
|
context: PythonSdkContext<SdkHttpOperation>,
|
|
279
358
|
parameter: SdkHeaderParameter,
|
|
359
|
+
method: SdkServiceMethod<SdkHttpOperation>,
|
|
280
360
|
): Record<string, any> {
|
|
281
|
-
const base = emitParamBase(context, parameter);
|
|
361
|
+
const base = emitParamBase(context, parameter, method);
|
|
282
362
|
const [delimiter, explode] = getDelimiterAndExplode(parameter);
|
|
283
363
|
let clientDefaultValue = parameter.clientDefaultValue;
|
|
284
364
|
if (isContentTypeParameter(parameter)) {
|
|
@@ -302,8 +382,9 @@ function emitHttpHeaderParameter(
|
|
|
302
382
|
function emitHttpQueryParameter(
|
|
303
383
|
context: PythonSdkContext<SdkHttpOperation>,
|
|
304
384
|
parameter: SdkQueryParameter,
|
|
385
|
+
method: SdkServiceMethod<SdkHttpOperation>,
|
|
305
386
|
): Record<string, any> {
|
|
306
|
-
const base = emitParamBase(context, parameter);
|
|
387
|
+
const base = emitParamBase(context, parameter, method);
|
|
307
388
|
const [delimiter, explode] = getDelimiterAndExplode(parameter);
|
|
308
389
|
return {
|
|
309
390
|
...base,
|
|
@@ -320,15 +401,16 @@ function emitHttpParameters(
|
|
|
320
401
|
context: PythonSdkContext<SdkHttpOperation>,
|
|
321
402
|
rootClient: SdkClientType<SdkHttpOperation>,
|
|
322
403
|
operation: SdkHttpOperation,
|
|
404
|
+
method: SdkServiceMethod<SdkHttpOperation>,
|
|
323
405
|
): Record<string, any>[] {
|
|
324
406
|
const parameters: Record<string, any>[] = [...context.__endpointPathParameters];
|
|
325
407
|
for (const parameter of operation.parameters) {
|
|
326
408
|
switch (parameter.kind) {
|
|
327
409
|
case "header":
|
|
328
|
-
parameters.push(emitHttpHeaderParameter(context, parameter));
|
|
410
|
+
parameters.push(emitHttpHeaderParameter(context, parameter, method));
|
|
329
411
|
break;
|
|
330
412
|
case "query":
|
|
331
|
-
parameters.push(emitHttpQueryParameter(context, parameter));
|
|
413
|
+
parameters.push(emitHttpQueryParameter(context, parameter, method));
|
|
332
414
|
break;
|
|
333
415
|
case "path":
|
|
334
416
|
parameters.push(emitHttpPathParameter(context, parameter));
|
|
@@ -387,7 +469,12 @@ function emitHttpResponse(
|
|
|
387
469
|
type,
|
|
388
470
|
contentTypes: response.contentTypes,
|
|
389
471
|
defaultContentType: response.defaultContentType ?? "application/json",
|
|
390
|
-
resultProperty:
|
|
472
|
+
resultProperty: getWireNameWithDiagnostics(
|
|
473
|
+
context,
|
|
474
|
+
method?.response.resultSegments,
|
|
475
|
+
"invalid-lro-result",
|
|
476
|
+
method,
|
|
477
|
+
),
|
|
391
478
|
};
|
|
392
479
|
}
|
|
393
480
|
|
package/emitter/src/lib.ts
CHANGED
|
@@ -83,6 +83,30 @@ const libDef = {
|
|
|
83
83
|
default: "Can't generate Python SDK since no client defined in typespec file.",
|
|
84
84
|
},
|
|
85
85
|
},
|
|
86
|
+
"invalid-paging-items": {
|
|
87
|
+
severity: "warning",
|
|
88
|
+
messages: {
|
|
89
|
+
default: paramMessage`No valid paging items for operation '${"operationId"}'.`,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
"invalid-next-link": {
|
|
93
|
+
severity: "warning",
|
|
94
|
+
messages: {
|
|
95
|
+
default: paramMessage`No valid next link for operation '${"operationId"}'.`,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
"invalid-lro-result": {
|
|
99
|
+
severity: "warning",
|
|
100
|
+
messages: {
|
|
101
|
+
default: paramMessage`No valid LRO result for operation '${"operationId"}'.`,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
"invalid-continuation-token": {
|
|
105
|
+
severity: "warning",
|
|
106
|
+
messages: {
|
|
107
|
+
default: paramMessage`No valid continuation token in '${"direction"}' for operation '${"operationId"}'.`,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
86
110
|
},
|
|
87
111
|
emitter: {
|
|
88
112
|
options: EmitterOptionsSchema as JSONSchemaType<PythonEmitterOptions>,
|
package/emitter/src/types.ts
CHANGED
|
@@ -294,7 +294,7 @@ function emitModel<TServiceOperation extends SdkServiceOperation>(
|
|
|
294
294
|
usage: type.usage,
|
|
295
295
|
isXml: type.usage & UsageFlags.Xml ? true : false,
|
|
296
296
|
xmlMetadata: getXmlMetadata(type),
|
|
297
|
-
clientNamespace: getClientNamespace(context, type.
|
|
297
|
+
clientNamespace: getClientNamespace(context, type.namespace),
|
|
298
298
|
};
|
|
299
299
|
|
|
300
300
|
typesMap.set(type, newValue);
|
|
@@ -341,13 +341,16 @@ function emitEnum<TServiceOperation extends SdkServiceOperation>(
|
|
|
341
341
|
if (!type.isFixed) {
|
|
342
342
|
types.push(emitBuiltInType(type.valueType));
|
|
343
343
|
}
|
|
344
|
-
|
|
344
|
+
|
|
345
|
+
const newValue = {
|
|
345
346
|
description: "",
|
|
346
347
|
internal: true,
|
|
347
348
|
type: "combined",
|
|
348
349
|
types,
|
|
349
350
|
xmlMetadata: {},
|
|
350
351
|
};
|
|
352
|
+
typesMap.set(type, newValue);
|
|
353
|
+
return newValue;
|
|
351
354
|
}
|
|
352
355
|
const values: Record<string, any>[] = [];
|
|
353
356
|
const name = type.name;
|
|
@@ -361,7 +364,7 @@ function emitEnum<TServiceOperation extends SdkServiceOperation>(
|
|
|
361
364
|
values,
|
|
362
365
|
xmlMetadata: {},
|
|
363
366
|
crossLanguageDefinitionId: type.crossLanguageDefinitionId,
|
|
364
|
-
clientNamespace: getClientNamespace(context, type.
|
|
367
|
+
clientNamespace: getClientNamespace(context, type.namespace),
|
|
365
368
|
};
|
|
366
369
|
for (const value of type.values) {
|
|
367
370
|
newValue.values.push(emitEnumMember(value, newValue));
|
|
@@ -479,7 +482,7 @@ function emitUnion<TServiceOperation extends SdkServiceOperation>(
|
|
|
479
482
|
type: "combined",
|
|
480
483
|
types: type.variantTypes.map((x) => getType(context, x)),
|
|
481
484
|
xmlMetadata: {},
|
|
482
|
-
clientNamespace: getClientNamespace(context, type.
|
|
485
|
+
clientNamespace: getClientNamespace(context, type.namespace),
|
|
483
486
|
});
|
|
484
487
|
}
|
|
485
488
|
|