Rename dbus_bindings (sometimes a.k.a. dbus.dbus_bindings) to _dbus_bindings.
[dbus-python-phuang.git] / dbus / proxies.py
blobbabbcd5cb3e6587e0dbffad8dfc183d33920e11c
1 import _dbus_bindings
2 import introspect_parser
3 import sys
4 from exceptions import MissingReplyHandlerException, MissingErrorHandlerException, IntrospectionParserException
6 class DeferedMethod:
7 """A DeferedMethod
9 This is returned instead of ProxyMethod when we are defering DBus calls
10 while waiting for introspection data to be returned
11 """
12 def __init__(self, proxy_method):
13 self._proxy_method = proxy_method
14 self._method_name = proxy_method._method_name
16 def __call__(self, *args, **keywords):
17 reply_handler = None
18 if keywords.has_key('reply_handler'):
19 reply_handler = keywords['reply_handler']
21 #block for now even on async
22 # FIXME: put ret in async queue in future if we have a reply handler
24 self._proxy_method._proxy._pending_introspect.block()
25 ret = self._proxy_method (*args, **keywords)
27 return ret
29 class ProxyMethod:
30 """A proxy Method.
32 Typically a member of a ProxyObject. Calls to the
33 method produce messages that travel over the Bus and are routed
34 to a specific named Service.
35 """
36 def __init__(self, proxy, connection, named_service, object_path, method_name, iface):
37 self._proxy = proxy
38 self._connection = connection
39 self._named_service = named_service
40 self._object_path = object_path
41 self._method_name = method_name
42 self._dbus_interface = iface
44 def __call__(self, *args, **keywords):
45 timeout = -1
46 if keywords.has_key('timeout'):
47 timeout = keywords['timeout']
49 reply_handler = None
50 if keywords.has_key('reply_handler'):
51 reply_handler = keywords['reply_handler']
53 error_handler = None
54 if keywords.has_key('error_handler'):
55 error_handler = keywords['error_handler']
57 ignore_reply = False
58 if keywords.has_key('ignore_reply'):
59 ignore_reply = keywords['ignore_reply']
62 if not(reply_handler and error_handler):
63 if reply_handler:
64 raise MissingErrorHandlerException()
65 elif error_handler:
66 raise MissingReplyHandlerException()
68 dbus_interface = self._dbus_interface
69 if keywords.has_key('dbus_interface'):
70 dbus_interface = keywords['dbus_interface']
72 tmp_iface = ''
73 if dbus_interface:
74 tmp_iface = dbus_interface + '.'
76 key = tmp_iface + self._method_name
78 introspect_sig = None
79 if self._proxy._introspect_method_map.has_key (key):
80 introspect_sig = self._proxy._introspect_method_map[key]
82 message = _dbus_bindings.MethodCall(self._object_path, dbus_interface, self._method_name)
83 message.set_destination(self._named_service)
85 # Add the arguments to the function
86 iter = message.get_iter(True)
88 if introspect_sig:
89 for (arg, sig) in zip(args, _dbus_bindings.Signature(introspect_sig)):
90 iter.append_strict(arg, sig)
91 else:
92 for arg in args:
93 iter.append(arg)
95 if ignore_reply:
96 result = self._connection.send(message)
97 args_tuple = (result,)
98 elif reply_handler:
99 result = self._connection.send_with_reply_handlers(message, timeout, reply_handler, error_handler)
100 args_tuple = result
101 else:
102 reply_message = self._connection.send_with_reply_and_block(message, timeout)
103 args_tuple = reply_message.get_args_list()
105 if len(args_tuple) == 0:
106 return
107 elif len(args_tuple) == 1:
108 return args_tuple[0]
109 else:
110 return args_tuple
113 class ProxyObject:
114 """A proxy to the remote Object.
116 A ProxyObject is provided by the Bus. ProxyObjects
117 have member functions, and can be called like normal Python objects.
119 ProxyMethodClass = ProxyMethod
120 DeferedMethodClass = DeferedMethod
122 INTROSPECT_STATE_DONT_INTROSPECT = 0
123 INTROSPECT_STATE_INTROSPECT_IN_PROGRESS = 1
124 INTROSPECT_STATE_INTROSPECT_DONE = 2
126 def __init__(self, bus, named_service, object_path, introspect=True):
127 self._bus = bus
128 self._named_service = named_service
129 self._object_path = object_path
131 #PendingCall object for Introspect call
132 self._pending_introspect = None
133 #queue of async calls waiting on the Introspect to return
134 self._pending_introspect_queue = []
135 #dictionary mapping method names to their input signatures
136 self._introspect_method_map = {}
138 if not introspect:
139 self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
140 else:
141 self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS
143 (result, self._pending_introspect) = self._Introspect()
146 def connect_to_signal(self, signal_name, handler_function, dbus_interface=None, **keywords):
147 self._bus.add_signal_receiver(handler_function,
148 signal_name=signal_name,
149 dbus_interface=dbus_interface,
150 named_service=self._named_service,
151 path=self._object_path,
152 **keywords)
154 def _Introspect(self):
155 message = _dbus_bindings.MethodCall(self._object_path, 'org.freedesktop.DBus.Introspectable', 'Introspect')
156 message.set_destination(self._named_service)
158 result = self._bus.get_connection().send_with_reply_handlers(message, -1,
159 self._introspect_reply_handler,
160 self._introspect_error_handler)
161 return result
163 def _introspect_execute_queue(self):
164 for call in self._pending_introspect_queue:
165 (member, iface, args, keywords) = call
167 introspect_sig = None
169 tmp_iface = ''
170 if iface:
171 tmp_iface = iface + '.'
173 key = tmp_iface + '.' + member
174 if self._introspect_method_map.has_key (key):
175 introspect_sig = self._introspect_method_map[key]
178 call_object = self.ProxyMethodClass(self._bus.get_connection(),
179 self._named_service,
180 self._object_path,
181 iface,
182 member,
183 introspect_sig)
185 call_object(args, keywords)
187 def _introspect_reply_handler(self, data):
188 try:
189 self._introspect_method_map = introspect_parser.process_introspection_data(data)
190 except IntrospectionParserException, e:
191 self._introspect_error_handler(e)
192 return
194 self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_DONE
195 #self._introspect_execute_queue()
197 def _introspect_error_handler(self, error):
198 self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
199 self._introspect_execute_queue()
200 sys.stderr.write("Introspect error: " + str(error) + "\n")
202 def __getattr__(self, member, dbus_interface=None):
203 if member == '__call__':
204 return object.__call__
205 elif member.startswith('__') and member.endswith('__'):
206 raise AttributeError(member)
207 else:
208 ret = self.ProxyMethodClass(self, self._bus.get_connection(),
209 self._named_service,
210 self._object_path, member,
211 dbus_interface)
213 if self._introspect_state == self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS:
214 ret = self.DeferedMethodClass(ret)
216 return ret
218 def __repr__(self):
219 return '<ProxyObject wrapping %s %s %s at %#x>'%(
220 self._bus, self._named_service, self._object_path , id(self))
221 __str__ = __repr__