예제 #1
0
    def _reflect_on_method(cls, func):
        args = func._dbus_args

        if func._dbus_in_signature:
            # convert signature into a tuple so length refers to number of
            # types, not number of characters. the length is checked by
            # the decorator to make sure it matches the length of args.
            in_sig = tuple(_dbus_bindings.Signature(func._dbus_in_signature))
        else:
            # magic iterator which returns as many v's as we need
            in_sig = _VariantSignature()

        if func._dbus_out_signature:
            out_sig = _dbus_bindings.Signature(func._dbus_out_signature)
        else:
            # its tempting to default to _dbus_bindings.Signature('v'), but
            # for methods that return nothing, providing incorrect
            # introspection data is worse than providing none at all
            out_sig = []

        reflection_data = '    <method name="%s">\n' % (func.__name__)
        for pair in zip(in_sig, args):
            reflection_data += '      <arg direction="in"  type="%s" name="%s" />\n' % pair
        for type in out_sig:
            reflection_data += '      <arg direction="out" type="%s" />\n' % type
        reflection_data += '    </method>\n'

        return reflection_data
예제 #2
0
    def _reflect_on_signal(cls, func):
        args = func._dbus_args

        if func._dbus_signature:
            # convert signature into a tuple so length refers to number of
            # types, not number of characters
            sig = tuple(_dbus_bindings.Signature(func._dbus_signature))
        else:
            # magic iterator which returns as many v's as we need
            sig = _VariantSignature()

        reflection_data = '    <signal name="%s">\n' % (func.__name__)
        for pair in zip(sig, args):
            reflection_data = reflection_data + '      <arg type="%s" name="%s" />\n' % pair
        reflection_data = reflection_data + '    </signal>\n'

        return reflection_data
예제 #3
0
    def decorator(func):
        args = inspect.getargspec(func)[0]
        args.pop(0)

        if async_callbacks:
            if type(async_callbacks) != tuple:
                raise TypeError('async_callbacks must be a tuple of (keyword for return callback, keyword for error callback)')
            if len(async_callbacks) != 2:
                raise ValueError('async_callbacks must be a tuple of (keyword for return callback, keyword for error callback)')
            args.remove(async_callbacks[0])
            args.remove(async_callbacks[1])

        if sender_keyword:
            args.remove(sender_keyword)
        if path_keyword:
            args.remove(path_keyword)
        if destination_keyword:
            args.remove(destination_keyword)
        if message_keyword:
            args.remove(message_keyword)
        if connection_keyword:
            args.remove(connection_keyword)

        if in_signature:
            in_sig = tuple(_dbus_bindings.Signature(in_signature))

            if len(in_sig) > len(args):
                raise ValueError, 'input signature is longer than the number of arguments taken'
            elif len(in_sig) < len(args):
                raise ValueError, 'input signature is shorter than the number of arguments taken'

        func._dbus_is_method = True
        func._dbus_async_callbacks = async_callbacks
        func._dbus_interface = dbus_interface
        func._dbus_in_signature = in_signature
        func._dbus_out_signature = out_signature
        func._dbus_sender_keyword = sender_keyword
        func._dbus_path_keyword = path_keyword
        func._dbus_destination_keyword = destination_keyword
        func._dbus_message_keyword = message_keyword
        func._dbus_connection_keyword = connection_keyword
        func._dbus_args = args
        func._dbus_get_args_options = {'byte_arrays': byte_arrays,
                                       'utf8_strings': utf8_strings}
        return func
