Wed 20 Apr 2005
So Johan Dahlin, PyGTK maintainer and Python guru extraordinaire, pointed me to some nice ideas for implementing the DBus bindings. While I didn’t quite like Twisted’s deffered stuff it did get me looking into some of the newer features of Python. After talking with Ray Strode I am thinking of doing things like this using decorators:
class my_object(dbus.Object):
@dbus_method('com.martianrock.MyInterface')
def my_exported_method(self, arg1, arg2, etc):
return 'you've called a method'
@dbus_signal('com.martianrock.MyInterface')
def my_exported_signal(self, arg1, arg2, etc):
pre_process()
emit()
post_process()
I don’t have a huge handle on decorators yet so I don’t know if the above is completely implementable but the idea is to decorate methods and signals one wants to export over the bus instead of passing in a list, as is done now, or register each member in the constructor.
The signal case is interesting because signals are emitted and not caught within a dbus.Object. The idea is the exported signal method is the emitter. In order to emit a signal the object just needs to call this method with the correct number of arguments it wants to send in the signal. Arbitrary code can be executed before and after the signal is emitted. An emit() function will be created local to the scope of the decorated method which does the actuall emittion. If no emit is called the signal is automaticly emitted at the end of the method. Again I don’t know if any of this is possible with decorators but it would be cool.
Another possible use of decorators is to use them to specify return types for methods and argument types for both methods and signals. Of course that would all be depricated once Python implement a more formal way to specify types.
P.S. To all you Ruby fans out there who are itching to post comments every time somone mentions the word Python, DON’T. XYZ language does it better this way, is just noise to me. I’m talking about DBus and Python and am not in the mood to start a language war. If I ever flame Ruby or XYZ flavor of the month project feel free to comment and flame back. I’m sure Ruby is a great language in its own right but it is way off topic here.
UPDATE: Ray just reminded me that signal emission is async and only happens when you go back to the main loop, so having an emit() call so you can do pre and post processing is useless. So now signals will be emitted after the decorated method returns.
[read this post in: ar de es fr it ja ko pt ru zh-CN ]
April 21st, 2005 at 12:40 am
You should be able to implement your dbus_method decorator with something like this:
def dbus_method(interface_name): def decorator(func): func.dbus_interface = interface_name return func return decoratorAfter the class is constructed, you can check for all methods with dbus_interface attributes to work out what interfaces to provide. Furthermore, if you use a custom meta-class for dbus.Object, you can do some extra processing at class creation time.
April 21st, 2005 at 11:37 am
For the dbus_signal() decorator, you might want to try something like this (hopefully the formatting won’t get too mangled):
def dbus_signal(dbus_interface): def decorator(func): def handler(self, *args, **kwargs): func(self, *args, **kwargs) # however you emit a dbus signal ... emit_signal(self, dbus_interface, func.func_name, *args, **kwargs) handler.func_name = func.func_name return handler return decoratorThis decorator wraps the function object so that you can perform a signal emission after running the function. The assignment to the func_name attribute is so that the proxy function reports the right name in stack traces, etc.