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__'

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.
  • Loading branch information
RomainMuller committed Aug 3, 2023
1 parent dd77211 commit f066874
Showing 1 changed file with 22 additions and 5 deletions.
27 changes: 22 additions & 5 deletions packages/@jsii/python-runtime/src/jsii/_reference_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import inspect

from typing import Any, Iterable, 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) -> Iterable[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 f066874

Please sign in to comment.