def _dispatch(self, method, message): """Dispatch a method call.""" log = self.logger context = 'methodcall %s:%s.%s' % \ (message.path, method.interface, method.name) log.setContext(context, store=self.connection.local) if method.args_in is not None and method.args_in != message.signature: log.error('invalid call signature (got: %s, expecting: %s)', repr(message.signature), repr(method.args_in)) self._error(dbusx.ERROR_INVALID_ARGS) return self.method = method self.message = message try: result = method(*message.args) except dbusx.NoReply: return except dbusx.MethodReply as e: result = e.args except dbusx.Error as e: error = str(e) if not dbusx.check_error_name(error): log.error('handler raised invalid error name: %s', repr(error)) error = dbusx.ERROR_FAILED self._error(error) return except Exception as e: log.error('uncaught exception in handler', exc_info=True) self._error(dbusx.ERROR_FAILED) return signature = method.args_out or '' nargs = len(dbusx.split_signature(signature)) if nargs == 0: if result is not None: log.error('handler should return None for signature %s ' '(got %s instead)', repr(signature), repr(result)) self._error(dbusx.ERROR_FAILED) result = () elif nargs == 1: result = (result,) else: if not isinstance(result, tuple): log.error('handler should return tuple for signature %s ' '(got %s instead)', repr(signature), repr(result)) self._error(dbusx.ERROR_FAILED) argtest = dbusx.Message(dbusx.MESSAGE_TYPE_METHOD_RETURN) try: argtest.set_args(signature, result) except (TypeError, ValueError): log.error('handler return value does not match signature %s ' '(got: %s)', repr(signature), repr(result)) self._error(dbusx.ERROR_FAILED) return self._reply(signature, result)
def Introspect(self): path = self.message.path doc = etree.Element('node', name=path) interfaces = {} for method in self.methods(): try: interfaces[method.interface][0].append(method) except KeyError: interfaces[method.interface] = ([method], []) for signal in self.signals(): try: interfaces[signal.interface][1].append(signal) except KeyError: interfaces[signal.interface] = ([], [signal]) for iface in interfaces: ifnode = etree.SubElement(doc, 'interface', name=iface) for method in interfaces[iface][0]: mnode = etree.SubElement(ifnode, 'method', name=method.name) if method.args_in is not None: for ix,arg in enumerate(dbusx.split_signature(method.args_in)): anode = etree.SubElement(mnode, 'arg', name='in%d' % ix, type=arg, direction='in') if method.args_out is not None: for ix,arg in enumerate(dbusx.split_signature(method.args_out)): anode = etree.SubElement(mnode, 'arg', name='out%d' % ix, type=arg, direction='out') for signal in interfaces[iface][1]: snode = etree.SubElement(ifnode, 'signal', name=signal.name) if signal.args is not None: for ix,arg in enumerate(dbusx.split_signature(signal.args)): anode = etree.SubElement(snode, 'arg', name='arg%d' % ix, type=arg) dbusx.util.etree_indent(doc) xml = dbusx.INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE.upper() # can etree output unicode directly? xml += etree.tostring(doc, encoding='utf-8').decode('utf-8') return xml
def test_dict_entry(self): assert dbusx.split_signature('{ss}u') == ['{ss}', 'u']
def test_struct(self): assert dbusx.split_signature('(ii)u') == ['(ii)', 'u']
def test_nested_array(self): assert dbusx.split_signature('aaiu') == ['aai', 'u']
def test_multiple(self): assert dbusx.split_signature('iu') == ['i', 'u']
def test_single(self): assert dbusx.split_signature('i') == ['i']
def test_empty(self): assert dbusx.split_signature('') == []