From cc3ec87e7e22acd97f5e3786b3fc8996d4e23bbb Mon Sep 17 00:00:00 2001 From: Donald Stufft Date: Tue, 12 Mar 2019 15:29:04 -0400 Subject: [PATCH] feat: Add Python Support Support producing Python 3.6+ artifacts --- .flake8 | 5 + packages/jsii-build-tools/bin/package-python | 7 + packages/jsii-build-tools/package.json | 3 +- packages/jsii-calc/lib/compliance.ts | 67 + packages/jsii-calc/test/assembly.jsii | 109 +- packages/jsii-pacmak/lib/targets/python.ts | 1583 +++++++++++++++++ packages/jsii-pacmak/package.json | 2 + .../.jsii | 109 +- .../PythonReservedWords.cs | 212 +++ .../jsii-calc-0.7.15.tgz | Bin 116 -> 72770 bytes .../amazon/jsii/tests/calculator/$Module.java | 1 + .../tests/calculator/PythonReservedWords.java | 141 ++ .../calculator/jsii-calc@0.7.15.jsii.tgz | Bin 116 -> 72770 bytes .../js/jsii-calc@0.7.15.jsii.tgz | Bin 116 -> 72770 bytes .../expected.jsii-calc/sphinx/jsii-calc.rst | 156 ++ packages/jsii-python-runtime/.gitignore | 12 + packages/jsii-python-runtime/MANIFEST.in | 2 + packages/jsii-python-runtime/bin/generate | 31 + .../jsii-python-runtime/bin/generate-calc | 33 + packages/jsii-python-runtime/mypy.ini | 2 + packages/jsii-python-runtime/package.json | 29 + packages/jsii-python-runtime/pyproject.toml | 2 + packages/jsii-python-runtime/pytest.ini | 2 + packages/jsii-python-runtime/requirements.txt | 3 + packages/jsii-python-runtime/setup.py | 27 + .../jsii-python-runtime/src/jsii/__init__.py | 57 + .../jsii-python-runtime/src/jsii/__meta__.py | 12 + .../jsii-python-runtime/src/jsii/_compat.py | 11 + .../src/jsii/_embedded/__init__.py | 0 .../src/jsii/_embedded/jsii/__init__.py | 0 .../src/jsii/_kernel/__init__.py | 224 +++ .../src/jsii/_kernel/providers/__init__.py | 5 + .../src/jsii/_kernel/providers/base.py | 71 + .../src/jsii/_kernel/providers/process.py | 343 ++++ .../src/jsii/_kernel/types.py | 255 +++ .../src/jsii/_reference_map.py | 91 + .../jsii-python-runtime/src/jsii/_runtime.py | 109 ++ .../jsii-python-runtime/src/jsii/_utils.py | 27 + .../jsii-python-runtime/src/jsii/compat.py | 7 + .../jsii-python-runtime/src/jsii/errors.py | 14 + .../jsii-python-runtime/src/jsii/py.typed | 0 .../jsii-python-runtime/src/jsii/python.py | 37 + .../jsii-python-runtime/tests/__init__.py | 0 .../jsii-python-runtime/tests/conftest.py | 3 + .../tests/test_compliance.py | 893 ++++++++++ .../jsii-python-runtime/tests/test_python.py | 15 + .../jsii-reflect/test/classes.expected.txt | 1 + .../test/jsii-tree.test.all.expected.txt | 68 + .../jsii-tree.test.inheritance.expected.txt | 1 + .../test/jsii-tree.test.members.expected.txt | 35 + .../test/jsii-tree.test.types.expected.txt | 1 + 51 files changed, 4815 insertions(+), 3 deletions(-) create mode 100644 .flake8 create mode 100755 packages/jsii-build-tools/bin/package-python create mode 100644 packages/jsii-pacmak/lib/targets/python.ts create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/PythonReservedWords.cs create mode 100644 packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/PythonReservedWords.java create mode 100644 packages/jsii-python-runtime/.gitignore create mode 100644 packages/jsii-python-runtime/MANIFEST.in create mode 100755 packages/jsii-python-runtime/bin/generate create mode 100755 packages/jsii-python-runtime/bin/generate-calc create mode 100644 packages/jsii-python-runtime/mypy.ini create mode 100644 packages/jsii-python-runtime/package.json create mode 100644 packages/jsii-python-runtime/pyproject.toml create mode 100644 packages/jsii-python-runtime/pytest.ini create mode 100644 packages/jsii-python-runtime/requirements.txt create mode 100644 packages/jsii-python-runtime/setup.py create mode 100644 packages/jsii-python-runtime/src/jsii/__init__.py create mode 100644 packages/jsii-python-runtime/src/jsii/__meta__.py create mode 100644 packages/jsii-python-runtime/src/jsii/_compat.py create mode 100644 packages/jsii-python-runtime/src/jsii/_embedded/__init__.py create mode 100644 packages/jsii-python-runtime/src/jsii/_embedded/jsii/__init__.py create mode 100644 packages/jsii-python-runtime/src/jsii/_kernel/__init__.py create mode 100644 packages/jsii-python-runtime/src/jsii/_kernel/providers/__init__.py create mode 100644 packages/jsii-python-runtime/src/jsii/_kernel/providers/base.py create mode 100644 packages/jsii-python-runtime/src/jsii/_kernel/providers/process.py create mode 100644 packages/jsii-python-runtime/src/jsii/_kernel/types.py create mode 100644 packages/jsii-python-runtime/src/jsii/_reference_map.py create mode 100644 packages/jsii-python-runtime/src/jsii/_runtime.py create mode 100644 packages/jsii-python-runtime/src/jsii/_utils.py create mode 100644 packages/jsii-python-runtime/src/jsii/compat.py create mode 100644 packages/jsii-python-runtime/src/jsii/errors.py create mode 100644 packages/jsii-python-runtime/src/jsii/py.typed create mode 100644 packages/jsii-python-runtime/src/jsii/python.py create mode 100644 packages/jsii-python-runtime/tests/__init__.py create mode 100644 packages/jsii-python-runtime/tests/conftest.py create mode 100644 packages/jsii-python-runtime/tests/test_compliance.py create mode 100644 packages/jsii-python-runtime/tests/test_python.py diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000000..7ea9c48f99 --- /dev/null +++ b/.flake8 @@ -0,0 +1,5 @@ +[flake8] +max-line-length = 88 +exclude = *.egg,*/interfaces.py,node_modules,.state +ignore = W503,E203 +select = E,W,F,N diff --git a/packages/jsii-build-tools/bin/package-python b/packages/jsii-build-tools/bin/package-python new file mode 100755 index 0000000000..8ea2d10df6 --- /dev/null +++ b/packages/jsii-build-tools/bin/package-python @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail + +rm -rf dist/python +mkdir -p dist/python +mv *.whl dist/python +mv *.tar.gz dist/python diff --git a/packages/jsii-build-tools/package.json b/packages/jsii-build-tools/package.json index 4e70c6212b..527f73ac39 100644 --- a/packages/jsii-build-tools/package.json +++ b/packages/jsii-build-tools/package.json @@ -8,7 +8,8 @@ "package-js": "bin/package-js", "package-java": "bin/package-java", "package-dotnet": "bin/package-dotnet", - "package-ruby": "bin/package-ruby" + "package-ruby": "bin/package-ruby", + "package-python": "bin/package-python" }, "scripts": { "build": "chmod +x bin/*" diff --git a/packages/jsii-calc/lib/compliance.ts b/packages/jsii-calc/lib/compliance.ts index 7db39297f1..65aad2efd9 100644 --- a/packages/jsii-calc/lib/compliance.ts +++ b/packages/jsii-calc/lib/compliance.ts @@ -856,6 +856,73 @@ export class JavaReservedWords { public while = 'hello'; } +export class PythonReservedWords { + + public and() {} + + public as() {} + + public assert() {} + + public async() {} + + public await() {} + + public break() {} + + public class() {} + + public continue() {} + + public def() {} + + public del() {} + + public elif() {} + + public else() {} + + public except() {} + + public finally() {} + + public for() {} + + public from() {} + + public global() {} + + public if() {} + + public import() {} + + public in() {} + + public is() {} + + public lambda() {} + + public nonlocal() {} + + public not() {} + + public or() {} + + public pass() {} + + public raise() {} + + public return() {} + + public try() {} + + public while() {} + + public with() {} + + public yield() {} +} + export interface UnionProperties { foo?: string | number; readonly bar: AllTypes | string | number; diff --git a/packages/jsii-calc/test/assembly.jsii b/packages/jsii-calc/test/assembly.jsii index c8d62b39f7..1911171cc8 100644 --- a/packages/jsii-calc/test/assembly.jsii +++ b/packages/jsii-calc/test/assembly.jsii @@ -2932,6 +2932,113 @@ ], "name": "PublicClass" }, + "jsii-calc.PythonReservedWords": { + "assembly": "jsii-calc", + "fqn": "jsii-calc.PythonReservedWords", + "initializer": { + "initializer": true + }, + "kind": "class", + "methods": [ + { + "name": "and" + }, + { + "name": "as" + }, + { + "name": "assert" + }, + { + "name": "async" + }, + { + "name": "await" + }, + { + "name": "break" + }, + { + "name": "class" + }, + { + "name": "continue" + }, + { + "name": "def" + }, + { + "name": "del" + }, + { + "name": "elif" + }, + { + "name": "else" + }, + { + "name": "except" + }, + { + "name": "finally" + }, + { + "name": "for" + }, + { + "name": "from" + }, + { + "name": "global" + }, + { + "name": "if" + }, + { + "name": "import" + }, + { + "name": "in" + }, + { + "name": "is" + }, + { + "name": "lambda" + }, + { + "name": "nonlocal" + }, + { + "name": "not" + }, + { + "name": "or" + }, + { + "name": "pass" + }, + { + "name": "raise" + }, + { + "name": "return" + }, + { + "name": "try" + }, + { + "name": "while" + }, + { + "name": "with" + }, + { + "name": "yield" + } + ], + "name": "PythonReservedWords" + }, "jsii-calc.ReferenceEnumFromScopedPackage": { "assembly": "jsii-calc", "docs": { @@ -3842,5 +3949,5 @@ } }, "version": "0.7.15", - "fingerprint": "P2Hdg9vVBT0QqTFN71VaRnkkGvJ74jnUBL7BduuDsjU=" + "fingerprint": "IWSOEhdZzuvrss5K2WBjZCawXayV13yCAKTj/kJ9+mo=" } diff --git a/packages/jsii-pacmak/lib/targets/python.ts b/packages/jsii-pacmak/lib/targets/python.ts new file mode 100644 index 0000000000..01c74a550e --- /dev/null +++ b/packages/jsii-pacmak/lib/targets/python.ts @@ -0,0 +1,1583 @@ +import path = require('path'); + +import { CodeMaker, toSnakeCase } from 'codemaker'; +import * as escapeStringRegexp from 'escape-string-regexp'; +import * as spec from 'jsii-spec'; +import { Generator, GeneratorOptions } from '../generator'; +import { Target, TargetOptions } from '../target'; +import { shell } from '../util'; + +export default class Python extends Target { + protected readonly generator = new PythonGenerator(); + + constructor(options: TargetOptions) { + super(options); + } + + public async build(sourceDir: string, outDir: string): Promise { + // Format our code to make it easier to read, we do this here instead of trying + // to do it in the code generation phase, because attempting to mix style and + // function makes the code generation harder to maintain and read, while doing + // this here is easy. + // await shell("black", ["--py36", sourceDir], {}); + + // Actually package up our code, both as a sdist and a wheel for publishing. + await shell("python3", ["setup.py", "sdist", "--dist-dir", outDir], { cwd: sourceDir }); + await shell("python3", ["setup.py", "bdist_wheel", "--dist-dir", outDir], { cwd: sourceDir }); + } +} + +// ################## +// # CODE GENERATOR # +// ################## + +const PYTHON_BUILTIN_TYPES = ["bool", "str", "None"]; + +const PYTHON_KEYWORDS = [ + "False", "None", "True", "and", "as", "assert", "async", "await", "break", "class", + "continue", "def", "del", "elif", "else", "except", "finally", "for", "from", + "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", + "raise", "return", "try", "while", "with", "yield" +]; + +const toPythonModuleName = (name: string): string => { + if (name.match(/^@[^/]+\/[^/]+$/)) { + name = name.replace(/^@/g, ""); + name = name.replace(/\//g, "."); + } + + name = toSnakeCase(name.replace(/-/g, "_")); + + return name; +}; + +const pythonModuleNameToFilename = (name: string): string => { + return name.replace(/\./g, "/"); +}; + +const toPythonPackageName = (name: string): string => { + return toPythonModuleName(name).replace(/_/g, "-"); +}; + +const toPythonIdentifier = (name: string): string => { + if (PYTHON_KEYWORDS.indexOf(name) > -1) { + return name + "_"; + } + + return name; +}; + +const toPythonMethodName = (name: string, protectedItem: boolean = false): string => { + let value = toPythonIdentifier(toSnakeCase(name)); + if (protectedItem) { + value = "_" + value; + } + return value; +}; + +const toPythonPropertyName = (name: string, constant: boolean = false, protectedItem: boolean = false): string => { + let value = toPythonIdentifier(toSnakeCase(name)); + + if (constant) { + value = value.toUpperCase(); + } + + if (protectedItem) { + value = "_" + value; + } + + return value; +}; + +const toPythonParameterName = (name: string): string => { + return toPythonIdentifier(toSnakeCase(name)); +}; + +const setDifference = (setA: Set, setB: Set): Set => { + const difference = new Set(setA); + for (const elem of setB) { + difference.delete(elem); + } + return difference; +}; + +const sortMembers = (sortable: PythonBase[], resolver: TypeResolver): PythonBase[] => { + const sorted: PythonBase[] = []; + const seen: Set = new Set(); + + // We're going to take a copy of our sortable item, because it'll make it easier if + // this method doesn't have side effects. + sortable = sortable.slice(); + + // The first thing we want to do, is push any item which is not sortable to the very + // front of the list. This will be things like methods, properties, etc. + for (const item of sortable) { + if (!isSortableType(item)) { + sorted.push(item); + seen.add(item); + } + } + sortable = sortable.filter(i => !seen.has(i)); + + // Now that we've pulled out everything that couldn't possibly have dependencies, + // we will go through the remaining items, and pull off any items which have no + // dependencies that we haven't already sorted. + while (sortable.length > 0) { + for (const item of (sortable as Array)) { + const itemDeps: Set = new Set(item.dependsOn(resolver)); + if (setDifference(itemDeps, seen).size === 0) { + sorted.push(item); + seen.add(item); + + break; + } + } + + const leftover = sortable.filter(i => !seen.has(i)); + if (leftover.length === sortable.length) { + throw new Error("Could not sort members (circular dependency?)."); + } else { + sortable = leftover; + } + } + + return sorted; +}; + +const recurseForNamedTypeReferences = (typeRef: spec.TypeReference): spec.NamedTypeReference[] => { + if (spec.isPrimitiveTypeReference(typeRef)) { + return []; + } else if (spec.isCollectionTypeReference(typeRef)) { + return recurseForNamedTypeReferences(typeRef.collection.elementtype); + } else if (spec.isNamedTypeReference(typeRef)) { + return [typeRef]; + } else if (typeRef.union) { + const types: spec.NamedTypeReference[] = []; + for (const type of typeRef.union.types) { + types.push(...recurseForNamedTypeReferences(type)); + } + return types; + } else { + throw new Error("Invalid type reference: " + JSON.stringify(typeRef)); + } +}; + +interface PythonBase { + readonly name: string; + + emit(code: CodeMaker, resolver: TypeResolver, opts?: any): void; +} + +interface PythonType extends PythonBase { + // The JSII FQN for this item, if this item doesn't exist as a JSII type, then it + // doesn't have a FQN and it should be null; + readonly fqn: string | null; + + addMember(member: PythonBase): void; +} + +interface ISortableType { + dependsOn(resolver: TypeResolver): PythonType[]; +} + +function isSortableType(arg: any): arg is ISortableType { + return arg.dependsOn !== undefined; +} + +interface PythonTypeOpts { + bases?: spec.TypeReference[]; +} + +abstract class BasePythonClassType implements PythonType, ISortableType { + + public readonly name: string; + public readonly fqn: string | null; + + protected bases: spec.TypeReference[]; + protected members: PythonBase[]; + + constructor(name: string, fqn: string, opts: PythonTypeOpts) { + const { + bases = [], + } = opts; + + this.name = name; + this.fqn = fqn; + this.bases = bases; + this.members = []; + } + + public dependsOn(resolver: TypeResolver): PythonType[] { + const dependencies: PythonType[] = []; + const parent = resolver.getParent(this.fqn!); + + // We need to return any bases that are in the same module at the same level of + // nesting. + const seen: Set = new Set(); + for (const base of this.bases) { + if (spec.isNamedTypeReference(base)) { + if (resolver.isInModule(base)) { + // Given a base, we need to locate the base's parent that is the same as + // our parent, because we only care about dependencies that are at the + // same level of our own. + // TODO: We might need to recurse into our members to also find their + // dependencies. + let baseItem = resolver.getType(base); + let baseParent = resolver.getParent(base); + while (baseParent !== parent) { + baseItem = baseParent; + baseParent = resolver.getParent(baseItem.fqn!); + } + + if (!seen.has(baseItem.fqn!)) { + dependencies.push(baseItem); + seen.add(baseItem.fqn!); + } + } + } + } + + return dependencies; + } + + public addMember(member: PythonBase) { + this.members.push(member); + } + + public emit(code: CodeMaker, resolver: TypeResolver) { + const classParams = this.getClassParams(resolver); + const bases = classParams.length > 0 ? `(${classParams.join(", ")})` : ""; + + code.openBlock(`class ${this.name}${bases}`); + + this.emitPreamble(code, resolver); + + if (this.members.length > 0) { + resolver = this.fqn ? resolver.bind(this.fqn) : resolver; + for (const member of sortMembers(this.members, resolver)) { + member.emit(code, resolver); + } + } else { + code.line("pass"); + } + + code.closeBlock(); + } + + protected abstract getClassParams(resolver: TypeResolver): string[]; + + protected emitPreamble(_code: CodeMaker, _resolver: TypeResolver) { return; } +} + +interface BaseMethodOpts { + abstract?: boolean; + liftedProp?: spec.InterfaceType, + parent?: spec.NamedTypeReference, +} + +interface BaseMethodEmitOpts { + renderAbstract?: boolean; +} + +abstract class BaseMethod implements PythonBase { + + public readonly name: string; + public readonly abstract: boolean; + + protected readonly abstract implicitParameter: string; + protected readonly jsiiMethod?: string; + protected readonly decorator?: string; + protected readonly classAsFirstParameter: boolean = false; + protected readonly returnFromJSIIMethod: boolean = true; + + private readonly jsName?: string; + private readonly parameters: spec.Parameter[]; + private readonly returns?: spec.TypeReference; + private readonly liftedProp?: spec.InterfaceType; + private readonly parent?: spec.NamedTypeReference; + + constructor(name: string, + jsName: string | undefined, + parameters: spec.Parameter[], + returns?: spec.TypeReference, + opts: BaseMethodOpts = {}) { + const { abstract = false } = opts; + + this.name = name; + this.abstract = abstract; + this.jsName = jsName; + this.parameters = parameters; + this.returns = returns; + this.liftedProp = opts.liftedProp; + this.parent = opts.parent; + } + + public emit(code: CodeMaker, resolver: TypeResolver, opts?: BaseMethodEmitOpts) { + const { renderAbstract = true } = opts || {}; + + let returnType: string; + if (this.returns !== undefined) { + returnType = resolver.resolve(this.returns, { forwardReferences: false }); + } else { + returnType = "None"; + } + + // We cannot (currently?) trust the JSII to accurately tell us whether a + // parameter is truly optional or not. Because of that, we have to selectively + // choose when we're going to respect the optional flag and emit a default value + // to only be at the tail end of the method signature. + // See: https://github.com/awslabs/jsii/issues/284 + let optionalStartsAt: number | undefined; + for (const [idx, param] of this.parameters.entries()) { + if (param.type.optional && optionalStartsAt === undefined) { + optionalStartsAt = idx; + } else if (!param.type.optional) { + optionalStartsAt = undefined; + } + } + + // 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/awslabs/jsii/issues/288 + // resolved, so build up a list of all of the prop names so we can check against + // them later. + const liftedPropNames: Set = new Set(); + if (this.liftedProp !== undefined + && this.liftedProp.properties !== undefined + && this.liftedProp.properties.length >= 1) { + 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[] = [this.implicitParameter]; + for (const [idx, param] of this.parameters.entries()) { + // 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/awslabs/jsii/issues/288 + // resolved. + let paramName: string = toPythonParameterName(param.name); + while (liftedPropNames.has(paramName)) { + paramName = `${paramName}_`; + } + + const paramType = resolver.resolve(param.type, { forwardReferences: false}); + const paramDefault = optionalStartsAt !== undefined && idx >= optionalStartsAt ? "=None" : ""; + + pythonParams.push(`${paramName}: ${paramType}${paramDefault}`); + } + + // 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(); + + if (this.liftedProp.properties !== undefined && this.liftedProp.properties.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 this.liftedProp.properties) { + const paramName = toPythonParameterName(prop.name); + const paramType = resolver.resolve(prop.type, { forwardReferences: false }); + const paramDefault = prop.type.optional ? "=None" : ""; + + pythonParams.push(`${paramName}: ${paramType}${paramDefault}`); + } + } + } else if (this.parameters.length >= 1 && this.parameters.slice(-1)[0].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 = resolver.resolve( + lastParameter.type, + { forwardReferences: false, ignoreOptional: true }, + ); + + pythonParams.push(`*${paramName}: ${paramType}`); + } + + if (this.jsName !== undefined) { + code.line(`@jsii.member(jsii_name="${this.jsName}")`); + } + + if (this.decorator !== undefined) { + code.line(`@${this.decorator}`); + } + + if (renderAbstract && this.abstract) { + code.line("@abc.abstractmethod"); + } + + code.openBlock(`def ${this.name}(${pythonParams.join(", ")}) -> ${returnType}`); + this.emitBody(code, resolver, renderAbstract); + code.closeBlock(); + } + + private emitBody(code: CodeMaker, resolver: TypeResolver, renderAbstract: boolean) { + if (this.jsiiMethod === undefined || (renderAbstract && this.abstract)) { + code.line("..."); + } else { + if (this.liftedProp !== undefined) { + this.emitAutoProps(code, resolver); + } + + this.emitJsiiMethodCall(code, resolver); + } + } + + private emitAutoProps(code: CodeMaker, resolver: TypeResolver) { + const lastParameter = this.parameters.slice(-1)[0]; + const argName = toPythonParameterName(lastParameter.name); + const typeName = resolver.resolve(lastParameter.type, {ignoreOptional: true }); + + // We need to build up a list of properties, which are mandatory, these are the + // ones we will specifiy to start with in our dictionary literal. + const mandatoryPropMembers: string[] = []; + for (const prop of this.liftedProp!.properties || []) { + if (prop.type.optional) { + continue; + } + + mandatoryPropMembers.push(`"${prop.name}": ${toPythonParameterName(prop.name)}`); + } + code.line(`${argName}: ${typeName} = {${mandatoryPropMembers.join(", ")}}`); + code.line(); + + // Now we'll go through our optional properties, and if they haven't been set + // we'll add them to our dictionary. + for (const prop of this.liftedProp!.properties || []) { + if (!prop.type.optional) { + continue; + } + + code.openBlock(`if ${toPythonParameterName(prop.name)} is not None`); + code.line(`${argName}["${prop.name}"] = ${toPythonParameterName(prop.name)}`); + code.closeBlock(); + } + } + + private emitJsiiMethodCall(code: CodeMaker, resolver: TypeResolver) { + const methodPrefix: string = this.returnFromJSIIMethod ? "return " : ""; + + const jsiiMethodParams: string[] = []; + if (this.classAsFirstParameter) { + if (this.parent === undefined) { + throw new Error("Parent not known."); + } + jsiiMethodParams.push(resolver.resolve(this.parent)); + } + jsiiMethodParams.push(this.implicitParameter); + if (this.jsName !== undefined) { + jsiiMethodParams.push(`"${this.jsName}"`); + } + + const paramNames: string[] = []; + for (const param of this.parameters) { + paramNames.push(toPythonParameterName(param.name)); + } + + code.line(`${methodPrefix}jsii.${this.jsiiMethod}(${jsiiMethodParams.join(", ")}, [${paramNames.join(", ")}])`); + } +} + +interface BasePropertyOpts { + abstract?: boolean; + immutable?: boolean; +} + +interface BasePropertyEmitOpts { + renderAbstract?: boolean; +} + +abstract class BaseProperty implements PythonBase { + + public readonly name: string; + public readonly abstract: boolean; + + protected readonly abstract decorator: string; + protected readonly abstract implicitParameter: string; + protected readonly jsiiGetMethod?: string; + protected readonly jsiiSetMethod?: string; + + private readonly jsName: string; + private readonly type: spec.TypeReference; + private readonly immutable: boolean; + + constructor(name: string, jsName: string, type: spec.TypeReference, opts: BasePropertyOpts = {}) { + const { + abstract = false, + immutable = false, + } = opts; + + this.name = name; + this.abstract = abstract; + this.jsName = jsName; + this.type = type; + this.immutable = immutable; + } + + public emit(code: CodeMaker, resolver: TypeResolver, opts?: BasePropertyEmitOpts) { + const { renderAbstract = true } = opts || {}; + const pythonType = resolver.resolve(this.type, { forwardReferences: false }); + + code.line(`@${this.decorator}`); + code.line(`@jsii.member(jsii_name="${this.jsName}")`); + if (renderAbstract && this.abstract) { + code.line("@abc.abstractmethod"); + } + code.openBlock(`def ${this.name}(${this.implicitParameter}) -> ${pythonType}`); + if (this.jsiiGetMethod !== undefined && (!renderAbstract || !this.abstract)) { + code.line(`return jsii.${this.jsiiGetMethod}(${this.implicitParameter}, "${this.jsName}")`); + } else { + code.line("..."); + } + code.closeBlock(); + + if (!this.immutable) { + code.line(`@${this.name}.setter`); + if (renderAbstract && this.abstract) { + code.line("@abc.abstractmethod"); + } + code.openBlock(`def ${this.name}(${this.implicitParameter}, value: ${pythonType})`); + if (this.jsiiSetMethod !== undefined && (!renderAbstract || !this.abstract)) { + code.line(`return jsii.${this.jsiiSetMethod}(${this.implicitParameter}, "${this.jsName}", value)`); + } else { + code.line("..."); + } + code.closeBlock(); + } + } +} + +class Interface extends BasePythonClassType { + + protected getClassParams(resolver: TypeResolver): string[] { + const params: string[] = this.bases.map(b => resolver.resolve(b)); + + params.push("jsii.compat.Protocol"); + + return params; + } + +} + +class InterfaceMethod extends BaseMethod { + protected readonly implicitParameter: string = "self"; +} + +class InterfaceProperty extends BaseProperty { + protected readonly decorator: string = "property"; + protected readonly implicitParameter: string = "self"; +} + +class TypedDict extends BasePythonClassType { + + public emit(code: CodeMaker, resolver: TypeResolver) { + resolver = this.fqn ? resolver.bind(this.fqn) : resolver; + + // MyPy doesn't let us mark some keys as optional, and some keys as mandatory, + // we can either mark either the entire class as mandatory or the entire class + // as optional. However, we can make two classes, one with all mandatory keys + // and one with all optional keys in order to emulate this. So we'll go ahead + // and implement this "split" class logic. + + const classParams = this.getClassParams(resolver); + + const mandatoryMembers = this.members.filter( + item => item instanceof TypedDictProperty ? !item.optional : true + ); + const optionalMembers = this.members.filter( + item => item instanceof TypedDictProperty ? item.optional : false + ); + + if (mandatoryMembers.length >= 1 && optionalMembers.length >= 1) { + // In this case, we have both mandatory *and* optional members, so we'll + // do our split class logic. + + // We'll emit the optional members first, just because it's a little nicer + // for the final class in the chain to have the mandatory members. + code.openBlock(`class _${this.name}(${classParams.concat(["total=False"]).join(", ")})`); + for (const member of optionalMembers) { + member.emit(code, resolver); + } + code.closeBlock(); + + // Now we'll emit the mandatory members. + code.line(`@jsii.data_type(jsii_type="${this.fqn}")`); + code.openBlock(`class ${this.name}(_${this.name})`); + for (const member of sortMembers(mandatoryMembers, resolver)) { + member.emit(code, resolver); + } + code.closeBlock(); + } else { + code.line(`@jsii.data_type(jsii_type="${this.fqn}")`); + + // In this case we either have no members, or we have all of one type, so + // we'll see if we have any optional members, if we don't then we'll use + // total=True instead of total=False for the class. + if (optionalMembers.length >= 1) { + code.openBlock(`class ${this.name}(${classParams.concat(["total=False"]).join(", ")})`); + } else { + code.openBlock(`class ${this.name}(${classParams.join(", ")})`); + } + + // Finally we'll just iterate over and emit all of our members. + if (this.members.length > 0) { + for (const member of sortMembers(this.members, resolver)) { + member.emit(code, resolver); + } + } else { + code.line("pass"); + } + + code.closeBlock(); + } + } + + protected getClassParams(resolver: TypeResolver): string[] { + const params: string[] = this.bases.map(b => resolver.resolve(b)); + + params.push("jsii.compat.TypedDict"); + + return params; + } + +} + +class TypedDictProperty implements PythonBase { + + public readonly name: string; + + private readonly type: spec.TypeReference; + + constructor(name: string, type: spec.TypeReference) { + this.name = name; + this.type = type; + } + + get optional(): boolean { + return this.type.optional !== undefined ? this.type.optional : false; + } + + public emit(code: CodeMaker, resolver: TypeResolver) { + const resolvedType = resolver.resolve( + this.type, + { forwardReferences: false, ignoreOptional: true } + ); + code.line(`${this.name}: ${resolvedType}`); + } +} + +interface ClassOpts extends PythonTypeOpts { + abstract?: boolean; + interfaces?: spec.NamedTypeReference[]; +} + +class Class extends BasePythonClassType { + + private abstract: boolean; + private interfaces: spec.NamedTypeReference[]; + + constructor(name: string, fqn: string, opts: ClassOpts) { + super(name, fqn, opts); + + const { abstract = false, interfaces = [] } = opts; + + this.abstract = abstract; + this.interfaces = interfaces; + } + + public dependsOn(resolver: TypeResolver): PythonType[] { + const dependencies: PythonType[] = super.dependsOn(resolver); + const parent = resolver.getParent(this.fqn!); + + // We need to return any ifaces that are in the same module at the same level of + // nesting. + const seen: Set = new Set(); + for (const iface of this.interfaces) { + if (resolver.isInModule(iface)) { + // Given a iface, we need to locate the ifaces's parent that is the same + // as our parent, because we only care about dependencies that are at the + // same level of our own. + // TODO: We might need to recurse into our members to also find their + // dependencies. + let ifaceItem = resolver.getType(iface); + let ifaceParent = resolver.getParent(iface); + while (ifaceParent !== parent) { + ifaceItem = ifaceParent; + ifaceParent = resolver.getParent(ifaceItem.fqn!); + } + + if (!seen.has(ifaceItem.fqn!)) { + dependencies.push(ifaceItem); + seen.add(ifaceItem.fqn!); + } + } + } + + return dependencies; + } + + public emit(code: CodeMaker, resolver: TypeResolver) { + // First we emit our implments decorator + if (this.interfaces.length > 0) { + const interfaces: string[] = this.interfaces.map(b => resolver.resolve(b)); + code.line(`@jsii.implements(${interfaces.join(", ")})`); + } + + // Then we do our normal class logic for emitting our members. + super.emit(code, resolver); + + // Then, if our class is Abstract, we have to go through and redo all of + // this logic, except only emiting abstract methods and properties as non + // abstract, and subclassing our initial class. + if (this.abstract) { + resolver = this.fqn ? resolver.bind(this.fqn) : resolver; + code.openBlock(`class ${this.getProxyClassName()}(${this.name})`); + + // Filter our list of members to *only* be abstract members, and not any + // other types. + const abstractMembers = this.members.filter( + m => (m instanceof BaseMethod || m instanceof BaseProperty) && m.abstract + ); + if (abstractMembers.length > 0) { + for (const member of abstractMembers) { + member.emit(code, resolver, { renderAbstract: false }); + } + } else { + code.line("pass"); + } + + code.closeBlock(); + } + } + + protected emitPreamble(code: CodeMaker, _resolver: TypeResolver) { + if (this.abstract) { + code.line("@staticmethod"); + code.openBlock("def __jsii_proxy_class__()"); + code.line(`return ${this.getProxyClassName()}`); + code.closeBlock(); + } + } + + protected getClassParams(resolver: TypeResolver): string[] { + const params: string[] = this.bases.map(b => resolver.resolve(b)); + const metaclass: string = this.abstract ? "JSIIAbstractClass" : "JSIIMeta"; + + params.push(`metaclass=jsii.${metaclass}`); + params.push(`jsii_type="${this.fqn}"`); + + return params; + } + + private getProxyClassName(): string { + return `_${this.name}Proxy`; + } +} + +class StaticMethod extends BaseMethod { + protected readonly decorator?: string = "classmethod"; + protected readonly implicitParameter: string = "cls"; + protected readonly jsiiMethod: string = "sinvoke"; +} + +class Initializer extends BaseMethod { + protected readonly implicitParameter: string = "self"; + protected readonly jsiiMethod: string = "create"; + protected readonly classAsFirstParameter: boolean = true; + protected readonly returnFromJSIIMethod: boolean = false; +} + +class Method extends BaseMethod { + protected readonly implicitParameter: string = "self"; + protected readonly jsiiMethod: string = "invoke"; +} + +class StaticProperty extends BaseProperty { + protected readonly decorator: string = "classproperty"; + protected readonly implicitParameter: string = "cls"; + protected readonly jsiiGetMethod: string = "sget"; + protected readonly jsiiSetMethod: string = "sset"; +} + +class Property extends BaseProperty { + protected readonly decorator: string = "property"; + protected readonly implicitParameter: string = "self"; + protected readonly jsiiGetMethod: string = "get"; + protected readonly jsiiSetMethod: string = "set"; +} + +class Enum extends BasePythonClassType { + + public emit(code: CodeMaker, resolver: TypeResolver) { + code.line(`@jsii.enum(jsii_type="${this.fqn}")`); + return super.emit(code, resolver); + } + + protected getClassParams(_resolver: TypeResolver): string[] { + return ["enum.Enum"]; + } + +} + +class EnumMember implements PythonBase { + + public readonly name: string; + + private readonly value: string; + + constructor(name: string, value: string) { + this.name = name; + this.value = value; + } + + public emit(code: CodeMaker, _resolver: TypeResolver) { + code.line(`${this.name} = "${this.value}"`); + } +} + +class Namespace extends BasePythonClassType { + protected getClassParams(_resolver: TypeResolver): string[] { + return []; + } +} + +interface ModuleOpts { + assembly: spec.Assembly, + assemblyFilename: string; + loadAssembly: boolean; +} + +class Module implements PythonType { + + public readonly name: string; + public readonly fqn: string | null; + + private assembly: spec.Assembly; + private assemblyFilename: string; + private loadAssembly: boolean; + private members: PythonBase[]; + + constructor(name: string, fqn: string | null, opts: ModuleOpts) { + this.name = name; + this.fqn = fqn; + + this.assembly = opts.assembly; + this.assemblyFilename = opts.assemblyFilename; + this.loadAssembly = opts.loadAssembly; + this.members = []; + } + + public addMember(member: PythonBase) { + this.members.push(member); + } + + public emit(code: CodeMaker, resolver: TypeResolver) { + resolver = this.fqn ? resolver.bind(this.fqn, this.name) : 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 datetime"); + code.line("import enum"); + code.line("import typing"); + code.line(); + code.line("import jsii"); + code.line("import jsii.compat"); + code.line("import publication"); + code.line(); + code.line("from jsii.python import classproperty"); + + // Go over all of the modules that we need to import, and import them. + this.emitDependencyImports(code, resolver); + + // Determine if we need to write out the kernel load line. + if (this.loadAssembly) { + code.line( + `__jsii_assembly__ = jsii.JSIIAssembly.load(` + + `"${this.assembly.name}", ` + + `"${this.assembly.version}", ` + + `__name__, ` + + `"${this.assemblyFilename}")` + ); + } + + // Emit all of our members. + for (const member of sortMembers(this.members, resolver)) { + member.emit(code, resolver); + } + + // Whatever names we've exported, we'll write out our __all__ that lists them. + const exportedMembers = this.members.map(m => `"${m.name}"`); + if (this.loadAssembly) { + exportedMembers.push(`"__jsii_assembly__"`); + } + code.line(`__all__ = [${exportedMembers.sort().join(", ")}]`); + + // Finally, 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()"); + } + + private emitDependencyImports(code: CodeMaker, _resolver: TypeResolver) { + const deps = Array.from( + new Set([ + ...Object.keys(this.assembly.dependencies || {}).map(d => toPythonModuleName(d)), + ]) + ); + + for (const [idx, moduleName] of deps.sort().entries()) { + // If this our first dependency, add a blank line to format our imports + // slightly nicer. + if (idx === 0) { + code.line(); + } + + code.line(`import ${moduleName}`); + } + } +} + +interface PackageData { + filename: string; + data: string | null; +} + +class Package { + + public readonly name: string; + public readonly version: string; + public readonly metadata: spec.Assembly; + + private modules: Map; + private data: Map; + + constructor(name: string, version: string, metadata: spec.Assembly) { + this.name = name; + this.version = version; + this.metadata = metadata; + + this.modules = new Map(); + this.data = new Map(); + } + + public addModule(module: Module) { + this.modules.set(module.name, module); + } + + public addData(module: Module, filename: string, data: string | null) { + if (!this.data.has(module.name)) { + this.data.set(module.name, new Array()); + } + + this.data.get(module.name)!.push({filename, data}); + } + + public write(code: CodeMaker, resolver: TypeResolver) { + const modules = [...this.modules.values()].sort((a, b) => a.name.localeCompare(b.name)); + + // Iterate over all of our modules, and write them out to disk. + for (const mod of modules) { + const filename = path.join("src", pythonModuleNameToFilename(mod.name), "__init__.py"); + + code.openFile(filename); + mod.emit(code, resolver); + code.closeFile(filename); + } + + // Handle our package data. + const packageData: {[key: string]: string[]} = {}; + for (const [mod, pdata] of this.data) { + for (const data of pdata) { + if (data.data != null) { + const filepath = path.join("src", pythonModuleNameToFilename(mod), data.filename); + + code.openFile(filepath); + code.line(data.data); + code.closeFile(filepath); + } + } + + packageData[mod] = pdata.map(pd => pd.filename); + } + + // Compute our list of dependencies + const dependencies: string[] = []; + const expectedDeps = this.metadata.dependencies || {}; + for (const depName of Object.keys(expectedDeps)) { + const depInfo = expectedDeps[depName]; + if (depInfo.peer) { + // We need to figure out what our version range is. + // Basically, if it starts with Zero we want to restrict things to + // ~=X.Y.Z. If it does not start with zero, then we want to do ~=X.Y,>=X.Y.Z. + const versionParts = depInfo.version.split("."); + let versionSpecifier: string; + if (versionParts[0] === "0") { + versionSpecifier = `~=${versionParts.slice(0, 3).join(".")}`; + } else { + versionSpecifier = `~=${versionParts.slice(0, 2).join(".")},>=${versionParts.slice(0, 3).join(".")}`; + } + + dependencies.push(`${toPythonPackageName(depName)}${versionSpecifier}`); + } + } + + code.openFile("README.md"); + code.line(this.metadata.readme !== undefined ? this.metadata.readme.markdown : ""); + code.closeFile("README.md"); + + const setupKwargs = { + name: this.name, + version: this.version, + description: this.metadata.description, + url: this.metadata.homepage, + long_description_content_type: "text/markdown", + author: this.metadata.author.name + ( + this.metadata.author.email !== undefined ? "<" + this.metadata.author.email + ">" : "" + ), + project_urls: { + Source: this.metadata.repository.url, + }, + package_dir: {"": "src"}, + packages: modules.map(m => m.name), + package_data: packageData, + python_requires: ">=3.6", + install_requires: ["jsii", "publication>=0.0.3"].concat(dependencies), + }; + + // We Need a setup.py to make this Package, actually a Package. + // TODO: + // - License + // - Classifiers + code.openFile("setup.py"); + code.line("import json"); + code.line("import setuptools"); + code.line(); + code.line('kwargs = json.loads("""'); + code.line(JSON.stringify(setupKwargs, null, 4)); + code.line('""")'); + code.line(); + code.openBlock("with open('README.md') as fp"); + code.line("kwargs['long_description'] = fp.read()"); + code.closeBlock(); + code.line(); + code.line("setuptools.setup(**kwargs)"); + code.closeFile("setup.py"); + + // Because we're good citizens, we're going to go ahead and support pyproject.toml + // as well. + // TODO: Might be easier to just use a TOML library to write this out. + code.openFile("pyproject.toml"); + code.line("[build-system]"); + code.line('requires = ["setuptools >= 38.6.0", "wheel >= 0.31.0"]'); + code.line('build-backend = "setuptools.build_meta"'); + code.closeFile("pyproject.toml"); + + // We also need to write out a MANIFEST.in to ensure that all of our required + // files are included. + code.openFile("MANIFEST.in"); + code.line("include pyproject.toml"); + code.closeFile("MANIFEST.in"); + } +} + +interface TypeResolverOpts { + forwardReferences?: boolean; + ignoreOptional?: boolean; +} + +class TypeResolver { + + private readonly types: Map; + private boundTo?: string; + private readonly stdTypesRe = new RegExp("^(datetime\\.datetime|typing\\.[A-Z][a-z]+|jsii\\.Number)$"); + private readonly boundRe: RegExp; + private readonly moduleName?: string; + private readonly moduleRe: RegExp; + + constructor(types: Map, boundTo?: string, moduleName?: string) { + this.types = types; + this.moduleName = moduleName; + this.boundTo = boundTo !== undefined ? this.toPythonFQN(boundTo) : boundTo; + + if (this.moduleName !== undefined) { + this.moduleRe = new RegExp(`^(${escapeStringRegexp(this.moduleName)})\\.(.+)$`); + } + + if (this.boundTo !== undefined) { + this.boundRe = new RegExp(`^(${escapeStringRegexp(this.boundTo)})\\.(.+)$`); + } + } + + public bind(fqn: string, moduleName?: string): TypeResolver { + return new TypeResolver( + this.types, + fqn, + moduleName !== undefined ? moduleName : this.moduleName, + ); + } + + public isInModule(typeRef: spec.NamedTypeReference | string): boolean { + const pythonType = typeof typeRef !== "string" ? this.toPythonFQN(typeRef.fqn) : typeRef; + return this.moduleRe.test(pythonType); + } + + public isInNamespace(typeRef: spec.NamedTypeReference | string): boolean { + const pythonType = typeof typeRef !== "string" ? this.toPythonFQN(typeRef.fqn) : typeRef; + return this.boundRe.test(pythonType); + } + + public getParent(typeRef: spec.NamedTypeReference | string): PythonType { + const fqn = typeof typeRef !== "string" ? typeRef.fqn : typeRef; + const [, parentFQN] = fqn.match(/^(.+)\.[^\.]+$/) as string[]; + const parent = this.types.get(parentFQN); + + if (parent === undefined) { + throw new Error(`Could not find parent: ${parentFQN}`); + } + + return parent; + } + + public getType(typeRef: spec.NamedTypeReference): PythonType { + const type = this.types.get(typeRef.fqn); + + if (type === undefined) { + throw new Error(`Could not locate type: "${typeRef.fqn}"`); + } + + return type; + } + + public resolve( + typeRef: spec.TypeReference, + opts: TypeResolverOpts = { forwardReferences: true, ignoreOptional: false }): string { + const { + forwardReferences = true, + } = opts; + + // First, we need to resolve our given type reference into the Python type. + let pythonType = this.toPythonType(typeRef, opts.ignoreOptional); + + // If we split our types by any of the "special" characters that can't appear in + // identifiers (like "[],") then we will get a list of all of the identifiers, + // no matter how nested they are. The downside is we might get trailing/leading + // spaces or empty items so we'll need to trim and filter this list. + const types = pythonType.split(/[\[\],]/).map((s: string) => s.trim()).filter(s => s !== ""); + + for (const innerType of types) { + // Built in types do not need formatted in any particular way. + if (PYTHON_BUILTIN_TYPES.indexOf(innerType) > -1) { + continue; + } + + // These are not exactly built in types, but they're also not types that + // this resolver has to worry about. + if (this.stdTypesRe.test(innerType)) { + continue; + } + + // If our resolver is bound to the same module as the type we're trying to + // resolve, then we'll implement the needed logic to use module relative naming + // and to handle forward references (if needed). + if (this.isInModule(innerType)) { + // If our type is part of the same namespace, then we'll return a namespace + // relative name, otherwise a module relative name. + let typeName: string; + if (this.isInNamespace(innerType)) { + [, , typeName] = innerType.match(this.boundRe) as string[]; + } else { + [, , typeName] = innerType.match(this.moduleRe) as string[]; + } + + // This re will look for the entire type, boxed by either the start/end of + // a string, a comma, a space, a quote, or open/closing brackets. This will + // ensure that we only match whole type names, and not partial ones. + const re = new RegExp('((?:^|[[,\\s])"?)' + innerType + '("?(?:$|[\\],\\s]))'); + + // We need to handle forward references, our caller knows if we're able to + // use them in the current context or not, so if not, we'll wrap our forward + // reference in quotes. + // We have special logic here for checking if our thing is actually *in* + // our module, behond what we've already done, because our other logic will + // work for submodules, but this can't. + if (!forwardReferences && this.isInModule(innerType)) { + pythonType = pythonType.replace(re, `$1"${innerType}"$2`); + } + + // Now that we've gotten forward references out of the way, we will want + // to replace the entire type string, with just the type portion. + pythonType = pythonType.replace(re, `$1${typeName}$2`); + } + } + + return pythonType; + } + + private toPythonType(typeRef: spec.TypeReference, ignoreOptional?: boolean): string { + let pythonType: string; + + // Get the underlying python type. + if (spec.isPrimitiveTypeReference(typeRef)) { + pythonType = this.toPythonPrimitive(typeRef.primitive); + } else if (spec.isCollectionTypeReference(typeRef)) { + pythonType = this.toPythonCollection(typeRef); + } else if (spec.isNamedTypeReference(typeRef)) { + pythonType = this.toPythonFQN(typeRef.fqn); + } else if (typeRef.union) { + const types = new Array(); + for (const subtype of typeRef.union.types) { + types.push(this.toPythonType(subtype)); + } + pythonType = `typing.Union[${types.join(", ")}]`; + } else { + throw new Error("Invalid type reference: " + JSON.stringify(typeRef)); + } + + // If our type is Optional, then we'll wrap our underlying type with typing.Optional + // However, if we're not respecting optionals, then we'll just skip over this. + // We explicitly don't emit this when our type is typing.Any, because typing.Any + // already implied that None is an accepted type. + // See: https://github.com/awslabs/jsii/issues/284 + if (!ignoreOptional && typeRef.optional && pythonType !== "typing.Any") { + pythonType = `typing.Optional[${pythonType}]`; + } + + return pythonType; + } + + private toPythonPrimitive(primitive: spec.PrimitiveType): string { + switch (primitive) { + case spec.PrimitiveType.Boolean: return "bool"; + case spec.PrimitiveType.Date: return "datetime.datetime"; + case spec.PrimitiveType.Json: return "typing.Mapping[typing.Any, typing.Any]"; + case spec.PrimitiveType.Number: return "jsii.Number"; + case spec.PrimitiveType.String: return "str"; + case spec.PrimitiveType.Any: return "typing.Any"; + default: + throw new Error("Unknown primitive type: " + primitive); + } + } + + private toPythonCollection(ref: spec.CollectionTypeReference): string { + const elementPythonType = this.toPythonType(ref.collection.elementtype); + switch (ref.collection.kind) { + case spec.CollectionKind.Array: return `typing.List[${elementPythonType}]`; + case spec.CollectionKind.Map: return `typing.Mapping[str,${elementPythonType}]`; + default: + throw new Error(`Unsupported collection kind: ${ref.collection.kind}`); + } + } + + private toPythonFQN(fqn: string): string { + const [, modulePart, typePart] = fqn.match(/^((?:[^A-Z\.][^\.]+\.?)+)(?:\.([A-Z].+))?$/) as string[]; + const fqnParts: string[] = [toPythonModuleName(modulePart)]; + + if (typePart) { + fqnParts.push(typePart.split(".").map(cur => toPythonIdentifier(cur)).join(".")); + } + + return fqnParts.join("."); + } +} + +class PythonGenerator extends Generator { + + private package: Package; + private types: Map; + + constructor(options = new GeneratorOptions()) { + super(options); + + this.code.openBlockFormatter = s => `${s}:`; + this.code.closeBlockFormatter = _s => ""; + + this.types = new Map(); + } + + protected getAssemblyOutputDir(assm: spec.Assembly) { + return path.join("src", pythonModuleNameToFilename(this.getAssemblyModuleName(assm))); + } + + protected onBeginAssembly(assm: spec.Assembly, _fingerprint: boolean) { + this.package = new Package( + toPythonPackageName(assm.name), + assm.version, + assm, + ); + + const assemblyModule = new Module( + this.getAssemblyModuleName(assm), + null, + { assembly: assm, + assemblyFilename: this.getAssemblyFileName(), + loadAssembly: false }, + ); + + this.package.addModule(assemblyModule); + this.package.addData(assemblyModule, this.getAssemblyFileName(), null); + } + + protected onEndAssembly(_assm: spec.Assembly, _fingerprint: boolean) { + this.package.write(this.code, new TypeResolver(this.types)); + } + + protected onBeginNamespace(ns: string) { + // If we're generating the Namespace that matches our assembly, then we'll + // actually be generating a module, otherwise we'll generate a class within + // that module. + if (ns === this.assembly.name) { + const module = new Module( + toPythonModuleName(ns), + ns, + { assembly: this.assembly, + assemblyFilename: this.getAssemblyFileName(), + loadAssembly: ns === this.assembly.name }, + ); + + this.package.addModule(module); + // Add our py.typed marker to ensure that gradual typing works for this + // package. + this.package.addData(module, "py.typed", ""); + + this.types.set(ns, module); + } else { + // This should be temporary code, which can be removed and turned into an + // error case once https://github.com/awslabs/jsii/issues/270 and + // https://github.com/awslabs/jsii/issues/283 are solved. + this.addPythonType( + new Namespace( + toPythonIdentifier(ns.replace(/^.+\.([^\.]+)$/, "$1")), + ns, + {}, + ), + ); + } + } + + protected onBeginClass(cls: spec.ClassType, abstract: boolean | undefined) { + const klass = new Class( + toPythonIdentifier(cls.name), + cls.fqn, + { abstract, bases: cls.base !== undefined ? [cls.base] : [], interfaces: cls.interfaces } + ); + + if (cls.initializer !== undefined) { + const { parameters = [] } = cls.initializer; + + klass.addMember( + new Initializer( + "__init__", + undefined, + parameters, + cls.initializer.returns, + { liftedProp: this.getliftedProp(cls.initializer), parent: cls }, + ) + ); + } + + this.addPythonType(klass); + } + + protected onStaticMethod(cls: spec.ClassType, method: spec.Method) { + const { parameters = [] } = method; + + this.getPythonType(cls.fqn).addMember( + new StaticMethod( + toPythonMethodName(method.name!), + method.name, + parameters, + method.returns, + { abstract: method.abstract, liftedProp: this.getliftedProp(method) }, + ) + ); + } + + protected onStaticProperty(cls: spec.ClassType, prop: spec.Property) { + this.getPythonType(cls.fqn).addMember( + new StaticProperty( + toPythonPropertyName(prop.name, prop.const), + prop.name, + prop.type, + { abstract: prop.abstract, immutable: prop.immutable }, + ) + ); + } + + protected onMethod(cls: spec.ClassType, method: spec.Method) { + const { parameters = [] } = method; + + this.getPythonType(cls.fqn).addMember( + new Method( + toPythonMethodName(method.name!, method.protected), + method.name, + parameters, + method.returns, + { abstract: method.abstract, liftedProp: this.getliftedProp(method) }, + ) + ); + } + + protected onProperty(cls: spec.ClassType, prop: spec.Property) { + this.getPythonType(cls.fqn).addMember( + new Property( + toPythonPropertyName(prop.name, prop.const, prop.protected), + prop.name, + prop.type, + { abstract: prop.abstract, immutable: prop.immutable }, + ) + ); + } + + protected onUnionProperty(cls: spec.ClassType, prop: spec.Property, _union: spec.UnionTypeReference) { + this.onProperty(cls, prop); + } + + protected onBeginInterface(ifc: spec.InterfaceType) { + let iface: Interface | TypedDict; + + if (ifc.datatype) { + iface = new TypedDict( + toPythonIdentifier(ifc.name), + ifc.fqn, + { bases: ifc.interfaces }, + ); + } else { + iface = new Interface( + toPythonIdentifier(ifc.name), + ifc.fqn, + { bases: ifc.interfaces }, + ); + } + + this.addPythonType(iface); + } + + protected onEndInterface(_ifc: spec.InterfaceType) { return; } + + protected onInterfaceMethod(ifc: spec.InterfaceType, method: spec.Method) { + const { parameters = [] } = method; + + this.getPythonType(ifc.fqn).addMember( + new InterfaceMethod( + toPythonMethodName(method.name!, method.protected), + method.name, + parameters, + method.returns, + { liftedProp: this.getliftedProp(method) }, + ) + ); + } + + protected onInterfaceProperty(ifc: spec.InterfaceType, prop: spec.Property) { + let ifaceProperty: InterfaceProperty | TypedDictProperty; + + if (ifc.datatype) { + ifaceProperty = new TypedDictProperty( + toPythonIdentifier(prop.name), + prop.type, + ); + } else { + ifaceProperty = new InterfaceProperty( + toPythonPropertyName(prop.name, prop.const, prop.protected), + prop.name, + prop.type, + { immutable: prop.immutable }, + ); + } + + this.getPythonType(ifc.fqn).addMember(ifaceProperty); + } + + protected onBeginEnum(enm: spec.EnumType) { + this.addPythonType(new Enum(toPythonIdentifier(enm.name), enm.fqn, {})); + } + + protected onEnumMember(enm: spec.EnumType, member: spec.EnumMember) { + this.getPythonType(enm.fqn).addMember( + new EnumMember( + toPythonIdentifier(member.name), + member.name, + ) + ); + } + + protected onInterfaceMethodOverload(_ifc: spec.InterfaceType, _overload: spec.Method, _originalMethod: spec.Method) { + throw new Error("Unhandled Type: InterfaceMethodOverload"); + } + + protected onMethodOverload(_cls: spec.ClassType, _overload: spec.Method, _originalMethod: spec.Method) { + throw new Error("Unhandled Type: MethodOverload"); + } + + protected onStaticMethodOverload(_cls: spec.ClassType, _overload: spec.Method, _originalMethod: spec.Method) { + throw new Error("Unhandled Type: StaticMethodOverload"); + } + + private getAssemblyModuleName(assm: spec.Assembly): string { + return `${toPythonModuleName(assm.name)}._jsii`; + } + + private getParentFQN(fqn: string): string { + const m = fqn.match(/^(.+)\.[^\.]+$/); + + if (m === null) { + throw new Error(`Could not determine parent FQN of: ${fqn}`); + } + + return m[1]; + } + + private getParent(fqn: string): PythonType { + return this.getPythonType(this.getParentFQN(fqn)); + } + + private getPythonType(fqn: string): PythonType { + const type = this.types.get(fqn); + + if (type === undefined) { + throw new Error(`Could not locate type: "${fqn}"`); + } + + return type; + } + + private addPythonType(type: PythonType) { + if (type.fqn === null) { + throw new Error("Cannot add a Python type without a FQN."); + } + + this.getParent(type.fqn).addMember(type); + this.types.set(type.fqn, type); + } + + private getliftedProp(method: spec.Method): spec.InterfaceType | undefined { + // If there are parameters to this method, and if the last parameter's type is + // a datatype interface, then we want to lift the members of that last paramter + // as keyword arguments to this function. + if (method.parameters !== undefined && method.parameters.length >= 1) { + const lastParameter = method.parameters.slice(-1)[0]; + if (spec.isNamedTypeReference(lastParameter.type)) { + const lastParameterType = this.findType(lastParameter.type.fqn); + if (spec.isInterfaceType(lastParameterType) && lastParameterType.datatype) { + return lastParameterType; + } + } + } + + return undefined; + } +} diff --git a/packages/jsii-pacmak/package.json b/packages/jsii-pacmak/package.json index 761c0cd88a..170a5faeec 100644 --- a/packages/jsii-pacmak/package.json +++ b/packages/jsii-pacmak/package.json @@ -22,6 +22,7 @@ "dependencies": { "clone": "^2.1.2", "codemaker": "^0.7.15", + "escape-string-regexp": "^1.0.5", "fs-extra": "^7.0.1", "jsii-spec": "^0.7.15", "spdx-license-list": "^5.0.0", @@ -31,6 +32,7 @@ "devDependencies": { "@scope/jsii-calc-lib": "^0.7.15", "@types/clone": "^0.1.30", + "@types/escape-string-regexp": "^1.0.0", "@types/fs-extra": "^5.0.5", "@types/node": "^8.10.43", "@types/nodeunit": "^0.0.30", diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii index c8d62b39f7..1911171cc8 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii @@ -2932,6 +2932,113 @@ ], "name": "PublicClass" }, + "jsii-calc.PythonReservedWords": { + "assembly": "jsii-calc", + "fqn": "jsii-calc.PythonReservedWords", + "initializer": { + "initializer": true + }, + "kind": "class", + "methods": [ + { + "name": "and" + }, + { + "name": "as" + }, + { + "name": "assert" + }, + { + "name": "async" + }, + { + "name": "await" + }, + { + "name": "break" + }, + { + "name": "class" + }, + { + "name": "continue" + }, + { + "name": "def" + }, + { + "name": "del" + }, + { + "name": "elif" + }, + { + "name": "else" + }, + { + "name": "except" + }, + { + "name": "finally" + }, + { + "name": "for" + }, + { + "name": "from" + }, + { + "name": "global" + }, + { + "name": "if" + }, + { + "name": "import" + }, + { + "name": "in" + }, + { + "name": "is" + }, + { + "name": "lambda" + }, + { + "name": "nonlocal" + }, + { + "name": "not" + }, + { + "name": "or" + }, + { + "name": "pass" + }, + { + "name": "raise" + }, + { + "name": "return" + }, + { + "name": "try" + }, + { + "name": "while" + }, + { + "name": "with" + }, + { + "name": "yield" + } + ], + "name": "PythonReservedWords" + }, "jsii-calc.ReferenceEnumFromScopedPackage": { "assembly": "jsii-calc", "docs": { @@ -3842,5 +3949,5 @@ } }, "version": "0.7.15", - "fingerprint": "P2Hdg9vVBT0QqTFN71VaRnkkGvJ74jnUBL7BduuDsjU=" + "fingerprint": "IWSOEhdZzuvrss5K2WBjZCawXayV13yCAKTj/kJ9+mo=" } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/PythonReservedWords.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/PythonReservedWords.cs new file mode 100644 index 0000000000..d1b8b845d6 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/PythonReservedWords.cs @@ -0,0 +1,212 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + [JsiiClass(typeof(PythonReservedWords), "jsii-calc.PythonReservedWords", "[]")] + public class PythonReservedWords : DeputyBase + { + public PythonReservedWords(): base(new DeputyProps(new object[]{})) + { + } + + protected PythonReservedWords(ByRefValue reference): base(reference) + { + } + + protected PythonReservedWords(DeputyProps props): base(props) + { + } + + [JsiiMethod("and", null, "[]")] + public virtual void And() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("as", null, "[]")] + public virtual void As() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("assert", null, "[]")] + public virtual void Assert() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("async", null, "[]")] + public virtual void Async() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("await", null, "[]")] + public virtual void Await() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("break", null, "[]")] + public virtual void Break() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("class", null, "[]")] + public virtual void Class() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("continue", null, "[]")] + public virtual void Continue() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("def", null, "[]")] + public virtual void Def() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("del", null, "[]")] + public virtual void Del() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("elif", null, "[]")] + public virtual void Elif() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("else", null, "[]")] + public virtual void Else() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("except", null, "[]")] + public virtual void Except() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("finally", null, "[]")] + public virtual void Finally() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("for", null, "[]")] + public virtual void For() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("from", null, "[]")] + public virtual void From() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("global", null, "[]")] + public virtual void Global() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("if", null, "[]")] + public virtual void If() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("import", null, "[]")] + public virtual void Import() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("in", null, "[]")] + public virtual void In() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("is", null, "[]")] + public virtual void Is() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("lambda", null, "[]")] + public virtual void Lambda() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("nonlocal", null, "[]")] + public virtual void Nonlocal() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("not", null, "[]")] + public virtual void Not() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("or", null, "[]")] + public virtual void Or() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("pass", null, "[]")] + public virtual void Pass() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("raise", null, "[]")] + public virtual void Raise() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("return", null, "[]")] + public virtual void Return() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("try", null, "[]")] + public virtual void Try() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("while", null, "[]")] + public virtual void While() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("with", null, "[]")] + public virtual void With() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("yield", null, "[]")] + public virtual void Yield() + { + InvokeInstanceVoidMethod(new object[]{}); + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/jsii-calc-0.7.15.tgz b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/jsii-calc-0.7.15.tgz index eef7587bf20015975a43efa48f8cd0487c889042..ed86b811e526056a84c870825fa150c655b7fcf4 100644 GIT binary patch literal 72770 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 AcmMzZ literal 116 zcmYMs%?X7-3`OC+Ron)&78f=UojYV8?~P<4TE0IZE)NI3(PW`kOLXMw2qk!|T!IO| qnl>Xsd=|5Ax?Ugf#tzj=_aIUw75?6;ll2h#CUgreKfGUIl diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java index c442f0c0ab..09aa4177c1 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java @@ -80,6 +80,7 @@ protected Class resolveClass(final String fqn) throws ClassNotFoundException case "jsii-calc.Polymorphism": return software.amazon.jsii.tests.calculator.Polymorphism.class; case "jsii-calc.Power": return software.amazon.jsii.tests.calculator.Power.class; case "jsii-calc.PublicClass": return software.amazon.jsii.tests.calculator.PublicClass.class; + case "jsii-calc.PythonReservedWords": return software.amazon.jsii.tests.calculator.PythonReservedWords.class; case "jsii-calc.ReferenceEnumFromScopedPackage": return software.amazon.jsii.tests.calculator.ReferenceEnumFromScopedPackage.class; case "jsii-calc.ReturnsPrivateImplementationOfInterface": return software.amazon.jsii.tests.calculator.ReturnsPrivateImplementationOfInterface.class; case "jsii-calc.RuntimeTypeChecking": return software.amazon.jsii.tests.calculator.RuntimeTypeChecking.class; diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/PythonReservedWords.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/PythonReservedWords.java new file mode 100644 index 0000000000..3d46980d54 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/PythonReservedWords.java @@ -0,0 +1,141 @@ +package software.amazon.jsii.tests.calculator; + +@javax.annotation.Generated(value = "jsii-pacmak") +@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.PythonReservedWords") +public class PythonReservedWords extends software.amazon.jsii.JsiiObject { + protected PythonReservedWords(final software.amazon.jsii.JsiiObject.InitializationMode mode) { + super(mode); + } + public PythonReservedWords() { + super(software.amazon.jsii.JsiiObject.InitializationMode.Jsii); + software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this); + } + + public void and() { + this.jsiiCall("and", Void.class); + } + + public void as() { + this.jsiiCall("as", Void.class); + } + + public void assert_() { + this.jsiiCall("assert", Void.class); + } + + public void async() { + this.jsiiCall("async", Void.class); + } + + public void await() { + this.jsiiCall("await", Void.class); + } + + public void break_() { + this.jsiiCall("break", Void.class); + } + + public void class_() { + this.jsiiCall("class", Void.class); + } + + public void continue_() { + this.jsiiCall("continue", Void.class); + } + + public void def() { + this.jsiiCall("def", Void.class); + } + + public void del() { + this.jsiiCall("del", Void.class); + } + + public void elif() { + this.jsiiCall("elif", Void.class); + } + + public void else_() { + this.jsiiCall("else", Void.class); + } + + public void except() { + this.jsiiCall("except", Void.class); + } + + public void finally_() { + this.jsiiCall("finally", Void.class); + } + + public void for_() { + this.jsiiCall("for", Void.class); + } + + public void from() { + this.jsiiCall("from", Void.class); + } + + public void global() { + this.jsiiCall("global", Void.class); + } + + public void if_() { + this.jsiiCall("if", Void.class); + } + + public void import_() { + this.jsiiCall("import", Void.class); + } + + public void in() { + this.jsiiCall("in", Void.class); + } + + public void is() { + this.jsiiCall("is", Void.class); + } + + public void lambda() { + this.jsiiCall("lambda", Void.class); + } + + public void nonlocal() { + this.jsiiCall("nonlocal", Void.class); + } + + public void not() { + this.jsiiCall("not", Void.class); + } + + public void or() { + this.jsiiCall("or", Void.class); + } + + public void pass() { + this.jsiiCall("pass", Void.class); + } + + public void raise() { + this.jsiiCall("raise", Void.class); + } + + public void return_() { + this.jsiiCall("return", Void.class); + } + + public void try_() { + this.jsiiCall("try", Void.class); + } + + public void while_() { + this.jsiiCall("while", Void.class); + } + + public void with() { + this.jsiiCall("with", Void.class); + } + + public void yield() { + this.jsiiCall("yield", Void.class); + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/resources/software/amazon/jsii/tests/calculator/jsii-calc@0.7.15.jsii.tgz b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/resources/software/amazon/jsii/tests/calculator/jsii-calc@0.7.15.jsii.tgz index eef7587bf20015975a43efa48f8cd0487c889042..ed86b811e526056a84c870825fa150c655b7fcf4 100644 GIT binary patch literal 72770 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 AcmMzZ literal 116 zcmYMs%?X7-3`OC+Ron)&78f=UojYV8?~P<4TE0IZE)NI3(PW`kOLXMw2qk!|T!IO| qnl>Xsd=|5Ax?Ugf#tzj=_aIUw75?6;ll2h#CUgreKfGUIl diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/js/jsii-calc@0.7.15.jsii.tgz b/packages/jsii-pacmak/test/expected.jsii-calc/js/jsii-calc@0.7.15.jsii.tgz index eef7587bf20015975a43efa48f8cd0487c889042..ed86b811e526056a84c870825fa150c655b7fcf4 100644 GIT binary patch literal 72770 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 AcmMzZ literal 116 zcmYMs%?X7-3`OC+Ron)&78f=UojYV8?~P<4TE0IZE)NI3(PW`kOLXMw2qk!|T!IO| qnl>Xsd=|5Ax?Ugf#tzj=_aIUw75?6;ll2h#CUgreKfGUIl diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst b/packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst index 9e2e502394..79ad16e900 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst +++ b/packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst @@ -3809,6 +3809,162 @@ PublicClass +PythonReservedWords +^^^^^^^^^^^^^^^^^^^ + +.. py:class:: PythonReservedWords() + + **Language-specific names:** + + .. tabs:: + + .. code-tab:: c# + + using Amazon.JSII.Tests.CalculatorNamespace; + + .. code-tab:: java + + import software.amazon.jsii.tests.calculator.PythonReservedWords; + + .. code-tab:: javascript + + const { PythonReservedWords } = require('jsii-calc'); + + .. code-tab:: typescript + + import { PythonReservedWords } from 'jsii-calc'; + + + + + .. py:method:: and() + + + + .. py:method:: as() + + + + .. py:method:: assert() + + + + .. py:method:: async() + + + + .. py:method:: await() + + + + .. py:method:: break() + + + + .. py:method:: class() + + + + .. py:method:: continue() + + + + .. py:method:: def() + + + + .. py:method:: del() + + + + .. py:method:: elif() + + + + .. py:method:: else() + + + + .. py:method:: except() + + + + .. py:method:: finally() + + + + .. py:method:: for() + + + + .. py:method:: from() + + + + .. py:method:: global() + + + + .. py:method:: if() + + + + .. py:method:: import() + + + + .. py:method:: in() + + + + .. py:method:: is() + + + + .. py:method:: lambda() + + + + .. py:method:: nonlocal() + + + + .. py:method:: not() + + + + .. py:method:: or() + + + + .. py:method:: pass() + + + + .. py:method:: raise() + + + + .. py:method:: return() + + + + .. py:method:: try() + + + + .. py:method:: while() + + + + .. py:method:: with() + + + + .. py:method:: yield() + + + ReferenceEnumFromScopedPackage ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/packages/jsii-python-runtime/.gitignore b/packages/jsii-python-runtime/.gitignore new file mode 100644 index 0000000000..6528982188 --- /dev/null +++ b/packages/jsii-python-runtime/.gitignore @@ -0,0 +1,12 @@ +src/jsii/_embedded +src/jsii/_metadata.json + +*.egg-info +dist/ +.env + +*.whl +*.tar.gz + +__pycache__ +.mypy_cache diff --git a/packages/jsii-python-runtime/MANIFEST.in b/packages/jsii-python-runtime/MANIFEST.in new file mode 100644 index 0000000000..8ab5288007 --- /dev/null +++ b/packages/jsii-python-runtime/MANIFEST.in @@ -0,0 +1,2 @@ +include pyproject.toml +include src/jsii/_metadata.json diff --git a/packages/jsii-python-runtime/bin/generate b/packages/jsii-python-runtime/bin/generate new file mode 100755 index 0000000000..4f9c1cbc9c --- /dev/null +++ b/packages/jsii-python-runtime/bin/generate @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +import json +import os +import os.path +import shutil + +EMBEDDED_SOURCE = "node_modules/jsii-runtime/webpack/" +EMBEDDED_INFO = "node_modules/jsii-runtime/package.json" + + +# Copy metadata over into the Python package +with open("package.json") as fp: + data = json.load(fp) + +with open(EMBEDDED_INFO) as fp: + embedded_data = json.load(fp) + +with open("src/jsii/_metadata.json", "w") as fp: + json.dump( + { + "version": data["version"], + "jsii-runtime": {"version": embedded_data["version"]}, + }, + fp, + ) + + +# Embed the JSII runtime into the Python Package. +for filename in os.listdir(EMBEDDED_SOURCE): + filepath = os.path.join(EMBEDDED_SOURCE, filename) + shutil.copy2(filepath, "src/jsii/_embedded/jsii") diff --git a/packages/jsii-python-runtime/bin/generate-calc b/packages/jsii-python-runtime/bin/generate-calc new file mode 100755 index 0000000000..6f71de2519 --- /dev/null +++ b/packages/jsii-python-runtime/bin/generate-calc @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +import os +import subprocess +import sys + +subprocess.run( + [ + "jsii-pacmak", + "-t", + "python", + "-o", + ".env/jsii-calc", + "--recurse", + "node_modules/jsii-calc", + ], + check=True, +) +subprocess.run( + [ + sys.executable, + "-m", + "pip", + "install", + "--force-reinstall", + "--upgrade", + "--find-links", + os.path.abspath("."), + "--find-links", + os.path.abspath(".env/jsii-calc/python"), + "jsii-calc", + ], + check=True, +) diff --git a/packages/jsii-python-runtime/mypy.ini b/packages/jsii-python-runtime/mypy.ini new file mode 100644 index 0000000000..976ba02946 --- /dev/null +++ b/packages/jsii-python-runtime/mypy.ini @@ -0,0 +1,2 @@ +[mypy] +ignore_missing_imports = True diff --git a/packages/jsii-python-runtime/package.json b/packages/jsii-python-runtime/package.json new file mode 100644 index 0000000000..f677c0bb38 --- /dev/null +++ b/packages/jsii-python-runtime/package.json @@ -0,0 +1,29 @@ +{ + "name": "jsii-python-runtime", + "version": "0.0.0", + "description": "Python client for jsii runtime", + "main": "index.js", + "scripts": { + "generate": "bin/generate", + "deps": "python -m venv .env && .env/bin/pip install pip==19.0.1 setuptools==40.7.0 wheel==0.32.3 && .env/bin/pip install -r requirements.txt", + "build": "npm run generate && npm run deps && .env/bin/python setup.py sdist -d . bdist_wheel -d . && rm -rf build", + "package": "package-python", + "test": ".env/bin/python bin/generate-calc && .env/bin/py.test -v --mypy" + }, + "dependencies": { + "jsii-build-tools": "^0.7.4", + "jsii-calc": "^0.7.13", + "jsii-pacmak": "^0.7.13", + "jsii-runtime": "^0.7.1" + }, + "repository": { + "type": "git", + "url": "git://github.com/awslabs/jsii" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0" +} diff --git a/packages/jsii-python-runtime/pyproject.toml b/packages/jsii-python-runtime/pyproject.toml new file mode 100644 index 0000000000..d1e6ae6e56 --- /dev/null +++ b/packages/jsii-python-runtime/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires = ["setuptools", "wheel"] diff --git a/packages/jsii-python-runtime/pytest.ini b/packages/jsii-python-runtime/pytest.ini new file mode 100644 index 0000000000..32fdfd80cf --- /dev/null +++ b/packages/jsii-python-runtime/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +norecursedirs = node_modules diff --git a/packages/jsii-python-runtime/requirements.txt b/packages/jsii-python-runtime/requirements.txt new file mode 100644 index 0000000000..69b20d4167 --- /dev/null +++ b/packages/jsii-python-runtime/requirements.txt @@ -0,0 +1,3 @@ +pytest +pytest-mypy +mypy_extensions diff --git a/packages/jsii-python-runtime/setup.py b/packages/jsii-python-runtime/setup.py new file mode 100644 index 0000000000..f5d6406fb8 --- /dev/null +++ b/packages/jsii-python-runtime/setup.py @@ -0,0 +1,27 @@ +import json +import setuptools + + +with open("src/jsii/_metadata.json") as fp: + metadata = json.load(fp) + + +setuptools.setup( + name="jsii", + version=metadata["version"], + package_dir={"": "src"}, + packages=setuptools.find_packages(where="src"), + package_data={ + "jsii": ["_metadata.json", "py.typed"], + "jsii._embedded.jsii": ["*.js", "*.js.map", "*.wasm"], + }, + install_requires=[ + "attrs", + "cattrs", + "importlib_resources ; python_version < '3.7'", + "python-dateutil", + "typing_extensions>=3.6.4", + "mypy_extensions>=0.4.0", + ], + python_requires=">=3.6", +) diff --git a/packages/jsii-python-runtime/src/jsii/__init__.py b/packages/jsii-python-runtime/src/jsii/__init__.py new file mode 100644 index 0000000000..14aba89137 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/__init__.py @@ -0,0 +1,57 @@ +from typing import Union + +from .__meta__ import __version__, __jsii_runtime_version__ +from ._runtime import ( + JSIIAssembly, + JSIIMeta, + JSIIAbstractClass, + enum, + data_type, + implements, + member, + kernel, +) + + +# JS doesn't have distinct float or integer types, but we do. So we'll define our own +# type alias that will allow either. +Number = Union[int, float] + + +# Alias our Kernel methods here, so that jsii. works. This will hide the fact +# that there is a kernel at all from our callers. +load = kernel.load +create = kernel.create +delete = kernel.delete +get = kernel.get +set = kernel.set +sget = kernel.sget +sset = kernel.sset +invoke = kernel.invoke +sinvoke = kernel.sinvoke +stats = kernel.stats + + +__all__ = [ + "__version__", + "__jsii_runtime_version__", + "JSIIAssembly", + "JSIIMeta", + "JSIIAbstractClass", + "Number", + "enum", + "data_type", + "implements", + "member", + "kernel", + "load", + "create", + "delete", + "get", + "set", + "sget", + "sset", + "invoke", + "sinvoke", + "stats", +] diff --git a/packages/jsii-python-runtime/src/jsii/__meta__.py b/packages/jsii-python-runtime/src/jsii/__meta__.py new file mode 100644 index 0000000000..38023f04e4 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/__meta__.py @@ -0,0 +1,12 @@ +import json + +from jsii._compat import importlib_resources + +# Load our version number and other metadata. +_meta = json.loads(importlib_resources.read_text("jsii", "_metadata.json")) + +__version__ = _meta["version"] +__jsii_runtime_version__ = _meta["jsii-runtime"]["version"] + + +__all__ = ["__version__", "__jsii_runtime_version__"] diff --git a/packages/jsii-python-runtime/src/jsii/_compat.py b/packages/jsii-python-runtime/src/jsii/_compat.py new file mode 100644 index 0000000000..27798ed192 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/_compat.py @@ -0,0 +1,11 @@ +# Internal Compatability Shims +import sys + + +if sys.version_info >= (3, 7): + import importlib.resources as importlib_resources +else: + import importlib_resources + + +__all__ = ["importlib_resources"] diff --git a/packages/jsii-python-runtime/src/jsii/_embedded/__init__.py b/packages/jsii-python-runtime/src/jsii/_embedded/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/jsii-python-runtime/src/jsii/_embedded/jsii/__init__.py b/packages/jsii-python-runtime/src/jsii/_embedded/jsii/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/jsii-python-runtime/src/jsii/_kernel/__init__.py b/packages/jsii-python-runtime/src/jsii/_kernel/__init__.py new file mode 100644 index 0000000000..30386dbe53 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/_kernel/__init__.py @@ -0,0 +1,224 @@ +import datetime +import inspect +import itertools + +from typing import Any, List, Optional, Type + +import functools + +import attr + +from jsii import _reference_map +from jsii._utils import Singleton +from jsii._kernel.providers import BaseKernel, ProcessKernel +from jsii._kernel.types import JSClass, Referenceable +from jsii._kernel.types import ( + EnumRef, + LoadRequest, + CreateRequest, + DeleteRequest, + GetRequest, + InvokeRequest, + SetRequest, + StaticGetRequest, + StaticInvokeRequest, + StaticSetRequest, + StatsRequest, + ObjRef, + Override, +) + + +_nothing = object() + + +class Object: + __jsii_type__ = "Object" + + +def _get_overides(klass: JSClass, obj: Any) -> List[Override]: + overrides = [] + + # We need to inspect each item in the MRO, until we get to our JSClass, at that + # point we'll bail, because those methods are not the overriden methods, but the + # "real" methods. + jsii_classes = [klass] + list( + itertools.chain.from_iterable( + (getattr(m, "__jsii_ifaces__", []) for m in type(obj).mro()) + ) + ) + for mro_klass in type(obj).mro(): + if mro_klass is klass: + break + + for name, item in mro_klass.__dict__.items(): + # We're only interested in things that also exist on the JSII class or + # interfaces, and which are themselves, jsii members. + for jsii_class in jsii_classes: + original = getattr(jsii_class, name, _nothing) + if original is not _nothing: + if inspect.isfunction(item) and hasattr(original, "__jsii_name__"): + overrides.append( + Override(method=original.__jsii_name__, cookie=name) + ) + elif inspect.isdatadescriptor(item) and hasattr( + getattr(original, "fget", None), "__jsii_name__" + ): + overrides.append( + Override(property_=original.fget.__jsii_name__, cookie=name) + ) + + return overrides + + +def _recursize_dereference(kernel, d): + if isinstance(d, dict): + return {k: _recursize_dereference(kernel, v) for k, v in d.items()} + elif isinstance(d, list): + return [_recursize_dereference(kernel, i) for i in d] + elif isinstance(d, ObjRef): + return _reference_map.resolve_reference(kernel, d) + elif isinstance(d, EnumRef): + return _recursize_dereference(kernel, d.ref)(d.member) + else: + return d + + +def _dereferenced(fn): + @functools.wraps(fn) + def wrapped(kernel, *args, **kwargs): + return _recursize_dereference(kernel, fn(kernel, *args, **kwargs)) + + return wrapped + + +# We need to recurse through our data structure and look for anything that the JSII +# doesn't natively handle. These items will be created as "Object" types in the JSII. +def _make_reference_for_native(kernel, d): + if isinstance(d, dict): + return {k: _make_reference_for_native(kernel, v) for k, v in d.items()} + elif isinstance(d, list): + return [_make_reference_for_native(kernel, i) for i in d] + elif hasattr(d, "__jsii_type__"): + return d + elif isinstance(d, (int, type(None), str, float, bool, datetime.datetime)): + return d + else: + d.__jsii__type__ = "Object" + kernel.create(Object, d) + _reference_map.register_reference(d) + return d + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class Statistics: + + object_count: int + + +class Kernel(metaclass=Singleton): + + # This class translates between the Pythonic interface for the kernel, and the + # Kernel Provider interface that maps more directly to the JSII Kernel interface. + # It currently only supports the idea of a process kernel provider, however it + # should be possible to move to other providers in the future. + + # TODO: We don't currently have any error handling, but we need to. This should + # probably live at the provider layer though, maybe with something catching + # them at this layer to translate it to something more Pythonic, depending + # on what the provider layer looks like. + + def __init__(self, provider_class: Type[BaseKernel] = ProcessKernel) -> None: + self.provider = provider_class() + + # TODO: Do we want to return anything from this method? Is the return value useful + # to anyone? + def load(self, name: str, version: str, tarball: str) -> None: + self.provider.load(LoadRequest(name=name, version=version, tarball=tarball)) + + # TODO: Is there a way to say that obj has to be an instance of klass? + def create( + self, klass: JSClass, obj: Any, args: Optional[List[Any]] = None + ) -> ObjRef: + if args is None: + args = [] + + overrides = _get_overides(klass, obj) + + obj.__jsii_ref__ = self.provider.create( + CreateRequest( + fqn=klass.__jsii_type__, + args=_make_reference_for_native(self, args), + overrides=overrides, + ) + ) + + return obj.__jsii_ref__ + + def delete(self, ref: ObjRef) -> None: + self.provider.delete(DeleteRequest(objref=ref)) + + @_dereferenced + def get(self, obj: Referenceable, property: str) -> Any: + return self.provider.get( + GetRequest(objref=obj.__jsii_ref__, property_=property) + ).value + + def set(self, obj: Referenceable, property: str, value: Any) -> None: + self.provider.set( + SetRequest( + objref=obj.__jsii_ref__, + property_=property, + value=_make_reference_for_native(self, value), + ) + ) + + @_dereferenced + def sget(self, klass: JSClass, property: str) -> Any: + return self.provider.sget( + StaticGetRequest(fqn=klass.__jsii_type__, property_=property) + ).value + + def sset(self, klass: JSClass, property: str, value: Any) -> None: + self.provider.sset( + StaticSetRequest( + fqn=klass.__jsii_type__, + property_=property, + value=_make_reference_for_native(self, value), + ) + ) + + @_dereferenced + def invoke( + self, obj: Referenceable, method: str, args: Optional[List[Any]] = None + ) -> Any: + if args is None: + args = [] + + return self.provider.invoke( + InvokeRequest( + objref=obj.__jsii_ref__, + method=method, + args=_make_reference_for_native(self, args), + ) + ).result + + @_dereferenced + def sinvoke( + self, klass: JSClass, method: str, args: Optional[List[Any]] = None + ) -> Any: + if args is None: + args = [] + + return self.provider.sinvoke( + StaticInvokeRequest( + fqn=klass.__jsii_type__, + method=method, + args=_make_reference_for_native(self, args), + ) + ).result + + def stats(self): + resp = self.provider.stats(StatsRequest()) + + return Statistics(object_count=resp.objectCount) diff --git a/packages/jsii-python-runtime/src/jsii/_kernel/providers/__init__.py b/packages/jsii-python-runtime/src/jsii/_kernel/providers/__init__.py new file mode 100644 index 0000000000..26ec99a6a2 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/_kernel/providers/__init__.py @@ -0,0 +1,5 @@ +from jsii._kernel.providers.base import BaseKernel +from jsii._kernel.providers.process import ProcessKernel + + +__all__ = ["BaseKernel", "ProcessKernel"] diff --git a/packages/jsii-python-runtime/src/jsii/_kernel/providers/base.py b/packages/jsii-python-runtime/src/jsii/_kernel/providers/base.py new file mode 100644 index 0000000000..27699379b4 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/_kernel/providers/base.py @@ -0,0 +1,71 @@ +import abc + +from typing import Optional + +from jsii._kernel.types import ( + LoadRequest, + LoadResponse, + CreateRequest, + CreateResponse, + GetRequest, + GetResponse, + InvokeRequest, + InvokeResponse, + DeleteRequest, + DeleteResponse, + SetRequest, + SetResponse, + StaticGetRequest, + StaticInvokeRequest, + StaticSetRequest, + StatsRequest, + StatsResponse, +) + + +class BaseKernel(metaclass=abc.ABCMeta): + + # The API provided by this Kernel is not very pythonic, however it is done to map + # this API as closely to the JSII runtime as possible. Higher level abstractions + # that layer ontop of the Kernel will provide a translation layer that make this + # much more Pythonic. + + @abc.abstractmethod + def load(self, request: LoadRequest) -> LoadResponse: + ... + + @abc.abstractmethod + def create(self, request: CreateRequest) -> CreateResponse: + ... + + @abc.abstractmethod + def get(self, request: GetRequest) -> GetResponse: + ... + + @abc.abstractmethod + def set(self, request: SetRequest) -> SetResponse: + ... + + @abc.abstractmethod + def sget(self, request: StaticGetRequest) -> GetResponse: + ... + + @abc.abstractmethod + def sset(self, request: StaticSetRequest) -> SetResponse: + ... + + @abc.abstractmethod + def invoke(self, request: InvokeRequest) -> InvokeResponse: + ... + + @abc.abstractmethod + def sinvoke(self, request: StaticInvokeRequest) -> InvokeResponse: + ... + + @abc.abstractmethod + def delete(self, request: DeleteRequest) -> DeleteResponse: + ... + + @abc.abstractmethod + def stats(self, request: Optional[StatsRequest] = None) -> StatsResponse: + ... diff --git a/packages/jsii-python-runtime/src/jsii/_kernel/providers/process.py b/packages/jsii-python-runtime/src/jsii/_kernel/providers/process.py new file mode 100644 index 0000000000..bc417af56b --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/_kernel/providers/process.py @@ -0,0 +1,343 @@ +import datetime +import contextlib +import enum +import importlib.machinery +import json +import os +import os.path +import platform +import subprocess +import tempfile + +from typing import TYPE_CHECKING, Type, Union, Mapping, Any, Optional + +import attr +import cattr # type: ignore +import dateutil.parser + +import jsii._embedded.jsii + +from jsii.__meta__ import __jsii_runtime_version__ +from jsii._compat import importlib_resources +from jsii._utils import memoized_property +from jsii._kernel.providers.base import BaseKernel +from jsii._kernel.types import ( + ObjRef, + EnumRef, + Override, + KernelRequest, + KernelResponse, + LoadRequest, + LoadResponse, + CreateRequest, + CreateResponse, + DeleteRequest, + DeleteResponse, + GetRequest, + GetResponse, + InvokeRequest, + InvokeResponse, + SetRequest, + SetResponse, + StaticGetRequest, + StaticInvokeRequest, + StaticSetRequest, + StatsRequest, + StatsResponse, +) +from jsii.errors import JSIIError, JavaScriptError + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class _HelloResponse: + + hello: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class _OkayResponse: + + # We could technically mark this as KernelResponse, because we know that + # it is going to be one of those. However, we can't disambiguate the different + # types because some of them have the same keys as each other, so the only way + # to know what type the result is expected to be, is to know what method is + # being called. Thus we'll expect Any here, and structure this value separately. + ok: Any + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class _ErrorRespose: + + error: str + stack: str + + +_ProcessResponse = Union[_OkayResponse, _ErrorRespose] +# Workaround for mypy#5354 +_ProcessResponse_R: Type[Any] +if not TYPE_CHECKING: + _ProcessResponse_R = _ProcessResponse + + +def _property_fix(asdict): + def unstructurer(value): + unstructured = asdict(value) + if "property_" in unstructured: + unstructured["property"] = unstructured.pop("property_") + + return unstructured + + return unstructurer + + +def _with_api_key(api_name, asdict): + def unstructurer(value): + unstructured = asdict(value) + unstructured["api"] = api_name + + return unstructured + + return unstructurer + + +def _with_reference(data, type_): + if not isinstance(data, type_): + return type_(ref=data.ref) + return data + + +def _unstructure_ref(value): + return {"$jsii.byref": value.ref} + + +def _unstructure_enum(member): + return {"$jsii.enum": f"{member.__class__.__jsii_type__}/{member.value}"} + + +def ohook(d): + if d.keys() == {"$jsii.byref"}: + return ObjRef(ref=d["$jsii.byref"]) + if d.keys() == {"$jsii.date"}: + return dateutil.parser.isoparse(d["$jsii.date"]) + if d.keys() == {"$jsii.enum"}: + ref, member = d["$jsii.enum"].rsplit("/", 1) + return EnumRef(ref=ObjRef(ref=ref + "@"), member=member) + return d + + +def jdefault(obj): + if hasattr(obj, "__jsii_ref__"): + return _unstructure_ref(obj.__jsii_ref__) + if isinstance(obj, datetime.datetime) and obj.tzinfo is not None: + return {"$jsii.date": obj.isoformat()} + elif isinstance(obj, datetime.datetime): + raise TypeError("Naive datetimes are not supported, please add a timzone.") + raise TypeError + + +class _NodeProcess: + def __init__(self): + self._serializer = cattr.Converter() + self._serializer.register_unstructure_hook(enum.Enum, _unstructure_enum) + self._serializer.register_unstructure_hook( + LoadRequest, + _with_api_key("load", self._serializer.unstructure_attrs_asdict), + ) + self._serializer.register_unstructure_hook( + CreateRequest, + _with_api_key("create", self._serializer.unstructure_attrs_asdict), + ) + self._serializer.register_unstructure_hook( + DeleteRequest, + _with_api_key("del", self._serializer.unstructure_attrs_asdict), + ) + self._serializer.register_unstructure_hook( + GetRequest, + _with_api_key( + "get", _property_fix(self._serializer.unstructure_attrs_asdict) + ), + ) + self._serializer.register_unstructure_hook( + StaticGetRequest, + _with_api_key( + "sget", _property_fix(self._serializer.unstructure_attrs_asdict) + ), + ) + self._serializer.register_unstructure_hook( + SetRequest, + _with_api_key( + "set", _property_fix(self._serializer.unstructure_attrs_asdict) + ), + ) + self._serializer.register_unstructure_hook( + StaticSetRequest, + _with_api_key( + "sset", _property_fix(self._serializer.unstructure_attrs_asdict) + ), + ) + self._serializer.register_unstructure_hook( + InvokeRequest, + _with_api_key("invoke", self._serializer.unstructure_attrs_asdict), + ) + self._serializer.register_unstructure_hook( + StaticInvokeRequest, + _with_api_key("sinvoke", self._serializer.unstructure_attrs_asdict), + ) + self._serializer.register_unstructure_hook( + StatsRequest, + _with_api_key("stats", self._serializer.unstructure_attrs_asdict), + ) + self._serializer.register_unstructure_hook( + Override, _property_fix(self._serializer.unstructure_attrs_asdict) + ) + self._serializer.register_unstructure_hook(ObjRef, _unstructure_ref) + self._serializer.register_structure_hook(ObjRef, _with_reference) + + self._ctx_stack = contextlib.ExitStack() + + def __del__(self): + self.stop() + + def _jsii_runtime(self): + # We have the JSII Runtime bundled with our package and we want to extract it, + # however if we just blindly use importlib.resources for this, we're going to + # have our jsii-runtime.js existing in a *different* temporary directory from + # the jsii-runtime.js.map, which we don't want. We can manually set up a + # temporary directory and extract our resources to there, but we don't want to + # pay the case of setting up a a temporary directory and shuffling bytes around + # in the common case where these files already exist on disk side by side. So + # we will check what loader the embedded package used, if it's a + # SourceFileLoader then we'll assume it's going to be on the filesystem and + # just use importlib.resources.path. + + # jsii-runtime.js MUST be the first item in this list. + filenames = ["jsii-runtime.js", "jsii-runtime.js.map", "mappings.wasm"] + + if isinstance( + jsii._embedded.jsii.__loader__, importlib.machinery.SourceFileLoader + ): + paths = [ + self._ctx_stack.enter_context( + importlib_resources.path(jsii._embedded.jsii, f) + ) + for f in filenames + ] + else: + tmpdir = self._ctx_stack.enter_context(tempfile.TemporaryDirectory()) + paths = [os.path.join(tmpdir, filename) for filename in filenames] + + for path, filename in zip(paths, filenames): + with open(path, "wb") as fp: + fp.write( + importlib_resources.read_binary(jsii._embedded.jsii, filename) + ) + + # Ensure that our jsii-runtime.js is the first entry in our paths, and that all + # of our paths, are in a commmon directory, and we didn't get them split into + # multiple directories somehow. + assert os.path.basename(paths[0]) == filenames[0] + assert os.path.commonpath(paths) == os.path.dirname(paths[0]) + + # Return our first path, which should be the path for jsii-runtime.js + return paths[0] + + def _next_message(self) -> Mapping[Any, Any]: + return json.loads(self._process.stdout.readline(), object_hook=ohook) + + def start(self): + environ = os.environ.copy() + environ["JSII_AGENT"] = f"Python/{platform.python_version()}" + + self._process = subprocess.Popen( + ["node", self._jsii_runtime()], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + env=environ, + ) + self.handshake() + + def stop(self): + # TODO: We can write an empty string here instead? + self._process.terminate() + + try: + self._process.wait(timeout=5) + except subprocess.TimeoutExpired: + self._process.kill() + + self._ctx_stack.close() + + def handshake(self): + # Get the version of the runtime that we're using. + resp: _HelloResponse = self._serializer.structure( + self._next_message(), _HelloResponse + ) + + # TODO: Replace with proper error. + assert ( + resp.hello == f"jsii-runtime@{__jsii_runtime_version__}" + ), f"Invalid JSII Runtime Version: {resp.hello!r}" + + def send( + self, request: KernelRequest, response_type: Type[KernelResponse] + ) -> KernelResponse: + req_dict = self._serializer.unstructure(request) + # TODO: We need a cleaner solution to this, ideally we'll get + # #python-attrs/attrs#429 fixed. + if "property_" in req_dict: + req_dict["property"] = req_dict.pop("property_") + data = json.dumps(req_dict, default=jdefault).encode("utf8") + + # Send our data, ensure that it is framed with a trailing \n + self._process.stdin.write(b"%b\n" % (data,)) + self._process.stdin.flush() + + resp: _ProcessResponse = self._serializer.structure( + self._next_message(), _ProcessResponse_R + ) + + if isinstance(resp, _OkayResponse): + return self._serializer.structure(resp.ok, response_type) + else: + raise JSIIError(resp.error) from JavaScriptError(resp.stack) + + +class ProcessKernel(BaseKernel): + @memoized_property + def _process(self) -> _NodeProcess: + process = _NodeProcess() + process.start() + + return process + + def load(self, request: LoadRequest) -> LoadResponse: + return self._process.send(request, LoadResponse) + + def create(self, request: CreateRequest) -> CreateResponse: + return self._process.send(request, CreateResponse) + + def get(self, request: GetRequest) -> GetResponse: + return self._process.send(request, GetResponse) + + def set(self, request: SetRequest) -> SetResponse: + return self._process.send(request, SetResponse) + + def sget(self, request: StaticGetRequest) -> GetResponse: + return self._process.send(request, GetResponse) + + def sset(self, request: StaticSetRequest) -> SetResponse: + return self._process.send(request, SetResponse) + + def invoke(self, request: InvokeRequest) -> InvokeResponse: + return self._process.send(request, InvokeResponse) + + def sinvoke(self, request: StaticInvokeRequest) -> InvokeResponse: + return self._process.send(request, InvokeResponse) + + def delete(self, request: DeleteRequest) -> DeleteResponse: + return self._process.send(request, DeleteResponse) + + def stats(self, request: Optional[StatsRequest] = None) -> StatsResponse: + if request is None: + request = StatsRequest() + return self._process.send(request, StatsResponse) diff --git a/packages/jsii-python-runtime/src/jsii/_kernel/types.py b/packages/jsii-python-runtime/src/jsii/_kernel/types.py new file mode 100644 index 0000000000..2a7d278596 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/_kernel/types.py @@ -0,0 +1,255 @@ +from typing import Union, List, Any, Optional, Mapping + +import attr + +from jsii.compat import Protocol + + +# TODO: +# - HelloResponse +# - OkayResponse +# - ErrorResponse + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class ObjRef: + + ref: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class EnumRef: + + ref: ObjRef + member: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class Override: + + method: Optional[str] = None + property_: Optional[str] = None + cookie: Optional[str] = None + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class LoadRequest: + + name: str + version: str + tarball: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class LoadResponse: + + assembly: str + types: int + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class CreateRequest: + + fqn: str + args: List[Any] = attr.Factory(list) + overrides: List[Override] = attr.Factory(list) + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class CreateResponse(ObjRef): + ... + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class DeleteRequest: + + objref: ObjRef + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class DeleteResponse: + ... + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class GetRequest: + + objref: ObjRef + property_: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class StaticGetRequest: + + fqn: str + property_: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class GetResponse: + + value: Any = None + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class StaticSetRequest: + + fqn: str + property_: str + value: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class SetRequest: + + objref: ObjRef + property_: str + value: Any + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class SetResponse: + ... + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class StaticInvokeRequest: + + fqn: str + method: str + args: Optional[List[Any]] = attr.Factory(list) + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class InvokeRequest: + + objref: ObjRef + method: str + args: Optional[List[Any]] = attr.Factory(list) + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class InvokeResponse: + + result: Any = None + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class BeginRequest: + + objref: ObjRef + method: str + args: Optional[List[Any]] = attr.Factory(list) + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class BeginResponse: + + promiseid: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class EndRequest: + + promiseid: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class EndResponse: + + result: Any + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class Callback: + + cbid: str + cookie: Optional[str] + invoke: Optional[InvokeRequest] + get: Optional[GetRequest] + set: Optional[SetRequest] + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class CallbacksRequest: + ... + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class CallbacksResponse: + + callbacks: List[Callback] + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class CompleteRequest: + + cbid: str + err: Optional[str] = None + result: Optional[Any] = None + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class CompleteResponse: + + cbid: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class NamingRequest: + + assembly: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class NamingResponse: + + naming: Mapping[str, Mapping[str, Optional[Any]]] + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class StatsRequest: + ... + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class StatsResponse: + + objectCount: int + + +KernelRequest = Union[ + LoadRequest, + CreateRequest, + DeleteRequest, + GetRequest, + StaticGetRequest, + InvokeRequest, + StaticInvokeRequest, + StatsRequest, +] + +KernelResponse = Union[ + LoadResponse, + CreateResponse, + DeleteResponse, + GetResponse, + InvokeResponse, + StatsResponse, +] + + +class JSClass(Protocol): + @property + def __jsii_type__(self) -> str: + """ + Returns a str that points to this class inside of the Javascript runtime. + """ + + +class Referenceable(Protocol): + @property + def __jsii_ref__(self) -> ObjRef: + """ + Returns an ObjRef that points to this object on the JS side. + """ diff --git a/packages/jsii-python-runtime/src/jsii/_reference_map.py b/packages/jsii-python-runtime/src/jsii/_reference_map.py new file mode 100644 index 0000000000..9c4c4cd258 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/_reference_map.py @@ -0,0 +1,91 @@ +# This module exists to break an import cycle between jsii.runtime and jsii.kernel +import inspect + +from typing import Any, MutableMapping + +from ._kernel.types import JSClass, Referenceable + + +_types = {} +_data_types: MutableMapping[str, Any] = {} +_enums: MutableMapping[str, Any] = {} + + +def register_type(klass: JSClass): + _types[klass.__jsii_type__] = klass + + +def register_data_type(data_type: Any): + _data_types[data_type.__jsii_type__] = data_type + + +def register_enum(enum_type: Any): + _enums[enum_type.__jsii_type__] = enum_type + + +class _FakeReference: + def __init__(self, ref: str) -> None: + self.__jsii_ref__ = ref + + +class _ReferenceMap: + def __init__(self, types): + # We are using a real dictionary here instead of a WeakValueDictionary because + # the nature of the JSII is such that we can never free the memory of JSII + # objects ever, because we have no idea how many references exist on the *other* + # side. + self._refs = {} + self._types = types + + def register(self, inst: Referenceable): + self._refs[inst.__jsii_ref__.ref] = inst + + def resolve(self, kernel, ref): + # First we need to check our reference map to see if we have any instance that + # already matches this reference. + try: + return self._refs[ref.ref] + except KeyError: + pass + + # If we got to this point, then we didn't have a referene for this, in that case + # we want to create a new instance, but we need to create it in such a way that + # we don't try to recreate the type inside of the JSII interface. + class_fqn = ref.ref.rsplit("@", 1)[0] + if class_fqn in _types: + klass = _types[class_fqn] + + # If this class is an abstract class, then we'll use the generated proxy + # class instead of the abstract class to handle return values for this type. + if inspect.isabstract(klass): + klass = klass.__jsii_proxy_class__() + + # Create our instance, bypassing __init__ by directly calling __new__, and + # then assign our reference to __jsii_ref__ + inst = klass.__new__(klass) + inst.__jsii_ref__ = ref + elif class_fqn in _data_types: + data_type = _data_types[class_fqn] + + # A Data type is nothing more than a dictionary, however we need to iterate + # over all of it's properties, and ask the kernel for the values of each of + # then in order to constitute our dict + inst = {} + + for name in data_type.__annotations__.keys(): + # This is a hack, because our kernel expects an object that has a + # __jsii_ref__ attached to it, and we don't have one of those. + inst[name] = kernel.get(_FakeReference(ref), name) + elif class_fqn in _enums: + inst = _enums[class_fqn] + else: + raise ValueError(f"Unknown type: {class_fqn}") + + return inst + + +_refs = _ReferenceMap(_types) + + +register_reference = _refs.register +resolve_reference = _refs.resolve diff --git a/packages/jsii-python-runtime/src/jsii/_runtime.py b/packages/jsii-python-runtime/src/jsii/_runtime.py new file mode 100644 index 0000000000..d792d42d7d --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/_runtime.py @@ -0,0 +1,109 @@ +import abc +import os + +import attr + +from jsii import _reference_map +from jsii._compat import importlib_resources +from jsii._kernel import Kernel +from jsii.python import _ClassPropertyMeta + + +# Yea, a global here is kind of gross, however, there's not really a better way of +# handling this. Fundamentally this is a global value, since we can only reasonably +# have a single kernel active at any one time in a real program. +kernel = Kernel() + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class JSIIAssembly: + + name: str + version: str + module: str + filename: str + + @classmethod + def load(cls, *args, _kernel=kernel, **kwargs): + # Our object here really just acts as a record for our JSIIAssembly, it doesn't + # offer any functionality itself, besides this class method that will trigger + # the loading of the given assembly in the JSII Kernel. + assembly = cls(*args, **kwargs) + + # Actually load the assembly into the kernel, we're using the + # importlib.resources API here isntead of manually constructing the path, in + # the hopes that this will make JSII modules able to be used with zipimport + # instead of only on the FS. + with importlib_resources.path( + f"{assembly.module}._jsii", assembly.filename + ) as assembly_path: + _kernel.load(assembly.name, assembly.version, os.fspath(assembly_path)) + + # Give our record of the assembly back to the caller. + return assembly + + +class JSIIMeta(_ClassPropertyMeta, type): + def __new__(cls, name, bases, attrs, *, jsii_type=None): + # We want to ensure that subclasses of a JSII class do not require setting the + # jsii_type keyword argument. They should be able to subclass it as normal. + # Since their parent class will have the __jsii_type__ variable defined, they + # will as well anyways. + if jsii_type is not None: + attrs["__jsii_type__"] = jsii_type + + obj = super().__new__(cls, name, bases, attrs) + + # Now that we've created the class, we'll need to register it with our reference + # mapper. We only do this for types that are actually jsii types, and not any + # subclasses of them. + if jsii_type is not None: + _reference_map.register_type(obj) + + return obj + + def __call__(cls, *args, **kwargs): + inst = super().__call__(*args, **kwargs) + + # Register this instance with our reference map. + _reference_map.register_reference(inst) + + return inst + + +class JSIIAbstractClass(abc.ABCMeta, JSIIMeta): + pass + + +def enum(*, jsii_type): + def deco(cls): + cls.__jsii_type__ = jsii_type + _reference_map.register_enum(cls) + return cls + + return deco + + +def data_type(*, jsii_type): + def deco(cls): + cls.__jsii_type__ = jsii_type + _reference_map.register_data_type(cls) + return cls + + return deco + + +def member(*, jsii_name): + def deco(fn): + fn.__jsii_name__ = jsii_name + return fn + + return deco + + +def implements(*interfaces): + def deco(cls): + cls.__jsii_ifaces__ = getattr(cls, "__jsii_ifaces__", []) + list(interfaces) + return cls + + return deco diff --git a/packages/jsii-python-runtime/src/jsii/_utils.py b/packages/jsii-python-runtime/src/jsii/_utils.py new file mode 100644 index 0000000000..08e69ba035 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/_utils.py @@ -0,0 +1,27 @@ +import functools + +from typing import Any, Mapping, Type + + +class Singleton(type): + + _instances: Mapping[Type[Any], Any] = {} + + def __call__(cls, *args, **kwargs): + if cls not in cls._instances: + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + + return cls._instances[cls] + + +def memoized_property(fgetter): + stored = [] + + @functools.wraps(fgetter) + def wrapped(self): + nonlocal stored + if not stored: + stored.append(fgetter(self)) + return stored[0] + + return property(wrapped) diff --git a/packages/jsii-python-runtime/src/jsii/compat.py b/packages/jsii-python-runtime/src/jsii/compat.py new file mode 100644 index 0000000000..ea8b6c8d87 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/compat.py @@ -0,0 +1,7 @@ +# External Compatability Shims + +from mypy_extensions import TypedDict +from typing_extensions import Protocol + + +__all__ = ["Protocol", "TypedDict"] diff --git a/packages/jsii-python-runtime/src/jsii/errors.py b/packages/jsii-python-runtime/src/jsii/errors.py new file mode 100644 index 0000000000..2a698cce07 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/errors.py @@ -0,0 +1,14 @@ +import textwrap + + +class JSIIError(Exception): + pass + + +class JavaScriptError(Exception): + + def __init__(self, stack): + self.stack = stack + + def __str__(self): + return "\n" + textwrap.indent(self.stack, " ", lambda line: bool(line)) diff --git a/packages/jsii-python-runtime/src/jsii/py.typed b/packages/jsii-python-runtime/src/jsii/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/jsii-python-runtime/src/jsii/python.py b/packages/jsii-python-runtime/src/jsii/python.py new file mode 100644 index 0000000000..123a4daf54 --- /dev/null +++ b/packages/jsii-python-runtime/src/jsii/python.py @@ -0,0 +1,37 @@ +class _ClassProperty: + def __init__(self, fget, fset=None): + self.fget = fget + self.fset = fset + + def __get__(self, obj, klass=None): + if klass is None: + klass = type(obj) + return self.fget.__get__(obj, klass)(klass) + + def __set__(self, obj, value): + if not self.fset: + raise AttributeError("Can't set attribute.") + + klass = type(obj) + return self.fset.__get__(obj, klass)(value) + + def setter(self, func): + if not isinstance(func, (classmethod, staticmethod)): + func = classmethod(func) + + self.fset = func + + return self + + +def classproperty(func): + return _ClassProperty(func) + + +class _ClassPropertyMeta(type): + def __setattr__(self, key, value): + obj = getattr(self, key, None) + if isinstance(obj, _ClassProperty): + return obj.__set__(self, value) + + return super().__setattr__(key, value) diff --git a/packages/jsii-python-runtime/tests/__init__.py b/packages/jsii-python-runtime/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/jsii-python-runtime/tests/conftest.py b/packages/jsii-python-runtime/tests/conftest.py new file mode 100644 index 0000000000..04db5eb90b --- /dev/null +++ b/packages/jsii-python-runtime/tests/conftest.py @@ -0,0 +1,3 @@ +import os + +os.environ["JSII_DEBUG"] = "1" diff --git a/packages/jsii-python-runtime/tests/test_compliance.py b/packages/jsii-python-runtime/tests/test_compliance.py new file mode 100644 index 0000000000..13e1cacfea --- /dev/null +++ b/packages/jsii-python-runtime/tests/test_compliance.py @@ -0,0 +1,893 @@ +import platform + +from datetime import datetime, timezone + +import pytest + +import jsii + +from jsii_calc import ( + AbstractClassReturner, + Add, + AllTypes, + AsyncVirtualMethods, + Calculator, + ClassWithPrivateConstructorAndAutomaticProperties, + DoNotOverridePrivates, + DoubleTrouble, + GreetingAugmenter, + IFriendlier, + IFriendlyRandomGenerator, + IRandomNumberGenerator, + InterfaceWithProperties, + JsiiAgent, + JSObjectLiteralForInterface, + JSObjectLiteralToNative, + Multiply, + Negate, + NodeStandardLibrary, + NullShouldBeTreatedAsUndefined, + NumberGenerator, + Polymorphism, + Power, + PythonReservedWords, + ReferenceEnumFromScopedPackage, + ReturnsPrivateImplementationOfInterface, + Statics, + Sum, + SyncVirtualMethods, + UsesInterfaceWithProperties, + composition, +) +from scope.jsii_calc_lib import IFriendly, EnumFromScopedModule, Number + + +# Note: The names of these test functions have been chosen to map as closely to the +# Java Compliance tests as possible. +# Note: While we could write more expressive and better tests using the functionality +# provided to us by pytest, we are making these tests match the Java Compliance +# Tests as closely as possible to make keeping them in sync easier. + +# These map distinct reasons for failures, so we an easily find them. +xfail_async = pytest.mark.xfail(reason="Implement async methods", strict=True) +xfail_literal_interface = pytest.mark.xfail( + reason="Implement someone returning a literal interface", strict=True +) +xfail_abstract_class = pytest.mark.xfail( + reason="Implement (or fix?) abstract class property", strict=True +) +xfail_private_class = pytest.mark.xfail( + reason="Implement receiving a private class", strict=True +) +xfail_callbacks = pytest.mark.xfail(reason="Implement callback support", strict=True) + + +class DerivedFromAllTypes(AllTypes): + pass + + +class OverrideAsyncMethods(AsyncVirtualMethods): + def override_me(self, mult): + return self.foo() * 2 + + def foo(self) -> int: + """ + Implement another method, which doesn't override anything in the base class. + This should obviously be possible. + """ + return 2222 + + +class OverrideAsyncMethodsByBaseClass(OverrideAsyncMethods): + pass + + +class OverrideCallsSuper(AsyncVirtualMethods): + def override_me(self, mult): + super_ret = super().override_me(mult) + return super_ret * 10 + 1 + + +class TwoOverrides(AsyncVirtualMethods): + def override_me(self, mult): + return 666 + + def override_me_too(self): + return 10 + + +class SyncOverrides(SyncVirtualMethods): + + multiplier = 1 + return_super = False + call_async = False + another_the_property = None + + def virtual_method(self, n): + if self.return_super: + return super().virtual_method(n) + + if self.call_async: + obj = OverrideAsyncMethods() + return obj.call_me() + + return 5 * n * self.multiplier + + @property + def the_property(self): + return "I am an override!" + + @the_property.setter + def the_property(self, value): + self.another_the_property = value + + +@jsii.implements(IFriendly) +@jsii.implements(IRandomNumberGenerator) +class SubclassNativeFriendlyRandom(Number): + def __init__(self): + super().__init__(908) + self.next_number = 100 + + def hello(self): + return "SubclassNativeFriendlyRandom" + + def next(self): + next_ = self.next_number + self.next_number += 100 + return next_ + + +@jsii.implements(IFriendlyRandomGenerator) +class PureNativeFriendlyRandom: + """ + In this case, the class does not derive from the JsiiObject hierarchy. It means + that when we pass it along to javascript, we won't have an objref. This should + result in creating a new empty javascript object and applying the overrides. + + The newly created objref will need to be stored somewhere (in the engine's object + map) so that subsequent calls won't create a new object every time. + """ + + next_number = 1000 + + def next(self): + n = self.next_number + self.next_number += 1000 + return n + + def hello(self): + return "I am a native!" + + +class AddTen(Add): + def __init__(self, value): + super().__init__(Number(value), Number(10)) + + +class MulTen(Multiply): + def __init__(self, value): + super().__init__(Number(value), Number(10)) + + +def test_primitiveTypes(): + types = AllTypes() + + # boolean + types.boolean_property = True + assert types.boolean_property + + # string + types.string_property = "foo" + assert types.string_property == "foo" + + # number + types.number_property = 1234 + assert types.number_property == 1234 + + # date + types.date_property = datetime.fromtimestamp(123 / 1000.0, tz=timezone.utc) + assert types.date_property == datetime.fromtimestamp(123 / 1000.0, tz=timezone.utc) + + # json + types.json_property = {"Foo": 123} + assert types.json_property.get("Foo") == 123 + + +def test_dates(): + types = AllTypes() + + # strong type + types.date_property = datetime.fromtimestamp(123 / 1000.0, tz=timezone.utc) + assert types.date_property == datetime.fromtimestamp(123 / 1000.0, tz=timezone.utc) + + # weak type + types.any_property = datetime.fromtimestamp(999 / 1000.0, tz=timezone.utc) + assert types.any_property == datetime.fromtimestamp(999 / 1000.0, tz=timezone.utc) + + +def test_collectionTypes(): + types = AllTypes() + + # array + types.array_property = ["Hello", "World"] + assert types.array_property[1] == "World" + + # map + map_ = {} + map_["Foo"] = Number(123) + types.map_property = map_ + # TODO: No Assertion? + + +def test_dynamicTypes(): + types = AllTypes() + + # boolean + types.any_property = False + assert not types.any_property + + # string + types.any_property = "String" + assert types.any_property == "String" + + # number + types.any_property = 12 + assert types.any_property == 12 + + # date + types.any_property = datetime.fromtimestamp(1234 / 1000.0, tz=timezone.utc) + assert types.any_property == datetime.fromtimestamp(1234 / 1000.0, tz=timezone.utc) + + # json (notice that when deserialized, it is deserialized as a map). + types.any_property = {"Goo": ["Hello", {"World": 123}]} + assert types.any_property.get("Goo")[1].get("World") == 123 + + # array + types.any_property = ["Hello", "World"] + assert types.any_property[0] == "Hello" + assert types.any_property[1] == "World" + + # array of any + types.any_array_property = ["Hybrid", Number(12), 123, False] + assert types.any_array_property[2] == 123 + + # map + map_ = {} + map_["MapKey"] = "MapValue" + types.any_property = map_ + assert types.any_property.get("MapKey") == "MapValue" + + # map of any + map_["Goo"] = 19_289_812 + types.any_map_property = map_ + types.any_map_property.get("Goo") == 19_289_812 + + # classes + mult = Multiply(Number(10), Number(20)) + types.any_property = mult + assert types.any_property is mult + assert isinstance(types.any_property, Multiply) + assert types.any_property.value == 200 + + +def test_unionTypes(): + types = AllTypes() + + # single valued property + types.union_property = 1234 + assert types.union_property == 1234 + + types.union_property = "Hello" + assert types.union_property == "Hello" + + types.union_property = Multiply(Number(2), Number(12)) + assert types.union_property.value == 24 + + # map + map_ = {} + map_["Foo"] = Multiply(Number(2), Number(99)) + types.union_map_property = map_ + # TODO: No Assertion? + + # array + types.union_array_property = ["Hello", 123, Number(33)] + assert types.union_array_property[2].value == 33 + + +def test_createObjectAndCtorOverloads(): + Calculator() + Calculator(maximum_value=10) + + +def test_getSetPrimitiveProperties(): + number = Number(20) + + assert number.value == 20 + assert number.double_value == 40 + assert Negate(Add(Number(20), Number(10))).value == -30 + assert Multiply(Add(Number(5), Number(5)), Number(2)).value == 20 + assert Power(Number(3), Number(4)).value == 3 ** 4 + assert Power(Number(999), Number(1)).value == 999 + assert Power(Number(999), Number(0)).value == 1 + + +def test_callMethods(): + calc = Calculator() + + calc.add(10) + assert calc.value == 10 + + calc.mul(2) + assert calc.value == 20 + + calc.pow(5) + assert calc.value == 20 ** 5 + + calc.neg() + assert calc.value == -3_200_000 + + +def test_unmarshallIntoAbstractType(): + calc = Calculator() + calc.add(120) + + assert calc.curr.value == 120 + + +def test_getAndSetNonPrimitiveProperties(): + calc = Calculator() + calc.add(3_200_000) + calc.neg() + calc.curr = Multiply(Number(2), calc.curr) + + assert calc.value == -6_400_000 + + +def test_getAndSetEnumValues(): + calc = Calculator() + calc.add(9) + calc.pow(3) + + CompositeOperation = composition.CompositeOperation + + assert calc.string_style == CompositeOperation.CompositionStringStyle.Normal + + calc.string_style = CompositeOperation.CompositionStringStyle.Decorated + + assert calc.string_style == CompositeOperation.CompositionStringStyle.Decorated + assert calc.to_string() == "<<[[{{(((1 * (0 + 9)) * (0 + 9)) * (0 + 9))}}]]>>" + + +def test_useEnumFromScopedModule(): + obj = ReferenceEnumFromScopedPackage() + assert obj.foo == EnumFromScopedModule.Value2 + obj.foo = EnumFromScopedModule.Value1 + assert obj.load_foo() == EnumFromScopedModule.Value1 + obj.save_foo(EnumFromScopedModule.Value2) + assert obj.foo == EnumFromScopedModule.Value2 + + +def test_undefinedAndNull(): + calc = Calculator() + assert calc.max_value is None + calc.max_value = None + + +def test_arrays(): + sum_ = Sum() + sum_.parts = [Number(5), Number(10), Multiply(Number(2), Number(3))] + + assert sum_.value == 5 + 10 + (2 * 3) + assert sum_.parts[0].value == 5 + assert sum_.parts[2].value == 6 + assert sum_.to_string() == "(((0 + 5) + 10) + (2 * 3))" + + +def test_maps(): + calc2 = Calculator() # Initializer overload (props is optional) + calc2.add(10) + calc2.add(20) + calc2.mul(2) + + assert len(calc2.operations_map.get("add")) == 2 + assert len(calc2.operations_map.get("mul")) == 1 + assert calc2.operations_map.get("add")[1].value == 30 + + +def test_exceptions(): + calc3 = Calculator(initial_value=20, maximum_value=30) + calc3.add(3) + + assert calc3.value == 23 + + with pytest.raises(Exception): + calc3.add(10) + + calc3.max_value = 40 + calc3.add(10) + + assert calc3.value == 33 + + +def test_unionProperties(): + calc3 = Calculator() + calc3.union_property = Multiply(Number(9), Number(3)) + + assert isinstance(calc3.union_property, Multiply) + assert calc3.read_union_value() == 9 * 3 + + calc3.union_property = Power(Number(10), Number(3)) + + assert isinstance(calc3.union_property, Power) + assert calc3.read_union_value() == 10 ** 3 + + +def test_subclassing(): + calc = Calculator() + calc.curr = AddTen(33) + calc.neg() + + assert calc.value == -43 + + +def test_testJSObjectLiteralToNative(): + obj = JSObjectLiteralToNative() + obj2 = obj.return_literal() + + assert obj2.prop_a == "Hello" + assert obj2.prop_b == 102 + + +def test_testFluentApiWithDerivedClasses(): + # make sure that fluent API can be assigned to objects from derived classes + obj = DerivedFromAllTypes() + obj.string_property = "Hello" + obj.number_property = 12 + + assert obj.string_property == "Hello" + assert obj.number_property == 12 + + +def test_creationOfNativeObjectsFromJavaScriptObjects(): + """ + See that we can create a native object, pass it JS and then unmarshal + back without type information. + """ + types = AllTypes() + + js_obj = Number(44) + types.any_property = js_obj + unmarshalled_js_obj = types.any_property + assert unmarshalled_js_obj.__class__ == Number + + native_obj = AddTen(10) + types.any_property = native_obj + + result1 = types.any_property + assert result1 is native_obj + + native_obj2 = MulTen(20) + types.any_property = native_obj2 + unmarshalled_native_obj = types.any_property + assert unmarshalled_native_obj.__class__ == MulTen + + +@xfail_async +def test_asyncOverrides_callAsyncMethod(): + obj = AsyncVirtualMethods() + assert obj.call_me() == 128 + assert obj.override_me(44) == 528 + + +@xfail_async +def test_asyncOverrides_overrideAsyncMethod(): + obj = OverrideAsyncMethods() + obj.call_me() == 4452 + + +@xfail_async +def test_asyncOverrides_overrideAsyncMethodByParentClass(): + obj = OverrideAsyncMethodsByBaseClass() + obj.call_me() == 4452 + + +@xfail_async +def test_asyncOverrides_overrideCallsSuper(): + obj = OverrideCallsSuper() + assert obj.override_me(12) == 1441 + assert obj.call_me() == 1209 + + +@xfail_async +def test_asyncOverrides_twoOverrides(): + obj = TwoOverrides() + assert obj.call_me() == 684 + + +@xfail_async +def test_asyncOverrides_overrideThrows(): + class ThrowingAsyncVirtualMethods(AsyncVirtualMethods): + def override_me(self, mult): + raise RuntimeError("Thrown by native code") + + obj = ThrowingAsyncVirtualMethods() + + with pytest.raises(Exception, match="Thrown by native code"): + obj.call_me() + + +@xfail_callbacks +def test_syncOverrides(): + obj = SyncOverrides() + assert obj.caller_is_method() == 10 * 5 + + # affect the result + obj.multiplier = 5 + assert obj.caller_is_method() == 10 * 5 * 5 + + # verify callbacks are invoked from a property + assert obj.caller_is_property == 10 * 5 * 5 + + # and from an async method + obj.multiplier = 3 + assert obj.caller_is_async == 10 * 5 * 3 + + +@xfail_callbacks +def test_propertyOverrides_get_set(): + so = SyncOverrides() + assert so.retrieve_value_of_the_property == "I am an override!" + so.modify_value_of_the_property("New Value") + assert so.another_the_property == "New Value" + + +@xfail_callbacks +def test_propertyOverrides_get_calls_super(): + class SuperSyncVirtualMethods(SyncVirtualMethods): + @property + def the_property(self): + return f"super:{super().the_property}" + + @the_property.setter + def the_property(self, value): + super().the_property = value + + so = SuperSyncVirtualMethods() + + assert so.retrieve_value_of_the_property() == "super:initial value" + assert so.the_property == "super:initial value" + + +@xfail_callbacks +def test_propertyOverrides_set_calls_super(): + class SuperSyncVirtualMethods(SyncVirtualMethods): + @property + def the_property(self): + return super().the_property + + @the_property.setter + def the_property(self, value): + super().the_property = f"{value}:by override" + + so = SuperSyncVirtualMethods() + so.modify_value_of_the_property("New Value") + + assert so.the_property == "New Value:by override" + + +@xfail_callbacks +def test_propertyOverrides_get_throws(): + class ThrowingSyncVirtualMethods(SyncVirtualMethods): + @property + def the_property(self): + raise RuntimeError("Oh no, this is bad") + + @the_property.setter + def the_property(self, value): + super().the_property = value + + so = ThrowingSyncVirtualMethods() + + with pytest.raises(Exception, match="Oh no, this is bad"): + so.retrieve_value_of_the_property() + + +@xfail_callbacks +def test_propertyOverrides_set_throws(): + class ThrowingSyncVirtualMethods(SyncVirtualMethods): + @property + def the_property(self): + return super().the_property + + @the_property.setter + def the_property(self, value): + raise RuntimeError("Exception from overloaded setter") + + so = ThrowingSyncVirtualMethods() + + with pytest.raises(Exception, match="Exception from overloaded setter"): + so.modify_value_of_the_property("Hii") + + +@pytest.mark.xfail( + reason="Test no longer makes sense with lifted properties.", strict=True +) +def test_propertyOverrides_interfaces(): + class TInterfaceWithProperties(InterfaceWithProperties): + + x = None + + @property + def read_only_string(self): + return "READ_ONLY_STRING" + + @property + def read_write_string(self): + return self.x + "?" + + @read_write_string.setter + def read_write_string(self, value): + self.x = value + "!" + + obj = TInterfaceWithProperties() + interact = UsesInterfaceWithProperties(obj) + + assert interact.just_read() == "READ_ONLY_STRING" + assert interact.write_and_read("Hello") == "Hello!?" + + +def test_interfaceBuilder(): + interact = UsesInterfaceWithProperties( + read_only_string="READ_ONLY", read_write_string="READ_WRITE" + ) + assert interact.just_read() == "READ_ONLY" + assert interact.write_and_read("Hello") == "Hello" + + +@xfail_callbacks +def test_syncOverrides_callsSuper(): + obj = SyncOverrides() + assert obj.caller_is_property == 10 * 5 + obj.return_super = True + assert obj.caller_is_property == 10 * 2 + + +@pytest.mark.skip +def test_fail_syncOverrides_callsDoubleAsync_method(): + obj = SyncOverrides() + obj.call_async = True + + # TODO: Error Handling + with pytest.raises(Exception): + obj.caller_is_method() + + +@pytest.mark.skip +def test_fail_syncOverrides_callsDoubleAsync_propertyGetter(): + obj = SyncOverrides() + obj.call_async = True + + # TODO: Error Handling + with pytest.raises(Exception): + obj.caller_is_property + + +@pytest.mark.skip +def test_fail_syncOverrides_callsDoubleAsync_propertySetter(): + obj = SyncOverrides() + obj.call_async = True + + # TODO: Error Handling + with pytest.raises(Exception): + obj.caller_is_property = 12 + + +@xfail_callbacks +def test_testInterfaces(): + friendly: IFriendly + friendlier: IFriendlier + random_number_generator: IRandomNumberGenerator + friendly_random_generator: IFriendlyRandomGenerator + + add = Add(Number(10), Number(20)) + friendly = add + assert friendly.hello() == "Hello, I am a binary operation. What's your name?" + + multiply = Multiply(Number(10), Number(30)) + friendly = multiply + friendlier = multiply + random_number_generator = multiply + assert friendly.hello() == "Hello, I am a binary operation. What's your name?" + assert friendlier.goodbye() == "Goodbye from Multiply!" + assert random_number_generator.next() == 89 + + friendly_random_generator = DoubleTrouble() + assert friendly_random_generator.hello() == "world" + assert friendly_random_generator.next() == 12 + + poly = Polymorphism() + assert ( + poly.say_hello(friendly) + == "oh, Hello, I am a binary operation. What's your name?" + ) + assert poly.say_hello(friendly_random_generator) == "oh, world" + assert ( + poly.say_hello(SubclassNativeFriendlyRandom()) + == "oh, SubclassNativeFriendlyRandom" + ) + assert poly.say_hello(PureNativeFriendlyRandom()) == "oh, I am a native!" + + +@xfail_callbacks +def test_testNativeObjectsWithInterfaces(): + # create a pure and native object, not part of the jsii hierarchy, only implements + # a jsii interface + pure_native = PureNativeFriendlyRandom() + subclassed_native = SubclassNativeFriendlyRandom() + generator_bound_to_p_subclassed_object = NumberGenerator(subclassed_native) + generator_bound_to_pure_native = NumberGenerator(pure_native) + + assert generator_bound_to_p_subclassed_object.generator is subclassed_native + generator_bound_to_p_subclassed_object.is_same_generator(subclassed_native) + assert generator_bound_to_p_subclassed_object.next_times100() == 10000 + + # When we invoke nextTimes100 again, it will use the objref and call into the same + # object. + assert generator_bound_to_p_subclassed_object.next_times100() == 20000 + + assert generator_bound_to_pure_native.generator is pure_native + generator_bound_to_pure_native.is_same_generator(pure_native) + assert generator_bound_to_pure_native.next_times100() == 100_000 + assert generator_bound_to_pure_native.next_times100() == 200_000 + + +@xfail_literal_interface +def test_testLiteralInterface(): + obj = JSObjectLiteralForInterface() + friendly = obj.give_me_friendly() + gen = obj.give_me_friendly_generator() + + assert friendly.hello() == "I am literally friendly!" + assert gen.hello() == "giveMeFriendlyGenerator" + assert gen.next() == 42 + + +@xfail_literal_interface +def test_testInterfaceParameter(): + obj = JSObjectLiteralForInterface() + friendly = obj.give_me_friendly() + greeting_augmenter = GreetingAugmenter() + + assert friendly.hello() == "I am literally friendly!" + assert ( + greeting_augmenter.better_greeting(friendly) + == "I am literally friendly! Let me buy you a drink!" + ) + + +def test_statics(): + assert Statics.static_method("Yoyo") == "hello ,Yoyo!" + assert Statics.instance.value == "default" + + new_statics = Statics("new value") + Statics.instance = new_statics + + assert Statics.instance is new_statics + assert Statics.instance.value == "new value" + + assert Statics.non_const_static == 100 + + +def test_consts(): + obj = Statics.CONST_OBJ + + assert Statics.FOO == "hello" + assert obj.hello() == "world" + assert Statics.BAR == 1234 + assert Statics.ZOO_BAR.get("hello") == "world" + + +def test_reservedKeywordsAreSlugifiedInMethodNames(): + obj = PythonReservedWords() + obj.import_() + obj.return_() + + +@xfail_async +def test_nodeStandardLibrary(): + obj = NodeStandardLibrary() + + assert obj.fs_read_file() == "Hello, resource!" + assert obj.fs_read_file_sync() == "Hello, resource! SYNC!" + assert len(obj.get_os_platform()) > 0 + assert ( + obj.crypto_sha_256() + == "6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50" + ) + + +@xfail_abstract_class +def test_returnAbstract(): + obj = AbstractClassReturner() + obj2 = obj.give_me_abstract() + + assert obj2.abstract_method("John") == "Hello, John!!" + assert obj2.prop_from_interface == "propFromInterfaceValue" + assert obj2.non_abstract_method() == 42 + + iface = obj.give_me_interface() + assert iface.prop_from_interface == "propFromInterfaceValue" + + assert ( + obj.return_abstract_from_property.abstract_property == "hello-abstract-property" + ) + + +def test_doNotOverridePrivates_method(): + class TDoNotOverridePrivates(DoNotOverridePrivates): + def private_method(self): + return "privateMethod-Override" + + obj = TDoNotOverridePrivates() + + assert obj.private_method_value() == "privateMethod" + + +def test_doNotOverridePrivates_property_by_name(): + class TDoNotOverridePrivates(DoNotOverridePrivates): + def private_property(self): + return "privateProperty-Override" + + obj = TDoNotOverridePrivates() + + assert obj.private_property_value() == "privateProperty" + + +def test_doNotOverridePrivates_property_getter(): + class TDoNotOverridePrivates(DoNotOverridePrivates): + @property + def private_property(self): + return "privateProperty-Override" + + @private_property.setter + def private_property(self): + raise RuntimeError("Boom") + + obj = TDoNotOverridePrivates() + + assert obj.private_property_value() == "privateProperty" + + # verify the setter override is not invoked. + obj.change_private_property_value("MyNewValue") + assert obj.private_property_value() == "MyNewValue" + + +def test_classWithPrivateConstructorAndAutomaticProperties(): + obj = ClassWithPrivateConstructorAndAutomaticProperties.create("Hello", "Bye") + assert obj.read_write_string == "Bye" + assert obj.read_only_string == "Hello" + + +def test_nullShouldBeTreatedAsUndefined(): + obj = NullShouldBeTreatedAsUndefined("hello", None) + obj.give_me_undefined(None) + obj.give_me_undefined_inside_an_object( + this_should_be_undefined=None, + array_with_three_elements_and_undefined_as_second_argument=[ + "hello", + None, + "boom", + ], + ) + obj.change_me_to_undefined = None + obj.verify_property_is_undefined() + + +def test_testJsiiAgent(): + assert JsiiAgent.jsii_agent == f"Python/{platform.python_version()}" + + +@xfail_private_class +def test_receiveInstanceOfPrivateClass(): + assert ReturnsPrivateImplementationOfInterface().private_implementation.success diff --git a/packages/jsii-python-runtime/tests/test_python.py b/packages/jsii-python-runtime/tests/test_python.py new file mode 100644 index 0000000000..1be5b4c191 --- /dev/null +++ b/packages/jsii-python-runtime/tests/test_python.py @@ -0,0 +1,15 @@ +import jsii +import pytest + +from jsii.errors import JSIIError +from jsii_calc import Calculator + + +class TestErrorHandling: + def test_jsii_error(self): + obj = Calculator() + + with pytest.raises( + JSIIError, match="Class jsii-calc.Calculator doesn't have a method" + ): + jsii.kernel.invoke(obj, "nonexistentMethod") diff --git a/packages/jsii-reflect/test/classes.expected.txt b/packages/jsii-reflect/test/classes.expected.txt index 5f73bd1d60..4723146f5c 100644 --- a/packages/jsii-reflect/test/classes.expected.txt +++ b/packages/jsii-reflect/test/classes.expected.txt @@ -43,6 +43,7 @@ OverrideReturnsObject Polymorphism Power PublicClass +PythonReservedWords ReferenceEnumFromScopedPackage ReturnsPrivateImplementationOfInterface RuntimeTypeChecking diff --git a/packages/jsii-reflect/test/jsii-tree.test.all.expected.txt b/packages/jsii-reflect/test/jsii-tree.test.all.expected.txt index 10b973ceba..51c230e60e 100644 --- a/packages/jsii-reflect/test/jsii-tree.test.all.expected.txt +++ b/packages/jsii-reflect/test/jsii-tree.test.all.expected.txt @@ -697,6 +697,74 @@ assemblies │ │ │ └── returns: void │ │ └─┬ hello() method │ │ └── returns: void + │ ├─┬ class PythonReservedWords + │ │ └─┬ members + │ │ ├─┬ () method + │ │ │ └── returns: void + │ │ ├─┬ and() method + │ │ │ └── returns: void + │ │ ├─┬ as() method + │ │ │ └── returns: void + │ │ ├─┬ assert() method + │ │ │ └── returns: void + │ │ ├─┬ async() method + │ │ │ └── returns: void + │ │ ├─┬ await() method + │ │ │ └── returns: void + │ │ ├─┬ break() method + │ │ │ └── returns: void + │ │ ├─┬ class() method + │ │ │ └── returns: void + │ │ ├─┬ continue() method + │ │ │ └── returns: void + │ │ ├─┬ def() method + │ │ │ └── returns: void + │ │ ├─┬ del() method + │ │ │ └── returns: void + │ │ ├─┬ elif() method + │ │ │ └── returns: void + │ │ ├─┬ else() method + │ │ │ └── returns: void + │ │ ├─┬ except() method + │ │ │ └── returns: void + │ │ ├─┬ finally() method + │ │ │ └── returns: void + │ │ ├─┬ for() method + │ │ │ └── returns: void + │ │ ├─┬ from() method + │ │ │ └── returns: void + │ │ ├─┬ global() method + │ │ │ └── returns: void + │ │ ├─┬ if() method + │ │ │ └── returns: void + │ │ ├─┬ import() method + │ │ │ └── returns: void + │ │ ├─┬ in() method + │ │ │ └── returns: void + │ │ ├─┬ is() method + │ │ │ └── returns: void + │ │ ├─┬ lambda() method + │ │ │ └── returns: void + │ │ ├─┬ nonlocal() method + │ │ │ └── returns: void + │ │ ├─┬ not() method + │ │ │ └── returns: void + │ │ ├─┬ or() method + │ │ │ └── returns: void + │ │ ├─┬ pass() method + │ │ │ └── returns: void + │ │ ├─┬ raise() method + │ │ │ └── returns: void + │ │ ├─┬ return() method + │ │ │ └── returns: void + │ │ ├─┬ try() method + │ │ │ └── returns: void + │ │ ├─┬ while() method + │ │ │ └── returns: void + │ │ ├─┬ with() method + │ │ │ └── returns: void + │ │ └─┬ yield() method + │ │ └── returns: void │ ├─┬ class ReferenceEnumFromScopedPackage │ │ └─┬ members │ │ ├─┬ () method diff --git a/packages/jsii-reflect/test/jsii-tree.test.inheritance.expected.txt b/packages/jsii-reflect/test/jsii-tree.test.inheritance.expected.txt index 1985805a66..f65536e262 100644 --- a/packages/jsii-reflect/test/jsii-tree.test.inheritance.expected.txt +++ b/packages/jsii-reflect/test/jsii-tree.test.inheritance.expected.txt @@ -57,6 +57,7 @@ assemblies │ ├─┬ class Power │ │ └── base: CompositeOperation │ ├── class PublicClass + │ ├── class PythonReservedWords │ ├── class ReferenceEnumFromScopedPackage │ ├── class ReturnsPrivateImplementationOfInterface │ ├── class RuntimeTypeChecking diff --git a/packages/jsii-reflect/test/jsii-tree.test.members.expected.txt b/packages/jsii-reflect/test/jsii-tree.test.members.expected.txt index bc0e98c769..2dc70c18fc 100644 --- a/packages/jsii-reflect/test/jsii-tree.test.members.expected.txt +++ b/packages/jsii-reflect/test/jsii-tree.test.members.expected.txt @@ -293,6 +293,41 @@ assemblies │ │ └─┬ members │ │ ├── () method │ │ └── hello() method + │ ├─┬ class PythonReservedWords + │ │ └─┬ members + │ │ ├── () method + │ │ ├── and() method + │ │ ├── as() method + │ │ ├── assert() method + │ │ ├── async() method + │ │ ├── await() method + │ │ ├── break() method + │ │ ├── class() method + │ │ ├── continue() method + │ │ ├── def() method + │ │ ├── del() method + │ │ ├── elif() method + │ │ ├── else() method + │ │ ├── except() method + │ │ ├── finally() method + │ │ ├── for() method + │ │ ├── from() method + │ │ ├── global() method + │ │ ├── if() method + │ │ ├── import() method + │ │ ├── in() method + │ │ ├── is() method + │ │ ├── lambda() method + │ │ ├── nonlocal() method + │ │ ├── not() method + │ │ ├── or() method + │ │ ├── pass() method + │ │ ├── raise() method + │ │ ├── return() method + │ │ ├── try() method + │ │ ├── while() method + │ │ ├── with() method + │ │ └── yield() method │ ├─┬ class ReferenceEnumFromScopedPackage │ │ └─┬ members │ │ ├── () method diff --git a/packages/jsii-reflect/test/jsii-tree.test.types.expected.txt b/packages/jsii-reflect/test/jsii-tree.test.types.expected.txt index 4eecd5adfc..674648f02a 100644 --- a/packages/jsii-reflect/test/jsii-tree.test.types.expected.txt +++ b/packages/jsii-reflect/test/jsii-tree.test.types.expected.txt @@ -42,6 +42,7 @@ assemblies │ ├── class Polymorphism │ ├── class Power │ ├── class PublicClass + │ ├── class PythonReservedWords │ ├── class ReferenceEnumFromScopedPackage │ ├── class ReturnsPrivateImplementationOfInterface │ ├── class RuntimeTypeChecking