summaryrefslogtreecommitdiff
path: root/doc/tutorial.txt
blob: cc7a99e841e96669114ff5f876d941c90e19ef3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
====================
dbus-python tutorial
====================

:Author: Simon McVittie, `Collabora Ltd.`_
:Date: 2006-06-14

.. _`Collabora Ltd.`: http://www.collabora.co.uk/

This tutorial requires Python 2.4 or up, and ``dbus-python`` 0.80rc4 or up.

.. contents::

.. --------------------------------------------------------------------

.. _Bus object:
.. _Bus objects:

Connecting to the Bus
=====================

Applications that use D-Bus typically connect to a *bus daemon*, which
forwards messages between the applications. To use D-Bus, you need to create a
``Bus`` object representing the connection to the bus daemon.

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

Of course, you can connect to both in the same application.

For special purposes, you might use a non-default Bus, or a connection
which isn't a Bus at all, using some new API added in dbus-python 0.81.0.
This is not described here, and will at some stage be the subject of a separate
tutorial.

.. _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

.. --------------------------------------------------------------------

Making method calls
===================

D-Bus applications can export objects for other applications' use. To
start working with an object in another application, you need to know:

* The *bus name*. This identifies which application you want to
  communicate with. You'll usually identify applications by a
  *well-known name*, which is a dot-separated string starting with a
  reversed domain name, such as ``org.freedesktop.NetworkManager``
  or ``com.example.WordProcessor``.

* The *object path*. Applications can export many objects - for
  instance, example.com's word processor might provide an object
  representing the word processor application itself and an object for
  each document window opened, or it might also provide an object for
  each paragraph within a document.
  
  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
-------------

To interact with a remote object, you use a *proxy object*. This is a
Python object which acts as a proxy or "stand-in" for the remote object -
when you call a method on a proxy object, this causes dbus-python to make
a method call on the remote object, passing back any return values from
the remote object's method as the return values of the proxy method call.

To obtain a proxy object, call the ``get_object`` method on the ``Bus``.
For example, NetworkManager_ has the well-known name
``org.freedesktop.NetworkManager`` and exports an object whose object
path is ``/org/freedesktop/NetworkManager``, plus an object per network
interface at object paths like
``/org/freedesktop/NetworkManager/Devices/eth0``. You can get a proxy
for the object representing eth0 like this::

    import dbus
    bus = dbus.SystemBus()
    proxy = bus.get_object('org.freedesktop.NetworkManager',
                           '/org/freedesktop/NetworkManager/Devices/eth0')
    # proxy is a dbus.proxies.ProxyObject

Interfaces and methods
----------------------

D-Bus uses *interfaces* to provide a namespacing mechanism for methods.
An interface is a group of related methods and signals (more on signals
later), identified by a name which is a series of dot-separated components
starting with a reversed domain name. For instance, each NetworkManager_
object representing a network interface implements the interface
``org.freedesktop.NetworkManager.Devices``, which has methods like
``getProperties``.

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

See the example in ``examples/example-client.py``. Before running it,
you'll need to run ``examples/example-service.py`` in the background or
in another shell.

Data types
----------

Unlike Python, D-Bus is statically typed - each method has a certain
*signature* representing the types of its arguments, and will not accept
arguments of other types.

D-Bus has an introspection mechanism, which ``dbus-python`` tries to use
to discover the correct argument types. If this succeeds, Python types
are converted into the right D-Bus data types automatically, if possible;
``TypeError`` is raised if the type is inappropriate.

If the introspection mechanism fails (or the argument's type is
variant - see below), you have to provide arguments of
the correct type. ``dbus-python`` provides Python types corresponding to
the D-Bus data types, and a few native Python types are also converted to
D-Bus data types automatically. If you use a type which isn't among these,
a ``TypeError`` will be raised telling you that ``dbus-python`` was
unable to guess the D-Bus signature.

Basic types
~~~~~~~~~~~

The following basic data types are supported.

