|
Packit |
130fc8 |
====================
|
|
Packit |
130fc8 |
dbus-python tutorial
|
|
Packit |
130fc8 |
====================
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
:Author: Simon McVittie, `Collabora Ltd.`_
|
|
Packit |
130fc8 |
:Date: 2006-06-14
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _`Collabora Ltd.`: http://www.collabora.co.uk/
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
This tutorial requires Python 2.4 or up, and ``dbus-python`` 0.80rc4 or up.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. contents::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. --------------------------------------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _Bus object:
|
|
Packit |
130fc8 |
.. _Bus objects:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Connecting to the Bus
|
|
Packit |
130fc8 |
=====================
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Applications that use D-Bus typically connect to a *bus daemon*, which
|
|
Packit |
130fc8 |
forwards messages between the applications. To use D-Bus, you need to create a
|
|
Packit |
130fc8 |
``Bus`` object representing the connection to the bus daemon.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
There are generally two bus daemons you may be interested in. Each user
|
|
Packit |
130fc8 |
login session should have a *session bus*, which is local to that
|
|
Packit |
130fc8 |
session. It's used to communicate between desktop applications. Connect
|
|
Packit |
130fc8 |
to the session bus by creating a ``SessionBus`` object::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
import dbus
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
session_bus = dbus.SessionBus()
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The *system bus* is global and usually started during boot; it's used to
|
|
Packit |
130fc8 |
communicate with system services like udev_, NetworkManager_, and the
|
|
Packit |
130fc8 |
`Hardware Abstraction Layer daemon (hald)`_. To connect to the system
|
|
Packit |
130fc8 |
bus, create a ``SystemBus`` object::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
import dbus
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
system_bus = dbus.SystemBus()
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Of course, you can connect to both in the same application.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
For special purposes, you might use a non-default Bus, or a connection
|
|
Packit |
130fc8 |
which isn't a Bus at all, using some new API added in dbus-python 0.81.0.
|
|
Packit |
130fc8 |
This is not described here, and will at some stage be the subject of a separate
|
|
Packit |
130fc8 |
tutorial.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _udev:
|
|
Packit |
130fc8 |
http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
|
|
Packit |
130fc8 |
.. _NetworkManager:
|
|
Packit |
130fc8 |
http://www.gnome.org/projects/NetworkManager/
|
|
Packit |
130fc8 |
.. _Hardware Abstraction Layer daemon (hald):
|
|
Packit |
130fc8 |
http://www.freedesktop.org/wiki/Software/hal
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. --------------------------------------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Making method calls
|
|
Packit |
130fc8 |
===================
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
D-Bus applications can export objects for other applications' use. To
|
|
Packit |
130fc8 |
start working with an object in another application, you need to know:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* The *bus name*. This identifies which application you want to
|
|
Packit |
130fc8 |
communicate with. You'll usually identify applications by a
|
|
Packit |
130fc8 |
*well-known name*, which is a dot-separated string starting with a
|
|
Packit |
130fc8 |
reversed domain name, such as ``org.freedesktop.NetworkManager``
|
|
Packit |
130fc8 |
or ``com.example.WordProcessor``.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* The *object path*. Applications can export many objects - for
|
|
Packit |
130fc8 |
instance, example.com's word processor might provide an object
|
|
Packit |
130fc8 |
representing the word processor application itself and an object for
|
|
Packit |
130fc8 |
each document window opened, or it might also provide an object for
|
|
Packit |
130fc8 |
each paragraph within a document.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To identify which one you want to interact with, you use an object path,
|
|
Packit |
130fc8 |
a slash-separated string resembling a filename. For instance, example.com's
|
|
Packit |
130fc8 |
word processor might provide an object at ``/`` representing the word
|
|
Packit |
130fc8 |
processor itself, and objects at ``/documents/123`` and
|
|
Packit |
130fc8 |
``/documents/345`` representing opened document windows.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
As you'd expect, one of the main things you can do with remote objects
|
|
Packit |
130fc8 |
is to call their methods. As in Python, methods may have parameters,
|
|
Packit |
130fc8 |
and they may return one or more values.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _proxy object:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Proxy objects
|
|
Packit |
130fc8 |
-------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To interact with a remote object, you use a *proxy object*. This is a
|
|
Packit |
130fc8 |
Python object which acts as a proxy or "stand-in" for the remote object -
|
|
Packit |
130fc8 |
when you call a method on a proxy object, this causes dbus-python to make
|
|
Packit |
130fc8 |
a method call on the remote object, passing back any return values from
|
|
Packit |
130fc8 |
the remote object's method as the return values of the proxy method call.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To obtain a proxy object, call the ``get_object`` method on the ``Bus``.
|
|
Packit |
130fc8 |
For example, NetworkManager_ has the well-known name
|
|
Packit |
130fc8 |
``org.freedesktop.NetworkManager`` and exports an object whose object
|
|
Packit |
130fc8 |
path is ``/org/freedesktop/NetworkManager``, plus an object per network
|
|
Packit |
130fc8 |
interface at object paths like
|
|
Packit |
130fc8 |
``/org/freedesktop/NetworkManager/Devices/eth0``. You can get a proxy
|
|
Packit |
130fc8 |
for the object representing eth0 like this::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
import dbus
|
|
Packit |
130fc8 |
bus = dbus.SystemBus()
|
|
Packit |
130fc8 |
proxy = bus.get_object('org.freedesktop.NetworkManager',
|
|
Packit |
130fc8 |
'/org/freedesktop/NetworkManager/Devices/eth0')
|
|
Packit |
130fc8 |
# proxy is a dbus.proxies.ProxyObject
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Interfaces and methods
|
|
Packit |
130fc8 |
----------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
D-Bus uses *interfaces* to provide a namespacing mechanism for methods.
|
|
Packit |
130fc8 |
An interface is a group of related methods and signals (more on signals
|
|
Packit |
130fc8 |
later), identified by a name which is a series of dot-separated components
|
|
Packit |
130fc8 |
starting with a reversed domain name. For instance, each NetworkManager_
|
|
Packit |
130fc8 |
object representing a network interface implements the interface
|
|
Packit |
130fc8 |
``org.freedesktop.NetworkManager.Devices``, which has methods like
|
|
Packit |
130fc8 |
``getProperties``.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To call a method, call the method of the same name on the proxy object,
|
|
Packit |
130fc8 |
passing in the interface name via the ``dbus_interface`` keyword argument::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
import dbus
|
|
Packit |
130fc8 |
bus = dbus.SystemBus()
|
|
Packit |
130fc8 |
eth0 = bus.get_object('org.freedesktop.NetworkManager',
|
|
Packit |
130fc8 |
'/org/freedesktop/NetworkManager/Devices/eth0')
|
|
Packit |
130fc8 |
props = eth0.getProperties(dbus_interface='org.freedesktop.NetworkManager.Devices')
|
|
Packit |
130fc8 |
# props is a tuple of properties, the first of which is the object path
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _dbus.Interface:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
As a short cut, if you're going to be calling many methods with the same
|
|
Packit |
130fc8 |
interface, you can construct a ``dbus.Interface`` object and call
|
|
Packit |
130fc8 |
methods on that, without needing to specify the interface again::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
import dbus
|
|
Packit |
130fc8 |
bus = dbus.SystemBus()
|
|
Packit |
130fc8 |
eth0 = bus.get_object('org.freedesktop.NetworkManager',
|
|
Packit |
130fc8 |
'/org/freedesktop/NetworkManager/Devices/eth0')
|
|
Packit |
130fc8 |
eth0_dev_iface = dbus.Interface(eth0,
|
|
Packit |
130fc8 |
dbus_interface='org.freedesktop.NetworkManager.Devices')
|
|
Packit |
130fc8 |
props = eth0_dev_iface.getProperties()
|
|
Packit |
130fc8 |
# props is the same as before
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
See also
|
|
Packit |
130fc8 |
~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
See the example in ``examples/example-client.py``. Before running it,
|
|
Packit |
130fc8 |
you'll need to run ``examples/example-service.py`` in the background or
|
|
Packit |
130fc8 |
in another shell.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Data types
|
|
Packit |
130fc8 |
----------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Unlike Python, D-Bus is statically typed - each method has a certain
|
|
Packit |
130fc8 |
*signature* representing the types of its arguments, and will not accept
|
|
Packit |
130fc8 |
arguments of other types.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
D-Bus has an introspection mechanism, which ``dbus-python`` tries to use
|
|
Packit |
130fc8 |
to discover the correct argument types. If this succeeds, Python types
|
|
Packit |
130fc8 |
are converted into the right D-Bus data types automatically, if possible;
|
|
Packit |
130fc8 |
``TypeError`` is raised if the type is inappropriate.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
If the introspection mechanism fails (or the argument's type is
|
|
Packit |
130fc8 |
variant - see below), you have to provide arguments of
|
|
Packit |
130fc8 |
the correct type. ``dbus-python`` provides Python types corresponding to
|
|
Packit |
130fc8 |
the D-Bus data types, and a few native Python types are also converted to
|
|
Packit |
130fc8 |
D-Bus data types automatically. If you use a type which isn't among these,
|
|
Packit |
130fc8 |
a ``TypeError`` will be raised telling you that ``dbus-python`` was
|
|
Packit |
130fc8 |
unable to guess the D-Bus signature.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Basic types
|
|
Packit |
130fc8 |
~~~~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The following basic data types are supported.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
========================== ============================= =====
|
|
Packit |
130fc8 |
Python type converted to D-Bus type notes
|
|
Packit |
130fc8 |
========================== ============================= =====
|
|
Packit |
130fc8 |
D-Bus `proxy object`_ ObjectPath (signature 'o') `(+)`_
|
|
Packit |
130fc8 |
`dbus.Interface`_ ObjectPath (signature 'o') `(+)`_
|
|
Packit |
130fc8 |
`dbus.service.Object`_ ObjectPath (signature 'o') `(+)`_
|
|
Packit |
130fc8 |
``dbus.Boolean`` Boolean (signature 'b') a subclass of ``int``
|
|
Packit |
130fc8 |
``dbus.Byte`` byte (signature 'y') a subclass of ``int``
|
|
Packit |
130fc8 |
``dbus.Int16`` 16-bit signed integer ('n') a subclass of ``int``
|
|
Packit |
130fc8 |
``dbus.Int32`` 32-bit signed integer ('i') a subclass of ``int``
|
|
Packit |
130fc8 |
``dbus.Int64`` 64-bit signed integer ('x') `(*)`_
|
|
Packit |
130fc8 |
``dbus.UInt16`` 16-bit unsigned integer ('q') a subclass of ``int``
|
|
Packit |
130fc8 |
``dbus.UInt32`` 32-bit unsigned integer ('u') `(*)_`
|
|
Packit |
130fc8 |
``dbus.UInt64`` 64-bit unsigned integer ('t') `(*)_`
|
|
Packit |
130fc8 |
``dbus.Double`` double-precision float ('d') a subclass of ``float``
|
|
Packit |
130fc8 |
``dbus.ObjectPath`` object path ('o') a subclass of ``str``
|
|
Packit |
130fc8 |
``dbus.Signature`` signature ('g') a subclass of ``str``
|
|
Packit |
130fc8 |
``dbus.String`` string ('s') a subclass of
|
|
Packit |
130fc8 |
``unicode``
|
|
Packit |
130fc8 |
``dbus.UTF8String`` string ('s') a subclass of ``str``
|
|
Packit |
130fc8 |
``bool`` Boolean ('b')
|
|
Packit |
130fc8 |
``int`` or subclass 32-bit signed integer ('i')
|
|
Packit |
130fc8 |
``long`` or subclass 64-bit signed integer ('x')
|
|
Packit |
130fc8 |
``float`` or subclass double-precision float ('d')
|
|
Packit |
130fc8 |
``str`` or subclass string ('s') must be valid UTF-8
|
|
Packit |
130fc8 |
``unicode`` or subclass string ('s')
|
|
Packit |
130fc8 |
========================== ============================= =====
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _(*):
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Types marked (*) may be a subclass of either ``int`` or ``long``, depending
|
|
Packit |
130fc8 |
on platform.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _(+):
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
(+): D-Bus proxy objects, exported D-Bus service objects and anything
|
|
Packit |
130fc8 |
else with the special attribute ``__dbus_object_path__``, which
|
|
Packit |
130fc8 |
must be a string, are converted to their object-path. This might be
|
|
Packit |
130fc8 |
useful if you're writing an object-oriented API using dbus-python.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Basic type conversions
|
|
Packit |
130fc8 |
~~~~~~~~~~~~~~~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
If introspection succeeded, ``dbus-python`` will also accept:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* for Boolean parameters, any object (converted as if via ``int(bool(...))``)
|
|
Packit |
130fc8 |
* for byte parameters, a single-character string (converted as if via ``ord()``)
|
|
Packit |
130fc8 |
* for byte and integer parameters, any integer (must be in the correct range)
|
|
Packit |
130fc8 |
* for object-path and signature parameters, any ``str`` or ``unicode``
|
|
Packit |
130fc8 |
subclass (the value must follow the appropriate syntax)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Container types
|
|
Packit |
130fc8 |
~~~~~~~~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
D-Bus supports four container types: array (a variable-length sequence of the
|
|
Packit |
130fc8 |
same type), struct (a fixed-length sequence whose members may have
|
|
Packit |
130fc8 |
different types), dictionary (a mapping from values of the same basic type to
|
|
Packit |
130fc8 |
values of the same type), and variant (a container which may hold any
|
|
Packit |
130fc8 |
D-Bus type, including another variant).
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Arrays are represented by Python lists, or by ``dbus.Array``, a subclass
|
|
Packit |
130fc8 |
of ``list``. When sending an array, if an introspected signature is
|
|
Packit |
130fc8 |
available, that will be used; otherwise, if the ``signature`` keyword
|
|
Packit |
130fc8 |
parameter was passed to the ``Array`` constructor, that will be used to
|
|
Packit |
130fc8 |
determine the contents' signature; otherwise, ``dbus-python`` will guess
|
|
Packit |
130fc8 |
from the array's first item.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The signature of an array is 'ax' where 'x' represents the signature of
|
|
Packit |
130fc8 |
one item. For instance, you could also have 'as' (array of strings) or
|
|
Packit |
130fc8 |
'a(ii)' (array of structs each containing two 32-bit integers).
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
There's also a type ``dbus.ByteArray`` which is a subclass of ``str``,
|
|
Packit |
130fc8 |
used as a more efficient representation of a D-Bus array of bytes
|
|
Packit |
130fc8 |
(signature 'ay').
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Structs are represented by Python tuples, or by ``dbus.Struct``, a
|
|
Packit |
130fc8 |
subclass of ``tuple``. When sending a struct, if an introspected signature is
|
|
Packit |
130fc8 |
available, that will be used; otherwise, if the ``signature`` keyword
|
|
Packit |
130fc8 |
parameter was passed to the ``Array`` constructor, that will be used to
|
|
Packit |
130fc8 |
determine the contents' signature; otherwise, ``dbus-python`` will guess
|
|
Packit |
130fc8 |
from the array's first item.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The signature of a struct consists of the signatures of the contents,
|
|
Packit |
130fc8 |
in parentheses - for instance '(is)' is the signature of a struct
|
|
Packit |
130fc8 |
containing a 32-bit integer and a string.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Dictionaries are represented by Python dictionaries, or by
|
|
Packit |
130fc8 |
``dbus.Dictionary``, a subclass of ``dict``. When sending a dictionary,
|
|
Packit |
130fc8 |
if an introspected signature is available, that will be used; otherwise,
|
|
Packit |
130fc8 |
if the ``signature`` keyword parameter was passed to the ``Dictionary``
|
|
Packit |
130fc8 |
constructor, that will be used to determine the contents' key and value
|
|
Packit |
130fc8 |
signatures; otherwise, ``dbus-python`` will guess from an arbitrary item
|
|
Packit |
130fc8 |
of the ``dict``.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The signature of a dictionary is 'a{xy}' where 'x' represents the
|
|
Packit |
130fc8 |
signature of the keys (which may not be a container type) and 'y'
|
|
Packit |
130fc8 |
represents the signature of the values. For instance,
|
|
Packit |
130fc8 |
'a{s(ii)}' is a dictionary where the keys are strings and the values are
|
|
Packit |
130fc8 |
structs containing two 32-bit integers.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Variants are represented by setting the ``variant_level`` keyword
|
|
Packit |
130fc8 |
argument in the constructor of any D-Bus data type to a value greater
|
|
Packit |
130fc8 |
than 0 (``variant_level`` 1 means a variant containing some other data type,
|
|
Packit |
130fc8 |
``variant_level`` 2 means a variant containing a variant containing some
|
|
Packit |
130fc8 |
other data type, and so on). If a non-variant is passed as an argument
|
|
Packit |
130fc8 |
but introspection indicates that a variant is expected, it'll
|
|
Packit |
130fc8 |
automatically be wrapped in a variant.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The signature of a variant is 'v'.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _byte_arrays and utf8_strings:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Return values, and the ``byte_arrays`` and ``utf8_strings`` options
|
|
Packit |
130fc8 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
If a D-Bus method returns no value, the Python proxy method will return
|
|
Packit |
130fc8 |
``None``.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
If a D-Bus method returns one value, the Python proxy method will return
|
|
Packit |
130fc8 |
that value as one of the ``dbus.`` types - by default, strings are
|
|
Packit |
130fc8 |
returned as ``dbus.String`` (a subclass of Unicode) and byte arrays are
|
|
Packit |
130fc8 |
returned as a ``dbus.Array`` of ``dbus.Byte``.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
If a D-Bus method returns multiple values, the Python proxy method
|
|
Packit |
130fc8 |
will return a tuple containing those values.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
If you want strings returned as ``dbus.UTF8String`` (a subclass of
|
|
Packit |
130fc8 |
``str``) pass the keyword parameter ``utf8_strings=True`` to the proxy
|
|
Packit |
130fc8 |
method.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
If you want byte arrays returned as ``dbus.ByteArray`` (also a
|
|
Packit |
130fc8 |
subclass of ``str`` - in practice, this is often what you want) pass
|
|
Packit |
130fc8 |
the keyword parameter ``byte_arrays=True`` to the proxy method.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. --------------------------------------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Making asynchronous method calls
|
|
Packit |
130fc8 |
================================
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Asynchronous (non-blocking) method calls allow multiple method calls to
|
|
Packit |
130fc8 |
be in progress simultaneously, and allow your application to do other
|
|
Packit |
130fc8 |
work while it's waiting for the results. To make asynchronous calls,
|
|
Packit |
130fc8 |
you first need an event loop or "main loop".
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Setting up an event loop
|
|
Packit |
130fc8 |
------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Currently, the only main loop supported by ``dbus-python`` is GLib.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
``dbus-python`` has a global default main loop, which is the easiest way
|
|
Packit |
130fc8 |
to use this functionality. To arrange for the GLib main loop to be the
|
|
Packit |
130fc8 |
default, use::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
from dbus.mainloop.glib import DBusGMainLoop
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
DBusGMainLoop(set_as_default=True)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
You must do this before `connecting to the bus`_.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Actually starting the main loop is as usual for ``pygi``::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
from gi.repository import GLib
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
loop = GLib.MainLoop()
|
|
Packit |
130fc8 |
loop.run()
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
While ``loop.run()`` is executing, GLib will run your callbacks when
|
|
Packit |
130fc8 |
appropriate. To stop, call ``loop.quit()``.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
You can also set a main loop on a per-connection basis, by passing a
|
|
Packit |
130fc8 |
main loop to the Bus constructor::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
import dbus
|
|
Packit |
130fc8 |
from dbus.mainloop.glib import DBusGMainLoop
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
dbus_loop = DBusGMainLoop()
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
bus = dbus.SessionBus(mainloop=dbus_loop)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
This isn't very useful until we support more than one main loop, though.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Backwards compatibility: ``dbus.glib``
|
|
Packit |
130fc8 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
In versions of ``dbus-python`` prior to 0.80, the way to set GLib as the
|
|
Packit |
130fc8 |
default main loop was::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
import dbus.glib
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Executing that import statement would automatically load the GLib main
|
|
Packit |
130fc8 |
loop and make this the default. This is now deprecated, since it's
|
|
Packit |
130fc8 |
highly non-obvious, but may be useful if you want to write or understand
|
|
Packit |
130fc8 |
backwards-compatible code.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The Qt main loop
|
|
Packit |
130fc8 |
~~~~~~~~~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
PyQt v4.2 and later includes support for integrating dbus-python with
|
|
Packit |
130fc8 |
the Qt event loop. To connect D-Bus to this main loop, call
|
|
Packit |
130fc8 |
``dbus.mainloop.qt.DBusQtMainLoop`` instead of
|
|
Packit |
130fc8 |
``dbus.mainloop.glib.DBusGMainLoop``. Otherwise the Qt loop is used in
|
|
Packit |
130fc8 |
exactly the same way as the GLib loop.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Making asynchronous calls
|
|
Packit |
130fc8 |
-------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To make a call asynchronous, pass two callables as keyword arguments
|
|
Packit |
130fc8 |
``reply_handler`` and ``error_handler`` to the proxy method. The proxy
|
|
Packit |
130fc8 |
method will immediately return `None`. At some later time, when the event
|
|
Packit |
130fc8 |
loop is running, one of these will happen: either
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* the ``reply_handler`` will be called with the method's return values
|
|
Packit |
130fc8 |
as arguments; or
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* the ``error_handler`` will be called with one argument, an instance of
|
|
Packit |
130fc8 |
``DBusException`` representing a remote exception.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
See also
|
|
Packit |
130fc8 |
~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
``examples/example-async-client.py`` makes asynchronous method calls to
|
|
Packit |
130fc8 |
the service provided by ``examples/example-service.py`` which return
|
|
Packit |
130fc8 |
either a value or an exception. As for ``examples/example-client.py``,
|
|
Packit |
130fc8 |
you need to run ``examples/example-service.py`` in the background or
|
|
Packit |
130fc8 |
in another shell first.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. --------------------------------------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Receiving signals
|
|
Packit |
130fc8 |
=================
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To receive signals, the Bus needs to be connected to an event loop - see
|
|
Packit |
130fc8 |
section `Setting up an event loop`_. Signals will only be received while
|
|
Packit |
130fc8 |
the event loop is running.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Signal matching
|
|
Packit |
130fc8 |
---------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To respond to signals, you can use the ``add_signal_receiver`` method on
|
|
Packit |
130fc8 |
`Bus objects`_. This arranges for a callback to be called when a
|
|
Packit |
130fc8 |
matching signal is received, and has the following arguments:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* a callable (the ``handler_function``) which will be called by the event loop
|
|
Packit |
130fc8 |
when the signal is received - its parameters will be the arguments of
|
|
Packit |
130fc8 |
the signal
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* the signal name, ``signal_name``: here None (the default) matches all names
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* the D-Bus interface, ``dbus_interface``: again None is the default,
|
|
Packit |
130fc8 |
and matches all interfaces
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* a sender bus name (well-known or unique), ``bus_name``: None is again
|
|
Packit |
130fc8 |
the default, and matches all senders. Well-known names match signals
|
|
Packit |
130fc8 |
from whatever application is currently the primary owner of that
|
|
Packit |
130fc8 |
well-known name.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* a sender object path, ``path``: once again None is the default and
|
|
Packit |
130fc8 |
matches all object paths
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
``add_signal_receiver`` also has keyword arguments ``utf8_strings`` and
|
|
Packit |
130fc8 |
``byte_arrays`` which influence the types used when calling the
|
|
Packit |
130fc8 |
handler function, in the same way as the `byte_arrays and utf8_strings`_
|
|
Packit |
130fc8 |
options on proxy methods.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
``add_signal_receiver`` returns a ``SignalMatch`` object. Its only
|
|
Packit |
130fc8 |
useful public API at the moment is a ``remove`` method with no
|
|
Packit |
130fc8 |
arguments, which removes the signal match from the connection.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Getting more information from a signal
|
|
Packit |
130fc8 |
--------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
You can also arrange for more information to be passed to the handler
|
|
Packit |
130fc8 |
function. If you pass the keyword arguments ``sender_keyword``,
|
|
Packit |
130fc8 |
``destination_keyword``, ``interface_keyword``, ``member_keyword`` or
|
|
Packit |
130fc8 |
``path_keyword`` to the ``connect_to_signal`` method, the appropriate
|
|
Packit |
130fc8 |
part of the signal message will be passed to the handler function as a
|
|
Packit |
130fc8 |
keyword argument: for instance if you use ::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
def handler(sender=None):
|
|
Packit |
130fc8 |
print "got signal from %r" % sender
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
iface.connect_to_signal("Hello", handler, sender_keyword='sender')
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
and a signal ``Hello`` with no arguments is received from
|
|
Packit |
130fc8 |
``com.example.Foo``, the ``handler`` function will be called with
|
|
Packit |
130fc8 |
``sender='com.example.Foo'``.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
String argument matching
|
|
Packit |
130fc8 |
------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
If there are keyword parameters for the form ``arg``\ *n* where n is a
|
|
Packit |
130fc8 |
small non-negative number, their values must be ``unicode`` objects
|
|
Packit |
130fc8 |
or UTF-8 strings. The handler will only be called if that argument
|
|
Packit |
130fc8 |
of the signal (numbered from zero) is a D-Bus string (in particular,
|
|
Packit |
130fc8 |
not an object-path or a signature) with that value.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. *this comment is to stop the above breaking vim syntax highlighting*
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Receiving signals from a proxy object
|
|
Packit |
130fc8 |
-------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
`Proxy objects`_ have a special method ``connect_to_signal`` which
|
|
Packit |
130fc8 |
arranges for a callback to be called when a signal is received
|
|
Packit |
130fc8 |
from the corresponding remote object. The parameters are:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* the name of the signal
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* a callable (the handler function) which will be called by the event loop
|
|
Packit |
130fc8 |
when the signal is received - its parameters will be the arguments of
|
|
Packit |
130fc8 |
the signal
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* the handler function, a callable: the same as for ``add_signal_receiver``
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
* the keyword argument ``dbus_interface`` qualifies the name with its
|
|
Packit |
130fc8 |
interface
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
`dbus.Interface` objects have a similar ``connect_to_signal`` method,
|
|
Packit |
130fc8 |
but in this case you don't need the ``dbus_interface`` keyword argument
|
|
Packit |
130fc8 |
since the interface to use is already known.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The same extra keyword arguments as for ``add_signal_receiver`` are also
|
|
Packit |
130fc8 |
available, and just like ``add_signal_receiver``, it returns a
|
|
Packit |
130fc8 |
SignalMatch.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
You shouldn't use proxy objects just to listen to signals, since they
|
|
Packit |
130fc8 |
might activate the relevant service when created, but if you already have a
|
|
Packit |
130fc8 |
proxy object in order to call methods, it's often convenient to use it to add
|
|
Packit |
130fc8 |
signal matches too.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
See also
|
|
Packit |
130fc8 |
--------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
``examples/signal-recipient.py`` receives signals - it demonstrates
|
|
Packit |
130fc8 |
general signal matching as well as ``connect_to_signal``. Before running it,
|
|
Packit |
130fc8 |
you'll need to run ``examples/signal-emitter.py`` in the background or
|
|
Packit |
130fc8 |
in another shell.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _BusName:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. --------------------------------------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Claiming a bus name
|
|
Packit |
130fc8 |
===================
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
FIXME describe `BusName`_ - perhaps fix its API first?
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The unique-instance idiom
|
|
Packit |
130fc8 |
-------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
FIXME provide exemplary code, put it in examples
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _exported object:
|
|
Packit |
130fc8 |
.. _exported objects:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. --------------------------------------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Exporting objects
|
|
Packit |
130fc8 |
=================
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Objects made available to other applications over D-Bus are said to be
|
|
Packit |
130fc8 |
*exported*. All subclasses of ``dbus.service.Object`` are automatically
|
|
Packit |
130fc8 |
exported.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To export objects, the Bus needs to be connected to an event loop - see
|
|
Packit |
130fc8 |
section `Setting up an event loop`_. Exported methods will only be called,
|
|
Packit |
130fc8 |
and queued signals will only be sent, while the event loop is running.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. _dbus.service.Object:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Inheriting from ``dbus.service.Object``
|
|
Packit |
130fc8 |
---------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To export an object onto the Bus, just subclass
|
|
Packit |
130fc8 |
``dbus.service.Object``. Object expects either a `BusName`_ or a `Bus
|
|
Packit |
130fc8 |
object`_, and an object-path, to be passed to its constructor: arrange
|
|
Packit |
130fc8 |
for this information to be available. For example::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
class Example(dbus.service.Object):
|
|
Packit |
130fc8 |
def __init__(self, object_path):
|
|
Packit |
130fc8 |
dbus.service.Object.__init__(self, dbus.SessionBus(), path)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
This object will automatically support introspection, but won't do
|
|
Packit |
130fc8 |
anything particularly interesting. To fix that, you'll need to export some
|
|
Packit |
130fc8 |
methods and signals too.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
FIXME also mention dbus.gobject.ExportedGObject once I've written it
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Exporting methods with ``dbus.service.method``
|
|
Packit |
130fc8 |
----------------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To export a method, use the decorator ``dbus.service.method``. For
|
|
Packit |
130fc8 |
example::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
class Example(dbus.service.Object):
|
|
Packit |
130fc8 |
def __init__(self, object_path):
|
|
Packit |
130fc8 |
dbus.service.Object.__init__(self, dbus.SessionBus(), path)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
@dbus.service.method(dbus_interface='com.example.Sample',
|
|
Packit |
130fc8 |
in_signature='v', out_signature='s')
|
|
Packit |
130fc8 |
def StringifyVariant(self, variant):
|
|
Packit |
130fc8 |
return str(variant)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The ``in_signature`` and ``out_signature`` are D-Bus signature strings
|
|
Packit |
130fc8 |
as described in `Data Types`_.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
As well as the keywords shown, you can pass ``utf8_strings`` and
|
|
Packit |
130fc8 |
``byte_arrays`` keyword arguments, which influence the types which will
|
|
Packit |
130fc8 |
be passed to the decorated method when it's called via D-Bus, in the
|
|
Packit |
130fc8 |
same way that the `byte_arrays and utf8_strings`_ options affect the
|
|
Packit |
130fc8 |
return value of a proxy method.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
You can find a simple example in ``examples/example-service.py``, which
|
|
Packit |
130fc8 |
we used earlier to demonstrate ``examples/example-client.py``.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Finding out the caller's bus name
|
|
Packit |
130fc8 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The ``method`` decorator accepts a ``sender_keyword`` keyword argument.
|
|
Packit |
130fc8 |
If you set that to a string, the unique bus name of the sender will be
|
|
Packit |
130fc8 |
passed to the decorated method as a keyword argument of that name::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
class Example(dbus.service.Object):
|
|
Packit |
130fc8 |
def __init__(self, object_path):
|
|
Packit |
130fc8 |
dbus.service.Object.__init__(self, dbus.SessionBus(), path)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
@dbus.service.method(dbus_interface='com.example.Sample',
|
|
Packit |
130fc8 |
in_signature='', out_signature='s',
|
|
Packit |
130fc8 |
sender_keyword='sender')
|
|
Packit |
130fc8 |
def SayHello(self, sender=None):
|
|
Packit |
130fc8 |
return 'Hello, %s!' % sender
|
|
Packit |
130fc8 |
# -> something like 'Hello, :1.1!'
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Asynchronous method implementations
|
|
Packit |
130fc8 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
FIXME and also add an example, perhaps examples/example-async-service.py
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Emitting signals with ``dbus.service.signal``
|
|
Packit |
130fc8 |
---------------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
To export a signal, use the decorator ``dbus.service.signal``; to emit
|
|
Packit |
130fc8 |
that signal, call the decorated method. The decorated method can also
|
|
Packit |
130fc8 |
contain code which will be run when called, as usual. For example::
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
class Example(dbus.service.Object):
|
|
Packit |
130fc8 |
def __init__(self, object_path):
|
|
Packit |
130fc8 |
dbus.service.Object.__init__(self, dbus.SessionBus(), path)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
@dbus.service.signal(dbus_interface='com.example.Sample',
|
|
Packit |
130fc8 |
signature='us')
|
|
Packit |
130fc8 |
def NumberOfBottlesChanged(self, number, contents):
|
|
Packit |
130fc8 |
print "%d bottles of %s on the wall" % (number, contents)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
e = Example('/bottle-counter')
|
|
Packit |
130fc8 |
e.NumberOfBottlesChanged(100, 'beer')
|
|
Packit |
130fc8 |
# -> emits com.example.Sample.NumberOfBottlesChanged(100, 'beer')
|
|
Packit |
130fc8 |
# and prints "100 bottles of beer on the wall"
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The signal will be queued for sending when the decorated method returns -
|
|
Packit |
130fc8 |
you can prevent the signal from being sent by raising an exception
|
|
Packit |
130fc8 |
from the decorated method (for instance, if the parameters are
|
|
Packit |
130fc8 |
inappropriate). The signal will only actually be sent when the event loop
|
|
Packit |
130fc8 |
next runs.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Example
|
|
Packit |
130fc8 |
~~~~~~~
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
``examples/example-signal-emitter.py`` emits some signals on demand when
|
|
Packit |
130fc8 |
one of its methods is called. (In reality, you'd emit a signal when some
|
|
Packit |
130fc8 |
sort of internal state changed, which may or may not be triggered by a
|
|
Packit |
130fc8 |
D-Bus method call.)
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
.. --------------------------------------------------------------------
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
License for this document
|
|
Packit |
130fc8 |
=========================
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Copyright 2006-2007 `Collabora Ltd.`_
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
Permission is hereby granted, free of charge, to any person
|
|
Packit |
130fc8 |
obtaining a copy of this software and associated documentation
|
|
Packit |
130fc8 |
files (the "Software"), to deal in the Software without
|
|
Packit |
130fc8 |
restriction, including without limitation the rights to use, copy,
|
|
Packit |
130fc8 |
modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
Packit |
130fc8 |
of the Software, and to permit persons to whom the Software is
|
|
Packit |
130fc8 |
furnished to do so, subject to the following conditions:
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
The above copyright notice and this permission notice shall be
|
|
Packit |
130fc8 |
included in all copies or substantial portions of the Software.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
Packit |
130fc8 |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
Packit |
130fc8 |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
Packit |
130fc8 |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
Packit |
130fc8 |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
Packit |
130fc8 |
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
Packit |
130fc8 |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
Packit |
130fc8 |
DEALINGS IN THE SOFTWARE.
|
|
Packit |
130fc8 |
|
|
Packit |
130fc8 |
..
|
|
Packit |
130fc8 |
vim:set ft=rst sw=4 sts=4 et tw=72:
|