tl;dr
Are there any ways to have a custom name for the exported d-bus methods which is different from the method name being decorated?
So here's the deal: I want to have a register a single object on D-Bus with multiple interfaces, where all interfaces have the same methods (different implementation):
/com/quaintous
|- com.quaintous.iface1
| |- GET
|- com.quaintous.iface2
| |- GET
If I was to use a class representing that single object and use the method decorator to export methods of that class to d-bus, I couldn't have two methods with the same name (the second one would overwrite the first one).
Example code (desired)
class Quaintous_DBus(dbus.service.Object):
def __init__(self):
bus_name = dbus.service.BusName('com.quaintous', bus=dbus.SessionBus())
dbus.service.Object.__init__(self, bus_name, '/com/quaintous')
@dbus.service.method('com.quaintous.iface1', name="GET")
def get_iface1(self, args):
# Impl
@dbus.service.method('com.quaintous.iface2', name="GET")
def get_iface1(self, args):
# Impl
something like name="GET"
.
Update
python-debus
actually does a one-to-one mapping of class method names to D-Bus method names and since a class cannot contains two methods with the same name, it seems impossible to do that. I was thinking of overwriting _method_lookup
as the last resort but I'm hoping for a better solution yet.
tl;dr
No I do not believe it can be done in that way with dbus-python, but below is a work-around:
If the requirement is to have one single class this will be problematic as Python itself does not support method overloading, so you cannot have more than one method with the exact same name in the same class. I assume the use-case is to share the implementation of a method between multiple methods exported on D-Bus under different interfaces? If so, there is a solution.
The D-Bus binding I believe you are using (dbus-python) will look for methods by name based on the method name which is called on the service, and match that with an interface string (if such a string exist).
The method lookup is done using the method name as key in the __dict__
dictionary in the classes in the class hierarchy of the service class. This, I believe, means there are no easy ways to make dbus-python look for another method without changing dbus-python itself. However, it means that there just needs to be a class somewhere in the hierarchy with a method with the correct name which is decorated with a specific interface string.
If you create an inheritance hierarchy where all methods appear in a separate class (with different interface strings for each method) and share a parent that implements the actual logic, it seems to appear on the bus in the way you want. Below is an example:
import gobject
import dbus
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
OPATH = "/temp/Test"
IFACE = "temp.Test"
BUS_NAME = "temp.Test"
class Implementation(object):
# This is the implementation shared by the methods exported on the bus
def theX(self, arg):
print arg
class MyService(dbus.service.Object):
def __init__(self):
bus = dbus.SessionBus()
bus.request_name(BUS_NAME, dbus.bus.NAME_FLAG_REPLACE_EXISTING)
bus_name = dbus.service.BusName(BUS_NAME, bus=bus)
dbus.service.Object.__init__(self, bus_name, OPATH)
class IfaceOne(MyService, Implementation):
def __init__(self):
MyService.__init__(self)
@dbus.service.method(dbus_interface=IFACE + ".IfaceOne", in_signature='s')
def X(self, arg):
super(IfaceOne, self).theX(arg)
class IfaceTwo(IfaceOne, Implementation):
def __init__(self):
MyService.__init__(self)
@dbus.service.method(dbus_interface=IFACE + ".IfaceTwo", in_signature='s')
def X(self, arg):
super(IfaceTwo, self).theX(arg)
if __name__ == "__main__":
iface_two = IfaceTwo()
loop = gobject.MainLoop()
loop.run()
For more details you can clone the dbus-python git and have a look around in the _method_lookup
method in service.py
. The method
decorator is implemented in decorators.py
.
Hope this helps.