+-----------------------+---------------------+-----------------------+
|Python type            |converted to         |notes                  |
|                       |D-Bus type           |                       |
+=======================+=====================+=======================+
|D-Bus `proxy object`_  |object path          |`(+)`_                 |
+-----------------------+(signature 'o')      |                       |
|`dbus.Interface`_      |                     |                       |
+-----------------------+                     |                       |
|`dbus.service.Object`_ |                     |                       |
+-----------------------+---------------------+-----------------------+
|``dbus.Boolean``       |Boolean              |a subclass of ``int``  |
|                       |(signature 'b')      |                       |
+-----------------------+---------------------+                       |
|``dbus.Byte``          |byte (signature 'y') |                       |
+-----------------------+---------------------+                       |
|``dbus.Int16``         |16-bit signed        |                       |
|                       |integer ('n')        |                       |
+-----------------------+---------------------+                       |
|``dbus.UInt16``        |16-bit unsigned      |                       |
|                       |integer ('q')        |                       |
+-----------------------+---------------------+                       |
|``dbus.Int32``         |32-bit signed        |                       |
|                       |integer ('i')        |                       |
+-----------------------+---------------------+-----------------------+
|``dbus.UInt32``        |32-bit unsigned      |a subclass of ``long`` |
|                       |integer ('u')        |(Python 2)             |
+-----------------------+---------------------+                       |
|``dbus.Int64``         |64-bit signed        |a subclass of ``int``  |
|                       |integer ('x')        |(Python 3)             |
+-----------------------+---------------------+                       |
|``dbus.UInt64``        |64-bit unsigned      |                       |
|                       |integer ('t')        |                       |
+-----------------------+---------------------+-----------------------+
|``dbus.Double``        |double-precision     |a subclass of ``float``|
|                       |floating point ('d') |                       |
+-----------------------+---------------------+-----------------------+
|``dbus.ObjectPath``    |object path ('o')    |a subclass of ``str``  |
+-----------------------+---------------------+                       |
|``dbus.Signature``     |signature ('g')      |                       |
+-----------------------+---------------------+-----------------------+
|``dbus.String``        |string ('s')         |a subclass of          |
|                       |                     |``unicode`` (Python 2) |
|                       |                     |                       |
|                       |                     |a subclass of ``str``  |
|                       |                     |(Python 3)             |
+-----------------------+---------------------+-----------------------+
|``dbus.UTF8String``    |string ('s')         |a subclass of ``str``, |
|                       |                     |only in Python 2       |
+-----------------------+---------------------+-----------------------+
|``bool``               |Boolean ('b')        |                       |
+-----------------------+---------------------+-----------------------+
|``int`` or subclass    |32-bit signed        |                       |
|                       |integer ('i')        |                       |
+-----------------------+---------------------+-----------------------+
|``long`` or subclass   |64-bit signed        | Python 2 only         |
|                       |integer ('i')        |                       |
+-----------------------+---------------------+-----------------------+
|``float`` or subclass  |double-precision     |                       |
|                       |floating point ('d') |                       |
+-----------------------+---------------------+-----------------------+
|``bytes`` or subclass  |string ('s')         | must be valid UTF-8   |
+-----------------------+---------------------+-----------------------+
|Python 2 ``unicode``   |string ('s')         |                       |
+-----------------------+                     |                       |
|Python 3 ``str``       |                     |                       |
+-----------------------+---------------------+-----------------------+

.. _(+):

(+): 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.

Basic type conversions
~~~~~~~~~~~~~~~~~~~~~~

If introspection succeeded, ``dbus-python`` will also accept:

* for Boolean parameters, any object (converted as if via ``int(bool(...))``)
* for byte parameters, a single-character string (converted as if via ``ord()``)
* for byte and integer parameters, any integer (must be in the correct range)
* for object-path and signature parameters, any ``str`` or ``unicode``
  subclass (the value must follow the appropriate syntax)

Container types
~~~~~~~~~~~~~~~

D-Bus supports four container types: array (a variable-length sequence of the
same type), struct (a fixed-length sequence whose members may have
different types), dictionary (a mapping from values of the same basic type to
values of the same type), and variant (a container which may hold any
D-Bus type, including another variant).

Arrays are represented by Python lists, or by ``dbus.Array``, a subclass
of ``list``. When sending an array, if an introspected signature is
available, that will be used; otherwise, if the ``signature`` keyword
parameter was passed to the ``Array`` constructor, that will be used to
determine the contents' signature; otherwise, ``dbus-python`` will guess
from the array's first item.

The signature of an array is 'ax' where 'x' represents the signature of
one item. For instance, you could also have 'as' (array of strings) or
'a(ii)' (array of structs each containing two 32-bit integers).

There's also a type ``dbus.ByteArray`` which is a subclass of ``bytes``,
used as a more efficient representation of a D-Bus array of bytes
(signature 'ay').

Structs are represented by Python tuples, or by ``dbus.Struct``, a
subclass of ``tuple``. When sending a struct, if an introspected signature is
available, that will be used; otherwise, if the ``signature`` keyword
parameter was passed to the ``Array`` constructor, that will be used to
determine the contents' signature; otherwise, ``dbus-python`` will guess
from the array's first item.

