Mercurial > libervia-backend
comparison src/bridge/DBus.py @ 468:c97640c90a94
D-Bus Bridge: use inspection to name attribute + fix asynchronous calls for dynamically added method, it now use deferred return value instead of callback/errback attributes
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 30 Mar 2012 09:23:23 +0200 |
parents | cf005701624b |
children | db4c2b82bab6 |
comparison
equal
deleted
inserted
replaced
467:47af60767013 | 468:c97640c90a94 |
---|---|
22 | 22 |
23 from bridge import Bridge | 23 from bridge import Bridge |
24 import dbus | 24 import dbus |
25 import dbus.service | 25 import dbus.service |
26 import dbus.mainloop.glib | 26 import dbus.mainloop.glib |
27 import inspect | |
27 from logging import debug, info, error | 28 from logging import debug, info, error |
28 from twisted.internet.defer import Deferred | 29 from twisted.internet.defer import Deferred |
29 | 30 |
30 const_INT_PREFIX = "org.goffi.SAT" #Interface prefix | 31 const_INT_PREFIX = "org.goffi.SAT" #Interface prefix |
31 const_ERROR_PREFIX = const_INT_PREFIX+".error" | 32 const_ERROR_PREFIX = const_INT_PREFIX+".error" |
80 result = self.cb[name](*args, **kwargs) | 81 result = self.cb[name](*args, **kwargs) |
81 if async: | 82 if async: |
82 if not isinstance(result, Deferred): | 83 if not isinstance(result, Deferred): |
83 error("Asynchronous method [%s] does not return a Deferred." % name) | 84 error("Asynchronous method [%s] does not return a Deferred." % name) |
84 raise AsyncNotDeferred | 85 raise AsyncNotDeferred |
85 result.addCallback(callback) | 86 result.addCallback(lambda result: callback() if result==None else callback(result)) |
86 result.addErrback(lambda err:errback(GenericException(err))) | 87 result.addErrback(lambda err:errback(GenericException(err))) |
87 else: | 88 else: |
88 if isinstance(result, Deferred): | 89 if isinstance(result, Deferred): |
89 error("Synchronous method [%s] return a Deferred." % name) | 90 error("Synchronous method [%s] return a Deferred." % name) |
90 raise DeferredNotAsync | 91 raise DeferredNotAsync |
424 if opening_count == 0: | 425 if opening_count == 0: |
425 break | 426 break |
426 i+=1 | 427 i+=1 |
427 return attr | 428 return attr |
428 | 429 |
429 def addMethod(self, name, int_suffix, in_sign, out_sign, async=False, doc={}): | 430 def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False): |
430 """Dynamically add a method to Dbus Bridge""" | 431 """Dynamically add a method to Dbus Bridge""" |
431 _attributes = self.__attributes(in_sign) | 432 inspect_args = inspect.getargspec(method) |
433 | |
434 _attributes = inspect_args.args | |
435 _defaults = list(inspect_args.defaults or []) | |
436 | |
437 if inspect.ismethod(method): | |
438 #if we have a method, we don't want the first argument (usually 'self') | |
439 del(_attributes[0]) | |
432 | 440 |
433 if async: | 441 if async: |
434 _attributes.extend(['callback','errback']) | 442 _attributes.extend(['callback','errback']) |
443 _defaults.extend(['callback', 'errback']) | |
435 | 444 |
436 attributes = ', '.join(_attributes) | 445 attributes = ', '.join(_attributes) |
437 | 446 |
438 code = compile ('def '+name+' (self,'+attributes+'): return self.cb["'+name+'"]('+attributes+')', '<DBus bridge>','exec') | 447 #now we create a second list with default values |
439 exec (code) | 448 for i in range(1, len(_defaults)+1): |
449 _attributes[-i] = "%s = %s" % (_attributes[-i], repr(_defaults[-i])) | |
450 | |
451 attributes_defaults = ', '.join(_attributes) | |
452 | |
453 code = compile ('def %(name)s (self,%(attributes_defaults)s): return self.cb["%(name)s"](%(attributes)s)' % | |
454 {'name':name, 'attributes_defaults':attributes_defaults, 'attributes':attributes}, '<DBus bridge>','exec') | |
455 exec (code) #FIXME: to the same thing in a cleaner way, without compile/exec | |
440 method = locals()[name] | 456 method = locals()[name] |
441 async_callbacks = ('callback', 'errback') if async else None | 457 async_callbacks = ('callback', 'errback') if async else None |
442 setattr(DbusObject, name, dbus.service.method( | 458 setattr(DbusObject, name, dbus.service.method( |
443 const_INT_PREFIX+int_suffix, in_signature=in_sign, out_signature=out_sign, | 459 const_INT_PREFIX+int_suffix, in_signature=in_sign, out_signature=out_sign, |
444 async_callbacks=async_callbacks)(method)) | 460 async_callbacks=async_callbacks)(method)) |
447 func_table[function.__name__] = function #Needed for introspection | 463 func_table[function.__name__] = function #Needed for introspection |
448 | 464 |
449 def addSignal(self, name, int_suffix, signature, doc={}): | 465 def addSignal(self, name, int_suffix, signature, doc={}): |
450 """Dynamically add a signal to Dbus Bridge""" | 466 """Dynamically add a signal to Dbus Bridge""" |
451 attributes = ', '.join(self.__attributes(signature)) | 467 attributes = ', '.join(self.__attributes(signature)) |
468 #TODO: use doc parameter to name attributes | |
452 | 469 |
453 #code = compile ('def '+name+' (self,'+attributes+'): debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the debug is too annoying with xmllog | 470 #code = compile ('def '+name+' (self,'+attributes+'): debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the debug is too annoying with xmllog |
454 code = compile ('def '+name+' (self,'+attributes+'): pass', '<DBus bridge>','exec') | 471 code = compile ('def '+name+' (self,'+attributes+'): pass', '<DBus bridge>','exec') |
455 exec (code) | 472 exec (code) |
456 signal = locals()[name] | 473 signal = locals()[name] |
516 debug("registering DBus bridge method [%s]", name) | 533 debug("registering DBus bridge method [%s]", name) |
517 self.dbus_bridge.register(name, callback) | 534 self.dbus_bridge.register(name, callback) |
518 | 535 |
519 def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}): | 536 def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}): |
520 """Dynamically add a method to Dbus Bridge""" | 537 """Dynamically add a method to Dbus Bridge""" |
538 #FIXME: doc parameter is kept only temporary, the time to remove it from calls | |
521 print ("Adding method [%s] to DBus bridge" % name) | 539 print ("Adding method [%s] to DBus bridge" % name) |
522 self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, async, doc) | 540 self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async) |
523 self.register(name, method) | 541 self.register(name, method) |
524 | 542 |
525 def addSignal(self, name, int_suffix, signature, doc={}): | 543 def addSignal(self, name, int_suffix, signature, doc={}): |
526 self.dbus_bridge.addSignal(name, int_suffix, signature, doc) | 544 self.dbus_bridge.addSignal(name, int_suffix, signature, doc) |
527 setattr(DBusBridge, name, getattr(self.dbus_bridge, name)) | 545 setattr(DBusBridge, name, getattr(self.dbus_bridge, name)) |