Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support query explode and path allowReserved #2775

Merged
merged 8 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: feature
packages:
- "@azure-tools/typespec-python"
---

support query `explode` and path `allowReserved`, also change the logic of generating spread body parameter
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,13 @@ def serialize_validation_file(self) -> str:
def serialize_cross_language_definition_file(self) -> str:
cross_langauge_def_dict = {
f"{self.code_model.namespace}.models.{model.name}": model.cross_language_definition_id
for model in self.code_model.model_types
for model in self.code_model.public_model_types
}
cross_langauge_def_dict.update(
{
f"{self.code_model.namespace}.models.{enum.name}": enum.cross_language_definition_id
for enum in self.code_model.enums
if not enum.internal
}
)
cross_langauge_def_dict.update(
Expand Down
2 changes: 1 addition & 1 deletion packages/typespec-python/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"@azure-tools/typespec-azure-core": ">=0.45.0 <1.0.0",
"@azure-tools/typespec-azure-resource-manager": ">=0.45.0 <1.0.0",
"@azure-tools/typespec-autorest": ">=0.45.0 <1.0.0",
"@azure-tools/typespec-client-generator-core": ">=0.45.1 <1.0.0",
"@azure-tools/typespec-client-generator-core": ">=0.45.4 <1.0.0",
"@azure-tools/typespec-azure-rulesets": ">=0.45.0 <3.0.0",
"@typespec/compiler": ">=0.59.1 <1.0.0",
"@typespec/http": ">=0.59.0 <1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/typespec-python/scripts/eng/regenerate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ function addOptions(spec: string, generatedFolder: string, flags: RegenerateFlag
if (flags.flavor === "unbranded") {
options["company-name"] = "Unbranded";
}
options["examples-directory"] = toPosix(join(dirname(spec), "examples"));
options["examples-dir"] = toPosix(join(dirname(spec), "examples"));
const configs = Object.entries(options).flatMap(([k, v]) => {
return `--option @azure-tools/typespec-python.${k}=${v}`;
});
Expand Down
7 changes: 6 additions & 1 deletion packages/typespec-python/src/code-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,12 @@ export function emitCodeModel<TServiceOperation extends SdkServiceOperation>(
}
// loop through models and enums since there may be some orphaned models needs to be generated
for (const model of sdkPackage.models) {
if (model.name === "" || (model.usage & UsageFlags.Spread) > 0) {
if (
model.name === "" ||
((model.usage & UsageFlags.Spread) > 0 &&
(model.usage & UsageFlags.Input) === 0 &&
(model.usage & UsageFlags.Output) === 0)
) {
continue;
}
if (!disableGenerationMap.has(model)) {
Expand Down
29 changes: 18 additions & 11 deletions packages/typespec-python/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
camelToSnakeCase,
emitParamBase,
getAddedOn,
getDelimeterAndExplode,
getDelimiterAndExplode,
getDescriptionAndSummary,
getImplementation,
isAbstract,
Expand Down Expand Up @@ -160,7 +160,7 @@ function emitHttpOperation(
rootClient: SdkClientType<SdkHttpOperation>,
operationGroupName: string,
operation: SdkHttpOperation,
method?: SdkServiceMethod<SdkHttpOperation>,
method: SdkServiceMethod<SdkHttpOperation>,
): Record<string, any> {
const responses: Record<string, any>[] = [];
const exceptions: Record<string, any>[] = [];
Expand Down Expand Up @@ -188,13 +188,16 @@ function emitHttpOperation(
crossLanguageDefinitionId: method?.crossLanguageDefintionId,
samples: arrayToRecord(method?.operation.examples),
};
if (
result.bodyParameter &&
operation.bodyParam?.type.kind === "model" &&
(operation.bodyParam?.type.usage & UsageFlags.Spread) > 0
) {
if (result.bodyParameter && isSpreadBody(operation.bodyParam)) {
result.bodyParameter["propertyToParameterName"] = {};
result.bodyParameter["defaultToUnsetSentinel"] = true;
// if body type is not only used for this spread body, but also used in other input/output, we should clone it, then change the type base to json
if (
(result.bodyParameter.type.usage & UsageFlags.Input) > 0 ||
(result.bodyParameter.type.usage & UsageFlags.Output) > 0
) {
result.bodyParameter.type = { ...result.bodyParameter.type, name: `${method.name}Request` };
}
result.bodyParameter.type.base = "json";
for (const property of result.bodyParameter.type.properties) {
result.bodyParameter["propertyToParameterName"][property["wireName"]] = property["clientName"];
Expand All @@ -204,6 +207,10 @@ function emitHttpOperation(
return result;
}

function isSpreadBody(bodyParam: SdkBodyParameter | undefined): boolean {
return bodyParam?.type.kind === "model" && bodyParam.type !== bodyParam.correspondingMethodParams[0]?.type;
}

function emitFlattenedParameter(
bodyParameter: Record<string, any>,
property: Record<string, any>,
Expand Down Expand Up @@ -237,15 +244,15 @@ function emitHttpPathParameter(context: PythonSdkContext<SdkHttpOperation>, para
location: parameter.kind,
implementation: getImplementation(context, parameter),
clientDefaultValue: parameter.clientDefaultValue,
skipUrlEncoding: parameter.urlEncode === false,
skipUrlEncoding: parameter.allowReserved,
};
}
function emitHttpHeaderParameter(
context: PythonSdkContext<SdkHttpOperation>,
parameter: SdkHeaderParameter,
): Record<string, any> {
const base = emitParamBase(context, parameter);
const [delimiter, explode] = getDelimeterAndExplode(parameter);
const [delimiter, explode] = getDelimiterAndExplode(parameter);
let clientDefaultValue = parameter.clientDefaultValue;
if (isContentTypeParameter(parameter)) {
// we switch to string type for content-type header
Expand All @@ -270,7 +277,7 @@ function emitHttpQueryParameter(
parameter: SdkQueryParameter,
): Record<string, any> {
const base = emitParamBase(context, parameter);
const [delimiter, explode] = getDelimeterAndExplode(parameter);
const [delimiter, explode] = getDelimiterAndExplode(parameter);
return {
...base,
wireName: parameter.serializedName,
Expand Down Expand Up @@ -310,7 +317,7 @@ function emitHttpBodyParameter(
): Record<string, any> | undefined {
if (bodyParam === undefined) return undefined;
return {
...emitParamBase(context, bodyParam, true),
...emitParamBase(context, bodyParam),
contentTypes: bodyParam.contentTypes,
location: bodyParam.kind,
clientName: bodyParam.isGeneratedName ? "body" : camelToSnakeCase(bodyParam.name),
Expand Down
2 changes: 2 additions & 0 deletions packages/typespec-python/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface PythonEmitterOptions {
"generate-test"?: boolean;
"debug"?: boolean;
"flavor"?: "azure";
"examples-dir"?: string;
}

export interface PythonSdkContext<TServiceOperation extends SdkServiceOperation>
Expand All @@ -41,6 +42,7 @@ const EmitterOptionsSchema: JSONSchemaType<PythonEmitterOptions> = {
"generate-test": { type: "boolean", nullable: true },
"debug": { type: "boolean", nullable: true },
"flavor": { type: "string", nullable: true },
"examples-dir": { type: "string", nullable: true, format: "absolute-path" },
},
required: [],
};
Expand Down
8 changes: 3 additions & 5 deletions packages/typespec-python/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,10 @@ export function getSimpleTypeResult(result: Record<string, any>): Record<string,
export function getType<TServiceOperation extends SdkServiceOperation>(
context: PythonSdkContext<TServiceOperation>,
type: CredentialType | CredentialTypeUnion | Type | SdkType | MultiPartFileType,
fromBody = false,
): Record<string, any> {
switch (type.kind) {
case "model":
return emitModel(context, type, fromBody);
return emitModel(context, type);
case "union":
return emitUnion(context, type);
case "enum":
Expand Down Expand Up @@ -239,7 +238,6 @@ function emitProperty<TServiceOperation extends SdkServiceOperation>(
function emitModel<TServiceOperation extends SdkServiceOperation>(
context: PythonSdkContext<TServiceOperation>,
type: SdkModelType,
fromBody: boolean,
): Record<string, any> {
if (isEmptyModel(type)) {
return KnownTypes.any;
Expand All @@ -257,7 +255,7 @@ function emitModel<TServiceOperation extends SdkServiceOperation>(
discriminatedSubtypes: {} as Record<string, Record<string, any>>,
properties: new Array<Record<string, any>>(),
snakeCaseName: camelToSnakeCase(type.name),
base: type.isGeneratedName && fromBody ? "json" : "dpg",
base: "dpg",
internal: type.access === "internal",
crossLanguageDefinitionId: type.crossLanguageDefinitionId,
usage: type.usage,
Expand Down Expand Up @@ -476,7 +474,7 @@ export function emitEndpointType<TServiceOperation extends SdkServiceOperation>(
location: "endpointPath",
implementation: getImplementation(context, param),
clientDefaultValue: param.clientDefaultValue,
skipUrlEncoding: param.urlEncode === false,
skipUrlEncoding: param.urlEncode === false, // eslint-disable-line deprecation/deprecation
});
context.__endpointPathParameters!.push(params.at(-1)!);
}
Expand Down
9 changes: 4 additions & 5 deletions packages/typespec-python/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ export function isAbstract<TServiceOperation extends SdkServiceOperation>(
return (method.operation.bodyParam?.contentTypes.length ?? 0) > 1 && method.access !== "internal";
}

export function getDelimeterAndExplode(
export function getDelimiterAndExplode(
parameter: SdkQueryParameter | SdkHeaderParameter,
): [string | undefined, boolean] {
if (parameter.type.kind !== "array") return [undefined, false];
let delimiter: string | undefined = undefined;
let explode = false;
if (parameter.collectionFormat === "csv") {
let explode = parameter.kind === "query" && parameter.explode;
if (parameter.collectionFormat === "csv" || parameter.collectionFormat === "simple") {
delimiter = "comma";
} else if (parameter.collectionFormat === "ssv") {
delimiter = "space";
Expand Down Expand Up @@ -90,9 +90,8 @@ export function getAddedOn<TServiceOperation extends SdkServiceOperation>(
export function emitParamBase<TServiceOperation extends SdkServiceOperation>(
context: PythonSdkContext<TServiceOperation>,
parameter: SdkParameter | SdkHttpParameter,
fromBody: boolean = false,
): ParamBase {
let type = getType(context, parameter.type, fromBody);
let type = getType(context, parameter.type);
if (parameter.isApiVersionParam) {
if (parameter.clientDefaultValue) {
type = getSimpleTypeResult({ type: "constant", value: parameter.clientDefaultValue, valueType: type });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
{
"CrossLanguagePackageId": "_Specs_.Azure.ClientGenerator.Core.Access",
"CrossLanguageDefinitionId": {
"specs.azure.clientgenerator.core.access.models.AbstractModel": "_Specs_.Azure.ClientGenerator.Core.Access.RelativeModelInOperation.AbstractModel",
"specs.azure.clientgenerator.core.access.models.BaseModel": "_Specs_.Azure.ClientGenerator.Core.Access.RelativeModelInOperation.BaseModel",
"specs.azure.clientgenerator.core.access.models.InnerModel": "_Specs_.Azure.ClientGenerator.Core.Access.RelativeModelInOperation.InnerModel",
"specs.azure.clientgenerator.core.access.models.InternalDecoratorModelInInternal": "_Specs_.Azure.ClientGenerator.Core.Access.InternalOperation.InternalDecoratorModelInInternal",
"specs.azure.clientgenerator.core.access.models.NoDecoratorModelInInternal": "_Specs_.Azure.ClientGenerator.Core.Access.InternalOperation.NoDecoratorModelInInternal",
"specs.azure.clientgenerator.core.access.models.NoDecoratorModelInPublic": "_Specs_.Azure.ClientGenerator.Core.Access.PublicOperation.NoDecoratorModelInPublic",
"specs.azure.clientgenerator.core.access.models.OuterModel": "_Specs_.Azure.ClientGenerator.Core.Access.RelativeModelInOperation.OuterModel",
"specs.azure.clientgenerator.core.access.models.PublicDecoratorModelInInternal": "_Specs_.Azure.ClientGenerator.Core.Access.InternalOperation.PublicDecoratorModelInInternal",
"specs.azure.clientgenerator.core.access.models.PublicDecoratorModelInPublic": "_Specs_.Azure.ClientGenerator.Core.Access.PublicOperation.PublicDecoratorModelInPublic",
"specs.azure.clientgenerator.core.access.models.RealModel": "_Specs_.Azure.ClientGenerator.Core.Access.RelativeModelInOperation.RealModel",
"specs.azure.clientgenerator.core.access.models.SharedModel": "_Specs_.Azure.ClientGenerator.Core.Access.SharedModelInOperation.SharedModel",
"specs.azure.clientgenerator.core.access.AccessClient.public_operation.no_decorator_in_public": "_Specs_.Azure.ClientGenerator.Core.Access.PublicOperation.noDecoratorInPublic",
"specs.azure.clientgenerator.core.access.AccessClient.public_operation.public_decorator_in_public": "_Specs_.Azure.ClientGenerator.Core.Access.PublicOperation.publicDecoratorInPublic",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"CrossLanguagePackageId": "Parameters.Basic",
"CrossLanguageDefinitionId": {
"parameters.basic.models.SimpleRequest": "Parameters.Basic.ImplicitBody.simple.Request.anonymous",
"parameters.basic.models.User": "Parameters.Basic.ExplicitBody.User",
"parameters.basic.BasicClient.explicit_body.simple": "Parameters.Basic.ExplicitBody.simple",
"parameters.basic.BasicClient.implicit_body.simple": "Parameters.Basic.ImplicitBody.simple"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"CrossLanguagePackageId": "Parameters.BodyOptionality",
"CrossLanguageDefinitionId": {
"parameters.bodyoptionality.models.BodyModel": "Parameters.BodyOptionality.BodyModel",
"parameters.bodyoptionality.models.RequiredImplicitRequest": "Parameters.BodyOptionality.requiredImplicit.Request.anonymous",
"parameters.bodyoptionality.BodyOptionalityClient.optional_explicit.set": "Parameters.BodyOptionality.OptionalExplicit.set",
"parameters.bodyoptionality.BodyOptionalityClient.optional_explicit.omit": "Parameters.BodyOptionality.OptionalExplicit.omit",
"parameters.bodyoptionality.BodyOptionalityClient.required_explicit": "Parameters.BodyOptionality.requiredExplicit",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@
"CrossLanguagePackageId": "Parameters.Spread",
"CrossLanguageDefinitionId": {
"parameters.spread.models.BodyParameter": "Parameters.Spread.Model.BodyParameter",
"parameters.spread.models.SpreadAsRequestBodyRequest": "Parameters.Spread.Alias.spreadAsRequestBody.Request.anonymous",
"parameters.spread.models.SpreadAsRequestBodyRequest1": "Parameters.Spread.Model.spreadAsRequestBody.Request.anonymous",
"parameters.spread.models.SpreadAsRequestParameterRequest": "spreadAsRequestParameter.Request.anonymous",
"parameters.spread.models.SpreadCompositeRequestMixRequest": "spreadCompositeRequestMix.Request.anonymous",
"parameters.spread.models.SpreadParameterWithInnerAliasRequest": "spreadParameterWithInnerAlias.Request.anonymous",
"parameters.spread.models.SpreadParameterWithInnerModelRequest": "spreadParameterWithInnerModel.Request.anonymous",
"parameters.spread.models.SpreadWithMultipleParametersRequest": "spreadWithMultipleParameters.Request.anonymous",
"parameters.spread.SpreadClient.model.spread_as_request_body": "Parameters.Spread.Model.spreadAsRequestBody",
"parameters.spread.SpreadClient.model.spread_composite_request_only_with_body": "Parameters.Spread.Model.spreadCompositeRequestOnlyWithBody",
"parameters.spread.SpreadClient.model.spread_composite_request_without_body": "Parameters.Spread.Model.spreadCompositeRequestWithoutBody",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"CrossLanguagePackageId": "Payload.MultiPart",
"CrossLanguageDefinitionId": {
"payload.multipart.models.Address": "Payload.MultiPart.Address",
"payload.multipart.models.AnonymousModelRequest": "anonymousModel.Request.anonymous",
"payload.multipart.models.BinaryArrayPartsRequest": "Payload.MultiPart.BinaryArrayPartsRequest",
"payload.multipart.models.ComplexHttpPartsModelRequest": "Payload.MultiPart.ComplexHttpPartsModelRequest",
"payload.multipart.models.ComplexPartsRequest": "Payload.MultiPart.ComplexPartsRequest",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,6 @@
"typetest.union.models.GetResponse9": "Type.Union.get.Response.anonymous",
"typetest.union.models.MixedLiteralsCases": "Type.Union.MixedLiteralsCases",
"typetest.union.models.MixedTypesCases": "Type.Union.MixedTypesCases",
"typetest.union.models.SendRequest": "Type.Union.send.Request.anonymous",
"typetest.union.models.SendRequest1": "Type.Union.send.Request.anonymous",
"typetest.union.models.SendRequest2": "Type.Union.send.Request.anonymous",
"typetest.union.models.SendRequest3": "Type.Union.send.Request.anonymous",
"typetest.union.models.SendRequest4": "Type.Union.send.Request.anonymous",
"typetest.union.models.SendRequest5": "Type.Union.send.Request.anonymous",
"typetest.union.models.SendRequest6": "Type.Union.send.Request.anonymous",
"typetest.union.models.SendRequest7": "Type.Union.send.Request.anonymous",
"typetest.union.models.SendRequest8": "Type.Union.send.Request.anonymous",
"typetest.union.models.SendRequest9": "Type.Union.send.Request.anonymous",
"typetest.union.models.StringAndArrayCases": "Type.Union.StringAndArrayCases",
"typetest.union.models.StringExtensibleNamedUnion": "Type.Union.StringExtensibleNamedUnion",
"typetest.union.UnionClient.strings_only.get": "Type.Union.StringsOnly.get",
Expand Down
Loading