The signature of a struct consists of the signatures of the contents,
in parentheses - for instance '(is)' is the signature of a struct
containing a 32-bit integer and a string.

Dictionaries are represented by Python dictionaries, or by
``dbus.Dictionary``, a subclass of ``dict``. When sending a dictionary,
if an introspected signature is available, that will be used; otherwise,
if the ``signature`` keyword parameter was passed to the ``Dictionary``
constructor, that will be used to determine the contents' key and value
signatures; otherwise, ``dbus-python`` will guess from an arbitrary item
of the ``dict``.

The signature of a dictionary is 'a{xy}' where 'x' represents the
signature of the keys (which may not be a container type) and 'y'
represents the signature of the values. For instance,
'a{s(ii)}' is a dictionary where the keys are strings and the values are
structs containing two 32-bit integers.

Variants are represented by setting the ``variant_level`` keyword
argument in the constructor of any D-Bus data type to a value greater
than 0 (``variant_level`` 1 means a variant containing some other data type,
``variant_level`` 2 means a variant containing a variant containing some
other data type, and so on). If a non-variant is passed as an argument
but introspection indicates that a variant is expected, it'll
automatically be wrapped in a variant.

The signature of a variant is 'v'.

.. _byte_arrays and utf8_strings:

Return values, and the ``byte_arrays`` and ``utf8_strings`` options
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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``.

If a D-Bus method returns multiple values, the Python proxy method
will return a tuple containing those values.

If you want strings returned as ``dbus.UTF8String`` (a subclass of
``bytes``) pass the keyword parameter ``utf8_strings=True`` to the proxy
method. This mode is only available in Python 2.

If you want byte arrays returned as ``dbus.ByteArray`` (also a
subclass of ``bytes`` - in practice, this is often what you want) pass
the keyword parameter ``byte_arrays=True`` to the proxy method.

.. --------------------------------------------------------------------

Making asynchronous method calls
================================

Asynchronous (non-blocking) method calls allow multiple method calls to
be in progress simultaneously, and allow your application to do other
work while it's waiting for the results. To make asynchronous calls,
you first need an event loop or "main loop".

Setting up an event loop
------------------------

Currently, the only main loop supported by ``dbus-python`` is GLib.

``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::

    from dbus.mainloop.glib import DBusGMainLoop

    DBusGMainLoop(set_as_default=True)

You must do this before `connecting to the bus`_.

Actually starting the main loop is as usual for ``pygi``::

    from gi.repository import GLib

    loop = GLib.MainLoop()
    loop.run()

While ``loop.run()`` is executing, GLib will run your callbacks when
appropriate. To stop, call ``loop.quit()``.

You can also set a main loop on a per-connection basis, by passing a
main loop to the Bus constructor::

    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.

Backwards compatibility: ``dbus.glib``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In versions of ``dbus-python`` prior to 0.80, the way to set GLib as the
default main loop was::

    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.

The Qt main loop
~~~~~~~~~~~~~~~~

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.

Making asynchronous calls
-------------------------

To make a call asynchronous, pass two callables as keyword arguments
``reply_handler`` and ``error_handler`` to the proxy method. The proxy
method will immediately return `None`. At some later time, when the event
loop is running, one of these will happen: either

* the ``reply_handler`` will be called with the method's return values
  as arguments; or

* the ``error_handler`` will be called with one argument, an instance of
  ``DBusException`` representing a remote exception.

See also
~~~~~~~~

``examples/example-async-client.py`` makes asynchronous method calls to
the service provided by ``examples/example-service.py`` which return
either a value or an exception. As for ``examples/example-client.py``,
you need to run ``examples/example-service.py`` in the background or
in another shell first.

.. --------------------------------------------------------------------

Receiving signals
=================

To receive signals, the Bus needs to be connected to an event loop - see
section `Setting up an event loop`_. Signals will only be received while
the event loop is running.

Signal matching
---------------

To respond to signals, you can use the ``add_signal_receiver`` method on
`Bus objects`_. This arranges for a callback to be called when a
matching signal is received, and has the following arguments:

* 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

* the signal name, ``signal_name``: here None (the default) matches all names

* the D-Bus interface, ``dbus_interface``: again None is the default,
  and matches all interfaces

* a sender bus name (well-known or unique), ``bus_name``: None is again
  the default, and matches all senders. Well-known names match signals
  from whatever application is currently the primary owner of that
  well-known name.

* a sender object path, ``path``: once again None is the default and
  matches all object paths

