Skip to content

Commit

Permalink
fix: Python's abstract class proxies now inherit from parent's proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
dstufft authored Mar 13, 2019
1 parent af1346f commit 6f1c9c0
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 4 deletions.
34 changes: 31 additions & 3 deletions packages/jsii-pacmak/lib/targets/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,20 +682,23 @@ class TypedDictProperty implements PythonBase {
interface ClassOpts extends PythonTypeOpts {
abstract?: boolean;
interfaces?: spec.NamedTypeReference[];
abstractBases?: spec.ClassType[];
}

class Class extends BasePythonClassType {

private abstract: boolean;
private abstractBases: spec.ClassType[];
private interfaces: spec.NamedTypeReference[];

constructor(name: string, fqn: string, opts: ClassOpts) {
super(name, fqn, opts);

const { abstract = false, interfaces = [] } = opts;
const { abstract = false, interfaces = [], abstractBases = [] } = opts;

this.abstract = abstract;
this.interfaces = interfaces;
this.abstractBases = abstractBases;
}

public dependsOn(resolver: TypeResolver): PythonType[] {
Expand Down Expand Up @@ -744,7 +747,13 @@ class Class extends BasePythonClassType {
// abstract, and subclassing our initial class.
if (this.abstract) {
resolver = this.fqn ? resolver.bind(this.fqn) : resolver;
code.openBlock(`class ${this.getProxyClassName()}(${this.name})`);

const proxyBases: string[] = [this.name];
for (const base of this.abstractBases) {
proxyBases.push(`jsii.proxy_for(${resolver.resolve(base)})`);
}

code.openBlock(`class ${this.getProxyClassName()}(${proxyBases.join(', ')})`);

// Filter our list of members to *only* be abstract members, and not any
// other types.
Expand Down Expand Up @@ -1372,7 +1381,8 @@ class PythonGenerator extends Generator {
const klass = new Class(
toPythonIdentifier(cls.name),
cls.fqn,
{ abstract, bases: cls.base !== undefined ? [cls.base] : [], interfaces: cls.interfaces }
{ abstract, bases: cls.base !== undefined ? [cls.base] : [], interfaces: cls.interfaces,
abstractBases: abstract ? this.getAbstractBases(cls) : [] }
);

if (cls.initializer !== undefined) {
Expand Down Expand Up @@ -1580,4 +1590,22 @@ class PythonGenerator extends Generator {

return undefined;
}

private getAbstractBases(cls: spec.ClassType): spec.ClassType[] {
const abstractBases: spec.ClassType[] = [];

if (cls.base !== undefined) {
const base = this.findType(cls.base.fqn);

if (!spec.isClassType(base)) {
throw new Error("Class inheritence that isn't a class?");
}

if (base.abstract) {
abstractBases.push(base);
}
}

return abstractBases;
}
}
2 changes: 2 additions & 0 deletions packages/jsii-python-runtime/src/jsii/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
implements,
member,
kernel,
proxy_for,
)


Expand Down Expand Up @@ -44,6 +45,7 @@
"implements",
"member",
"kernel",
"proxy_for",
"load",
"create",
"delete",
Expand Down
7 changes: 7 additions & 0 deletions packages/jsii-python-runtime/src/jsii/_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,10 @@ def deco(cls):
return cls

return deco


def proxy_for(abstract_class):
if not hasattr(abstract_class, "__jsii_proxy_class__"):
raise TypeError(f"{abstract_class} is not a JSII Abstract class.")

return abstract_class.__jsii_proxy_class__()
1 change: 0 additions & 1 deletion packages/jsii-python-runtime/tests/test_compliance.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,6 @@ def test_nodeStandardLibrary():
)


@xfail_abstract_class
def test_returnAbstract():
obj = AbstractClassReturner()
obj2 = obj.give_me_abstract()
Expand Down

0 comments on commit 6f1c9c0

Please sign in to comment.