Skip to content

Commit bfbc8d4

Browse files
msyyctadelesh
andauthored
[python] always respect namespace from TCGC (#5649)
fix #5661 --------- Co-authored-by: Chenjie Shi <tadelesh.shi@live.cn>
1 parent 676f47f commit bfbc8d4

File tree

17 files changed

+220
-129
lines changed

17 files changed

+220
-129
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
3+
changeKind: fix
4+
packages:
5+
- "@typespec/http-client-python"
6+
---
7+
8+
Always respect namespace from TCGC

packages/http-client-python/emitter/src/code-model.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
SdkApiVersionParameter,
32
SdkBasicServiceMethod,
43
SdkClientType,
54
SdkCredentialParameter,
@@ -33,12 +32,7 @@ import {
3332
simpleTypesMap,
3433
typesMap,
3534
} from "./types.js";
36-
import {
37-
emitParamBase,
38-
getClientNamespace,
39-
getImplementation,
40-
removeUnderscoresFromNamespace,
41-
} from "./utils.js";
35+
import { emitParamBase, getClientNamespace, getImplementation, getRootNamespace } from "./utils.js";
4236

4337
function emitBasicMethod<TServiceOperation extends SdkServiceOperation>(
4438
context: PythonSdkContext<TServiceOperation>,
@@ -106,11 +100,7 @@ function emitLroPagingMethod<TServiceOperation extends SdkServiceOperation>(
106100

107101
function emitMethodParameter<TServiceOperation extends SdkServiceOperation>(
108102
context: PythonSdkContext<TServiceOperation>,
109-
parameter:
110-
| SdkEndpointParameter
111-
| SdkCredentialParameter
112-
| SdkMethodParameter
113-
| SdkApiVersionParameter,
103+
parameter: SdkEndpointParameter | SdkCredentialParameter | SdkMethodParameter,
114104
): Record<string, any>[] {
115105
if (parameter.kind === "endpoint") {
116106
if (parameter.type.kind === "union") {
@@ -286,7 +276,7 @@ export function emitCodeModel<TServiceOperation extends SdkServiceOperation>(
286276
// Get types
287277
const sdkPackage = sdkContext.sdkPackage;
288278
const codeModel: Record<string, any> = {
289-
namespace: removeUnderscoresFromNamespace(sdkPackage.rootNamespace).toLowerCase(),
279+
namespace: getRootNamespace(sdkContext),
290280
clients: [],
291281
};
292282
for (const client of sdkPackage.clients) {

packages/http-client-python/emitter/src/emitter.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { saveCodeModelAsYaml } from "./external-process.js";
1616
import { PythonEmitterOptions, PythonSdkContext, reportDiagnostic } from "./lib.js";
1717
import { runPython3 } from "./run-python3.js";
1818
import { disableGenerationMap, simpleTypesMap, typesMap } from "./types.js";
19-
import { md2Rst, removeUnderscoresFromNamespace } from "./utils.js";
19+
import { getRootNamespace, md2Rst } from "./utils.js";
2020

2121
export function getModelsMode(context: SdkContext): "dpg" | "none" {
2222
const specifiedModelsMode = context.emitContext.options["models-mode"];
@@ -50,9 +50,14 @@ function addDefaultOptions(sdkContext: SdkContext) {
5050
options["package-mode"] = sdkContext.arm ? "azure-mgmt" : "azure-dataplane";
5151
}
5252
if (!options["package-name"]) {
53-
options["package-name"] = removeUnderscoresFromNamespace(
54-
(sdkContext.sdkPackage.rootNamespace ?? "").toLowerCase(),
55-
).replace(/\./g, "-");
53+
const namespace = getRootNamespace(sdkContext as PythonSdkContext<SdkServiceOperation>);
54+
const packageName = namespace.replace(/\./g, "-");
55+
reportDiagnostic(sdkContext.program, {
56+
code: "no-package-name",
57+
target: NoTarget,
58+
format: { namespace, packageName },
59+
});
60+
options["package-name"] = packageName;
5661
}
5762
if (options.flavor !== "azure") {
5863
// if they pass in a flavor other than azure, we want to ignore the value
@@ -61,9 +66,6 @@ function addDefaultOptions(sdkContext: SdkContext) {
6166
if (!options.flavor && sdkContext.emitContext.emitterOutputDir.includes("azure")) {
6267
options.flavor = "azure";
6368
}
64-
if (options["enable-typespec-namespace"] === undefined) {
65-
options["enable-typespec-namespace"] = options.flavor !== "azure";
66-
}
6769
}
6870

6971
async function createPythonSdkContext<TServiceOperation extends SdkServiceOperation>(

packages/http-client-python/emitter/src/lib.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ export interface PythonEmitterOptions {
1717
debug?: boolean;
1818
flavor?: "azure";
1919
"examples-dir"?: string;
20-
// If true, package namespace will respect the typespec namespace. Otherwise,
21-
// package namespace is always aligned with package name.
22-
"enable-typespec-namespace"?: boolean;
20+
namespace?: string;
2321
"use-pyodide"?: boolean;
2422
}
2523

@@ -47,7 +45,7 @@ const EmitterOptionsSchema: JSONSchemaType<PythonEmitterOptions> = {
4745
debug: { type: "boolean", nullable: true },
4846
flavor: { type: "string", nullable: true },
4947
"examples-dir": { type: "string", nullable: true, format: "absolute-path" },
50-
"enable-typespec-namespace": { type: "boolean", nullable: true },
48+
namespace: { type: "string", nullable: true },
5149
"use-pyodide": { type: "boolean", nullable: true },
5250
},
5351
required: [],
@@ -77,6 +75,12 @@ const libDef = {
7775
},
7876
},
7977
// warning
78+
"no-package-name": {
79+
severity: "warning",
80+
messages: {
81+
default: paramMessage`No package-name configured in tspconfig.yaml and will infer package-name '${"packageName"}' from namespace '${"namespace"}'.`,
82+
},
83+
},
8084
"no-valid-client": {
8185
severity: "warning",
8286
messages: {

packages/http-client-python/emitter/src/utils.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -242,31 +242,45 @@ export function capitalize(name: string): string {
242242
return name[0].toUpperCase() + name.slice(1);
243243
}
244244

245+
const LIB_NAMESPACE = [
246+
"azure.core",
247+
"azure.resourcemanager",
248+
"azure.clientgenerator.core",
249+
"typespec.rest",
250+
"typespec.http",
251+
"typespec.versioning",
252+
];
253+
254+
export function getRootNamespace(context: PythonSdkContext<SdkServiceOperation>): string {
255+
let rootNamespace = "";
256+
if (context.sdkPackage.clients.length > 0) {
257+
rootNamespace = context.sdkPackage.clients[0].namespace;
258+
} else if (context.sdkPackage.models.length > 0) {
259+
const result = context.sdkPackage.models
260+
.map((model) => model.namespace)
261+
.filter((namespace) => !LIB_NAMESPACE.includes(namespace));
262+
if (result.length > 0) {
263+
result.sort();
264+
rootNamespace = result[0];
265+
}
266+
} else if (context.sdkPackage.namespaces.length > 0) {
267+
rootNamespace = context.sdkPackage.namespaces[0].fullName;
268+
}
269+
270+
return removeUnderscoresFromNamespace(rootNamespace).toLowerCase();
271+
}
272+
245273
export function getClientNamespace<TServiceOperation extends SdkServiceOperation>(
246274
context: PythonSdkContext<TServiceOperation>,
247275
clientNamespace: string,
248276
) {
249-
const rootNamespace = removeUnderscoresFromNamespace(
250-
context.sdkPackage.rootNamespace,
251-
).toLowerCase();
252-
if (!context.emitContext.options["enable-typespec-namespace"]) {
253-
return rootNamespace;
254-
}
255277
if (
256-
[
257-
"azure.core",
258-
"azure.resourcemanager",
259-
"azure.clientgenerator.core",
260-
"typespec.rest",
261-
"typespec.http",
262-
"typespec.versioning",
263-
].some((item) => clientNamespace.toLowerCase().startsWith(item))
278+
clientNamespace === "" ||
279+
LIB_NAMESPACE.some((item) => clientNamespace.toLowerCase().startsWith(item))
264280
) {
265-
return rootNamespace;
281+
return getRootNamespace(context);
266282
}
267-
return clientNamespace === ""
268-
? rootNamespace
269-
: removeUnderscoresFromNamespace(clientNamespace).toLowerCase();
283+
return removeUnderscoresFromNamespace(clientNamespace).toLowerCase();
270284
}
271285

272286
function parseToken(token: Token): string {

0 commit comments

Comments
 (0)