Skip to content

Commit

Permalink
fix(python): type object 'InterfaceDynamicProxy' has no attribute '__…
Browse files Browse the repository at this point in the history
…jsii_type__' (#4209)

In the odd case where an opaque reference is returned (FQN is `Object`) and no interfaces are registered, the `InterfaceDynamicProxy` instance created to represent the value in Python did not have any delegate, resulting it in not having any visible properties; including a `__jsii_type__` value on the `__class__`, or the `__jsii_ref__` property, both of which are required for the vlaue to be able to correctly make it back to JavaScript.



---

By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license].

[Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0
  • Loading branch information
RomainMuller committed Aug 3, 2023
1 parent dd77211 commit 057b267
Showing 1 changed file with 23 additions and 6 deletions.
29 changes: 23 additions & 6 deletions packages/@jsii/python-runtime/src/jsii/_reference_map.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# This module exists to break an import cycle between jsii.runtime and jsii.kernel
import inspect

from typing import Any, Iterable, Mapping, MutableMapping, Type
from typing import Any, Iterable, List, Mapping, MutableMapping, Type
from ._kernel.types import ObjRef


_types = {}
Expand Down Expand Up @@ -32,15 +33,15 @@ def __init__(self, ref: str) -> None:


class _ReferenceMap:
def __init__(self, types):
def __init__(self, types: Mapping[str, Type]) -> None:
# 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._refs: MutableMapping[str, Any] = {}
self._types = types

def register(self, inst: Any):
def register(self, inst: Any) -> None:
self._refs[inst.__jsii_ref__.ref] = inst

def resolve(self, kernel, ref):
Expand Down Expand Up @@ -129,18 +130,34 @@ def resolve(self, kernel, ref):
else:
raise ValueError(f"Unknown type: {class_fqn}")

def resolve_id(self, id):
def resolve_id(self, id: str) -> Any:
return self._refs[id]

def build_interface_proxies_for_ref(self, ref):
def build_interface_proxies_for_ref(self, ref: ObjRef) -> List[Any]:
ifaces = [_interfaces[fqn] for fqn in ref.interfaces or []]
classes = [iface.__jsii_proxy_class__() for iface in ifaces]

# If there's no classes, use an Opaque reference to make sure the
# __jsii_ref__ property is visible through the InterfaceDynamicProxy.
if len(classes) == 0:
return [Opaque(ref)]

insts = [klass.__new__(klass) for klass in classes]
for inst in insts:
inst.__jsii_ref__ = ref
return insts


class Opaque:
def __init__(self, ref: ObjRef) -> None:
# Set the __jsii_type__ property on the class if it's not there already
if getattr(self.__class__, "__jsii_type__", None) is None:
setattr(self.__class__, "__jsii_type__", "Object")

# Track the jsii reference
self.__jsii_ref__ = ref


class InterfaceDynamicProxy(object):
def __init__(self, delegates):
self._delegates = delegates
Expand Down

0 comments on commit 057b267

Please sign in to comment.