Skip to content

Commit

Permalink
fix(python): reference isomorphism is broken within __init__
Browse files Browse the repository at this point in the history
Within the `__init__` of a class, reading `self` back from the JS
process would result in a proxy object created for the parent type,
instead of returning `self`. This is because the `JSIIMeta` metaclass
only registered the instance in the rerefence map **after** the
constructor had returned.

This adds an additional registration point right after the `create` API
returned from the kernel, making the reference available as early as it
can possibly be known.

Fixes aws/aws-cdk#8262
  • Loading branch information
RomainMuller committed Jun 9, 2020
1 parent 61f8883 commit df12ec8
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 2 deletions.
4 changes: 4 additions & 0 deletions packages/@jsii/python-runtime/src/jsii/_kernel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ def create(
obj.__jsii_ref__ = _callback_till_result(self, response, CreateResponse)
else:
obj.__jsii_ref__ = response

# Register this to the reference map already (so it's available within the rest of the __init__)
_reference_map.register_reference(obj)

return obj.__jsii_ref__

def delete(self, ref: ObjRef) -> None:
Expand Down
10 changes: 10 additions & 0 deletions packages/@jsii/python-runtime/tests/test_compliance.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
InterfaceCollections,
IInterfaceWithProperties,
IStructReturningDelegate,
Isomorphism,
JsiiAgent,
JSObjectLiteralForInterface,
JSObjectLiteralToNative,
Expand Down Expand Up @@ -1196,3 +1197,12 @@ def test_parameter_named_self_ClassWithSelf():
def test_parameter_named_self_ClassWithSelfKwarg():
subject = ClassWithSelfKwarg(self='Howdy!')
assert subject.props.self == 'Howdy!'


def test_isomorphism_within_constructor():
class Subject(Isomorphism):
def __init__(self):
super().__init__()
assert self == self.myself()

Subject()
12 changes: 12 additions & 0 deletions packages/jsii-calc/lib/compliance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2490,3 +2490,15 @@ export class InterfaceCollections {
export interface IOptionalMethod {
optional(): string | undefined;
}

/**
* Checks the "same instance" isomorphism is preserved within the constructor.
*
* Create a subclass of this, and assert that `this.myself()` actually returns
* `this` from within the constructor.
*/
export abstract class Isomorphism {
public myself(): Isomorphism {
return this;
}
}
36 changes: 35 additions & 1 deletion packages/jsii-calc/test/assembly.jsii
Original file line number Diff line number Diff line change
Expand Up @@ -6566,6 +6566,40 @@
],
"name": "InterfacesMaker"
},
"jsii-calc.Isomorphism": {
"abstract": true,
"assembly": "jsii-calc",
"docs": {
"remarks": "Create a subclass of this, and assert that `this.myself()` actually returns\n`this` from within the constructor.",
"stability": "experimental",
"summary": "Checks the \"same instance\" isomorphism is preserved within the constructor."
},
"fqn": "jsii-calc.Isomorphism",
"initializer": {},
"kind": "class",
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 2500
},
"methods": [
{
"docs": {
"stability": "experimental"
},
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 2501
},
"name": "myself",
"returns": {
"type": {
"fqn": "jsii-calc.Isomorphism"
}
}
}
],
"name": "Isomorphism"
},
"jsii-calc.JSII417Derived": {
"assembly": "jsii-calc",
"base": "jsii-calc.JSII417PublicBaseOfBase",
Expand Down Expand Up @@ -13128,5 +13162,5 @@
}
},
"version": "0.0.0",
"fingerprint": "5SbCJfv1kDW24DUhPcwzoQ1k7Moq+rKOB+Q4TSZlKPE="
"fingerprint": "miVjqwWxNOLMY7fR23c/SVvfiGqkgqLgG+18qp4f8MM="
}
Original file line number Diff line number Diff line change
Expand Up @@ -6566,6 +6566,40 @@
],
"name": "InterfacesMaker"
},
"jsii-calc.Isomorphism": {
"abstract": true,
"assembly": "jsii-calc",
"docs": {
"remarks": "Create a subclass of this, and assert that `this.myself()` actually returns\n`this` from within the constructor.",
"stability": "experimental",
"summary": "Checks the \"same instance\" isomorphism is preserved within the constructor."
},
"fqn": "jsii-calc.Isomorphism",
"initializer": {},
"kind": "class",
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 2500
},
"methods": [
{
"docs": {
"stability": "experimental"
},
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 2501
},
"name": "myself",
"returns": {
"type": {
"fqn": "jsii-calc.Isomorphism"
}
}
}
],
"name": "Isomorphism"
},
"jsii-calc.JSII417Derived": {
"assembly": "jsii-calc",
"base": "jsii-calc.JSII417PublicBaseOfBase",
Expand Down Expand Up @@ -13128,5 +13162,5 @@
}
},
"version": "0.0.0",
"fingerprint": "5SbCJfv1kDW24DUhPcwzoQ1k7Moq+rKOB+Q4TSZlKPE="
"fingerprint": "miVjqwWxNOLMY7fR23c/SVvfiGqkgqLgG+18qp4f8MM="
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Amazon.JSII.Runtime.Deputy;