예제 #4
0
    def decorator(func):
        member_name = func.__name__
        _dbus_bindings.validate_member_name(member_name)

        def emit_signal(self, *args, **keywords):
            abs_path = None
            if path_keyword is not None:
                if self.SUPPORTS_MULTIPLE_OBJECT_PATHS:
                    raise TypeError('path_keyword cannot be used on the '
                                    'signals of an object that supports '
                                    'multiple object paths')
                abs_path = keywords.pop(path_keyword, None)
                if (abs_path != self.__dbus_object_path__ and
                    not self.__dbus_object_path__.startswith(abs_path + '/')):
                    raise ValueError('Path %r is not below %r', abs_path,
                                     self.__dbus_object_path__)

            rel_path = None
            if rel_path_keyword is not None:
                rel_path = keywords.pop(rel_path_keyword, None)

            func(self, *args, **keywords)

            for location in self.locations:
                if abs_path is None:
                    # non-deprecated case
                    if rel_path is None or rel_path in ('/', ''):
                        object_path = location[1]
                    else:
                        # will be validated by SignalMessage ctor in a moment
                        object_path = location[1] + rel_path
                else:
                    object_path = abs_path

                message = _dbus_bindings.SignalMessage(object_path,
                                                       dbus_interface,
                                                       member_name)
                message.append(signature=signature, *args)

                location[0].send_message(message)
        # end emit_signal

        args = inspect.getargspec(func)[0]
        args.pop(0)

        for keyword in rel_path_keyword, path_keyword:
            if keyword is not None:
                try:
                    args.remove(keyword)
                except ValueError:
                    raise ValueError('function has no argument "%s"' % keyword)

        if signature:
            sig = tuple(_dbus_bindings.Signature(signature))

            if len(sig) > len(args):
                raise ValueError, 'signal signature is longer than the number of arguments provided'
            elif len(sig) < len(args):
                raise ValueError, 'signal signature is shorter than the number of arguments provided'

        emit_signal.__name__ = func.__name__
        emit_signal.__doc__ = func.__doc__
        emit_signal._dbus_is_signal = True
        emit_signal._dbus_interface = dbus_interface
        emit_signal._dbus_signature = signature
        emit_signal._dbus_args = args
        return emit_signal
예제 #5
0
    def _message_cb(self, connection, message):
        try:
            # lookup candidate method and parent method
            method_name = message.get_member()
            interface_name = message.get_interface()
            (candidate_method,
             parent_method) = _method_lookup(self, method_name, interface_name)

            # set up method call parameters
            args = message.get_args_list(
                **parent_method._dbus_get_args_options)
            keywords = {}

            if parent_method._dbus_out_signature is not None:
                signature = _dbus_bindings.Signature(
                    parent_method._dbus_out_signature)
            else:
                signature = None

            # set up async callback functions
            if parent_method._dbus_async_callbacks:
                (return_callback,
                 error_callback) = parent_method._dbus_async_callbacks
                keywords[
                    return_callback] = lambda *retval: _method_reply_return(
                        connection, message, method_name, signature, *retval)
                keywords[
                    error_callback] = lambda exception: _method_reply_error(
                        connection, message, exception)

            # include the sender etc. if desired
            if parent_method._dbus_sender_keyword:
                keywords[
                    parent_method._dbus_sender_keyword] = message.get_sender()
            if parent_method._dbus_path_keyword:
                keywords[parent_method._dbus_path_keyword] = message.get_path()
            if parent_method._dbus_destination_keyword:
                keywords[
                    parent_method.
                    _dbus_destination_keyword] = message.get_destination()
            if parent_method._dbus_message_keyword:
                keywords[parent_method._dbus_message_keyword] = message
            if parent_method._dbus_connection_keyword:
                keywords[parent_method._dbus_connection_keyword] = connection

            # call method
            retval = candidate_method(self, *args, **keywords)

            # we're done - the method has got callback functions to reply with
            if parent_method._dbus_async_callbacks:
                return

            # otherwise we send the return values in a reply. if we have a
            # signature, use it to turn the return value into a tuple as
            # appropriate
            if signature is not None:
                signature_tuple = tuple(signature)
                # if we have zero or one return values we want make a tuple
                # for the _method_reply_return function, otherwise we need
                # to check we're passing it a sequence
                if len(signature_tuple) == 0:
                    if retval == None:
                        retval = ()
                    else:
                        raise TypeError(
                            '%s has an empty output signature but did not return None'
                            % method_name)
                elif len(signature_tuple) == 1:
                    retval = (retval, )
                else:
                    if operator.isSequenceType(retval):
                        # multi-value signature, multi-value return... proceed unchanged
                        pass
                    else:
                        raise TypeError(
                            '%s has multiple output values in signature %s but did not return a sequence'
                            % (method_name, signature))

            # no signature, so just turn the return into a tuple and send it as normal
            else:
                if retval is None:
                    retval = ()
                elif (isinstance(retval, tuple)
                      and not isinstance(retval, _dbus_bindings.Struct)):
                    # If the return is a tuple that is not a Struct, we use it
                    # as-is on the assumption that there are multiple return
                    # values - this is the usual Python idiom. (fd.o #10174)
                    pass
                else:
                    retval = (retval, )

            _method_reply_return(connection, message, method_name, signature,
                                 *retval)
        except Exception, exception:
            # send error reply
            _method_reply_error(connection, message, exception)