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))