# HG changeset patch # User Goffi # Date 1333092203 -7200 # Node ID c97640c90a94858af1c8de8757fafddbb4a5dee7 # Parent 47af6076701398d727c2aeab829c29b296e1fa30 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 diff -r 47af60767013 -r c97640c90a94 src/bridge/DBus.py --- a/src/bridge/DBus.py Thu Mar 29 00:04:31 2012 +0200 +++ b/src/bridge/DBus.py Fri Mar 30 09:23:23 2012 +0200 @@ -24,6 +24,7 @@ import dbus import dbus.service import dbus.mainloop.glib +import inspect from logging import debug, info, error from twisted.internet.defer import Deferred @@ -82,7 +83,7 @@ if not isinstance(result, Deferred): error("Asynchronous method [%s] does not return a Deferred." % name) raise AsyncNotDeferred - result.addCallback(callback) + result.addCallback(lambda result: callback() if result==None else callback(result)) result.addErrback(lambda err:errback(GenericException(err))) else: if isinstance(result, Deferred): @@ -426,17 +427,32 @@ i+=1 return attr - def addMethod(self, name, int_suffix, in_sign, out_sign, async=False, doc={}): + def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False): """Dynamically add a method to Dbus Bridge""" - _attributes = self.__attributes(in_sign) + inspect_args = inspect.getargspec(method) + + _attributes = inspect_args.args + _defaults = list(inspect_args.defaults or []) + + if inspect.ismethod(method): + #if we have a method, we don't want the first argument (usually 'self') + del(_attributes[0]) if async: _attributes.extend(['callback','errback']) + _defaults.extend(['callback', 'errback']) attributes = ', '.join(_attributes) + + #now we create a second list with default values + for i in range(1, len(_defaults)+1): + _attributes[-i] = "%s = %s" % (_attributes[-i], repr(_defaults[-i])) - code = compile ('def '+name+' (self,'+attributes+'): return self.cb["'+name+'"]('+attributes+')', '','exec') - exec (code) + attributes_defaults = ', '.join(_attributes) + + code = compile ('def %(name)s (self,%(attributes_defaults)s): return self.cb["%(name)s"](%(attributes)s)' % + {'name':name, 'attributes_defaults':attributes_defaults, 'attributes':attributes}, '','exec') + exec (code) #FIXME: to the same thing in a cleaner way, without compile/exec method = locals()[name] async_callbacks = ('callback', 'errback') if async else None setattr(DbusObject, name, dbus.service.method( @@ -449,6 +465,7 @@ def addSignal(self, name, int_suffix, signature, doc={}): """Dynamically add a signal to Dbus Bridge""" attributes = ', '.join(self.__attributes(signature)) + #TODO: use doc parameter to name attributes #code = compile ('def '+name+' (self,'+attributes+'): debug ("'+name+' signal")', '','exec') #XXX: the debug is too annoying with xmllog code = compile ('def '+name+' (self,'+attributes+'): pass', '','exec') @@ -518,8 +535,9 @@ def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}): """Dynamically add a method to Dbus Bridge""" + #FIXME: doc parameter is kept only temporary, the time to remove it from calls print ("Adding method [%s] to DBus bridge" % name) - self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, async, doc) + self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async) self.register(name, method) def addSignal(self, name, int_suffix, signature, doc={}): diff -r 47af60767013 -r c97640c90a94 src/bridge/bridge_constructor/dbus_core_template.py --- a/src/bridge/bridge_constructor/dbus_core_template.py Thu Mar 29 00:04:31 2012 +0200 +++ b/src/bridge/bridge_constructor/dbus_core_template.py Fri Mar 30 09:23:23 2012 +0200 @@ -24,6 +24,7 @@ import dbus import dbus.service import dbus.mainloop.glib +import inspect from logging import debug, info, error from twisted.internet.defer import Deferred @@ -82,7 +83,7 @@ if not isinstance(result, Deferred): error("Asynchronous method [%s] does not return a Deferred." % name) raise AsyncNotDeferred - result.addCallback(callback) + result.addCallback(lambda result: callback() if result==None else callback(result)) result.addErrback(lambda err:errback(GenericException(err))) else: if isinstance(result, Deferred): @@ -142,17 +143,32 @@ i+=1 return attr - def addMethod(self, name, int_suffix, in_sign, out_sign, async=False, doc={}): + def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False): """Dynamically add a method to Dbus Bridge""" - _attributes = self.__attributes(in_sign) + inspect_args = inspect.getargspec(method) + + _attributes = inspect_args.args + _defaults = list(inspect_args.defaults or []) + + if inspect.ismethod(method): + #if we have a method, we don't want the first argument (usually 'self') + del(_attributes[0]) if async: _attributes.extend(['callback','errback']) + _defaults.extend(['callback', 'errback']) attributes = ', '.join(_attributes) + + #now we create a second list with default values + for i in range(1, len(_defaults)+1): + _attributes[-i] = "%s = %s" % (_attributes[-i], repr(_defaults[-i])) - code = compile ('def '+name+' (self,'+attributes+'): return self.cb["'+name+'"]('+attributes+')', '','exec') - exec (code) + attributes_defaults = ', '.join(_attributes) + + code = compile ('def %(name)s (self,%(attributes_defaults)s): return self.cb["%(name)s"](%(attributes)s)' % + {'name':name, 'attributes_defaults':attributes_defaults, 'attributes':attributes}, '','exec') + exec (code) #FIXME: to the same thing in a cleaner way, without compile/exec method = locals()[name] async_callbacks = ('callback', 'errback') if async else None setattr(DbusObject, name, dbus.service.method( @@ -165,6 +181,7 @@ def addSignal(self, name, int_suffix, signature, doc={}): """Dynamically add a signal to Dbus Bridge""" attributes = ', '.join(self.__attributes(signature)) + #TODO: use doc parameter to name attributes #code = compile ('def '+name+' (self,'+attributes+'): debug ("'+name+' signal")', '','exec') #XXX: the debug is too annoying with xmllog code = compile ('def '+name+' (self,'+attributes+'): pass', '','exec') @@ -193,8 +210,9 @@ def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}): """Dynamically add a method to Dbus Bridge""" + #FIXME: doc parameter is kept only temporary, the time to remove it from calls print ("Adding method [%s] to DBus bridge" % name) - self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, async, doc) + self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async) self.register(name, method) def addSignal(self, name, int_suffix, signature, doc={}): diff -r 47af60767013 -r c97640c90a94 src/plugins/plugin_xep_0077.py --- a/src/plugins/plugin_xep_0077.py Thu Mar 29 00:04:31 2012 +0200 +++ b/src/plugins/plugin_xep_0077.py Fri Mar 30 09:23:23 2012 +0200 @@ -48,7 +48,7 @@ self.host = host self.triggers = {} #used by other protocol (e.g. XEP-0100) to finish registration. key = target_jid host.bridge.addMethod("in_band_register", ".plugin", in_sign='ss', out_sign='s', method=self.in_band_register) - host.bridge.addMethod("in_band_submit", ".plugin", in_sign='sa(ss)', out_sign='s', method=self.in_band_submit) + host.bridge.addMethod("in_band_submit", ".plugin", in_sign='ssa(ss)s', out_sign='s', method=self.in_band_submit) def addTrigger(self, target, cb, profile): """Add a callback which is called when registration to target is successful""" diff -r 47af60767013 -r c97640c90a94 src/plugins/plugin_xep_0277.py --- a/src/plugins/plugin_xep_0277.py Thu Mar 29 00:04:31 2012 +0200 +++ b/src/plugins/plugin_xep_0277.py Fri Mar 30 09:23:23 2012 +0200 @@ -146,7 +146,7 @@ self.host.plugins["XEP-0060"].publish(None, NS_MICROBLOG, [item], profile_key = profile) return 0 - def getLastMicroblogs(self, pub_jid, max_items=10, profile_key='@DEFAULT@', callback=None, errback=None): + def getLastMicroblogs(self, pub_jid, max_items=10, profile_key='@DEFAULT@'): """Get the last published microblogs @param pub_jid: jid of the publisher @param max_items: how many microblogs we want to get @@ -156,9 +156,9 @@ """ assert(callback) d = self.host.plugins["XEP-0060"].getItems(jid.JID(pub_jid), NS_MICROBLOG, max_items=max_items, profile_key=profile_key) - d.addCallbacks(lambda items: callback(map(self.item2mbdata, items)), errback) + d.addCallback(lambda items: map(self.item2mbdata, items)) - def setMicroblogAccess(self, access="presence", profile_key='@DEFAULT@', callback=None, errback=None): + def setMicroblogAccess(self, access="presence", profile_key='@DEFAULT@'): """Create a microblog node on PEP with given access If the node already exists, it change options @param access: Node access model, according to xep-0060 #4.5 @@ -173,12 +173,11 @@ def cb(result): #Node is created with right permission debug(_("Microblog node has now access %s") % access) - callback() def fatal_err(s_error): #Something went wrong error(_("Can't set microblog access")) - errback(NodeAccessChangeException()) + raise NodeAccessChangeException() def err_cb(s_error): #If the node already exists, the condition is "conflict",