Skip to content

Commit

Permalink
feat: allow varargs callback for signals (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdegat01 authored Sep 19, 2022
1 parent f4d173e commit a3379c7
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 2 deletions.
6 changes: 4 additions & 2 deletions src/dbus_fast/proxy_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ def _message_handler(self, msg):
def _add_signal(self, intr_signal, interface):
def on_signal_fn(fn):
fn_signature = inspect.signature(fn)
if not callable(fn) or len(fn_signature.parameters) != len(
intr_signal.args
if len(fn_signature.parameters) != len(intr_signal.args) and (
inspect.Parameter.VAR_POSITIONAL
not in [par.kind for par in fn_signature.parameters.values()]
or len(fn_signature.parameters) - 1 > len(intr_signal.args)
):
raise TypeError(
f"reply_notify must be a function with {len(intr_signal.args)} parameters"
Expand Down
95 changes: 95 additions & 0 deletions tests/client/test_signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from dbus_fast import Message
from dbus_fast.aio import MessageBus
from dbus_fast.aio.proxy_object import ProxyInterface
from dbus_fast.constants import RequestNameReply
from dbus_fast.introspection import Node
from dbus_fast.service import ServiceInterface, signal
Expand Down Expand Up @@ -158,6 +159,100 @@ def dummy_signal_handler(what):
bus3.disconnect()


@pytest.mark.asyncio
async def test_varargs_callback():
"""Test varargs callback for signal."""
bus1 = await MessageBus().connect()
bus2 = await MessageBus().connect()

await bus1.request_name("test.signals.name")
service_interface = ExampleInterface()
bus1.export("/test/path", service_interface)

obj = bus2.get_proxy_object(
"test.signals.name", "/test/path", bus1._introspect_export_path("/test/path")
)
interface = obj.get_interface(service_interface.name)

async def ping():
await bus2.call(
Message(
destination=bus1.unique_name,
interface="org.freedesktop.DBus.Peer",
path="/test/path",
member="Ping",
)
)

varargs_handler_counter = 0
varargs_handler_err = None
varargs_plus_handler_counter = 0
varargs_plus_handler_err = None

def varargs_handler(*args):
nonlocal varargs_handler_counter
nonlocal varargs_handler_err
try:
assert args[0] == "hello"
varargs_handler_counter += 1
except AssertionError as ex:
varargs_handler_err = ex

def varargs_plus_handler(value, *_):
nonlocal varargs_plus_handler_counter
nonlocal varargs_plus_handler_err
try:
assert value == "hello"
varargs_plus_handler_counter += 1
except AssertionError as ex:
varargs_plus_handler_err = ex

interface.on_some_signal(varargs_handler)
interface.on_some_signal(varargs_plus_handler)
await ping()

service_interface.SomeSignal()
await ping()
assert varargs_handler_err is None
assert varargs_handler_counter == 1
assert varargs_plus_handler_err is None
assert varargs_plus_handler_counter == 1

bus1.disconnect()
bus2.disconnect()


@pytest.mark.asyncio
async def test_on_signal_type_error():
"""Test on callback raises type errors for invalid callbacks."""
bus1 = await MessageBus().connect()
bus2 = await MessageBus().connect()

await bus1.request_name("test.signals.name")
service_interface = ExampleInterface()
bus1.export("/test/path", service_interface)

obj = bus2.get_proxy_object(
"test.signals.name", "/test/path", bus1._introspect_export_path("/test/path")
)
interface = obj.get_interface(service_interface.name)

with pytest.raises(TypeError):
interface.on_some_signal("not_a_callable")

with pytest.raises(TypeError):
interface.on_some_signal(lambda a, b: "Too many parameters")

with pytest.raises(TypeError):
interface.on_some_signal(lambda: "Too few parameters")

with pytest.raises(TypeError):
interface.on_some_signal(lambda a, b, *args: "Too many before varargs")

bus1.disconnect()
bus2.disconnect()


@pytest.mark.asyncio
async def test_signals_with_changing_owners():
well_known_name = "test.signals.changing.name"
Expand Down

0 comments on commit a3379c7

Please sign in to comment.