Académique Documents
Professionnel Documents
Culture Documents
dbus-python tutorial
====================
.. contents::
.. --------------------------------------------------------------------
.. _Bus object:
.. _Bus objects:
There are generally two bus daemons you may be interested in. Each user
login session should have a *session bus*, which is local to that
session. It's used to communicate between desktop applications. Connect
to the session bus by creating a ``SessionBus`` object::
import dbus
session_bus = dbus.SessionBus()
The *system bus* is global and usually started during boot; it's used to
communicate with system services like udev_, NetworkManager_, and the
`Hardware Abstraction Layer daemon (hald)`_. To connect to the system
bus, create a ``SystemBus`` object::
import dbus
system_bus = dbus.SystemBus()
.. _udev:
http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
.. _NetworkManager:
http://www.gnome.org/projects/NetworkManager/
.. _Hardware Abstraction Layer daemon (hald):
http://www.freedesktop.org/wiki/Software/hal
.. --------------------------------------------------------------------
To identify which one you want to interact with, you use an object path,
a slash-separated string resembling a filename. For instance, example.com's
word processor might provide an object at ``/`` representing the word
processor itself, and objects at ``/documents/123`` and
``/documents/345`` representing opened document windows.
As you'd expect, one of the main things you can do with remote objects
is to call their methods. As in Python, methods may have parameters,
and they may return one or more values.
.. _proxy object:
Proxy objects
-------------
import dbus
bus = dbus.SystemBus()
proxy = bus.get_object('org.freedesktop.NetworkManager',
'/org/freedesktop/NetworkManager/Devices/eth0')
# proxy is a dbus.proxies.ProxyObject
To call a method, call the method of the same name on the proxy object,
passing in the interface name via the ``dbus_interface`` keyword argument::
import dbus
bus = dbus.SystemBus()
eth0 = bus.get_object('org.freedesktop.NetworkManager',
'/org/freedesktop/NetworkManager/Devices/eth0')
props =
eth0.getProperties(dbus_interface='org.freedesktop.NetworkManager.Devices')
# props is a tuple of properties, the first of which is the object path
.. _dbus.Interface:
As a short cut, if you're going to be calling many methods with the same
interface, you can construct a ``dbus.Interface`` object and call
methods on that, without needing to specify the interface again::
import dbus
bus = dbus.SystemBus()
eth0 = bus.get_object('org.freedesktop.NetworkManager',
'/org/freedesktop/NetworkManager/Devices/eth0')
eth0_dev_iface = dbus.Interface(eth0,
dbus_interface='org.freedesktop.NetworkManager.Devices')
props = eth0_dev_iface.getProperties()
# props is the same as before
See also
~~~~~~~~
Data types
----------
Basic types
~~~~~~~~~~~
.. _(*):
.. _(+):
(+): D-Bus proxy objects, exported D-Bus service objects and anything
else with the special attribute ``__dbus_object_path__``, which
must be a string, are converted to their object-path. This might be
useful if you're writing an object-oriented API using dbus-python.
Container types
~~~~~~~~~~~~~~~
If a D-Bus method returns no value, the Python proxy method will return
``None``.
If a D-Bus method returns one value, the Python proxy method will return
that value as one of the ``dbus.`` types - by default, strings are
returned as ``dbus.String`` (a subclass of Unicode) and byte arrays are
returned as a ``dbus.Array`` of ``dbus.Byte``.
.. --------------------------------------------------------------------
``dbus-python`` has a global default main loop, which is the easiest way
to use this functionality. To arrange for the GLib main loop to be the
default, use::
DBusGMainLoop(set_as_default=True)
import gobject
loop = gobject.MainLoop()
loop.run()
import dbus
from dbus.mainloop.glib import DBusGMainLoop
dbus_loop = DBusGMainLoop()
bus = dbus.SessionBus(mainloop=dbus_loop)
This isn't very useful until we support more than one main loop, though.
import dbus.glib
Executing that import statement would automatically load the GLib main
loop and make this the default. This is now deprecated, since it's
highly non-obvious, but may be useful if you want to write or understand
backwards-compatible code.
PyQt v4.2 and later includes support for integrating dbus-python with
the Qt event loop. To connect D-Bus to this main loop, call
``dbus.mainloop.qt.DBusQtMainLoop`` instead of
``dbus.mainloop.glib.DBusGMainLoop``. Otherwise the Qt loop is used in
exactly the same way as the GLib loop.
See also
~~~~~~~~
.. --------------------------------------------------------------------
Receiving signals
=================
* the signal name, ``signal_name``: here None (the default) matches all names
* a sender object path, ``path``: once again None is the default and
matches all object paths
You can also arrange for more information to be passed to the handler
function. If you pass the keyword arguments ``sender_keyword``,
``destination_keyword``, ``interface_keyword``, ``member_keyword`` or
``path_keyword`` to the ``connect_to_signal`` method, the appropriate
part of the signal message will be passed to the handler function as a
keyword argument: for instance if you use ::
def handler(sender=None):
print "got signal from %r" % sender
If there are keyword parameters for the form ``arg``\ *n* where n is a
small non-negative number, their values must be ``unicode`` objects
or UTF-8 strings. The handler will only be called if that argument
of the signal (numbered from zero) is a D-Bus string (in particular,
not an object-path or a signature) with that value.
* a callable (the handler function) which will be called by the event loop
when the signal is received - its parameters will be the arguments of
the signal
You shouldn't use proxy objects just to listen to signals, since they
might activate the relevant service when created, but if you already have a
proxy object in order to call methods, it's often convenient to use it to add
signal matches too.
See also
--------
.. _BusName:
.. --------------------------------------------------------------------
.. --------------------------------------------------------------------
Exporting objects
=================
.. _dbus.service.Object:
class Example(dbus.service.Object):
def __init__(self, object_path):
dbus.service.Object.__init__(self, dbus.SessionBus(), path)
class Example(dbus.service.Object):
def __init__(self, object_path):
dbus.service.Object.__init__(self, dbus.SessionBus(), path)
@dbus.service.method(dbus_interface='com.example.Sample',
in_signature='v', out_signature='s')
def StringifyVariant(self, variant):
return str(variant)
class Example(dbus.service.Object):
def __init__(self, object_path):
dbus.service.Object.__init__(self, dbus.SessionBus(), path)
@dbus.service.method(dbus_interface='com.example.Sample',
in_signature='', out_signature='s',
sender_keyword='sender')
def SayHello(self, sender=None):
return 'Hello, %s!' % sender
# -> something like 'Hello, :1.1!'
class Example(dbus.service.Object):
def __init__(self, object_path):
dbus.service.Object.__init__(self, dbus.SessionBus(), path)
@dbus.service.signal(dbus_interface='com.example.Sample',
signature='us')
def NumberOfBottlesChanged(self, number, contents):
print "%d bottles of %s on the wall" % (number, contents)
e = Example('/bottle-counter')
e.NumberOfBottlesChanged(100, 'beer')
# -> emits com.example.Sample.NumberOfBottlesChanged(100, 'beer')
# and prints "100 bottles of beer on the wall"
The signal will be queued for sending when the decorated method returns -
you can prevent the signal from being sent by raising an exception
from the decorated method (for instance, if the parameters are
inappropriate). The signal will only actually be sent when the event loop
next runs.
Example
~~~~~~~
``examples/example-signal-emitter.py`` emits some signals on demand when
one of its methods is called. (In reality, you'd emit a signal when some
sort of internal state changed, which may or may not be triggered by a
D-Bus method call.)
.. --------------------------------------------------------------------
..
vim:set ft=rst sw=4 sts=4 et tw=72: