5 import dbus
.introspect_parser
as introspect_parser
6 from dbus
.exceptions
import MissingReplyHandlerException
, MissingErrorHandlerException
, IntrospectionParserException
, DBusException
8 __docformat__
= 'restructuredtext'
11 _logger
= logging
.getLogger('dbus.proxies')
14 class _ReplyHandler(object):
15 __slots__
= ('_on_error', '_on_reply')
16 def __init__(self
, on_reply
, on_error
):
17 self
._on
_error
= on_error
18 self
._on
_reply
= on_reply
20 def __call__(self
, message
):
21 if isinstance(message
, _dbus_bindings
.MethodReturnMessage
):
22 self
._on
_reply
(*message
.get_args_list())
23 elif isinstance(message
, _dbus_bindings
.ErrorMessage
):
24 args
= message
.get_args_list()
26 self
._on
_error
(DBusException(args
[0]))
28 self
._on
_error
(DBusException())
30 self
._on
_error
(DBusException('Unexpected reply message type: %s'
37 This is returned instead of ProxyMethod when we are defering DBus calls
38 while waiting for introspection data to be returned
40 def __init__(self
, proxy_method
):
41 self
._proxy
_method
= proxy_method
42 self
._method
_name
= proxy_method
._method
_name
44 def __call__(self
, *args
, **keywords
):
46 if keywords
.has_key('reply_handler'):
47 reply_handler
= keywords
['reply_handler']
49 #block for now even on async
50 # FIXME: put ret in async queue in future if we have a reply handler
52 self
._proxy
_method
._proxy
._pending
_introspect
._block
()
53 ret
= self
._proxy
_method
(*args
, **keywords
)
60 Typically a member of a ProxyObject. Calls to the
61 method produce messages that travel over the Bus and are routed
62 to a specific named Service.
64 def __init__(self
, proxy
, connection
, named_service
, object_path
, method_name
, iface
):
66 self
._connection
= connection
67 self
._named
_service
= named_service
68 self
._object
_path
= object_path
69 self
._method
_name
= method_name
70 self
._dbus
_interface
= iface
72 def __call__(self
, *args
, **keywords
):
74 if keywords
.has_key('timeout'):
75 timeout
= keywords
['timeout']
78 if keywords
.has_key('reply_handler'):
79 reply_handler
= keywords
['reply_handler']
82 if keywords
.has_key('error_handler'):
83 error_handler
= keywords
['error_handler']
86 if keywords
.has_key('ignore_reply'):
87 ignore_reply
= keywords
['ignore_reply']
90 if not(reply_handler
and error_handler
):
92 raise MissingErrorHandlerException()
94 raise MissingReplyHandlerException()
96 dbus_interface
= self
._dbus
_interface
97 if keywords
.has_key('dbus_interface'):
98 dbus_interface
= keywords
['dbus_interface']
102 tmp_iface
= dbus_interface
+ '.'
104 key
= tmp_iface
+ self
._method
_name
106 introspect_sig
= None
107 if self
._proxy
._introspect
_method
_map
.has_key (key
):
108 introspect_sig
= self
._proxy
._introspect
_method
_map
[key
]
110 message
= _dbus_bindings
.MethodCallMessage(destination
=None,
111 path
=self
._object
_path
,
112 interface
=dbus_interface
,
113 method
=self
._method
_name
)
114 message
.set_destination(self
._named
_service
)
116 # Add the arguments to the function
118 message
.append(signature
=introspect_sig
, *args
)
120 _logger
.error('Unable to set arguments %r according to '
121 'introspected signature %r: %s: %s',
122 args
, introspect_sig
, e
.__class
__, e
)
125 # FIXME: using private API on Connection while I decide whether to
126 # make it public or what
128 result
= self
._connection
._send
(message
)
131 result
= self
._connection
._send
_with
_reply
(message
, _ReplyHandler(reply_handler
, error_handler
), timeout
/1000.0)
134 reply_message
= self
._connection
._send
_with
_reply
_and
_block
(message
, timeout
)
135 args_list
= reply_message
.get_args_list()
136 if len(args_list
) == 0:
138 elif len(args_list
) == 1:
141 return tuple(args_list
)
145 """A proxy to the remote Object.
147 A ProxyObject is provided by the Bus. ProxyObjects
148 have member functions, and can be called like normal Python objects.
150 ProxyMethodClass
= ProxyMethod
151 DeferedMethodClass
= DeferedMethod
153 INTROSPECT_STATE_DONT_INTROSPECT
= 0
154 INTROSPECT_STATE_INTROSPECT_IN_PROGRESS
= 1
155 INTROSPECT_STATE_INTROSPECT_DONE
= 2
157 def __init__(self
, bus
, named_service
, object_path
, introspect
=True):
158 """Initialize the proxy object.
162 The bus on which to find this object
163 `named_service` : str
164 A bus name for the endpoint owning the object (need not
165 actually be a service name)
167 The object path at which the endpoint exports the object
169 If true (default), attempt to introspect the remote
170 object to find out supported methods and their signatures
173 self
._named
_service
= named_service
174 self
._object
_path
= object_path
176 #PendingCall object for Introspect call
177 self
._pending
_introspect
= None
178 #queue of async calls waiting on the Introspect to return
179 self
._pending
_introspect
_queue
= []
180 #dictionary mapping method names to their input signatures
181 self
._introspect
_method
_map
= {}
184 self
._introspect
_state
= self
.INTROSPECT_STATE_DONT_INTROSPECT
186 self
._introspect
_state
= self
.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS
188 self
._pending
_introspect
= self
._Introspect
()
191 def connect_to_signal(self
, signal_name
, handler_function
, dbus_interface
=None, **keywords
):
192 """Arrange for the given function to be called when the given signal
197 The name of the signal
198 `handler_function` : callable
199 A function to be called (FIXME arguments?) when the signal
200 is emitted by the remote object.
201 `dbus_interface` : str
202 Optional interface with which to qualify the signal name.
203 The default is to use the interface this Interface represents.
204 `sender_keyword` : str
205 If not None (the default), the handler function will receive
206 the unique name of the sending endpoint as a keyword
207 argument with this name
209 If not None (the default), the handler function will receive
210 the object-path of the sending object as a keyword argument
213 If there are additional keyword parameters of the form
214 ``arg``\ *n*, match only signals where the *n*\ th argument
215 is the value given for that keyword parameter
217 self
._bus
.add_signal_receiver(handler_function
,
218 signal_name
=signal_name
,
219 dbus_interface
=dbus_interface
,
220 named_service
=self
._named
_service
,
221 path
=self
._object
_path
,
224 def _Introspect(self
):
225 message
= _dbus_bindings
.MethodCallMessage(None, self
._object
_path
, 'org.freedesktop.DBus.Introspectable', 'Introspect')
226 message
.set_destination(self
._named
_service
)
228 result
= self
._bus
.get_connection()._send
_with
_reply
(message
, _ReplyHandler(self
._introspect
_reply
_handler
, self
._introspect
_error
_handler
), -1)
231 def _introspect_execute_queue(self
):
232 for call
in self
._pending
_introspect
_queue
:
233 (member
, iface
, args
, keywords
) = call
235 introspect_sig
= None
239 tmp_iface
= iface
+ '.'
241 key
= tmp_iface
+ '.' + member
242 if self
._introspect
_method
_map
.has_key (key
):
243 introspect_sig
= self
._introspect
_method
_map
[key
]
246 call_object
= self
.ProxyMethodClass(self
._bus
.get_connection(),
253 call_object(args
, keywords
)
255 def _introspect_reply_handler(self
, data
):
257 self
._introspect
_method
_map
= introspect_parser
.process_introspection_data(data
)
258 except IntrospectionParserException
, e
:
259 self
._introspect
_error
_handler
(e
)
262 self
._introspect
_state
= self
.INTROSPECT_STATE_INTROSPECT_DONE
263 #self._introspect_execute_queue()
265 def _introspect_error_handler(self
, error
):
266 self
._introspect
_state
= self
.INTROSPECT_STATE_DONT_INTROSPECT
267 self
._introspect
_execute
_queue
()
268 sys
.stderr
.write("Introspect error: " + str(error
) + "\n")
270 def __getattr__(self
, member
, dbus_interface
=None):
271 if member
== '__call__':
272 return object.__call
__
273 elif member
.startswith('__') and member
.endswith('__'):
274 raise AttributeError(member
)
276 ret
= self
.ProxyMethodClass(self
, self
._bus
.get_connection(),
278 self
._object
_path
, member
,
281 if self
._introspect
_state
== self
.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS
:
282 ret
= self
.DeferedMethodClass(ret
)
287 return '<ProxyObject wrapping %s %s %s at %#x>'%(
288 self
._bus
, self
._named
_service
, self
._object
_path
, id(self
))