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
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
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
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
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
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
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
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
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)
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
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