diff options
Diffstat (limited to 'python')
-rw-r--r-- | python/Makefile.am | 6 | ||||
-rw-r--r-- | python/__init__.py | 6 | ||||
-rw-r--r-- | python/_dbus.py | 219 | ||||
-rw-r--r-- | python/_util.py | 12 | ||||
-rw-r--r-- | python/dbus.py | 562 | ||||
-rw-r--r-- | python/dbus_bindings.pyx.in | 146 | ||||
-rw-r--r-- | python/decorators.py | 37 | ||||
-rw-r--r-- | python/examples/example-service.py | 2 | ||||
-rw-r--r-- | python/examples/example-signal-emitter.py | 2 | ||||
-rw-r--r-- | python/examples/example-signal-recipient.py | 2 | ||||
-rw-r--r-- | python/examples/gconf-proxy-client.py | 2 | ||||
-rw-r--r-- | python/examples/gconf-proxy-service.py | 2 | ||||
-rw-r--r-- | python/examples/gconf-proxy-service2.py | 2 | ||||
-rw-r--r-- | python/examples/list-system-services.py | 2 | ||||
-rw-r--r-- | python/exceptions.py | 32 | ||||
-rw-r--r-- | python/proxies.py | 90 | ||||
-rw-r--r-- | python/services.py | 187 | ||||
-rw-r--r-- | python/types.py | 18 |
18 files changed, 761 insertions, 568 deletions
diff --git a/python/Makefile.am b/python/Makefile.am index 25191630..f7a56318 100644 --- a/python/Makefile.am +++ b/python/Makefile.am @@ -2,10 +2,10 @@ SUBDIRS=examples INCLUDES=-I$(top_builddir) -I$(top_builddir)/dbus $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) $(PYTHON_INCLUDES) -dbusdir = $(pythondir) -dbus_PYTHON = dbus.py +dbusdir = $(pythondir)/dbus +dbus_PYTHON = __init__.py _dbus.py decorators.py exceptions.py services.py proxies.py _util.py types.py -dbusbindingsdir = $(pythondir) +dbusbindingsdir = $(pythondir)/dbus dbusbindings_LTLIBRARIES = dbus_bindings.la dbus_bindings_la_LDFLAGS = -module -avoid-version -fPIC -export-symbols-regex initdbus_bindings diff --git a/python/__init__.py b/python/__init__.py new file mode 100644 index 00000000..0fd1d804 --- /dev/null +++ b/python/__init__.py @@ -0,0 +1,6 @@ +from _dbus import * +from decorators import * +from services import * +from types import * + +version = (0, 40, 1) diff --git a/python/_dbus.py b/python/_dbus.py new file mode 100644 index 00000000..9dc3bd0a --- /dev/null +++ b/python/_dbus.py @@ -0,0 +1,219 @@ + +"""Module for high-level communication over the FreeDesktop.org Bus (DBus) + +DBus allows you to share and access remote objects between processes +running on the desktop, and also to access system services (such as +the print spool). + +To use DBus, first get a Bus object, which provides a connection to one +of a few standard dbus-daemon instances that might be running. From the +Bus you can get a RemoteService. A service is provided by an application or +process connected to the Bus, and represents a set of objects. Once you +have a RemoteService you can get a RemoteObject that implements a specific interface +(an interface is just a standard group of member functions). Then you can call +those member functions directly. + +You can think of a complete method call as looking something like: + +Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org') + +This communicates over the SESSION Bus to the org.gnome.Evolution process to call the +Forward method of the /org/gnome/Evolution/Inbox object (which provides the +org.gnome.Evolution.MailFolder interface) with two string arguments. + +For example, the dbus-daemon itself provides a service and some objects: + +# Get a connection to the desktop-wide SESSION bus +bus = dbus.Bus(dbus.Bus.TYPE_SESSION) + +# Get the service provided by the dbus-daemon named org.freedesktop.DBus +dbus_service = bus.get_service('org.freedesktop.DBus') + +# Get a reference to the desktop bus' standard object, denoted +# by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus +# implements the 'org.freedesktop.DBus' interface +dbus_object = dbus_service.get_object('/org/freedesktop/DBus', + 'org.freedesktop.DBus') + +# One of the member functions in the org.freedesktop.DBus interface +# is ListServices(), which provides a list of all the other services +# registered on this bus. Call it, and print the list. +print(dbus_object.ListServices()) +""" + +import dbus_bindings +from decorators import * +from proxies import * +from exceptions import * +from services import * + +import re +import inspect + +_threads_initialized = 0 +def init_gthreads (): + global _threads_initialized + if not _threads_initialized: + dbus_bindings.init_gthreads () + _threads_initialized = 1 + +class Bus: + """A connection to a DBus daemon. + + One of three possible standard buses, the SESSION, SYSTEM, + or STARTER bus + """ + TYPE_SESSION = dbus_bindings.BUS_SESSION + TYPE_SYSTEM = dbus_bindings.BUS_SYSTEM + TYPE_STARTER = dbus_bindings.BUS_STARTER + + """bus_type=[Bus.TYPE_SESSION | Bus.TYPE_SYSTEM | Bus.TYPE_STARTER] + """ + + START_REPLY_SUCCESS = dbus_bindings.DBUS_START_REPLY_SUCCESS + START_REPLY_ALREADY_RUNNING = dbus_bindings.DBUS_START_REPLY_ALREADY_RUNNING + + def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True): + self._connection = dbus_bindings.bus_get(bus_type) + + self._connection.add_filter(self._signal_func) + self._match_rule_to_receivers = { } + if (glib_mainloop): + self._connection.setup_with_g_main() + + def get_connection(self): + return self._connection + + def get_session(): + """Static method that returns the session bus""" + return SessionBus() + + get_session = staticmethod(get_session) + + def get_system(): + """Static method that returns the system bus""" + return SystemBus() + + get_system = staticmethod(get_system) + + + def get_starter(): + """Static method that returns the starter bus""" + return StarterBus() + + get_starter = staticmethod(get_starter) + + + def get_object(self, named_service, object_path): + """Get a proxy object to call over the bus""" + return ProxyObject(self, named_service, object_path) + + def add_signal_receiver(self, handler_function, signal_name=None, dbus_interface=None, named_service=None, path=None): + match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path) + + if (not self._match_rule_to_receivers.has_key(match_rule)): + self._match_rule_to_receivers[match_rule] = [handler_function] + else: + self._match_rule_to_receivers[match_rule].append(handler_function) + + dbus_bindings.bus_add_match(self._connection, match_rule) + + def remove_signal_receiver(self, handler_function, signal_name=None, dbus_interface=None, named_service=None, path=None): + match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path) + + if self._match_rule_to_receivers.has_key(match_rule): + if self._match_rule_to_receivers[match_rule].__contains__(handler_function): + self._match_rule_to_receivers[match_rule].pop(handler_function) + dbus_bindings.bus_remove_match(self._connection, match_rule) + + def get_unix_user(self, named_service): + """Get the unix user for the given named_service on this Bus""" + return dbus_bindings.bus_get_unix_user(self._connection, named_service) + + #TODO: Rethink match rules. Right now matches have to be exact. + def _get_match_rule(self, signal_name, dbus_interface, named_service, path): + match_rule = "type='signal'" + if (dbus_interface): + match_rule = match_rule + ",interface='%s'" % (dbus_interface) + if (named_service): + if (named_service[0] != ':' and named_service != "org.freedesktop.DBus"): + bus_object = self.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus') + named_service = bus_object.GetNameOwner(named_service, dbus_interface='org.freedesktop.DBus') + + match_rule = match_rule + ",sender='%s'" % (named_service) + if (path): + match_rule = match_rule + ",path='%s'" % (path) + if (signal_name): + match_rule = match_rule + ",member='%s'" % (signal_name) + return match_rule + + def _signal_func(self, connection, message): + if (message.get_type() != dbus_bindings.MESSAGE_TYPE_SIGNAL): + return dbus_bindings.HANDLER_RESULT_NOT_YET_HANDLED + + dbus_interface = message.get_interface() + named_service = message.get_sender() + path = message.get_path() + signal_name = message.get_member() + + match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path) + + if (self._match_rule_to_receivers.has_key(match_rule)): + receivers = self._match_rule_to_receivers[match_rule] + + for receiver in receivers: + args = message.get_args_list() + receiver(*args) + + def start_service_by_name(self, named_service): + return dbus_bindings.bus_start_service_by_name(self._connection, named_service) + +class SystemBus(Bus): + """The system-wide message bus + """ + def __init__(self): + Bus.__init__(self, Bus.TYPE_SYSTEM) + +class SessionBus(Bus): + """The session (current login) message bus + """ + def __init__(self): + Bus.__init__(self, Bus.TYPE_SESSION) + +class StarterBus(Bus): + """The bus that activated this process (if + this process was launched by DBus activation) + """ + def __init__(self): + Bus.__init__(self, Bus.TYPE_STARTER) + + +class Interface: + """An inteface into a remote object + + An Interface can be used to wrap ProxyObjects + so that calls can be routed to their correct + dbus interface + """ + + def __init__(self, object, dbus_interface): + self._obj = object + self._dbus_interface = dbus_interface + + def connect_to_signal(self, signal_name, handler_function, dbus_interface = None): + if not dbus_interface: + dbus_interface = self._dbus_interface + + self._obj.connect_to_signal(signal_name, handler_function, dbus_interface) + + def __getattr__(self, member, **keywords): + if (keywords.has_key('dbus_interface')): + _dbus_interface = keywords['dbus_interface'] + else: + _dbus_interface = self._dbus_interface + + if member == '__call__': + return object.__call__ + else: + return self._obj.__getattr__(member, dbus_interface=_dbus_interface) + diff --git a/python/_util.py b/python/_util.py new file mode 100644 index 00000000..3f7061c3 --- /dev/null +++ b/python/_util.py @@ -0,0 +1,12 @@ +import re + +def _validate_interface_or_name(value): + elements = value.split('.') + if len(elements) <= 1: + raise ValidationException("%s must contain at least two elements seperated by a period ('.')"%(value)) + + validate = re.compile('[A-Za-z][\w_]*') + for element in elements: + if not validate.match(element): + raise ValidationException("Element %s of %s has invalid characters"%(element ,value)) + diff --git a/python/dbus.py b/python/dbus.py deleted file mode 100644 index 6b1ea558..00000000 --- a/python/dbus.py +++ /dev/null @@ -1,562 +0,0 @@ - -"""Module for high-level communication over the FreeDesktop.org Bus (DBus) - -DBus allows you to share and access remote objects between processes -running on the desktop, and also to access system services (such as -the print spool). - -To use DBus, first get a Bus object, which provides a connection to one -of a few standard dbus-daemon instances that might be running. From the -Bus you can get a RemoteService. A service is provided by an application or -process connected to the Bus, and represents a set of objects. Once you -have a RemoteService you can get a RemoteObject that implements a specific interface -(an interface is just a standard group of member functions). Then you can call -those member functions directly. - -You can think of a complete method call as looking something like: - -Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org') - -This communicates over the SESSION Bus to the org.gnome.Evolution process to call the -Forward method of the /org/gnome/Evolution/Inbox object (which provides the -org.gnome.Evolution.MailFolder interface) with two string arguments. - -For example, the dbus-daemon itself provides a service and some objects: - -# Get a connection to the desktop-wide SESSION bus -bus = dbus.Bus(dbus.Bus.TYPE_SESSION) - -# Get the service provided by the dbus-daemon named org.freedesktop.DBus -dbus_service = bus.get_service('org.freedesktop.DBus') - -# Get a reference to the desktop bus' standard object, denoted -# by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus -# implements the 'org.freedesktop.DBus' interface -dbus_object = dbus_service.get_object('/org/freedesktop/DBus', - 'org.freedesktop.DBus') - -# One of the member functions in the org.freedesktop.DBus interface -# is ListServices(), which provides a list of all the other services -# registered on this bus. Call it, and print the list. -print(dbus_object.ListServices()) -""" - -import dbus_bindings -import re -import inspect - - -version = (0, 40, 0) - -_threads_initialized = 0 -def init_gthreads (): - global _threads_initialized - if not _threads_initialized: - dbus_bindings.init_gthreads () - _threads_initialized = 1 - -def _validate_interface_or_name(value): - elements = value.split('.') - if len(elements) <= 1: - raise ValidationException("%s must contain at least two elements seperated by a period ('.')"%(value)) - - validate = re.compile('[A-Za-z][\w_]*') - for element in elements: - if not validate.match(element): - raise ValidationException("Element %s of %s has invalid characters"%(element ,value)) - - -#Decorators -def method(dbus_interface): - _validate_interface_or_name(dbus_interface) - - def decorator(func): - func._dbus_is_method = True - func._dbus_interface = dbus_interface - func._dbus_args = inspect.getargspec(func)[0] - func._dbus_args.pop(0) - return func - - return decorator - -def signal(dbus_interface): - _validate_interface_or_name(dbus_interface) - def decorator(func): - def emit_signal(self, *args, **keywords): - func(self, *args, **keywords) - message = dbus_bindings.Signal(self._object_path, dbus_interface, func.__name__) - iter = message.get_iter(True) - for arg in args: - iter.append(arg) - - self._connection.send(message) - - emit_signal._dbus_is_signal = True - emit_signal._dbus_interface = dbus_interface - emit_signal.__name__ = func.__name__ - emit_signal._dbus_args = inspect.getargspec(func)[0] - emit_signal._dbus_args.pop(0) - return emit_signal - - return decorator - - -class Bus: - """A connection to a DBus daemon. - - One of three possible standard buses, the SESSION, SYSTEM, - or STARTER bus - """ - TYPE_SESSION = dbus_bindings.BUS_SESSION - TYPE_SYSTEM = dbus_bindings.BUS_SYSTEM - TYPE_STARTER = dbus_bindings.BUS_STARTER - - """bus_type=[Bus.TYPE_SESSION | Bus.TYPE_SYSTEM | Bus.TYPE_STARTER] - """ - - START_REPLY_SUCCESS = dbus_bindings.DBUS_START_REPLY_SUCCESS - START_REPLY_ALREADY_RUNNING = dbus_bindings.DBUS_START_REPLY_ALREADY_RUNNING - - def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True): - self._connection = dbus_bindings.bus_get(bus_type) - - self._connection.add_filter(self._signal_func) - self._match_rule_to_receivers = { } - if (glib_mainloop): - self._connection.setup_with_g_main() - - def get_connection(self): - return self._connection - - def get_session(): - """Static method that returns the session bus""" - return SessionBus() - - get_session = staticmethod(get_session) - - def get_system(): - """Static method that returns the system bus""" - return SystemBus() - - get_system = staticmethod(get_system) - - - def get_starter(): - """Static method that returns the starter bus""" - return StarterBus() - - get_starter = staticmethod(get_starter) - - - def get_object(self, named_service, object_path): - """Get a proxy object to call over the bus""" - return ProxyObject(self, named_service, object_path) - - def add_signal_receiver(self, handler_function, signal_name=None, dbus_interface=None, named_service=None, path=None): - match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path) - - if (not self._match_rule_to_receivers.has_key(match_rule)): - self._match_rule_to_receivers[match_rule] = [handler_function] - else: - self._match_rule_to_receivers[match_rule].append(handler_function) - - dbus_bindings.bus_add_match(self._connection, match_rule) - - def remove_signal_receiver(self, handler_function, signal_name=None, dbus_interface=None, named_service=None, path=None): - match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path) - - if self._match_rule_to_receivers.has_key(match_rule): - if self._match_rule_to_receivers[match_rule].__contains__(handler_function): - self._match_rule_to_receivers[match_rule].pop(handler_function) - dbus_bindings.bus_remove_match(self._connection, match_rule) - - def get_unix_user(self, named_service): - """Get the unix user for the given named_service on this Bus""" - return dbus_bindings.bus_get_unix_user(self._connection, named_service) - - def _get_match_rule(self, signal_name, dbus_interface, named_service, path): - match_rule = "type='signal'" - if (dbus_interface): - match_rule = match_rule + ",interface='%s'" % (dbus_interface) - if (named_service): - if (named_service[0] != ':' and named_service != "org.freedesktop.DBus"): - bus_object = self.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus') - named_service = bus_object.GetNameOwner(named_service, dbus_interface='org.freedesktop.DBus') - - match_rule = match_rule + ",sender='%s'" % (named_service) - if (path): - match_rule = match_rule + ",path='%s'" % (path) - if (signal_name): - match_rule = match_rule + ",member='%s'" % (signal_name) - return match_rule - - def _signal_func(self, connection, message): - if (message.get_type() != dbus_bindings.MESSAGE_TYPE_SIGNAL): - return dbus_bindings.HANDLER_RESULT_NOT_YET_HANDLED - - dbus_interface = message.get_interface() - named_service = message.get_sender() - path = message.get_path() - signal_name = message.get_member() - - match_rule = self._get_match_rule(signal_name, dbus_interface, named_service, path) - - if (self._match_rule_to_receivers.has_key(match_rule)): - receivers = self._match_rule_to_receivers[match_rule] - - for receiver in receivers: - args = message.get_args_list() - receiver(*args) - - def start_service_by_name(self, named_service): - return dbus_bindings.bus_start_service_by_name(self._connection, named_service) - -class SystemBus(Bus): - """The system-wide message bus - """ - def __init__(self): - Bus.__init__(self, Bus.TYPE_SYSTEM) - -class SessionBus(Bus): - """The session (current login) message bus - """ - def __init__(self): - Bus.__init__(self, Bus.TYPE_SESSION) - -class StarterBus(Bus): - """The bus that activated this process (if - this process was launched by DBus activation) - """ - def __init__(self): - Bus.__init__(self, Bus.TYPE_STARTER) - - -class Interface: - """An inteface into a remote object - - An Interface can be used to wrap ProxyObjects - so that calls can be routed to their correct - dbus interface - """ - - def __init__(self, object, dbus_interface): - self._obj = object - self._dbus_interface = dbus_interface - - def connect_to_signal(self, signal_name, handler_function, dbus_interface = None): - if not dbus_interface: - dbus_interface = self._dbus_interface - - self._obj.connect_to_signal(signal_name, handler_function, dbus_interface) - - def __getattr__(self, member, **keywords): - if (keywords.has_key('dbus_interface')): - _dbus_interface = keywords['dbus_interface'] - else: - _dbus_interface = self._dbus_interface - - if member == '__call__': - return object.__call__ - else: - return self._obj.__getattr__(member, dbus_interface=_dbus_interface) - -class ProxyObject: - """A proxy to the remote Object. - - A ProxyObject is provided by the Bus. ProxyObjects - have member functions, and can be called like normal Python objects. - """ - def __init__(self, bus, named_service, object_path): - self._bus = bus - self._named_service = named_service - self._object_path = object_path - - def connect_to_signal(self, signal_name, handler_function, dbus_interface=None): - self._bus.add_signal_receiver(handler_function, - signal_name=signal_name, - dbus_interface=dbus_interface, - named_service=self._named_service, - path=self._object_path) - - - - def __getattr__(self, member, **keywords): - if member == '__call__': - return object.__call__ - else: - iface = None - if (keywords.has_key('dbus_interface')): - iface = keywords['dbus_interface'] - - return ProxyMethod(self._bus.get_connection(), - self._named_service, - self._object_path, iface, member) - - -class ProxyMethod: - """A proxy Method. - - Typically a member of a ProxyObject. Calls to the - method produce messages that travel over the Bus and are routed - to a specific named Service. - """ - def __init__(self, connection, named_service, object_path, dbus_interface, method_name): - self._connection = connection - self._named_service = named_service - self._object_path = object_path - self._method_name = method_name - self._dbus_interface = dbus_interface - - def __call__(self, *args, **keywords): - dbus_interface = self._dbus_interface - if (keywords.has_key('dbus_interface')): - dbus_interface = keywords['dbus_interface'] - - reply_handler = None - if (keywords.has_key('reply_handler')): - reply_handler = keywords['reply_handler'] - - error_handler = None - if (keywords.has_key('error_handler')): - error_handler = keywords['error_handler'] - - if not(reply_handler and error_handler): - if reply_handler: - raise MissingErrorself, HandlerException() - elif error_handler: - raise MissingReplyHandlerException() - - message = dbus_bindings.MethodCall(self._object_path, dbus_interface, self._method_name) - message.set_destination(self._named_service) - - # Add the arguments to the function - iter = message.get_iter(True) - for arg in args: - iter.append(arg) - - if reply_handler: - result = self._connection.send_with_reply_handlers(message, -1, reply_handler, error_handler) - args_tuple = (result,) - else: - reply_message = self._connection.send_with_reply_and_block(message, -1) - args_tuple = reply_message.get_args_list() - - if len(args_tuple) == 0: - return - elif len(args_tuple) == 1: - return args_tuple[0] - else: - return args_tuple - -class Service: - """A base class for exporting your own Services across the Bus - - Just inherit from Service, providing the name of your service - (e.g. org.designfu.SampleService). - """ - def __init__(self, named_service, bus=None): - self._named_service = named_service - - if bus == None: - # Get the default bus - self._bus = Bus() - else: - self._bus = bus - - dbus_bindings.bus_request_name(self._bus.get_connection(), named_service) - - def get_bus(self): - """Get the Bus this Service is on""" - return self._bus - - def get_name(self): - """Get the name of this service""" - return self._named_service - -def _dispatch_dbus_method_call(target_methods, self, argument_list, message): - """Calls method_to_call using argument_list, but handles - exceptions, etc, and generates a reply to the DBus Message message - """ - try: - target_method = None - - dbus_interface = message.get_interface() - if dbus_interface == None: - if target_methods: - target_method = target_methods[0] - else: - for dbus_method in target_methods: - if dbus_method._dbus_interface == dbus_interface: - target_method = dbus_method - break - - if target_method: - retval = target_method(self, *argument_list) - else: - if not dbus_interface: - raise UnknownMethodException('%s is not a valid method'%(message.get_member())) - else: - raise UnknownMethodException('%s is not a valid method of interface %s'%(message.get_member(), dbus_interface)) - except Exception, e: - if e.__module__ == '__main__': - # FIXME: is it right to use .__name__ here? - error_name = e.__class__.__name__ - else: - error_name = e.__module__ + '.' + str(e.__class__.__name__) - error_contents = str(e) - reply = dbus_bindings.Error(message, error_name, error_contents) - else: - reply = dbus_bindings.MethodReturn(message) - if retval != None: - iter = reply.get_iter(append=True) - iter.append(retval) - - return reply - -class ObjectType(type): - def __init__(cls, name, bases, dct): - - #generate out vtable - method_vtable = getattr(cls, '_dbus_method_vtable', {}) - reflection_data = getattr(cls, '_dbus_reflection_data', "") - - reflection_interface_method_hash = {} - reflection_interface_signal_hash = {} - - for func in dct.values(): - if getattr(func, '_dbus_is_method', False): - if method_vtable.has_key(func.__name__): - method_vtable[func.__name__].append(func) - else: - method_vtable[func.__name__] = [func] - - #generate a hash of interfaces so we can group - #methods in the xml data - if reflection_interface_method_hash.has_key(func._dbus_interface): - reflection_interface_method_hash[func._dbus_interface].append(func) - else: - reflection_interface_method_hash[func._dbus_interface] = [func] - - elif getattr(func, '_dbus_is_signal', False): - if reflection_interface_signal_hash.has_key(func._dbus_interface): - reflection_interface_signal_hash[func._dbus_interface].append(func) - else: - reflection_interface_signal_hash[func._dbus_interface] = [func] - - for interface in reflection_interface_method_hash.keys(): - reflection_data = reflection_data + ' <interface name="%s">\n'%(interface) - for func in reflection_interface_method_hash[interface]: - reflection_data = reflection_data + ' <method name="%s">\n'%(func.__name__) - for arg in func._dbus_args: - reflection_data = reflection_data + ' <arg name="%s" type="v" />\n'%(arg) - - #reclaim some memory - func._dbus_args = None - reflection_data = reflection_data + ' </method>\n' - if reflection_interface_signal_hash.has_key(interface): - for func in reflection_interface_signal_hash[interface]: - reflection_data = reflection_data + ' <signal name="%s">\n'%(func.__name__) - for arg in func._dbus_args: - reflection_data = reflection_data + ' <arg name="%s" type="v" />\n'%(arg) - #reclaim some memory - func._dbus_args = None - reflection_data = reflection_data + ' </signal>\n' - - del reflection_interface_signal_hash[interface] - reflection_data = reflection_data + ' </interface>\n' - - for interface in reflection_interface_signal_hash.keys(): - reflection_data = reflection_data + ' <interface name="%s">\n'%(interface) - - for func in reflection_interface_signal_hash[interface]: - reflection_data = reflection_data + ' <signal name="%s">\n'%(func.__name__) - for arg in func._dbus_args: - reflection_data = reflection_data + ' <arg name="%s" type="v" />\n'%(arg) - - #reclaim some memory - func._dbus_args = None - reflection_data = reflection_data + ' </signal>\n' - - reflection_data = reflection_data + ' </interface>\n' - - cls._dbus_reflection_data = reflection_data - cls._dbus_method_vtable = method_vtable - - super(ObjectType, cls).__init__(name, bases, dct) - - -class Object: - """A base class for exporting your own Objects across the Bus. - - Just inherit from Object and provide a list of methods to share - across the Bus. These will appear as member functions of your - ServiceObject. - """ - __metaclass__ = ObjectType - - def __init__(self, object_path, service): - self._object_path = object_path - self._service = service - self._bus = service.get_bus() - - self._connection = self._bus.get_connection() - - self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb) - - def _unregister_cb(self, connection): - print ("Unregister") - - def _message_cb(self, connection, message): - target_method_name = message.get_member() - target_methods = self._dbus_method_vtable[target_method_name] - args = message.get_args_list() - - reply = _dispatch_dbus_method_call(target_methods, self, args, message) - - self._connection.send(reply) - - @method('org.freedesktop.DBus.Introspectable') - def Introspect(self): - reflection_data = '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">\n' - reflection_data = reflection_data + '<node name="%s">\n'%(self._object_path) - reflection_data = reflection_data + self._dbus_reflection_data - reflection_data = reflection_data + '</node>\n' - - return reflection_data - -#Exceptions -class MissingErrorHandlerException(Exception): - def __init__(self): - Exception.__init__(self) - - - def __str__(self): - return "error_handler not defined: if you define a reply_handler you must also define an error_handler" - - -class MissingReplyHandlerException(Exception): - def __init__(self): - Exception.__init__(self) - - def __str__(self): - return "reply_handler not defined: if you define an error_handler you must also define a reply_handler" - -class ValidationException(Exception): - def __init__(self, msg=''): - self.msg = msg - Exception.__init__(self) - - def __str__(self): - return "Error validating string: %s" % self.msg - -class UnknownMethodException(Exception): - def __init__(self, msg=''): - self.msg = msg - Exception.__init__(self) - - def __str__(self): - return "Unknown method: %s" % self.msg - -ObjectPath = dbus_bindings.ObjectPath -ByteArray = dbus_bindings.ByteArray - diff --git a/python/dbus_bindings.pyx.in b/python/dbus_bindings.pyx.in index 0bfb9942..8d41b1e4 100644 --- a/python/dbus_bindings.pyx.in +++ b/python/dbus_bindings.pyx.in @@ -82,6 +82,64 @@ class Signature(str): def __init__(self, value): str.__init__(value) +class Byte(int): + def __init__(self, value): + int.__init__(value) + +class Boolean(int): + def __init__(self, value): + int.__init__(value) + +class Int16(int): + def __init__(self, value): + int.__init__(value) + +class UInt16(int): + def __init__(self, value): + if value < 0: + raise TypeError('Unsigned integers must not have a negitive value') + int.__init__(value) + +class Int32(int): + def __init__(self, value): + int.__init__(value) + +class UInt32(long): + def __init__(self, value): + if value < 0: + raise TypeError('Unsigned integers must not have a negitive value') + long.__init__(value) + +class Int64(long): + def __init__(self, value): + long.__init__(value) + +class UInt64(long): + def __init__(self, value): + if value < 0: + raise TypeError('Unsigned integers must not have a negitive value') + long.__init__(value) + +class Double(float): + def __init__(self, value): + float.__init__(self, value) + +class String(str): + def __init__(self, value): + str.__init__(value) + +class Array(list): + def __init__(self, value): + list.__init__(value) + +class Struct(tuple): + def __init__(self, value): + tuple.__init__(value) + +class Dictionary(dict): + def __init__(self, value): + dict.__init__(value) + #forward delcerations cdef class Connection cdef class Message @@ -707,7 +765,7 @@ cdef class MessageIter: ret = TYPE_STRING ret = str(chr(ret)) elif ptype == float: - ret = TYPE_FLOAT + ret = TYPE_DOUBLE ret = str(chr(ret)) elif ptype == dict: dict_list = value.items() @@ -734,6 +792,52 @@ cdef class MessageIter: elif isinstance(Signature): ret = TYPE_SIGNATURE ret = str(chr(ret)) + elif isinstance(value, Byte): + ret = TYPE_BYTE + ret = str(chr(ret)) + elif isinstance(value, Boolean): + ret = TYPE_BOOL + ret = str(chr(ret)) + elif isinstance(value, Int16): + ret = TYPE_INT16 + ret = str(chr(ret)) + elif isinstance(value, UInt16): + ret = TYPE_UINT16 + ret = str(chr(ret)) + elif isinstance(value, Int32): + ret = TYPE_INT32 + ret = str(chr(ret)) + elif isinstance(value, UInt32): + ret = TYPE_UINT32 + ret = str(chr(ret)) + elif isinstance(value, Int64): + ret = TYPE_INT64 + ret = str(chr(ret)) + elif isinstance(value, UInt64): + ret = TYPE_UINT64 + ret = str(chr(ret)) + elif isinstance(value, Double): + ret = TYPE_DOUBLE + ret = str(chr(ret)) + elif isinstance(value, String): + ret = TYPE_STRING + ret = str(chr(ret)) + elif isinstance(value, Array): + ret = str(chr(TYPE_ARRAY)) + ret = ret + self.python_value_to_dbus_sig(value[0], level) + elif isinstance(value, Struct): + ret = str(chr(STRUCT_BEGIN)) + for item in value: + ret = ret + self.python_value_to_dbus_sig(item, level) + ret = ret + str(chr(STRUCT_END)) + elif isinstance(value, Dictionary): + dict_list = value.items() + key, value = dict_list[0] + + ret = str(chr(TYPE_ARRAY)) + str(chr(DICT_ENTRY_BEGIN)) + ret = ret + self.python_value_to_dbus_sig(key, level) + ret = ret + self.python_value_to_dbus_sig(value, level) + ret = ret + str(chr(DICT_ENTRY_END)) else: raise TypeError, "Argument of unknown type '%s'" % (ptype) @@ -767,6 +871,32 @@ cdef class MessageIter: retval = self.append_array(value) elif isinstance(value, Signature): retval = self.append_signature(value) + elif isinstance(value, Byte): + retval = self.append_byte(value) + elif isinstance(value, Boolean): + retval = self.append_boolean(value) + elif isinstance(value, Int16): + retval = self.append_int16(value) + elif isinstance(value, UInt16): + retval = self.append_uint16(value) + elif isinstance(value, Int32): + retval = self.append_int32(value) + elif isinstance(value, UInt32): + retval = self.append_uint32(value) + elif isinstance(value, Int64): + retval = self.append_int64(value) + elif isinstance(value, UInt64): + retval = self.append_uint64(value) + elif isinstance(value, Double): + retval = self.append_double(value) + elif isinstance(value, String): + retval = self.append_string(value) + elif isinstance(value, Array): + retval = self.append_array(value) + elif isinstance(value, Struct): + retval = self.append_struct(value) + elif isinstance(value, Dictionary): + retval = self.append_dict(value) else: raise TypeError, "Argument of unknown type '%s'" % (value_type) @@ -784,7 +914,17 @@ cdef class MessageIter: b = ord(value) return dbus_message_iter_append_basic(self.iter, TYPE_BYTE, <char *>&b) - + + def append_int16(self, value): + cdef dbus_int32_t c_value + c_value = value + return dbus_message_iter_append_basic(self.iter, TYPE_INT16, <dbus_int32_t *>&c_value) + + def append_uint16(self, value): + cdef dbus_uint32_t c_value + c_value = value + return dbus_message_iter_append_basic(self.iter, TYPE_UINT16, <dbus_uint32_t *>&c_value) + def append_int32(self, value): cdef dbus_int32_t c_value c_value = value @@ -952,7 +1092,7 @@ cdef class MessageIter: (MESSAGE_TYPE_INVALID, MESSAGE_TYPE_METHOD_CALL, MESSAGE_TYPE_METHOD_RETURN, MESSAGE_TYPE_ERROR, MESSAGE_TYPE_SIGNAL) = range(5) -(TYPE_INVALID, TYPE_BYTE, TYPE_BOOLEAN, TYPE_INT16, TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, TYPE_OBJECT_PATH, TYPE_SIGNATURE, TYPE_ARRAY, TYPE_STRUCT, STRUCT_BEGIN, STRUCT_END, TYPE_VARIANT, TYPE_DICT_ENTRY, DICT_ENTRY_BEGIN, DICT_ENTRY_END) = (0, ord('y'), ord('b'), ord('n'), ord('i'), ord('u'), ord('q'), ord('x'), ord('t'), ord('d'), ord('s'), ord('o'), ord('g'), ord('a'), ord('r'), ord('('), ord(')'), ord('v'), ord('e'), ord('{'), ord('}')) +(TYPE_INVALID, TYPE_BYTE, TYPE_BOOLEAN, TYPE_INT16, TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, TYPE_OBJECT_PATH, TYPE_SIGNATURE, TYPE_ARRAY, TYPE_STRUCT, STRUCT_BEGIN, STRUCT_END, TYPE_VARIANT, TYPE_DICT_ENTRY, DICT_ENTRY_BEGIN, DICT_ENTRY_END) = (0, ord('y'), ord('b'), ord('n'), ord('q'), ord('i'), ord('u'), ord('x'), ord('t'), ord('d'), ord('s'), ord('o'), ord('g'), ord('a'), ord('r'), ord('('), ord(')'), ord('v'), ord('e'), ord('{'), ord('}')) (HANDLER_RESULT_HANDLED, HANDLER_RESULT_NOT_YET_HANDLED, HANDLER_RESULT_NEED_MEMORY) = range(3) cdef class Message: diff --git a/python/decorators.py b/python/decorators.py new file mode 100644 index 00000000..4be6e207 --- /dev/null +++ b/python/decorators.py @@ -0,0 +1,37 @@ +import _util +import inspect + + +def method(dbus_interface): + _util._validate_interface_or_name(dbus_interface) + + def decorator(func): + func._dbus_is_method = True + func._dbus_interface = dbus_interface + func._dbus_args = inspect.getargspec(func)[0] + func._dbus_args.pop(0) + return func + + return decorator + +def signal(dbus_interface): + _util._validate_interface_or_name(dbus_interface) + def decorator(func): + def emit_signal(self, *args, **keywords): + func(self, *args, **keywords) + message = dbus_bindings.Signal(self._object_path, dbus_interface, func.__name__) + iter = message.get_iter(True) + for arg in args: + iter.append(arg) + + self._connection.send(message) + + emit_signal._dbus_is_signal = True + emit_signal._dbus_interface = dbus_interface + emit_signal.__name__ = func.__name__ + emit_signal._dbus_args = inspect.getargspec(func)[0] + emit_signal._dbus_args.pop(0) + return emit_signal + + return decorator + diff --git a/python/examples/example-service.py b/python/examples/example-service.py index 2209ff9f..9963454f 100644 --- a/python/examples/example-service.py +++ b/python/examples/example-service.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import dbus import pygtk diff --git a/python/examples/example-signal-emitter.py b/python/examples/example-signal-emitter.py index 8797e5f6..662c2bc7 100644 --- a/python/examples/example-signal-emitter.py +++ b/python/examples/example-signal-emitter.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import dbus import gtk diff --git a/python/examples/example-signal-recipient.py b/python/examples/example-signal-recipient.py index 2da65ecb..1dbf6a65 100644 --- a/python/examples/example-signal-recipient.py +++ b/python/examples/example-signal-recipient.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import gtk import dbus import gobject diff --git a/python/examples/gconf-proxy-client.py b/python/examples/gconf-proxy-client.py index f9c63097..f763e3fa 100644 --- a/python/examples/gconf-proxy-client.py +++ b/python/examples/gconf-proxy-client.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import dbus gconf_key = "/desktop/gnome/file_views/icon_theme" diff --git a/python/examples/gconf-proxy-service.py b/python/examples/gconf-proxy-service.py index 25ecbe9d..18c8047f 100644 --- a/python/examples/gconf-proxy-service.py +++ b/python/examples/gconf-proxy-service.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import dbus import gtk diff --git a/python/examples/gconf-proxy-service2.py b/python/examples/gconf-proxy-service2.py index 5ba77db7..3667a853 100644 --- a/python/examples/gconf-proxy-service2.py +++ b/python/examples/gconf-proxy-service2.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import dbus import gtk diff --git a/python/examples/list-system-services.py b/python/examples/list-system-services.py index 80f63f98..d4280551 100644 --- a/python/examples/list-system-services.py +++ b/python/examples/list-system-services.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + """Lists services on the system bus """ import dbus diff --git a/python/exceptions.py b/python/exceptions.py new file mode 100644 index 00000000..66b8c566 --- /dev/null +++ b/python/exceptions.py @@ -0,0 +1,32 @@ +class MissingErrorHandlerException(Exception): + def __init__(self): + Exception.__init__(self) + + + def __str__(self): + return "error_handler not defined: if you define a reply_handler you must also define an error_handler" + + +class MissingReplyHandlerException(Exception): + def __init__(self): + Exception.__init__(self) + + def __str__(self): + return "reply_handler not defined: if you define an error_handler you must also define a reply_handler" + +class ValidationException(Exception): + def __init__(self, msg=''): + self.msg = msg + Exception.__init__(self) + + def __str__(self): + return "Error validating string: %s" % self.msg + +class UnknownMethodException(Exception): + def __init__(self, msg=''): + self.msg = msg + Exception.__init__(self) + + def __str__(self): + return "Unknown method: %s" % self.msg + diff --git a/python/proxies.py b/python/proxies.py new file mode 100644 index 00000000..0e00d64a --- /dev/null +++ b/python/proxies.py @@ -0,0 +1,90 @@ +import dbus_bindings + +class ProxyObject: + """A proxy to the remote Object. + + A ProxyObject is provided by the Bus. ProxyObjects + have member functions, and can be called like normal Python objects. + """ + def __init__(self, bus, named_service, object_path): + self._bus = bus + self._named_service = named_service + self._object_path = object_path + + def connect_to_signal(self, signal_name, handler_function, dbus_interface=None): + self._bus.add_signal_receiver(handler_function, + signal_name=signal_name, + dbus_interface=dbus_interface, + named_service=self._named_service, + path=self._object_path) + + + + def __getattr__(self, member, **keywords): + if member == '__call__': + return object.__call__ + else: + iface = None + if (keywords.has_key('dbus_interface')): + iface = keywords['dbus_interface'] + + return ProxyMethod(self._bus.get_connection(), + self._named_service, + self._object_path, iface, member) + + +class ProxyMethod: + """A proxy Method. + + Typically a member of a ProxyObject. Calls to the + method produce messages that travel over the Bus and are routed + to a specific named Service. + """ + def __init__(self, connection, named_service, object_path, dbus_interface, method_name): + self._connection = connection + self._named_service = named_service + self._object_path = object_path + self._method_name = method_name + self._dbus_interface = dbus_interface + + def __call__(self, *args, **keywords): + dbus_interface = self._dbus_interface + if (keywords.has_key('dbus_interface')): + dbus_interface = keywords['dbus_interface'] + + reply_handler = None + if (keywords.has_key('reply_handler')): + reply_handler = keywords['reply_handler'] + + error_handler = None + if (keywords.has_key('error_handler')): + error_handler = keywords['error_handler'] + + if not(reply_handler and error_handler): + if reply_handler: + raise MissingErrorself, HandlerException() + elif error_handler: + raise MissingReplyHandlerException() + + message = dbus_bindings.MethodCall(self._object_path, dbus_interface, self._method_name) + message.set_destination(self._named_service) + + # Add the arguments to the function + iter = message.get_iter(True) + for arg in args: + iter.append(arg) + + if reply_handler: + result = self._connection.send_with_reply_handlers(message, -1, reply_handler, error_handler) + args_tuple = (result,) + else: + reply_message = self._connection.send_with_reply_and_block(message, -1) + args_tuple = reply_message.get_args_list() + + if len(args_tuple) == 0: + return + elif len(args_tuple) == 1: + return args_tuple[0] + else: + return args_tuple + diff --git a/python/services.py b/python/services.py new file mode 100644 index 00000000..7e0b58b7 --- /dev/null +++ b/python/services.py @@ -0,0 +1,187 @@ +from decorators import * + +import dbus_bindings + +class Service: + """A base class for exporting your own Services across the Bus + + Just inherit from Service, providing the name of your service + (e.g. org.designfu.SampleService). + """ + def __init__(self, named_service, bus=None): + self._named_service = named_service + + if bus == None: + # Get the default bus + self._bus = Bus() + else: + self._bus = bus + + dbus_bindings.bus_request_name(self._bus.get_connection(), named_service) + + def get_bus(self): + """Get the Bus this Service is on""" + return self._bus + + def get_name(self): + """Get the name of this service""" + return self._named_service + +def _dispatch_dbus_method_call(target_methods, self, argument_list, message): + """Calls method_to_call using argument_list, but handles + exceptions, etc, and generates a reply to the DBus Message message + """ + try: + target_method = None + + dbus_interface = message.get_interface() + if dbus_interface == None: + if target_methods: + target_method = target_methods[0] + else: + for dbus_method in target_methods: + if dbus_method._dbus_interface == dbus_interface: + target_method = dbus_method + break + + if target_method: + retval = target_method(self, *argument_list) + else: + if not dbus_interface: + raise UnknownMethodException('%s is not a valid method'%(message.get_member())) + else: + raise UnknownMethodException('%s is not a valid method of interface %s'%(message.get_member(), dbus_interface)) + except Exception, e: + if e.__module__ == '__main__': + # FIXME: is it right to use .__name__ here? + error_name = e.__class__.__name__ + else: + error_name = e.__module__ + '.' + str(e.__class__.__name__) + error_contents = str(e) + reply = dbus_bindings.Error(message, error_name, error_contents) + else: + reply = dbus_bindings.MethodReturn(message) + if retval != None: + iter = reply.get_iter(append=True) + iter.append(retval) + + return reply + +class ObjectType(type): + def __init__(cls, name, bases, dct): + + #generate out vtable + method_vtable = getattr(cls, '_dbus_method_vtable', {}) + reflection_data = getattr(cls, '_dbus_reflection_data', "") + + reflection_interface_method_hash = {} + reflection_interface_signal_hash = {} + + for func in dct.values(): + if getattr(func, '_dbus_is_method', False): + if method_vtable.has_key(func.__name__): + method_vtable[func.__name__].append(func) + else: + method_vtable[func.__name__] = [func] + + #generate a hash of interfaces so we can group + #methods in the xml data + if reflection_interface_method_hash.has_key(func._dbus_interface): + reflection_interface_method_hash[func._dbus_interface].append(func) + else: + reflection_interface_method_hash[func._dbus_interface] = [func] + + elif getattr(func, '_dbus_is_signal', False): + if reflection_interface_signal_hash.has_key(func._dbus_interface): + reflection_interface_signal_hash[func._dbus_interface].append(func) + else: + reflection_interface_signal_hash[func._dbus_interface] = [func] + + for interface in reflection_interface_method_hash.keys(): + reflection_data = reflection_data + ' <interface name="%s">\n'%(interface) + for func in reflection_interface_method_hash[interface]: + reflection_data = reflection_data + cls._reflect_on_method(func) + + if reflection_interface_signal_hash.has_key(interface): + for func in reflection_interface_signal_hash[interface]: + reflection_data = reflection_data + cls._reflect_on_signal(func) + + del reflection_interface_signal_hash[interface] + + reflection_data = reflection_data + ' </interface>\n' + + for interface in reflection_interface_signal_hash.keys(): + reflection_data = reflection_data + ' <interface name="%s">\n'%(interface) + + for func in reflection_interface_signal_hash[interface]: + reflection_data = reflection_data + cls._reflect_on_signal(func) + + reflection_data = reflection_data + ' </interface>\n' + + cls._dbus_reflection_data = reflection_data + cls._dbus_method_vtable = method_vtable + + super(ObjectType, cls).__init__(name, bases, dct) + + #reflections on methods and signals may look like similar code but may in fact + #diverge in the future so keep them seperate + def _reflect_on_method(cls, func): + reflection_data = ' <method name="%s">\n'%(func.__name__) + for arg in func._dbus_args: + reflection_data = reflection_data + ' <arg name="%s" type="v" />\n'%(arg) + + #reclaim some memory + func._dbus_args = None + reflection_data = reflection_data + ' </method>\n' + + return reflection_data + + def _reflect_on_signal(cls, func): + reflection_data = ' <signal name="%s">\n'%(func.__name__) + for arg in func._dbus_args: + reflection_data = reflection_data + ' <arg name="%s" type="v" />\n'%(arg) + #reclaim some memory + func._dbus_args = None + reflection_data = reflection_data + ' </signal>\n' + + return reflection_data + +class Object: + """A base class for exporting your own Objects across the Bus. + + Just inherit from Object and provide a list of methods to share + across the Bus. These will appear as member functions of your + ServiceObject. + """ + __metaclass__ = ObjectType + + def __init__(self, object_path, service): + self._object_path = object_path + self._service = service + self._bus = service.get_bus() + + self._connection = self._bus.get_connection() + + self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb) + + def _unregister_cb(self, connection): + print ("Unregister") + + def _message_cb(self, connection, message): + target_method_name = message.get_member() + target_methods = self._dbus_method_vtable[target_method_name] + args = message.get_args_list() + + reply = _dispatch_dbus_method_call(target_methods, self, args, message) + + self._connection.send(reply) + + @method('org.freedesktop.DBus.Introspectable') + def Introspect(self): + reflection_data = '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">\n' + reflection_data = reflection_data + '<node name="%s">\n'%(self._object_path) + reflection_data = reflection_data + self._dbus_reflection_data + reflection_data = reflection_data + '</node>\n' + + return reflection_data + diff --git a/python/types.py b/python/types.py new file mode 100644 index 00000000..1a01d8e4 --- /dev/null +++ b/python/types.py @@ -0,0 +1,18 @@ +import dbus_bindings + +ObjectPath = dbus_bindings.ObjectPath +ByteArray = dbus_bindings.ByteArray +Signature = dbus_bindings.Signature +Byte = dbus_bindings.Byte +Boolean = dbus_bindings.Boolean +Int16 = dbus_bindings.Int16 +UInt16 = dbus_bindings.UInt16 +Int32 = dbus_bindings.Int32 +UInt32 = dbus_bindings.UInt32 +Int64 = dbus_bindings.Int64 +UInt64 = dbus_bindings.UInt64 +Double = dbus_bindings.Double +String = dbus_bindings.String +Array = dbus_bindings.Array +Struct = dbus_bindings.Struct +Dictionary = dbus_bindings.Dictionary |