f41a8de1e14f5d23ea9d2629e6b5bffcf1959dfa
[platform/upstream/dbus.git] / python / proxies.py
1 import dbus_bindings
2 from exceptions import MissingReplyHandlerException, MissingErrorHandlerException
3
4 class DeferedMethod:
5     """A DeferedMethod
6     
7     This is returned instead of ProxyMethod when we are defering DBus calls
8     while waiting for introspection data to be returned
9     
10     This class can be used for debugging purposes
11     """
12     def __call__(self, *args, **keywords):
13         return None
14
15 class ProxyMethod:
16     """A proxy Method.
17
18     Typically a member of a ProxyObject. Calls to the
19     method produce messages that travel over the Bus and are routed
20     to a specific named Service.
21     """
22     def __init__(self, connection, named_service, object_path, dbus_interface, method_name):
23         self._connection   = connection
24         self._named_service = named_service
25         self._object_path  = object_path
26         self._method_name  = method_name
27         self._dbus_interface = dbus_interface
28
29     def __call__(self, *args, **keywords):
30         dbus_interface = self._dbus_interface
31         if keywords.has_key('dbus_interface'):
32             dbus_interface = keywords['dbus_interface']
33
34         timeout = -1
35         if keywords.has_key('timeout'):
36             timeout = keywords['timeout']
37
38         reply_handler = None
39         if keywords.has_key('reply_handler'):
40             reply_handler = keywords['reply_handler']
41
42         error_handler = None
43         if keywords.has_key('error_handler'):
44             error_handler = keywords['error_handler']            
45
46         if not(reply_handler and error_handler):
47             if reply_handler:
48                 raise MissingErrorHandlerException()
49             elif error_handler:
50                 raise MissingReplyHandlerException()
51
52         message = dbus_bindings.MethodCall(self._object_path, dbus_interface, self._method_name)
53         message.set_destination(self._named_service)
54         
55         # Add the arguments to the function
56         iter = message.get_iter(True)
57         for arg in args:
58             iter.append(arg)
59
60         if reply_handler:
61             result = self._connection.send_with_reply_handlers(message, timeout, reply_handler, error_handler)
62             args_tuple = result
63         else:
64             reply_message = self._connection.send_with_reply_and_block(message, timeout)
65             args_tuple = reply_message.get_args_list()
66
67         if len(args_tuple) == 0:
68             return
69         elif len(args_tuple) == 1:
70             return args_tuple[0]
71         else:
72             return args_tuple
73
74
75 class ProxyObject:
76     """A proxy to the remote Object.
77
78     A ProxyObject is provided by the Bus. ProxyObjects
79     have member functions, and can be called like normal Python objects.
80     """
81     ProxyMethodClass = ProxyMethod
82     DeferedMethodClass = DeferedMethod
83
84     INTROSPECT_STATE_DONT_INTROSPECT = 0
85     INTROSPECT_STATE_INTROSPECT_IN_PROGRESS = 1
86     INTROSPECT_STATE_INTROSPECT_DONE = 2
87
88     #TODO: default introspect to False right now because it is not done yet
89     #      make sure to default to True later
90     def __init__(self, bus, named_service, object_path, introspect=False):
91         self._bus           = bus
92         self._named_service = named_service
93         self._object_path   = object_path
94         
95         #PendingCall object for Introspect call
96         self._pending_introspect = None
97         #queue of async calls waiting on the Introspect to return 
98         self._pending_introspect_queue = []
99  
100         if not introspect:
101             self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
102         else:
103             self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS
104             
105             (result, self._pending_introspect) = self._Introspect()
106             
107
108     def connect_to_signal(self, signal_name, handler_function, dbus_interface=None, **keywords):
109         self._bus.add_signal_receiver(handler_function,
110                                       signal_name=signal_name,
111                                       dbus_interface=dbus_interface,
112                                       named_service=self._named_service,
113                                       path=self._object_path,
114                                       **keywords)
115
116     def _Introspect(self):
117         message = dbus_bindings.MethodCall(self._object_path, 'org.freedesktop.DBus.Introspectable', 'Introspect')
118         message.set_destination(self._named_service)
119         
120         result = self._bus.get_connection().send_with_reply_handlers(message, -1, 
121                                                                                            self._introspect_reply_handler, 
122                                                                                            self._introspect_error_handler)
123         return result   
124             
125     def _introspect_reply_handler(self, data):
126         self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_DONE
127         
128         for call in self._pending_introspect_queue:
129             (member, iface, args, keywords) = call
130             call_object = self.ProxyMethodClass(self._bus.get_connection(),
131                                                                        self._named_service,
132                                                                        self._object_path, iface, member)
133                                                                        
134             call_object(args, keywords)
135
136     def _introspect_error_handler(self, error):
137         self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
138
139     def __getattr__(self, member, **keywords):
140         if member == '__call__':
141             return object.__call__
142         elif member.startswith('__') and member.endswith('__'):
143             raise AttributeError(member)
144         else:
145             iface = None
146             if keywords.has_key('dbus_interface'):
147                 iface = keywords['dbus_interface']
148
149             if self._introspect_state == self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS:
150                 reply_handler = None
151                 if keywords.has_key('reply_handler'):
152                     reply_handler = keywords['reply_handler']
153
154                 error_handler = None
155                 if keywords.has_key('error_handler'):
156                     error_handler = keywords['error_handler']
157
158                 if not reply_handler:
159                     self._pending_introspect.block()
160                 else:
161                     call = (memeber, iface, args, keywords)
162                     self._pending_introspect_queue.append(call)
163                     
164                     ret = self.DeferedMethodClass()
165                     return ret
166                    
167             ret = self.ProxyMethodClass(self._bus.get_connection(),
168                                 self._named_service,
169                                 self._object_path, iface, member)
170             return ret
171
172     def __repr__(self):
173         return '<ProxyObject wrapping %s %s %s at %x>'%( 
174             self._bus, self._named_service, self._object_path , id(self))
175     __str__ = __repr__
176