``add_signal_receiver`` also has keyword arguments ``utf8_strings`` and
``byte_arrays`` which influence the types used when calling the
handler function, in the same way as the `byte_arrays and utf8_strings`_
options on proxy methods.

``add_signal_receiver`` returns a ``SignalMatch`` object. Its only
useful public API at the moment is a ``remove`` method with no
arguments, which removes the signal match from the connection.

Getting more information from a signal
--------------------------------------

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

    iface.connect_to_signal("Hello", handler, sender_keyword='sender')

and a signal ``Hello`` with no arguments is received from
``com.example.Foo``, the ``handler`` function will be called with
``sender='com.example.Foo'``.

String argument matching
------------------------

If there are keyword parameters for the form ``arg``\ *n* where n is a
small non-negative number, their values must be Unicode strings (Python
2 ``unicode`` or Python 3 ``str``) or UTF-8 bytestrings. 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.

.. *this comment is to stop the above breaking vim syntax highlighting*

Receiving signals from a proxy object
-------------------------------------

`Proxy objects`_ have a special method ``connect_to_signal`` which
arranges for a callback to be called when a signal is received
from the corresponding remote object. The parameters are:

* the name of the signal

* 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

* the handler function, a callable: the same as for ``add_signal_receiver``

* the keyword argument ``dbus_interface`` qualifies the name with its
  interface

`dbus.Interface` objects have a similar ``connect_to_signal`` method,
but in this case you don't need the ``dbus_interface`` keyword argument
since the interface to use is already known.

The same extra keyword arguments as for ``add_signal_receiver`` are also
available, and just like ``add_signal_receiver``, it returns a
SignalMatch.

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

``examples/signal-recipient.py`` receives signals - it demonstrates
general signal matching as well as ``connect_to_signal``. Before running it,
you'll need to run ``examples/signal-emitter.py`` in the background or
in another shell.

.. _BusName:

.. --------------------------------------------------------------------

Claiming a bus name
===================

FIXME describe `BusName`_ - perhaps fix its API first?

The unique-instance idiom
-------------------------

FIXME provide exemplary code, put it in examples

.. _exported object:
.. _exported objects:

.. --------------------------------------------------------------------

Exporting objects
=================

Objects made available to other applications over D-Bus are said to be
*exported*. All subclasses of ``dbus.service.Object`` are automatically
exported.

To export objects, the Bus needs to be connected to an event loop - see
section `Setting up an event loop`_. Exported methods will only be called,
and queued signals will only be sent, while the event loop is running.

.. _dbus.service.Object:

Inheriting from ``dbus.service.Object``
---------------------------------------

To export an object onto the Bus, just subclass
``dbus.service.Object``. Object expects either a `BusName`_ or a `Bus
object`_, and an object-path, to be passed to its constructor: arrange
for this information to be available. For example::

    class Example(dbus.service.Object):
        def __init__(self, object_path):
            dbus.service.Object.__init__(self, dbus.SessionBus(), path)

This object will automatically support introspection, but won't do
anything particularly interesting. To fix that, you'll need to export some
methods and signals too.

FIXME also mention dbus.gobject.ExportedGObject once I've written it

Exporting methods with ``dbus.service.method``
----------------------------------------------

To export a method, use the decorator ``dbus.service.method``. For
example::

    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)

The ``in_signature`` and ``out_signature`` are D-Bus signature strings
as described in `Data Types`_.

As well as the keywords shown, you can pass ``utf8_strings`` and
``byte_arrays`` keyword arguments, which influence the types which will
be passed to the decorated method when it's called via D-Bus, in the
same way that the `byte_arrays and utf8_strings`_ options affect the
return value of a proxy method.

You can find a simple example in ``examples/example-service.py``, which
we used earlier to demonstrate ``examples/example-client.py``.

Finding out the caller's bus name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``method`` decorator accepts a ``sender_keyword`` keyword argument.
If you set that to a string, the unique bus name of the sender will be
passed to the decorated method as a keyword argument of that name::

    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!'

Asynchronous method implementations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FIXME and also add an example, perhaps examples/example-async-service.py

Emitting signals with ``dbus.service.signal``
---------------------------------------------

To export a signal, use the decorator ``dbus.service.signal``; to emit
that signal, call the decorated method. The decorated method can also
contain code which will be run when called, as usual. For example::

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

.. --------------------------------------------------------------------

License for this document
=========================

Copyright 2006-2007 `Collabora Ltd.`_

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

..
  vim:set ft=rst sw=4 sts=4 et tw=72: