@dbus.service.method decorator fails if the method uses var args.
Submitted by James Henstridge
Assigned to Simon McVittie
Description
I was trying to write a decorator to make it easier to implement dbus methods using Twisted deferred objects.
My initial thought was to use a wrapper that hooked the Deferred object from Twisted to the DBus async callbacks. I implemented this as a decorator:
from twisted.internet import defer from twisted.python.util import mergeFunctionMetadata
def dbus_deferred_method(*args, **kwargs): def decorator(function): def wrapper(*args, **kwargs): dbus_callback = kwargs.pop('_dbus_callback') dbus_errback = kwargs.pop('_dbus_errback') d = defer.maybeDeferred(function, *args, **kwargs) d.addBoth( dbus_callback, lambda failure: dbus_errback(failure.value)) mergeFunctionMetadata(function, wrapper) return dbus.service.method( async_callbacks=('_dbus_callback', '_dbus_errback'), *args, **kwargs)(wrapper) return decorator
Unfortunately this resulted in the following exception:
Traceback (most recent call last): ... File "dbusutil.py", line 18, in decorator *args, **kwargs)(wrapper) File "dbus/decorators.py", line 158, in decorator args.pop(0) exceptions.IndexError: pop from empty list
As the wrapper doesn't have the expected function signature, the inspect.getargspec() based checks in dbus.service.method fail. It would be nice if this kind of use was supported.
I did manage to work around this problem, but the solution involved touching some of the private dbus attributes:
def dbus_deferred_method(*args, **kwargs): def decorator(function): function = dbus.service.method(*args, **kwargs)(function) def wrapper(*args, **kwargs): dbus_callback = kwargs.pop('_dbus_callback') dbus_errback = kwargs.pop('_dbus_errback') d = defer.maybeDeferred(function, *args, **kwargs) d.addBoth( dbus_callback, lambda failure: dbus_errback(failure.value)) # This will also merge the attributes added by the # @dbus.service.method decorator. mergeFunctionMetadata(function, wrapper) wrapper._dbus_async_callbacks = ('_dbus_callback', '_dbus_errback') return wrapper return decorator