Update NEWS, README for 0.80.0
[dbus-python-phuang.git] / dbus / decorators.py
blob654e044ca7783f937b82d2249c0c382455c5bd84
1 """Service-side D-Bus decorators."""
3 # Copyright (C) 2003, 2004, 2005, 2006 Red Hat Inc. <http://www.redhat.com/>
4 # Copyright (C) 2003 David Zeuthen
5 # Copyright (C) 2004 Rob Taylor
6 # Copyright (C) 2005, 2006 Collabora Ltd. <http://www.collabora.co.uk/>
8 # Licensed under the Academic Free License version 2.1
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 __all__ = ('method', 'signal')
27 __docformat__ = 'restructuredtext'
29 import inspect
31 import _dbus_bindings
34 def method(dbus_interface, in_signature=None, out_signature=None, async_callbacks=None, sender_keyword=None, utf8_strings=False, byte_arrays=False):
35 """Factory for decorators used to mark methods of a `dbus.service.Object`
36 to be exported on the D-Bus.
38 The decorated method will be exported over D-Bus as the method of the
39 same name on the given D-Bus interface.
41 :Parameters:
42 `dbus_interface` : str
43 Name of a D-Bus interface
44 `in_signature` : str or None
45 If not None, the signature of the method parameters in the usual
46 D-Bus notation
47 `out_signature` : str or None
48 If not None, the signature of the return value in the usual
49 D-Bus notation
50 `async_callbacks` : tuple containing (str,str), or None
51 If None (default) the decorated method is expected to return
52 values matching the `out_signature` as usual, or raise
53 an exception on error. If not None, the following applies:
55 `async_callbacks` contains the names of two keyword arguments to
56 the decorated function, which will be used to provide a success
57 callback and an error callback (in that order).
59 When the decorated method is called via the D-Bus, its normal
60 return value will be ignored; instead, a pair of callbacks are
61 passed as keyword arguments, and the decorated method is
62 expected to arrange for one of them to be called.
64 On success the success callback must be called, passing the
65 results of this method as positional parameters in the format
66 given by the `out_signature`.
68 On error the decorated method may either raise an exception
69 before it returns, or arrange for the error callback to be
70 called with an Exception instance as parameter.
72 `sender_keyword` : str or None
73 If not None, contains the name of a keyword argument to the
74 decorated function, conventionally ``'sender'``. When the
75 method is called, the sender's unique name will be passed as
76 this keyword argument.
78 `utf8_strings` : bool
79 If False (default), D-Bus strings are passed to the decorated
80 method as objects of class dbus.String, a unicode subclass.
82 If True, D-Bus strings are passed to the decorated method
83 as objects of class dbus.UTF8String, a str subclass guaranteed
84 to be encoded in UTF-8.
86 This option does not affect object-paths and signatures, which
87 are always 8-bit strings (str subclass) encoded in ASCII.
89 `byte_arrays` : bool
90 If False (default), a byte array will be passed to the decorated
91 method as an `Array` (a list subclass) of `Byte` objects.
93 If True, a byte array will be passed to the decorated method as
94 a `ByteArray`, a str subclass. This is usually what you want,
95 but is switched off by default to keep dbus-python's API
96 consistent.
97 """
98 _dbus_bindings.validate_interface_name(dbus_interface)
100 def decorator(func):
101 args = inspect.getargspec(func)[0]
102 args.pop(0)
104 if async_callbacks:
105 if type(async_callbacks) != tuple:
106 raise TypeError('async_callbacks must be a tuple of (keyword for return callback, keyword for error callback)')
107 if len(async_callbacks) != 2:
108 raise ValueError('async_callbacks must be a tuple of (keyword for return callback, keyword for error callback)')
109 args.remove(async_callbacks[0])
110 args.remove(async_callbacks[1])
112 if sender_keyword:
113 args.remove(sender_keyword)
115 if in_signature:
116 in_sig = tuple(_dbus_bindings.Signature(in_signature))
118 if len(in_sig) > len(args):
119 raise ValueError, 'input signature is longer than the number of arguments taken'
120 elif len(in_sig) < len(args):
121 raise ValueError, 'input signature is shorter than the number of arguments taken'
123 func._dbus_is_method = True
124 func._dbus_async_callbacks = async_callbacks
125 func._dbus_interface = dbus_interface
126 func._dbus_in_signature = in_signature
127 func._dbus_out_signature = out_signature
128 func._dbus_sender_keyword = sender_keyword
129 func._dbus_args = args
130 func._dbus_get_args_options = {'byte_arrays': byte_arrays,
131 'utf8_strings': utf8_strings}
132 return func
134 return decorator
137 def signal(dbus_interface, signature=None):
138 """Factory for decorators used to mark methods of a `dbus.service.Object`
139 to emit signals on the D-Bus.
141 Whenever the decorated method is called in Python, after the method
142 body is executed, a signal with the same name as the decorated method,
143 from the given D-Bus interface, will be emitted.
145 :Parameters:
146 `dbus_interface` : str
147 The D-Bus interface whose signal is emitted
148 `signature` : str
149 The signature of the signal in the usual D-Bus notation
151 _dbus_bindings.validate_interface_name(dbus_interface)
152 def decorator(func):
153 def emit_signal(self, *args, **keywords):
154 func(self, *args, **keywords)
155 message = _dbus_bindings.SignalMessage(self._object_path, dbus_interface, func.__name__)
157 if emit_signal._dbus_signature:
158 message.append(signature=emit_signal._dbus_signature,
159 *args)
160 else:
161 message.append(*args)
163 self._connection.send_message(message)
165 args = inspect.getargspec(func)[0]
166 args.pop(0)
168 if signature:
169 sig = tuple(_dbus_bindings.Signature(signature))
171 if len(sig) > len(args):
172 raise ValueError, 'signal signature is longer than the number of arguments provided'
173 elif len(sig) < len(args):
174 raise ValueError, 'signal signature is shorter than the number of arguments provided'
176 emit_signal.__name__ = func.__name__
177 emit_signal.__doc__ = func.__doc__
178 emit_signal._dbus_is_signal = True
179 emit_signal._dbus_interface = dbus_interface
180 emit_signal._dbus_signature = signature
181 emit_signal._dbus_args = args
182 return emit_signal
184 return decorator