Skip to content

Commit

Permalink
Rework inheritance code
Browse files Browse the repository at this point in the history
Less carry over sets of methods
  • Loading branch information
igo95862 committed Jul 30, 2022
1 parent fb97f75 commit bbe9efc
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 58 deletions.
101 changes: 56 additions & 45 deletions src/sdbus/dbus_proxy_async_interface_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
Dict,
List,
Optional,
Set,
Tuple,
Type,
TypeVar,
Expand Down Expand Up @@ -66,8 +65,24 @@ def __new__(cls, name: str,
) -> DbusInterfaceMetaAsync:

dbus_to_python_name_map: Dict[str, str] = {}
declared_interfaces = set()
# Set interface name
superclass_members: Dict[str, DbusBindedAsync] = {}

for base in bases:
if issubclass(base, DbusInterfaceBaseAsync):
dbus_to_python_name_map.update(
base._dbus_to_python_name_map
)

for name, value in getmembers(base):
if isinstance(
value,
(
DbusMethodAsyncBinded,
DbusPropertyAsyncBinded,
)
):
superclass_members[name] = value

for key, value in namespace.items():
assert not isinstance(value, DbusSomethingSync), (
"Can't mix sync methods in async interface."
Expand All @@ -76,7 +91,6 @@ def __new__(cls, name: str,
if isinstance(value, DbusSomethingAsync):
value.interface_name = interface_name
value.serving_enabled = serving_enabled
declared_interfaces.add(key)

if isinstance(value, DbusMethodAsync):
dbus_to_python_name_map[value.method_name] = key
Expand All @@ -85,48 +99,46 @@ def __new__(cls, name: str,
elif isinstance(value, DbusSignalAsync):
dbus_to_python_name_map[value.signal_name] = key

super_declared_interfaces = set()
for base in bases:
if issubclass(base, DbusInterfaceBaseAsync):
super_declared_interfaces.update(
base._dbus_declared_interfaces)

dbus_to_python_name_map.update(
base._dbus_to_python_name_map
)

for key in super_declared_interfaces & namespace.keys():
value = namespace[key]

if isinstance(value, DbusOverload):
for base in bases:
try:
sc_dbus_def = base.__dict__[key]
break
except KeyError:
continue

assert isinstance(sc_dbus_def, DbusSomethingAsync)
new_dbus_def = deepcopy(sc_dbus_def)
if isinstance(new_dbus_def, DbusMethodAsync):
new_dbus_def.original_method = cast(
MethodType, value.original)
elif isinstance(new_dbus_def, DbusPropertyAsync):
new_dbus_def.property_getter = cast(
Callable[[DbusInterfaceBaseAsync], Any],
value.original)
if value.setter_overload is not None:
new_dbus_def.property_setter = value.setter_overload
else:
raise TypeError('Unknown overload')

namespace[key] = new_dbus_def
declared_interfaces.add(key)
try:
superclass_dbus_def = superclass_members[key]
except KeyError:
if isinstance(value, DbusOverload):
raise TypeError(
f"No D-Bus member '{key}' to overload with."
)
else:
raise TypeError("Attempted to overload dbus definition"
" without using @dbus_overload decorator")
if isinstance(value, DbusOverload):
if isinstance(
superclass_dbus_def,
DbusMethodAsyncBinded):
new_method_def = deepcopy(
superclass_dbus_def.dbus_method)
new_method_def.original_method = cast(
MethodType, value.original)

namespace[key] = new_method_def
elif isinstance(
superclass_dbus_def,
DbusPropertyAsyncBinded):
new_property_def = deepcopy(
superclass_dbus_def.dbus_property)
new_property_def.property_getter = cast(
Callable[[DbusInterfaceBaseAsync], Any],
value.original)
if value.setter_overload is not None:
new_property_def.property_setter = (
value.setter_overload
)

namespace[key] = new_property_def
else:
raise TypeError('Unknown D-Bus overload')
else:
raise TypeError(
"Attempted to overload dbus definition"
" without using @dbus_overload decorator"
)

namespace['_dbus_declared_interfaces'] = declared_interfaces
namespace['_dbus_to_python_name_map'] = dbus_to_python_name_map
namespace['_dbus_interface_name'] = interface_name
namespace['_dbus_serving_enabled'] = serving_enabled
Expand All @@ -140,7 +152,6 @@ def __new__(cls, name: str,


class DbusInterfaceBaseAsync(metaclass=DbusInterfaceMetaAsync):
_dbus_declared_interfaces: Set[str]
_dbus_interface_name: Optional[str]
_dbus_serving_enabled: bool
_dbus_to_python_name_map: Dict[str, str]
Expand Down
9 changes: 8 additions & 1 deletion src/sdbus/dbus_proxy_async_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,16 @@ def __init__(self,
dbus_method: DbusMethodAsync,
interface: DbusInterfaceBaseAsync):
self.dbus_method = dbus_method
self.interface_ref = weak_ref(interface)
self.interface_ref = (
weak_ref(interface)
if interface is not None
else None
)

self.__doc__ = dbus_method.__doc__

async def _call_dbus_async(self, *args: Any) -> Any:
assert self.interface_ref is not None
interface = self.interface_ref()
assert interface is not None

Expand Down Expand Up @@ -105,6 +110,7 @@ async def _call_dbus_async(self, *args: Any) -> Any:
return reply_message.get_contents()

def __call__(self, *args: Any, **kwargs: Any) -> Any:
assert self.interface_ref is not None
interface = self.interface_ref()
assert interface is not None

Expand Down Expand Up @@ -147,6 +153,7 @@ async def _call_method_from_dbus(
async def _call_from_dbus(
self,
request_message: SdBusMessage) -> None:
assert self.interface_ref is not None
interface = self.interface_ref()
assert interface is not None

Expand Down
10 changes: 9 additions & 1 deletion src/sdbus/dbus_proxy_async_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,19 @@ def __init__(self,
dbus_property: DbusPropertyAsync[T],
interface: DbusInterfaceBaseAsync):
self.dbus_property = dbus_property
self.interface_ref = weak_ref(interface)
self.interface_ref = (
weak_ref(interface)
if interface is not None
else None
)

self.__doc__ = dbus_property.__doc__

def __await__(self) -> Generator[Any, None, T]:
return self.get_async().__await__()

async def get_async(self) -> T:
assert self.interface_ref is not None
interface = self.interface_ref()
assert interface is not None

Expand All @@ -145,13 +150,15 @@ async def get_async(self) -> T:
return cast(T, reply_message.get_contents()[1])

def _reply_get_sync(self, message: SdBusMessage) -> None:
assert self.interface_ref is not None
interface = self.interface_ref()
assert interface is not None

reply_data: Any = self.dbus_property.property_getter(interface)
message.append_data(self.dbus_property.property_signature, reply_data)

def _reply_set_sync(self, message: SdBusMessage) -> None:
assert self.interface_ref is not None
interface = self.interface_ref()
assert interface is not None

Expand All @@ -176,6 +183,7 @@ def _reply_set_sync(self, message: SdBusMessage) -> None:
)

async def set_async(self, complete_object: T) -> None:
assert self.interface_ref is not None
interface = self.interface_ref()
assert interface is not None

Expand Down
10 changes: 5 additions & 5 deletions src/sdbus/dbus_proxy_async_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ def __init__(self,
dbus_signal: DbusSignalAsync[T],
interface: Optional[DbusInterfaceBaseAsync]):
self.dbus_signal = dbus_signal
if interface is not None:
self.interface_ref: Optional[weak_ref[DbusInterfaceBaseAsync]] \
= weak_ref(interface)
else:
self.interface_ref = None
self.interface_ref = (
weak_ref(interface)
if interface is not None
else None
)

self.__doc__ = dbus_signal.__doc__

Expand Down
16 changes: 10 additions & 6 deletions test/test_sd_bus_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ async def test_subclass(self) -> None:

test_var = ['asdasd']

class TestInheritnce(TestInterface):
class TestInheritence(TestInterface):
@dbus_method_async_override()
async def test_int(self) -> int:
return 2
Expand All @@ -308,13 +308,13 @@ def test_property_setter(self, var: str) -> None:
nonlocal test_var
test_var.insert(0, var)

test_subclass = TestInheritnce()
test_subclass = TestInheritence()

test_subclass.export_to_dbus('/subclass', self.bus)

self.assertEqual(await test_subclass.test_int(), 2)

test_subclass_connection = TestInheritnce.new_proxy(
test_subclass_connection = TestInheritence.new_proxy(
TEST_SERVICE_NAME, '/subclass', self.bus)

self.assertEqual(await test_subclass_connection.test_int(), 2)
Expand Down Expand Up @@ -343,12 +343,16 @@ def test_property_setter(self, var: str) -> None:
)

async def test_bad_subclass(self) -> None:
def bad_call() -> None:
class TestInheritnce(TestInterface):
with self.assertRaises(TypeError):
class TestInheritence(TestInterface):
async def test_int(self) -> int:
return 2

self.assertRaises(TypeError, bad_call)
with self.assertRaises(TypeError):
class TestInheritence2(TestInterface):
@dbus_method_async_override()
async def test_unrelated(self) -> int:
return 2

async def test_properties(self) -> None:
test_object, test_object_connection = initialize_object()
Expand Down

0 comments on commit bbe9efc

Please sign in to comment.