Mercurial > libervia-backend
comparison src/bridge/bridge_constructor/dbus_core_template.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 |
140 if opening_count == 0: | 141 if opening_count == 0: |
141 break | 142 break |
142 i+=1 | 143 i+=1 |
143 return attr | 144 return attr |
144 | 145 |
145 def addMethod(self, name, int_suffix, in_sign, out_sign, async=False, doc={}): | 146 def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False): |
146 """Dynamically add a method to Dbus Bridge""" | 147 """Dynamically add a method to Dbus Bridge""" |
147 _attributes = self.__attributes(in_sign) | 148 inspect_args = inspect.getargspec(method) |
149 | |
150 _attributes = inspect_args.args | |
151 _defaults = list(inspect_args.defaults or []) | |
152 | |
153 if inspect.ismethod(method): | |
154 #if we have a method, we don't want the first argument (usually 'self') | |
155 del(_attributes[0]) | |
148 | 156 |
149 if async: | 157 if async: |
150 _attributes.extend(['callback','errback']) | 158 _attributes.extend(['callback','errback']) |
159 _defaults.extend(['callback', 'errback']) | |
151 | 160 |
152 attributes = ', '.join(_attributes) | 161 attributes = ', '.join(_attributes) |
153 | 162 |
154 code = compile ('def '+name+' (self,'+attributes+'): return self.cb["'+name+'"]('+attributes+')', '<DBus bridge>','exec') | 163 #now we create a second list with default values |
155 exec (code) | 164 for i in range(1, len(_defaults)+1): |
165 _attributes[-i] = "%s = %s" % (_attributes[-i], repr(_defaults[-i])) | |
166 | |
167 attributes_defaults = ', '.join(_attributes) | |
168 | |
169 code = compile ('def %(name)s (self,%(attributes_defaults)s): return self.cb["%(name)s"](%(attributes)s)' % | |
170 {'name':name, 'attributes_defaults':attributes_defaults, 'attributes':attributes}, '<DBus bridge>','exec') | |
171 exec (code) #FIXME: to the same thing in a cleaner way, without compile/exec | |
156 method = locals()[name] | 172 method = locals()[name] |
157 async_callbacks = ('callback', 'errback') if async else None | 173 async_callbacks = ('callback', 'errback') if async else None |
158 setattr(DbusObject, name, dbus.service.method( | 174 setattr(DbusObject, name, dbus.service.method( |
159 const_INT_PREFIX+int_suffix, in_signature=in_sign, out_signature=out_sign, | 175 const_INT_PREFIX+int_suffix, in_signature=in_sign, out_signature=out_sign, |
160 async_callbacks=async_callbacks)(method)) | 176 async_callbacks=async_callbacks)(method)) |
163 func_table[function.__name__] = function #Needed for introspection | 179 func_table[function.__name__] = function #Needed for introspection |
164 | 180 |
165 def addSignal(self, name, int_suffix, signature, doc={}): | 181 def addSignal(self, name, int_suffix, signature, doc={}): |
166 """Dynamically add a signal to Dbus Bridge""" | 182 """Dynamically add a signal to Dbus Bridge""" |
167 attributes = ', '.join(self.__attributes(signature)) | 183 attributes = ', '.join(self.__attributes(signature)) |
184 #TODO: use doc parameter to name attributes | |
168 | 185 |
169 #code = compile ('def '+name+' (self,'+attributes+'): debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the debug is too annoying with xmllog | 186 #code = compile ('def '+name+' (self,'+attributes+'): debug ("'+name+' signal")', '<DBus bridge>','exec') #XXX: the debug is too annoying with xmllog |
170 code = compile ('def '+name+' (self,'+attributes+'): pass', '<DBus bridge>','exec') | 187 code = compile ('def '+name+' (self,'+attributes+'): pass', '<DBus bridge>','exec') |
171 exec (code) | 188 exec (code) |
172 signal = locals()[name] | 189 signal = locals()[name] |
191 debug("registering DBus bridge method [%s]", name) | 208 debug("registering DBus bridge method [%s]", name) |
192 self.dbus_bridge.register(name, callback) | 209 self.dbus_bridge.register(name, callback) |
193 | 210 |
194 def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}): | 211 def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}): |
195 """Dynamically add a method to Dbus Bridge""" | 212 """Dynamically add a method to Dbus Bridge""" |
213 #FIXME: doc parameter is kept only temporary, the time to remove it from calls | |
196 print ("Adding method [%s] to DBus bridge" % name) | 214 print ("Adding method [%s] to DBus bridge" % name) |
197 self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, async, doc) | 215 self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async) |
198 self.register(name, method) | 216 self.register(name, method) |
199 | 217 |
200 def addSignal(self, name, int_suffix, signature, doc={}): | 218 def addSignal(self, name, int_suffix, signature, doc={}): |
201 self.dbus_bridge.addSignal(name, int_suffix, signature, doc) | 219 self.dbus_bridge.addSignal(name, int_suffix, signature, doc) |
202 setattr(DBusBridge, name, getattr(self.dbus_bridge, name)) | 220 setattr(DBusBridge, name, getattr(self.dbus_bridge, name)) |