in packages/jsii-pacmak/lib/targets/python.ts [572:743]
public emit(
code: CodeMaker,
context: EmitContext,
opts?: BaseMethodEmitOpts,
) {
const { renderAbstract = true, forceEmitBody = false } = opts ?? {};
const returnType: string = toTypeName(this.returns).pythonType(context);
// We cannot (currently?) blindly use the names given to us by the JSII for
// initializers, because our keyword lifting will allow two names to clash.
// This can hopefully be removed once we get https://github.com/aws/jsii/issues/288
// resolved, so build up a list of all of the prop names so we can check against
// them later.
const liftedPropNames = new Set<string>();
if (this.liftedProp?.properties != null) {
for (const prop of this.liftedProp.properties) {
liftedPropNames.add(toPythonParameterName(prop.name));
}
}
// We need to turn a list of JSII parameters, into Python style arguments with
// gradual typing, so we'll have to iterate over the list of parameters, and
// build the list, converting as we go.
const pythonParams: string[] = [];
for (const param of this.parameters) {
// We cannot (currently?) blindly use the names given to us by the JSII for
// initializers, because our keyword lifting will allow two names to clash.
// This can hopefully be removed once we get https://github.com/aws/jsii/issues/288
// resolved.
const paramName: string = toPythonParameterName(
param.name,
liftedPropNames,
);
const paramType = toTypeName(param).pythonType({
...context,
parameterType: true,
});
const paramDefault = param.optional ? ' = None' : '';
pythonParams.push(`${paramName}: ${paramType}${paramDefault}`);
}
const documentableArgs: DocumentableArgument[] = this.parameters
.map(
(p) =>
({
name: p.name,
docs: p.docs,
definingType: this.parent,
}) as DocumentableArgument,
)
// If there's liftedProps, the last argument is the struct and it won't be _actually_ emitted.
.filter((_, index) =>
this.liftedProp != null ? index < this.parameters.length - 1 : true,
)
.map((param) => ({
...param,
name: toPythonParameterName(param.name, liftedPropNames),
}));
// If we have a lifted parameter, then we'll drop the last argument to our params
// and then we'll lift all of the params of the lifted type as keyword arguments
// to the function.
if (this.liftedProp !== undefined) {
// Remove our last item.
pythonParams.pop();
const liftedProperties = this.getLiftedProperties(context.resolver);
if (liftedProperties.length >= 1) {
// All of these parameters are keyword only arguments, so we'll mark them
// as such.
pythonParams.push('*');
// Iterate over all of our props, and reflect them into our params.
for (const prop of liftedProperties) {
const paramName = toPythonParameterName(prop.prop.name);
const paramType = toTypeName(prop.prop).pythonType({
...context,
parameterType: true,
typeAnnotation: true,
});
const paramDefault = prop.prop.optional ? ' = None' : '';
pythonParams.push(`${paramName}: ${paramType}${paramDefault}`);
}
}
// Document them as keyword arguments
documentableArgs.push(
...liftedProperties.map(
(p) =>
({
name: p.prop.name,
docs: p.prop.docs,
definingType: p.definingType,
}) as DocumentableArgument,
),
);
} else if (
this.parameters.length >= 1 &&
this.parameters[this.parameters.length - 1].variadic
) {
// Another situation we could be in, is that instead of having a plain parameter
// we have a variadic parameter where we need to expand the last parameter as a
// *args.
pythonParams.pop();
const lastParameter = this.parameters.slice(-1)[0];
const paramName = toPythonParameterName(lastParameter.name);
const paramType = toTypeName(lastParameter.type).pythonType(context);
pythonParams.push(`*${paramName}: ${paramType}`);
}
const decorators = new Array<string>();
if (this.jsName !== undefined) {
decorators.push(`@jsii.member(jsii_name="${this.jsName}")`);
}
if (this.decorator !== undefined) {
decorators.push(`@${this.decorator}`);
}
if (renderAbstract && this.abstract) {
decorators.push('@abc.abstractmethod');
}
if (decorators.length > 0) {
for (const decorator of decorators) {
code.line(decorator);
}
}
pythonParams.unshift(
slugifyAsNeeded(
this.implicitParameter,
pythonParams.map((param) => param.split(':')[0].trim()),
),
);
openSignature(code, 'def', this.pythonName, pythonParams, returnType);
this.generator.emitDocString(code, this.apiLocation, this.docs, {
arguments: documentableArgs,
documentableItem: `method-${this.pythonName}`,
});
if (
(this.shouldEmitBody || forceEmitBody) &&
(!renderAbstract || !this.abstract)
) {
emitParameterTypeChecks(
code,
context,
pythonParams.slice(1),
`${this.pythonParent.fqn ?? this.pythonParent.pythonName}#${
this.pythonName
}`,
);
}
this.emitBody(
code,
context,
renderAbstract,
forceEmitBody,
liftedPropNames,
pythonParams[0],
returnType,
);
code.closeBlock();
}