#pragma warning disable CS0672,CS0809,CS1591

namespace Amazon.JSII.Tests.CalculatorNamespace
{
/// <summary>Checks the "same instance" isomorphism is preserved within the constructor.</summary>
/// <remarks>
/// Create a subclass of this, and assert that <c>this.myself()</c> actually returns
/// <c>this</c> from within the constructor.
///
/// <strong>Stability</strong>: Experimental
/// </remarks>
[JsiiClass(nativeType: typeof(Amazon.JSII.Tests.CalculatorNamespace.Isomorphism), fullyQualifiedName: "jsii-calc.Isomorphism")]
public abstract class Isomorphism : DeputyBase
{
protected Isomorphism(): base(new DeputyProps(new object[]{}))
{
}

/// <summary>Used by jsii to construct an instance of this class from a Javascript-owned object reference</summary>
/// <param name="reference">The Javascript-owned object reference</param>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
protected Isomorphism(ByRefValue reference): base(reference)
{
}

/// <summary>Used by jsii to construct an instance of this class from DeputyProps</summary>
/// <param name="props">The deputy props</param>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
protected Isomorphism(DeputyProps props): base(props)
{
}

/// <remarks>
/// <strong>Stability</strong>: Experimental
/// </remarks>
[JsiiMethod(name: "myself", returnsJson: "{\"type\":{\"fqn\":\"jsii-calc.Isomorphism\"}}")]
public virtual Amazon.JSII.Tests.CalculatorNamespace.Isomorphism Myself()
{
return InvokeInstanceMethod<Amazon.JSII.Tests.CalculatorNamespace.Isomorphism>(new System.Type[]{}, new object[]{});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Amazon.JSII.Runtime.Deputy;

#pragma warning disable CS0672,CS0809,CS1591

namespace Amazon.JSII.Tests.CalculatorNamespace
{
/// <summary>Checks the "same instance" isomorphism is preserved within the constructor.</summary>
/// <remarks>
/// Create a subclass of this, and assert that <c>this.myself()</c> actually returns
/// <c>this</c> from within the constructor.
///
/// <strong>Stability</strong>: Experimental
/// </remarks>
[JsiiTypeProxy(nativeType: typeof(Amazon.JSII.Tests.CalculatorNamespace.Isomorphism), fullyQualifiedName: "jsii-calc.Isomorphism")]
internal sealed class IsomorphismProxy : Amazon.JSII.Tests.CalculatorNamespace.Isomorphism
{
private IsomorphismProxy(ByRefValue reference): base(reference)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package software.amazon.jsii.tests.calculator;

/**
* Checks the "same instance" isomorphism is preserved within the constructor.
* <p>
* Create a subclass of this, and assert that <code>this.myself()</code> actually returns
* <code>this</code> from within the constructor.
* <p>
* EXPERIMENTAL
*/
@javax.annotation.Generated(value = "jsii-pacmak")
@software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental)
@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.Isomorphism")
public abstract class Isomorphism extends software.amazon.jsii.JsiiObject {

protected Isomorphism(final software.amazon.jsii.JsiiObjectRef objRef) {
super(objRef);
}

protected Isomorphism(final software.amazon.jsii.JsiiObject.InitializationMode initializationMode) {
super(initializationMode);
}

protected Isomorphism() {
super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);
software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this);
}

/**
* EXPERIMENTAL
*/
@software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental)
public @org.jetbrains.annotations.NotNull software.amazon.jsii.tests.calculator.Isomorphism myself() {
return this.jsiiCall("myself", software.amazon.jsii.tests.calculator.Isomorphism.class);
}

/**
* A proxy class which represents a concrete javascript instance of this type.
*/
final static class Jsii$Proxy extends software.amazon.jsii.tests.calculator.Isomorphism {
protected Jsii$Proxy(final software.amazon.jsii.JsiiObjectRef objRef) {
super(objRef);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ jsii-calc.InterfaceInNamespaceIncludesClasses.Foo=software.amazon.jsii.tests.cal
jsii-calc.InterfaceInNamespaceIncludesClasses.Hello=software.amazon.jsii.tests.calculator.interface_in_namespace_includes_classes.Hello
jsii-calc.InterfaceInNamespaceOnlyInterface.Hello=software.amazon.jsii.tests.calculator.interface_in_namespace_only_interface.Hello
jsii-calc.InterfacesMaker=software.amazon.jsii.tests.calculator.InterfacesMaker
jsii-calc.Isomorphism=software.amazon.jsii.tests.calculator.Isomorphism
jsii-calc.JSII417Derived=software.amazon.jsii.tests.calculator.JSII417Derived
jsii-calc.JSII417PublicBaseOfBase=software.amazon.jsii.tests.calculator.JSII417PublicBaseOfBase
jsii-calc.JSObjectLiteralForInterface=software.amazon.jsii.tests.calculator.JSObjectLiteralForInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4348,6 +4348,34 @@ def make_interfaces(cls, count: jsii.Number) -> typing.List[scope.jsii_calc_lib.
return jsii.sinvoke(cls, "makeInterfaces", [count])


class Isomorphism(metaclass=jsii.JSIIAbstractClass, jsii_type="jsii-calc.Isomorphism"):
"""Checks the "same instance" isomorphism is preserved within the constructor.
Create a subclass of this, and assert that ``this.myself()`` actually returns
``this`` from within the constructor.
stability
:stability: experimental
"""
@builtins.staticmethod
def __jsii_proxy_class__():
return _IsomorphismProxy

def __init__(self) -> None:
jsii.create(Isomorphism, self, [])

@jsii.member(jsii_name="myself")
def myself(self) -> "Isomorphism":
"""
stability
:stability: experimental
"""
return jsii.invoke(self, "myself", [])


class _IsomorphismProxy(Isomorphism):
pass

class JSII417PublicBaseOfBase(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.JSII417PublicBaseOfBase"):
"""
stability
Expand Down Expand Up @@ -8685,6 +8713,7 @@ def next(self) -> jsii.Number:
"InbetweenClass",
"InterfaceCollections",
"InterfacesMaker",
"Isomorphism",
"JSII417Derived",
"JSII417PublicBaseOfBase",
"JSObjectLiteralForInterface",
Expand Down
11 changes: 11 additions & 0 deletions packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,11 @@ exports[`jsii-tree --all 1`] = `
│ │ │ └─┬ count
│ │ │ └── type: number
│ │ └── returns: Array<@scope/jsii-calc-lib.IDoublable>
│ ├─┬ class Isomorphism (experimental)
│ │ └─┬ members
│ │ ├── <initializer>() initializer (experimental)
│ │ └─┬ myself() method (experimental)
│ │ └── returns: jsii-calc.Isomorphism
│ ├─┬ class JSII417Derived (experimental)
│ │ ├── base: JSII417PublicBaseOfBase
│ │ └─┬ members
Expand Down Expand Up @@ -2734,6 +2739,7 @@ exports[`jsii-tree --inheritance 1`] = `
│ │ └── interfaces: IPublicInterface2
│ ├── class InterfaceCollections
│ ├── class InterfacesMaker
│ ├── class Isomorphism
│ ├─┬ class JSII417Derived
│ │ └── base: JSII417PublicBaseOfBase
│ ├── class JSII417PublicBaseOfBase
Expand Down Expand Up @@ -3365,6 +3371,10 @@ exports[`jsii-tree --members 1`] = `
│ ├─┬ class InterfacesMaker
│ │ └─┬ members
│ │ └── static makeInterfaces(count) method
│ ├─┬ class Isomorphism
│ │ └─┬ members
│ │ ├── <initializer>() initializer
│ │ └── myself() method
│ ├─┬ class JSII417Derived
│ │ └─┬ members
│ │ ├── <initializer>(property) initializer
Expand Down Expand Up @@ -4241,6 +4251,7 @@ exports[`jsii-tree --types 1`] = `
│ ├── class InbetweenClass
│ ├── class InterfaceCollections
│ ├── class InterfacesMaker
│ ├── class Isomorphism
│ ├── class JSII417Derived
│ ├── class JSII417PublicBaseOfBase
│ ├── class JSObjectLiteralForInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Array [
"jsii-calc.InterfaceCollections",
"jsii-calc.InterfaceInNamespaceIncludesClasses.Foo",
"jsii-calc.InterfacesMaker",
"jsii-calc.Isomorphism",
"jsii-calc.JSII417Derived",
"jsii-calc.JSII417PublicBaseOfBase",
"jsii-calc.JSObjectLiteralForInterface",
Expand Down

0 comments on commit df12ec8

Please sign in to comment.