_dbus_bindings/module.c: PEP7-style whitespace
[dbus-python-phuang.git] / dbus / decorators.py
blob5486bb78a3069ef63cc5ee3c7e22c2ead34a56ac
1 """Service-side D-Bus decorators."""
3 __all__ = ('explicitly_pass_message', 'method', 'signal')
4 __docformat__ = 'restructuredtext'
6 import _util
7 import inspect
8 import _dbus_bindings
10 def method(dbus_interface, in_signature=None, out_signature=None, async_callbacks=None, sender_keyword=None):
11 """Factory for decorators used to mark methods of a `dbus.service.Object`
12 to be exported on the D-Bus.
14 The decorated method will be exported over D-Bus as the method of the
15 same name on the given D-Bus interface.
17 :Parameters:
18 `dbus_interface` : str
19 Name of a D-Bus interface
20 `in_signature` : str or None
21 If not None, the signature of the method parameters in the usual
22 D-Bus notation
23 `out_signature` : str or None
24 If not None, the signature of the return value in the usual
25 D-Bus notation
26 `async_callbacks` : tuple containing (str,str), or None
27 If None (default) the decorated method is expected to return
28 values matching the `out_signature` as usual, or raise
29 an exception on error. If not None, the following applies:
31 `async_callbacks` contains the names of two keyword arguments to
32 the decorated function, which will be used to provide a success
33 callback and an error callback (in that order).
35 When the decorated method is called via the D-Bus, its normal
36 return value will be ignored; instead, a pair of callbacks are
37 passed as keyword arguments, and the decorated method is
38 expected to arrange for one of them to be called.
40 On success the success callback must be called, passing the
41 results of this method as positional parameters in the format
42 given by the `out_signature`.
44 On error the decorated method may either raise an exception
45 before it returns, or arrange for the error callback to be
46 called with an Exception instance as parameter.
48 `sender_keyword` : str or None
49 If not None, contains the name of a keyword argument to the
50 decorated function. When the method is called, the sender's
51 unique name will be passed as this keyword argument.
52 """
53 _util._validate_interface_or_name(dbus_interface)
55 def decorator(func):
56 args = inspect.getargspec(func)[0]
57 args.pop(0)
59 if async_callbacks:
60 if type(async_callbacks) != tuple:
61 raise TypeError('async_callbacks must be a tuple of (keyword for return callback, keyword for error callback)')
62 if len(async_callbacks) != 2:
63 raise ValueError('async_callbacks must be a tuple of (keyword for return callback, keyword for error callback)')
64 args.remove(async_callbacks[0])
65 args.remove(async_callbacks[1])
67 if sender_keyword:
68 args.remove(sender_keyword)
70 if in_signature:
71 in_sig = tuple(_dbus_bindings.Signature(in_signature))
73 if len(in_sig) > len(args):
74 raise ValueError, 'input signature is longer than the number of arguments taken'
75 elif len(in_sig) < len(args):
76 raise ValueError, 'input signature is shorter than the number of arguments taken'
78 func._dbus_is_method = True
79 func._dbus_async_callbacks = async_callbacks
80 func._dbus_interface = dbus_interface
81 func._dbus_in_signature = in_signature
82 func._dbus_out_signature = out_signature
83 func._dbus_sender_keyword = sender_keyword
84 func._dbus_args = args
85 return func
87 return decorator
89 def signal(dbus_interface, signature=None):
90 """Factory for decorators used to mark methods of a `dbus.service.Object`
91 to emit signals on the D-Bus.
93 Whenever the decorated method is called in Python, after the method
94 body is executed, a signal with the same name as the decorated method,
95 from the given D-Bus interface, will be emitted.
97 :Parameters:
98 `dbus_interface` : str
99 The D-Bus interface whose signal is emitted
100 `signature` : str
101 The signature of the signal in the usual D-Bus notation
103 _util._validate_interface_or_name(dbus_interface)
104 def decorator(func):
105 def emit_signal(self, *args, **keywords):
106 func(self, *args, **keywords)
107 message = _dbus_bindings.SignalMessage(self._object_path, dbus_interface, func.__name__)
109 if emit_signal._dbus_signature:
110 message.append(signature=emit_signal._dbus_signature,
111 *args)
112 else:
113 message.append(*args)
115 self._connection._send(message)
117 args = inspect.getargspec(func)[0]
118 args.pop(0)
120 if signature:
121 sig = tuple(_dbus_bindings.Signature(signature))
123 if len(sig) > len(args):
124 raise ValueError, 'signal signature is longer than the number of arguments provided'
125 elif len(sig) < len(args):
126 raise ValueError, 'signal signature is shorter than the number of arguments provided'
128 emit_signal.__name__ = func.__name__
129 emit_signal.__doc__ = func.__doc__
130 emit_signal._dbus_is_signal = True
131 emit_signal._dbus_interface = dbus_interface
132 emit_signal._dbus_signature = signature
133 emit_signal._dbus_args = args
134 return emit_signal
136 return decorator
138 def explicitly_pass_message(func):
139 """Decorator which marks the given function such that, if it is called
140 as a D-Bus signal recipient, then the Signal message will be passed
141 to it as a keyword parameter named ``dbus_message``.
143 Deprecated? Should Messages really be exposed to client code?
145 FIXME: this alters the namespace of the decorated function without
146 using the ``__magic__`` naming convention.
148 func._dbus_pass_message = True
149 return func