Skip to content

Commit

Permalink
Fixed interface classes having corrupted __name__ attribute
Browse files Browse the repository at this point in the history
Seems like calling `getmembers` in metaclass corrupts `__name__`

Added tests so that does not repeat
  • Loading branch information
igo95862 committed Aug 3, 2022
1 parent 7928ef9 commit 2a1c397
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 38 deletions.
70 changes: 32 additions & 38 deletions src/sdbus/dbus_proxy_async_interface_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ def __new__(cls, name: str,
else set()
)
dbus_to_python_name_map: Dict[str, str] = {}
superclass_members: Dict[str, DbusBindedAsync] = {}
dbus_declared_members: Dict[str, DbusSomethingAsync] = {}
superclass_members: Dict[str, DbusSomethingAsync] = {}

for base in bases:
if issubclass(base, DbusInterfaceBaseAsync):
Expand All @@ -82,15 +83,9 @@ def __new__(cls, name: str,
base._dbus_served_interfaces_names
)

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

for key, value in namespace.items():
assert not isinstance(value, DbusSomethingSync), (
Expand All @@ -100,6 +95,7 @@ def __new__(cls, name: str,
if isinstance(value, DbusSomethingAsync):
value.interface_name = interface_name
value.serving_enabled = serving_enabled
dbus_declared_members[key] = value

if isinstance(value, DbusMethodAsync):
dbus_to_python_name_map[value.method_name] = key
Expand All @@ -109,50 +105,47 @@ def __new__(cls, name: str,
dbus_to_python_name_map[value.signal_name] = key

try:
superclass_dbus_def = superclass_members[key]
super_dbus_def = superclass_members[key]
except KeyError:
if isinstance(value, DbusOverload):
raise TypeError(
f"No D-Bus member '{key}' to overload with."
)
else:
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:
if not isinstance(value, DbusOverload):
raise TypeError(
"Attempted to overload dbus definition"
" without using @dbus_overload decorator"
)

if isinstance(super_dbus_def, DbusMethodAsync):
new_method_def = deepcopy(super_dbus_def)
new_method_def.original_method = cast(
MethodType, value.original)

namespace[key] = new_method_def
elif isinstance(super_dbus_def, DbusPropertyAsync):
new_property_def = deepcopy(super_dbus_def)
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')

dbus_declared_members.update(superclass_members)

namespace['_dbus_served_interfaces_names'] = \
dbus_served_interfaces_names
namespace['_dbus_to_python_name_map'] = dbus_to_python_name_map
namespace['_dbus_interface_name'] = interface_name
namespace['_dbus_serving_enabled'] = serving_enabled
namespace['_dbus_declared_members'] = dbus_declared_members
new_cls = super().__new__(
cls, name, bases, namespace,
interface_name,
Expand All @@ -167,6 +160,7 @@ class DbusInterfaceBaseAsync(metaclass=DbusInterfaceMetaAsync):
_dbus_serving_enabled: bool
_dbus_to_python_name_map: Dict[str, str]
_dbus_served_interfaces_names: Set[str]
_dbus_declared_members: Dict[str, DbusSomethingAsync]

def __init__(self) -> None:
self._activated_interfaces: List[SdBusInterface] = []
Expand Down
3 changes: 3 additions & 0 deletions test/test_proxies.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ async def test_connection(self) -> None:
self.assertIsInstance(await dbus_object.get_id(), str)
self.assertIsInstance(await dbus_object.features, list)

with self.subTest('Check __name__'):
self.assertEqual(FreedesktopDbus.__name__, 'FreedesktopDbus')


if __name__ == "__main__":
main()
25 changes: 25 additions & 0 deletions test/test_sd_bus_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,31 @@ def test_property_setter(self, var: str) -> None:
test_subclass._dbus_to_python_name_map,
)

with self.subTest('Tripple subclass'):
class TestInheritenceTri(TestInheritence):
@dbus_method_async_override()
async def test_int(self) -> int:
return 3

@dbus_property_async_override()
def test_property(self) -> str:
return 'tri'

test_subclass_tri = TestInheritenceTri()

test_subclass_tri.export_to_dbus('/subclass/tri', self.bus)

self.assertEqual(await test_subclass_tri.test_int(), 3)

test_subclass_tri_connection = TestInheritenceTri.new_proxy(
TEST_SERVICE_NAME, '/subclass/tri', self.bus)

self.assertEqual(await test_subclass_tri_connection.test_int(), 3)

self.assertEqual(await test_subclass_tri.test_property, 'tri')
self.assertEqual(
await test_subclass_tri_connection.test_property, 'tri')

async def test_bad_subclass(self) -> None:
with self.assertRaises(TypeError):
class TestInheritence(TestInterface):
Expand Down

0 comments on commit 2a1c397

Please sign in to comment.