in packages/jsii-pacmak/lib/targets/python.ts [1576:1698]
public emit(code: CodeMaker, context: EmitContext) {
this.emitModuleDocumentation(code);
const resolver = this.fqn
? context.resolver.bind(this.fqn, this.pythonName)
: context.resolver;
context = {
...context,
submodule: this.fqn ?? context.submodule,
resolver,
};
// Before we write anything else, we need to write out our module headers, this
// is where we handle stuff like imports, any required initialization, etc.
code.line('import abc');
code.line('import builtins');
code.line('import datetime');
code.line('import enum');
code.line('import typing');
code.line();
code.line('import jsii');
code.line('import publication');
code.line('import typing_extensions');
// Determine if we need to write out the kernel load line.
if (this.loadAssembly) {
this.emitDependencyImports(code);
code.line();
emitList(
code,
'__jsii_assembly__ = jsii.JSIIAssembly.load(',
[
JSON.stringify(this.assembly.name),
JSON.stringify(this.assembly.version),
'__name__[0:-6]',
`${JSON.stringify(this.assemblyFilename)}`,
],
')',
);
} else {
// Then we must import the ._jsii subpackage.
code.line();
let distanceFromRoot = 0;
for (
let curr = this.fqn!;
curr !== this.assembly.name;
curr = curr.substring(0, curr.lastIndexOf('.'))
) {
distanceFromRoot++;
}
code.line(`from ${'.'.repeat(distanceFromRoot + 1)}_jsii import *`);
this.emitRequiredImports(code, context);
}
// Emit all of our members.
for (const member of prepareMembers(this.members, resolver)) {
code.line();
code.line();
member.emit(code, context);
}
// Whatever names we've exported, we'll write out our __all__ that lists them.
const exportedMembers = this.members.map((m) => `"${m.pythonName}"`);
if (this.loadAssembly) {
exportedMembers.push('"__jsii_assembly__"');
}
// Declare the list of "public" members this module exports
if (this.members.length > 0) {
code.line();
}
code.line();
if (exportedMembers.length > 0) {
code.indent('__all__ = [');
for (const member of exportedMembers.sort()) {
// Writing one by line might be _a lot_ of lines, but it'll make reviewing changes to the list easier. Trust me.
code.line(`${member},`);
}
code.unindent(']');
} else {
code.line('__all__: typing.List[typing.Any] = []');
}
// Next up, we'll use publication to ensure that all of the non-public names
// get hidden from dir(), tab-complete, etc.
code.line();
code.line('publication.publish()');
// Finally, we'll load all registered python modules
if (this.modules.length > 0) {
code.line();
code.line(
'# Loading modules to ensure their types are registered with the jsii runtime library',
);
for (const module of this.modules.sort((l, r) =>
l.pythonName.localeCompare(r.pythonName),
)) {
// Rather than generating an absolute import like
// "import jsii_calc.submodule.nested_submodule.deeply_nested"
// this builds a relative import like
// "from .submodule.nested_submodule import deeply_nested"
// This enables distributing python packages and using the
// generated modules in the same codebase.
const assemblyName = toPythonFqn(
module.assembly.name,
module.assembly,
).pythonFqn;
const submodule = module.pythonName
.replace(`${assemblyName}.`, '')
.split('.');
const submodulePath = submodule
.slice(0, submodule.length - 1)
.join('.');
const submoduleName = submodule[submodule.length - 1];
code.line(`from .${submodulePath} import ${submoduleName}`);
}
}
}