Ejemplo n.º 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(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 = Signature(func._dbus_out_signature)
        else:
            # its tempting to default to 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
Ejemplo n.º 2
0
    def _message_cb(self, connection, message):
        method_name = message.get_member()
        interface_name = message.get_interface()

        # should we move this stuff into the OptionsConfig and ActionConfig
        # classes ?
        args = message.get_args_list()

        if interface_name == 'org.freedesktop.DBus.Properties' and \
           len(args) > 1 and args[0] == self.dbus_ns:
            if method_name == "Get":
                opt = self._options[args[1]]
                typ = self.object_to_dbus(opt.type)
                _method_reply_return(connection,
                                     message,
                                     method_name,
                                     Signature(typ),
                                     opt.value)
                return
            elif method_name == "Set":
                self._options[args[1]] = args[2]
                return
            elif method_name == "GetAll":
                rv = {}
                for name, opt in self._options.iteritems():
                    rv[name] = opt.value
                _method_reply_return(connection,
                                     message,
                                     method_name,
                                     Signature('{sv}'),
                                     rv)
                return

        if interface_name == self.dbus_ns:
            if method_name[0:9] == "activate_" and \
               method_name[9:] not in self.dbus_no_activate:
                act = self._actions.get_action(method_name[9:])
                try:
                    #_method_reply_error(connection, message, exception)
                    gcall(act.emit, 'activate')
                    _method_reply_return(connection,
                                         message,
                                         method_name,
                                         Signature(''))
                except Exception, exception:
                    _method_reply_error(connection, message, exception)
                return
            elif method_name == 'CONFIG_CHANGED' or \
                 method_name == 'CONFIG_EXTRA_CHANGED':
                    return
Ejemplo n.º 3
0
    def __init__(self, dbus_interface=None, signature=None,
                 property_name=None, emits_changed_signal=None,
                 fget=None, fset=None, doc=None):
        """Initialize the decorator used to mark properties of a
        `dbus.service.Object`.

        :Parameters:
            `dbus_interface` : str
                The D-Bus interface owning the property

            `signature` : str
                The signature of the property in the usual D-Bus notation. The
                signature must be suitable to be carried in a variant.

            `property_name` : str
                A name for the property. Defaults to the name of the getter or
                setter function.

            `emits_changed_signal` : True, False, "invalidates", or None
                Tells for introspection if the object emits PropertiesChanged
                signal.

            `fget` : func
                Getter function taking the instance from which to read the
                property.

            `fset` : func
                Setter function taking the instance to which set the property
                and the property value.

            `doc` : str
                Documentation string for the property. Defaults to documentation
                string of getter function.

                :Since: 1.3.0
        """
        validate_interface_name(dbus_interface)
        self._dbus_interface = dbus_interface

        self._init_property_name = property_name
        if property_name is None:
            if fget is not None:
                property_name = fget.__name__
            elif fset is not None:
                property_name = fset.__name__
        if property_name:
            validate_member_name(property_name)
        self.__name__ = property_name

        self._init_doc = doc
        if doc is None and fget is not None:
            doc = getattr(fget, "__doc__", None)
        self.fget = fget
        self.fset = fset
        self.__doc__ = doc

        self._emits_changed_signal = emits_changed_signal
        if len(tuple(Signature(signature))) != 1:
            raise ValueError('signature must have only one item')
        self._dbus_signature = signature
Ejemplo n.º 4
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 rel_path_keyword:
            args.remove(rel_path_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(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_rel_path_keyword = rel_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 = dict(byte_arrays=byte_arrays)
        if is_py2:
            func._dbus_get_args_options['utf8_strings'] = kwargs.get(
                'utf8_strings', False)
        elif 'utf8_strings' in kwargs:
            raise TypeError("unexpected keyword argument 'utf8_strings'")
        return func
Ejemplo n.º 5
0
def _get_types(s: str) -> List[Type]:
    signature = Signature(s)
    out = []
    for entry in signature:
        if entry in _PRIMITIVES:
            out.append(_PRIMITIVES[entry])
        elif entry.startswith("("):
            out.append(Tuple[tuple(_get_types(entry[1:-1]))])
        elif entry.startswith("a{"):
            out.append(Dict[tuple(_get_types(entry[2:-1]))])
        elif entry.startswith("a"):
            out.append(List[tuple(_get_types(entry[1:]))])

    return out
Ejemplo n.º 6
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(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
Ejemplo n.º 7
0
def _get_dbus_types(s: str) -> List[Type]:
    signature = Signature(s)
    out = []
    for entry in signature:
        if entry in _DBUS_PRIMITIVES:
            if entry == "y":
                raise TypeError(
                    "dbus.Byte cannot be instantiated with default value! "
                    "Use ByteArray ('ay') or UInt16 ('q') instead."
                )
            out.append(_DBUS_PRIMITIVES[entry])
        # FIXME: DBus container types get instantiated here instead of in _instantiate.
        elif entry.startswith("("):
            defaults = _instantiate(_get_dbus_types(entry[1:-1]))
            out.append(dtype.Struct(defaults, signature=entry[1:-1]))
        elif entry.startswith("a{"):
            out.append(dtype.Dictionary(signature=entry[2:-1]))
        elif entry.startswith("a"):
            out.append(dtype.Array(signature=entry[1:]))

    return out
Ejemplo n.º 8
0
    def decorator(func):
        member_name = func.__name__
        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 = 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(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
Ejemplo n.º 9
0
    def _message_cb(self, connection, message):
        if not isinstance(message, MethodCallMessage):
            return

        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 = 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_rel_path_keyword:
                path = message.get_path()
                rel_path = path
                for exp in self._locations:
                    # pathological case: if we're exported in two places,
                    # one of which is a subtree of the other, then pick the
                    # subtree by preference (i.e. minimize the length of
                    # rel_path)
                    if exp[0] is connection:
                        if path == exp[1]:
                            rel_path = '/'
                            break
                        if exp[1] == '/':
                            # we already have rel_path == path at the beginning
                            continue
                        if path.startswith(exp[1] + '/'):
                            # yes we're in this exported subtree
                            suffix = path[len(exp[1]):]
                            if len(suffix) < len(rel_path):
                                rel_path = suffix
                rel_path = ObjectPath(rel_path)
                keywords[parent_method._dbus_rel_path_keyword] = rel_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 is 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 isinstance(retval, Sequence):
                        # 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, 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 as exception:
            # send error reply
            _method_reply_error(connection, message, exception)
Ejemplo n.º 10
0
    def decorator(func):
        # If the function is decorated and uses @functools.wrapper then use the
        # __wrapped__ attribute to look at the original function signature.
        #
        # This allows us to see past the generic *args, **kwargs seen on most decorators.
        if hasattr(func, '__wrapped__'):
            args = inspect.getfullargspec(func.__wrapped__)[0]
        else:
            args = inspect.getfullargspec(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 rel_path_keyword:
            args.remove(rel_path_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(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_rel_path_keyword = rel_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 = dict(byte_arrays=byte_arrays)
        if is_py2:
            func._dbus_get_args_options['utf8_strings'] = kwargs.get(
                'utf8_strings', False)
        elif 'utf8_strings' in kwargs:
            raise TypeError("unexpected keyword argument 'utf8_strings'")

        @functools.wraps(func)
        def sanity(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except DBusException:
                raise
            except Exception:
                _logger.exception("DBus method call failed")
                raise
        return sanity
Ejemplo n.º 11
0
    def decorator(func):
        if hasattr(inspect, 'Signature'):
            args = []

            for arg in inspect.signature(func).parameters.values():
                if arg.kind in (inspect.Parameter.POSITIONAL_ONLY,
                                inspect.Parameter.POSITIONAL_OR_KEYWORD):
                    args.append(arg.name)
        else:
            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 rel_path_keyword:
            args.remove(rel_path_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(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_rel_path_keyword = rel_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 = dict(byte_arrays=byte_arrays)
        if 'utf8_strings' in kwargs:
            raise TypeError("unexpected keyword argument 'utf8_strings'")
        return func