* dbus.service.Object: don't let the user try to export objects on the local
[dbus-python-phuang.git] / dbus / decorators.py
blob9a7be2fe0c98e027913c379acfa15722b4b75716
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 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 __all__ = ('method', 'signal')
25 __docformat__ = 'restructuredtext'
27 import inspect
29 import _dbus_bindings
32 def method(dbus_interface, in_signature=None, out_signature=None, async_callbacks=None, sender_keyword=None, utf8_strings=False, byte_arrays=False):
33 """Factory for decorators used to mark methods of a `dbus.service.Object`
34 to be exported on the D-Bus.
36 The decorated method will be exported over D-Bus as the method of the
37 same name on the given D-Bus interface.
39 :Parameters:
40 `dbus_interface` : str
41 Name of a D-Bus interface
42 `in_signature` : str or None
43 If not None, the signature of the method parameters in the usual
44 D-Bus notation
45 `out_signature` : str or None
46 If not None, the signature of the return value in the usual
47 D-Bus notation
48 `async_callbacks` : tuple containing (str,str), or None
49 If None (default) the decorated method is expected to return
50 values matching the `out_signature` as usual, or raise
51 an exception on error. If not None, the following applies:
53 `async_callbacks` contains the names of two keyword arguments to
54 the decorated function, which will be used to provide a success
55 callback and an error callback (in that order).
57 When the decorated method is called via the D-Bus, its normal
58 return value will be ignored; instead, a pair of callbacks are
59 passed as keyword arguments, and the decorated method is
60 expected to arrange for one of them to be called.
62 On success the success callback must be called, passing the
63 results of this method as positional parameters in the format
64 given by the `out_signature`.
66 On error the decorated method may either raise an exception
67 before it returns, or arrange for the error callback to be
68 called with an Exception instance as parameter.
70 `sender_keyword` : str or None
71 If not None, contains the name of a keyword argument to the
72 decorated function, conventionally ``'sender'``. When the
73 method is called, the sender's unique name will be passed as
74 this keyword argument.
76 `utf8_strings` : bool
77 If False (default), D-Bus strings are passed to the decorated
78 method as objects of class dbus.String, a unicode subclass.
80 If True, D-Bus strings are passed to the decorated method
81 as objects of class dbus.UTF8String, a str subclass guaranteed
82 to be encoded in UTF-8.
84 This option does not affect object-paths and signatures, which
85 are always 8-bit strings (str subclass) encoded in ASCII.
87 `byte_arrays` : bool
88 If False (default), a byte array will be passed to the decorated
89 method as an `Array` (a list subclass) of `Byte` objects.
91 If True, a byte array will be passed to the decorated method as
92 a `ByteArray`, a str subclass. This is usually what you want,
93 but is switched off by default to keep dbus-python's API
94 consistent.
95 """
96 _dbus_bindings.validate_interface_name(dbus_interface)
98 def decorator(func):
99 args = inspect.getargspec(func)[0]
100 args.pop(0)
102 if async_callbacks:
103 if type(async_callbacks) != tuple:
104 raise TypeError('async_callbacks must be a tuple of (keyword for return callback, keyword for error callback)')
105 if len(async_callbacks) != 2:
106 raise ValueError('async_callbacks must be a tuple of (keyword for return callback, keyword for error callback)')
107 args.remove(async_callbacks[0])
108 args.remove(async_callbacks[1])
110 if sender_keyword:
111 args.remove(sender_keyword)
113 if in_signature:
114 in_sig = tuple(_dbus_bindings.Signature(in_signature))
116 if len(in_sig) > len(args):
117 raise ValueError, 'input signature is longer than the number of arguments taken'
118 elif len(in_sig) < len(args):
119 raise ValueError, 'input signature is shorter than the number of arguments taken'
121 func._dbus_is_method = True
122 func._dbus_async_callbacks = async_callbacks
123 func._dbus_interface = dbus_interface
124 func._dbus_in_signature = in_signature
125 func._dbus_out_signature = out_signature
126 func._dbus_sender_keyword = sender_keyword
127 func._dbus_args = args
128 func._dbus_get_args_options = {'byte_arrays': byte_arrays,
129 'utf8_strings': utf8_strings}
130 return func
132 return decorator
135 def signal(dbus_interface, signature=None):
136 """Factory for decorators used to mark methods of a `dbus.service.Object`
137 to emit signals on the D-Bus.
139 Whenever the decorated method is called in Python, after the method
140 body is executed, a signal with the same name as the decorated method,
141 from the given D-Bus interface, will be emitted.
143 :Parameters:
144 `dbus_interface` : str
145 The D-Bus interface whose signal is emitted
146 `signature` : str
147 The signature of the signal in the usual D-Bus notation
149 _dbus_bindings.validate_interface_name(dbus_interface)
150 def decorator(func):
151 def emit_signal(self, *args, **keywords):
152 func(self, *args, **keywords)
153 message = _dbus_bindings.SignalMessage(self._object_path, dbus_interface, func.__name__)
155 if emit_signal._dbus_signature:
156 message.append(signature=emit_signal._dbus_signature,
157 *args)
158 else:
159 message.append(*args)
161 self._connection.send_message(message)
163 args = inspect.getargspec(func)[0]
164 args.pop(0)
166 if signature:
167 sig = tuple(_dbus_bindings.Signature(signature))
169 if len(sig) > len(args):
170 raise ValueError, 'signal signature is longer than the number of arguments provided'
171 elif len(sig) < len(args):
172 raise ValueError, 'signal signature is shorter than the number of arguments provided'
174 emit_signal.__name__ = func.__name__
175 emit_signal.__doc__ = func.__doc__
176 emit_signal._dbus_is_signal = True
177 emit_signal._dbus_interface = dbus_interface
178 emit_signal._dbus_signature = signature
179 emit_signal._dbus_args = args
180 return emit_signal
182 return decorator