Accept keyword argument introspect=False to Bus.get_object(),
[dbus-python-phuang.git] / dbus / _dbus.py
blob714f7787307630197eb61f686daacd5b604ad78c
1 """Implementation for dbus.Bus. Not to be imported directly."""
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 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 from __future__ import generators
28 __all__ = ('Bus', 'SystemBus', 'SessionBus', 'StarterBus', 'Interface')
29 __docformat__ = 'reStructuredText'
31 import _dbus_bindings
32 UTF8String = _dbus_bindings.UTF8String
33 DBusException = _dbus_bindings.DBusException
34 BusImplementation = _dbus_bindings.BusImplementation
36 import logging
37 import weakref
39 from dbus.proxies import ProxyObject
41 try:
42 import thread
43 except ImportError:
44 import dummy_thread as thread
46 logger = logging.getLogger('dbus._dbus')
47 BUS_DAEMON_NAME = 'org.freedesktop.DBus'
48 BUS_DAEMON_PATH = '/org/freedesktop/DBus'
49 BUS_DAEMON_IFACE = BUS_DAEMON_NAME
51 _NAME_OWNER_CHANGE_MATCH = ("type='signal',sender='%s',"
52 "interface='%s',member='NameOwnerChanged',"
53 "path='%s',arg0='%%s'"
54 % (BUS_DAEMON_NAME, BUS_DAEMON_IFACE,
55 BUS_DAEMON_PATH))
56 """(_NAME_OWNER_CHANGE_MATCH % sender) matches relevant NameOwnerChange
57 messages"""
60 class SignalMatch(object):
61 __slots__ = ('sender_unique', '_member', '_interface', '_sender',
62 '_path', '_handler', '_args_match', '_rule',
63 '_utf8_strings', '_byte_arrays', '_conn_weakref',
64 '_destination_keyword', '_interface_keyword',
65 '_message_keyword', '_member_keyword',
66 '_sender_keyword', '_path_keyword', '_int_args_match')
68 def __init__(self, conn, sender, object_path, dbus_interface,
69 member, handler, utf8_strings=False, byte_arrays=False,
70 sender_keyword=None, path_keyword=None,
71 interface_keyword=None, member_keyword=None,
72 message_keyword=None, destination_keyword=None,
73 **kwargs):
74 self._conn_weakref = weakref.ref(conn)
75 self._sender = sender
76 self._interface = dbus_interface
77 self._member = member
78 self._path = object_path
79 self._handler = handler
80 if (sender is not None and sender[:1] != ':'
81 and sender != BUS_DAEMON_NAME):
82 self.sender_unique = conn.get_object(BUS_DAEMON_NAME, BUS_DAEMON_PATH).GetNameOwner(sender, dbus_interface=BUS_DAEMON_IFACE)
83 else:
84 self.sender_unique = sender
85 self._utf8_strings = utf8_strings
86 self._byte_arrays = byte_arrays
87 self._sender_keyword = sender_keyword
88 self._path_keyword = path_keyword
89 self._member_keyword = member_keyword
90 self._interface_keyword = interface_keyword
91 self._message_keyword = message_keyword
92 self._destination_keyword = destination_keyword
94 self._args_match = kwargs
95 if not kwargs:
96 self._int_args_match = None
97 else:
98 self._int_args_match = {}
99 for kwarg in kwargs:
100 if not kwarg.startswith('arg'):
101 raise TypeError('SignalMatch: unknown keyword argument %s'
102 % kwarg)
103 try:
104 index = int(kwarg[3:])
105 except ValueError:
106 raise TypeError('SignalMatch: unknown keyword argument %s'
107 % kwarg)
108 if index < 0 or index > 63:
109 raise TypeError('SignalMatch: arg match index must be in '
110 'range(64), not %d' % index)
111 self._int_args_match[index] = kwargs[kwarg]
113 # we're always going to have to calculate the match rule for
114 # the Bus's benefit, so this constructor might as well do the work
115 rule = ["type='signal'"]
116 if self._sender is not None:
117 rule.append("sender='%s'" % self._sender)
118 if self._path is not None:
119 rule.append("path='%s'" % self._path)
120 if self._interface is not None:
121 rule.append("interface='%s'" % self._interface)
122 if self._member is not None:
123 rule.append("member='%s'" % self._member)
124 for kwarg, value in kwargs.iteritems():
125 rule.append("%s='%s'" % (kwarg, value))
127 self._rule = ','.join(rule)
129 def __str__(self):
130 return self._rule
132 def __repr__(self):
133 return ('<%s at %x "%s" on conn %r>'
134 % (self.__class__, id(self), self._rule, self._conn_weakref()))
136 def matches_removal_spec(self, sender, object_path,
137 dbus_interface, member, handler, **kwargs):
138 if handler not in (None, self._handler):
139 #logger.debug('No match: handler %r is not %r', handler, self._handler)
140 return False
141 if sender != self._sender:
142 #logger.debug('No match: sender %r is not %r', sender, self._sender)
143 return False
144 if object_path != self._path:
145 #logger.debug('No match: path %r is not %r', object_path, self._path)
146 return False
147 if dbus_interface != self._interface:
148 #logger.debug('No match: interface %r is not %r', dbus_interface, self._interface)
149 return False
150 if member != self._member:
151 #logger.debug('No match: member %r is not %r', member, self._member)
152 return False
153 if kwargs != self._args_match:
154 #logger.debug('No match: args %r are not %r', kwargs, self._args_match)
155 return False
156 return True
158 def maybe_handle_message(self, message):
159 #logger.debug('%r: Considering whether I match %r %r', self, message,
160 #message.get_args_list())
161 args = None
163 # these haven't been checked yet by the match tree
164 if self.sender_unique not in (None, message.get_sender()):
165 #logger.debug('%r: not the desired sender, it was %r and I want '
166 #'%r', self, message.get_sender(), self.sender_unique)
167 return False
168 if self._int_args_match is not None:
169 # extracting args with utf8_strings and byte_arrays is less work
170 args = message.get_args_list(utf8_strings=True, byte_arrays=True)
171 for index, value in self._int_args_match.iteritems():
172 if (index >= len(args)
173 or not isinstance(args[index], UTF8String)
174 or args[index] != value):
175 #logger.debug('%r: not the desired args', self)
176 return False
178 # these have likely already been checked by the match tree
179 if self._member not in (None, message.get_member()):
180 #logger.debug('%r: not the desired member', self)
181 return False
182 if self._interface not in (None, message.get_interface()):
183 #logger.debug('%r: not the desired interface', self)
184 return False
185 if self._path not in (None, message.get_path()):
186 #logger.debug('%r: not the desired path', self)
187 return False
189 #logger.debug('%r: yes, I want to handle that signal', self)
190 # minor optimization: if we already extracted the args with the right
191 # calling convention to do the args match, don't bother doing so again
192 if args is None or not self._utf8_strings or not self._byte_arrays:
193 args = message.get_args_list(utf8_strings=self._utf8_strings,
194 byte_arrays=self._byte_arrays)
195 #logger.debug('%r: extracted signal arguments', self)
196 kwargs = {}
197 if self._sender_keyword is not None:
198 kwargs[self._sender_keyword] = message.get_sender()
199 if self._destination_keyword is not None:
200 kwargs[self._destination_keyword] = message.get_destination()
201 if self._path_keyword is not None:
202 kwargs[self._path_keyword] = message.get_path()
203 if self._member_keyword is not None:
204 kwargs[self._member_keyword] = message.get_member()
205 if self._interface_keyword is not None:
206 kwargs[self._interface_keyword] = message.get_interface()
207 if self._message_keyword is not None:
208 kwargs[self._message_keyword] = message
209 #logger.debug('%r: calling handler with %r and %r', self, args, kwargs)
210 self._handler(*args, **kwargs)
211 #logger.debug('%r: signal handled', self)
212 return True
214 def remove(self):
215 #logger.debug('%r: removing', self)
216 conn = self._conn_weakref()
217 # do nothing if the connection has already vanished
218 if conn is not None:
219 #logger.debug('%r: removing from connection %r', self, conn)
220 conn.remove_signal_receiver(self, self._member,
221 self._interface, self._sender,
222 self._path,
223 **self._args_match)
226 class Bus(BusImplementation):
227 """A connection to a DBus daemon.
229 One of three possible standard buses, the SESSION, SYSTEM,
230 or STARTER bus
233 TYPE_SESSION = _dbus_bindings.BUS_SESSION
234 """Represents a session bus (same as the global dbus.BUS_SESSION)"""
236 TYPE_SYSTEM = _dbus_bindings.BUS_SYSTEM
237 """Represents the system bus (same as the global dbus.BUS_SYSTEM)"""
239 TYPE_STARTER = _dbus_bindings.BUS_STARTER
240 """Represents the bus that started this service by activation (same as
241 the global dbus.BUS_STARTER)"""
243 ProxyObjectClass = ProxyObject
245 START_REPLY_SUCCESS = _dbus_bindings.DBUS_START_REPLY_SUCCESS
246 START_REPLY_ALREADY_RUNNING = _dbus_bindings.DBUS_START_REPLY_ALREADY_RUNNING
248 _shared_instances = {}
250 def __new__(cls, bus_type=TYPE_SESSION, private=False, mainloop=None):
251 """Constructor, returning an existing instance where appropriate.
253 The returned instance is actually always an instance of `SessionBus`,
254 `SystemBus` or `StarterBus`.
256 :Parameters:
257 `bus_type` : cls.TYPE_SESSION, cls.TYPE_SYSTEM or cls.TYPE_STARTER
258 Connect to the appropriate bus
259 `private` : bool
260 If true, never return an existing shared instance, but instead
261 return a private connection
262 `mainloop` : dbus.mainloop.NativeMainLoop
263 The main loop to use. The default is to use the default
264 main loop if one has been set up, or raise an exception
265 if none has been.
266 :ToDo:
267 - There is currently no way to connect this class to a custom
268 address.
269 - Some of this functionality should be available on
270 peer-to-peer D-Bus connections too.
271 :Changed: in dbus-python 0.80:
272 converted from a wrapper around a Connection to a Connection
273 subclass.
275 if (not private and bus_type in cls._shared_instances):
276 return cls._shared_instances[bus_type]
278 # this is a bit odd, but we create instances of the subtypes
279 # so we can return the shared instances if someone tries to
280 # construct one of them (otherwise we'd eg try and return an
281 # instance of Bus from __new__ in SessionBus). why are there
282 # three ways to construct this class? we just don't know.
283 if bus_type == cls.TYPE_SESSION:
284 subclass = SessionBus
285 elif bus_type == cls.TYPE_SYSTEM:
286 subclass = SystemBus
287 elif bus_type == cls.TYPE_STARTER:
288 subclass = StarterBus
289 else:
290 raise ValueError('invalid bus_type %s' % bus_type)
292 bus = _dbus_bindings.BusImplementation.__new__(subclass, bus_type,
293 mainloop=mainloop)
295 bus._bus_type = bus_type
296 # _bus_names is used by dbus.service.BusName!
297 bus._bus_names = weakref.WeakValueDictionary()
299 bus._signal_recipients_by_object_path = {}
300 """Map from object path to dict mapping dbus_interface to dict
301 mapping member to list of SignalMatch objects."""
303 bus._signal_sender_matches = {}
304 """Map from sender well-known name to list of match rules for all
305 signal handlers that match on sender well-known name."""
307 bus._signals_lock = thread.allocate_lock()
308 """Lock used to protect signal data structures if doing two
309 removals at the same time (everything else is atomic, thanks to
310 the GIL)"""
312 bus.add_message_filter(bus.__class__._signal_func)
314 if not private:
315 cls._shared_instances[bus_type] = bus
317 return bus
319 def close(self):
320 t = self._bus_type
321 if self.__class__._shared_instances[t] is self:
322 del self.__class__._shared_instances[t]
323 BusImplementation.close(self)
325 def get_connection(self):
326 """(Deprecated - in new code, just use self)
328 Return self, for backwards compatibility with earlier dbus-python
329 versions where Bus was not a subclass of Connection.
331 return self
332 _connection = property(get_connection, None, None,
333 """self._connection == self, for backwards
334 compatibility with earlier dbus-python versions
335 where Bus was not a subclass of Connection.""")
337 def get_session(private=False):
338 """Static method that returns a connection to the session bus.
340 :Parameters:
341 `private` : bool
342 If true, do not return a shared connection.
344 return SessionBus(private=private)
346 get_session = staticmethod(get_session)
348 def get_system(private=False):
349 """Static method that returns a connection to the system bus.
351 :Parameters:
352 `private` : bool
353 If true, do not return a shared connection.
355 return SystemBus(private=private)
357 get_system = staticmethod(get_system)
360 def get_starter(private=False):
361 """Static method that returns a connection to the starter bus.
363 :Parameters:
364 `private` : bool
365 If true, do not return a shared connection.
367 return StarterBus(private=private)
369 get_starter = staticmethod(get_starter)
371 def get_object(self, named_service, object_path, introspect=True):
372 """Return a local proxy for the given remote object.
374 Method calls on the proxy are translated into method calls on the
375 remote object.
377 If the given object path is a well-known name (as opposed to a
378 unique name) the proxy will use the well-known name for
379 communication, meaning that if the owner of the well-known
380 name changes, the proxy will point to the new owner.
382 If state needs to be maintained between
384 :Parameters:
385 `named_service` : str
386 A bus name (either the unique name or a well-known name)
387 of the application owning the object
388 `object_path` : str
389 The object path of the desired object
390 `introspect` : bool
391 If true (default), attempt to introspect the remote
392 object to find out supported methods and their signatures
393 :Returns: a `dbus.proxies.ProxyObject`
395 return self.ProxyObjectClass(self, named_service, object_path, introspect=introspect)
397 def get_object_by_unique_name(self, named_service, object_path, introspect=True):
398 """Return a local proxy for the given remote object,
399 first resolving the given bus name to the unique name of
400 the current owner of that name.
402 Method calls on the proxy are translated into method calls on the
403 remote object.
405 If the given object path is a well-known name (as opposed to a
406 unique name) query the bus for the unique name of the application
407 currently owning that well-known name, and use that for
408 communication.
410 :Parameters:
411 `named_service` : str
412 A bus name (either the unique name or a well-known name)
413 of the application owning the object; if a well-known name,
414 will be converted to the owning unique name immediately
415 `object_path` : str
416 The object path of the desired object
417 `introspect` : bool
418 If true (default), attempt to introspect the remote
419 object to find out supported methods and their signatures
420 :Returns: a `dbus.proxies.ProxyObject`
421 :Raises `DBusException`: if resolving the well-known name to a
422 unique name fails
425 if named_service[:1] == ':' or named_service == BUS_DAEMON_NAME:
426 unique = named_service
427 else:
428 bus_object = self.ProxyObjectClass(self, BUS_DAEMON_NAME, BUS_DAEMON_PATH)
429 unique = bus_object.GetNameOwner(named_service,
430 dbus_interface=BUS_DAEMON_IFACE)
431 if not unique:
432 raise DBusException('Well-known name %r is not '
433 'present on %r', named_service, self)
435 return self.ProxyObjectClass(self, unique, object_path, introspect=introspect)
437 def add_signal_receiver(self, handler_function,
438 signal_name=None,
439 dbus_interface=None,
440 named_service=None,
441 path=None,
442 **keywords):
443 """Arrange for the given function to be called when a signal matching
444 the parameters is received.
446 :Parameters:
447 `handler_function` : callable
448 The function to be called. Its positional arguments will
449 be the arguments of the signal. By default it will receive
450 no keyword arguments, but see the description of
451 the optional keyword arguments below.
452 `signal_name` : str
453 The signal name; None (the default) matches all names
454 `dbus_interface` : str
455 The D-Bus interface name with which to qualify the signal;
456 None (the default) matches all interface names
457 `named_service` : str
458 A bus name for the sender, which will be resolved to a
459 unique name if it is not already; None (the default) matches
460 any sender
461 `path` : str
462 The object path of the object which must have emitted the
463 signal; None (the default) matches any object path
464 :Keywords:
465 `utf8_strings` : bool
466 If True, the handler function will receive any string
467 arguments as dbus.UTF8String objects (a subclass of str
468 guaranteed to be UTF-8). If False (default) it will receive
469 any string arguments as dbus.String objects (a subclass of
470 unicode).
471 `byte_arrays` : bool
472 If True, the handler function will receive any byte-array
473 arguments as dbus.ByteArray objects (a subclass of str).
474 If False (default) it will receive any byte-array
475 arguments as a dbus.Array of dbus.Byte (subclasses of:
476 a list of ints).
477 `sender_keyword` : str
478 If not None (the default), the handler function will receive
479 the unique name of the sending endpoint as a keyword
480 argument with this name.
481 `destination_keyword` : str
482 If not None (the default), the handler function will receive
483 the bus name of the destination (or None if the signal is a
484 broadcast, as is usual) as a keyword argument with this name.
485 `interface_keyword` : str
486 If not None (the default), the handler function will receive
487 the signal interface as a keyword argument with this name.
488 `member_keyword` : str
489 If not None (the default), the handler function will receive
490 the signal name as a keyword argument with this name.
491 `path_keyword` : str
492 If not None (the default), the handler function will receive
493 the object-path of the sending object as a keyword argument
494 with this name.
495 `message_keyword` : str
496 If not None (the default), the handler function will receive
497 the `dbus.lowlevel.SignalMessage` as a keyword argument with
498 this name.
499 `arg...` : unicode or UTF-8 str
500 If there are additional keyword parameters of the form
501 ``arg``\ *n*, match only signals where the *n*\ th argument
502 is the value given for that keyword parameter. As of this
503 time only string arguments can be matched (in particular,
504 object paths and signatures can't).
507 match = SignalMatch(self, named_service, path, dbus_interface,
508 signal_name, handler_function, **keywords)
509 by_interface = self._signal_recipients_by_object_path.setdefault(path,
511 by_member = by_interface.setdefault(dbus_interface, {})
512 matches = by_member.setdefault(signal_name, [])
513 # The bus daemon is special - its unique-name is org.freedesktop.DBus
514 # rather than starting with :
515 if (named_service is not None and named_service[:1] != ':'
516 and named_service != BUS_DAEMON_NAME):
517 notification = self._signal_sender_matches.setdefault(named_service,
519 if not notification:
520 self.add_match_string(_NAME_OWNER_CHANGE_MATCH % named_service)
521 notification.append(match)
522 # make sure nobody is currently manipulating the list
523 self._signals_lock.acquire()
524 try:
525 matches.append(match)
526 finally:
527 self._signals_lock.release()
528 self.add_match_string(str(match))
529 return match
531 def _iter_easy_matches(self, path, dbus_interface, member):
532 if path is not None:
533 path_keys = (None, path)
534 else:
535 path_keys = (None,)
536 if dbus_interface is not None:
537 interface_keys = (None, dbus_interface)
538 else:
539 interface_keys = (None,)
540 if member is not None:
541 member_keys = (None, member)
542 else:
543 member_keys = (None,)
545 for path in path_keys:
546 by_interface = self._signal_recipients_by_object_path.get(path,
547 None)
548 if by_interface is None:
549 continue
550 for dbus_interface in interface_keys:
551 by_member = by_interface.get(dbus_interface, None)
552 if by_member is None:
553 continue
554 for member in member_keys:
555 matches = by_member.get(member, None)
556 if matches is None:
557 continue
558 for m in matches:
559 yield m
561 def _remove_name_owner_changed_for_match(self, named_service, match):
562 notification = self._signal_sender_matches.get(named_service, False)
563 if notification:
564 try:
565 notification.remove(match)
566 except LookupError:
567 pass
568 if not notification:
569 self.remove_match_string(_NAME_OWNER_CHANGE_MATCH
570 % named_service)
572 def remove_signal_receiver(self, handler_or_match,
573 signal_name=None,
574 dbus_interface=None,
575 named_service=None,
576 path=None,
577 **keywords):
578 #logger.debug('%r: removing signal receiver %r: member=%s, '
579 #'iface=%s, sender=%s, path=%s, kwargs=%r',
580 #self, handler_or_match, signal_name,
581 #dbus_interface, named_service, path, keywords)
582 #logger.debug('%r', self._signal_recipients_by_object_path)
583 by_interface = self._signal_recipients_by_object_path.get(path, None)
584 if by_interface is None:
585 return
586 by_member = by_interface.get(dbus_interface, None)
587 if by_member is None:
588 return
589 matches = by_member.get(signal_name, None)
590 if matches is None:
591 return
592 self._signals_lock.acquire()
593 #logger.debug(matches)
594 try:
595 new = []
596 for match in matches:
597 if (handler_or_match is match
598 or match.matches_removal_spec(named_service,
599 path,
600 dbus_interface,
601 signal_name,
602 handler_or_match,
603 **keywords)):
604 #logger.debug('Removing match string: %s', match)
605 self.remove_match_string(str(match))
606 self._remove_name_owner_changed_for_match(named_service,
607 match)
608 else:
609 new.append(match)
610 by_member[signal_name] = new
611 finally:
612 self._signals_lock.release()
614 def _signal_func(self, message):
615 """D-Bus filter function. Handle signals by dispatching to Python
616 callbacks kept in the match-rule tree.
619 #logger.debug('Incoming message %r with args %r', message,
620 #message.get_args_list())
622 if (message.get_type() != _dbus_bindings.MESSAGE_TYPE_SIGNAL):
623 return _dbus_bindings.HANDLER_RESULT_NOT_YET_HANDLED
625 # If it's NameOwnerChanged, we'll need to update our
626 # sender well-known name -> sender unique name mappings
627 if (message.is_signal(BUS_DAEMON_NAME, 'NameOwnerChanged')
628 and message.has_path(BUS_DAEMON_PATH)):
629 name, unused, new = message.get_args_list()
630 for match in self._signal_sender_matches.get(name, (None,))[1:]:
631 match.sender_unique = new
633 # See if anyone else wants to know
634 dbus_interface = message.get_interface()
635 path = message.get_path()
636 signal_name = message.get_member()
638 ret = _dbus_bindings.HANDLER_RESULT_NOT_YET_HANDLED
639 for match in self._iter_easy_matches(path, dbus_interface,
640 signal_name):
641 if match.maybe_handle_message(message):
642 ret = _dbus_bindings.HANDLER_RESULT_HANDLED
643 return ret
645 def __repr__(self):
646 if self._bus_type == self.TYPE_SESSION:
647 name = 'SESSION'
648 elif self._bus_type == self.TYPE_SYSTEM:
649 name = 'SYSTEM'
650 elif self._bus_type == self.TYPE_STARTER:
651 name = 'STARTER'
652 else:
653 raise AssertionError('Unable to represent unknown bus type.')
655 return '<dbus.Bus on %s at %#x>' % (name, id(self))
656 __str__ = __repr__
659 # FIXME: Drop the subclasses here? I can't think why we'd ever want
660 # polymorphism
661 class SystemBus(Bus):
662 """The system-wide message bus."""
663 def __new__(cls, private=False, mainloop=None):
664 """Return a connection to the system bus.
666 :Parameters:
667 `private` : bool
668 If true, never return an existing shared instance, but instead
669 return a private connection.
670 `mainloop` : dbus.mainloop.NativeMainLoop
671 The main loop to use. The default is to use the default
672 main loop if one has been set up, or raise an exception
673 if none has been.
675 return Bus.__new__(cls, Bus.TYPE_SYSTEM, mainloop=mainloop,
676 private=private)
678 class SessionBus(Bus):
679 """The session (current login) message bus."""
680 def __new__(cls, private=False, mainloop=None):
681 """Return a connection to the session bus.
683 :Parameters:
684 `private` : bool
685 If true, never return an existing shared instance, but instead
686 return a private connection.
687 `mainloop` : dbus.mainloop.NativeMainLoop
688 The main loop to use. The default is to use the default
689 main loop if one has been set up, or raise an exception
690 if none has been.
692 return Bus.__new__(cls, Bus.TYPE_SESSION, private=private,
693 mainloop=mainloop)
695 class StarterBus(Bus):
696 """The bus that activated this process (only valid if
697 this process was launched by DBus activation).
699 def __new__(cls, private=False, mainloop=None):
700 """Return a connection to the bus that activated this process.
702 :Parameters:
703 `private` : bool
704 If true, never return an existing shared instance, but instead
705 return a private connection.
706 `mainloop` : dbus.mainloop.NativeMainLoop
707 The main loop to use. The default is to use the default
708 main loop if one has been set up, or raise an exception
709 if none has been.
711 return Bus.__new__(cls, Bus.TYPE_STARTER, private=private,
712 mainloop=mainloop)
714 class Interface:
715 """An interface into a remote object.
717 An Interface can be used to wrap ProxyObjects
718 so that calls can be routed to their correct
719 dbus interface
722 def __init__(self, object, dbus_interface):
723 """Construct a proxy for the given interface on the given object.
725 :Parameters:
726 `object` : `dbus.proxies.ProxyObject`
727 The remote object
728 `dbus_interface` : str
729 An interface the `object` implements
731 self._obj = object
732 self._dbus_interface = dbus_interface
734 def connect_to_signal(self, signal_name, handler_function, dbus_interface = None, **keywords):
735 """Arrange for a function to be called when the given signal is
736 emitted.
738 :Parameters:
739 `signal_name` : str
740 The name of the signal
741 `handler_function` : callable
742 A function to be called when the signal is emitted by the
743 remote object. It will receive the signal's arguments
744 as its positional arguments.
745 `dbus_interface` : str
746 Optional interface with which to qualify the signal name.
747 The default is to use the interface this Interface represents.
748 (FIXME: deprecate this? Violates least astonishment)
749 :Keywords:
750 `utf8_strings` : bool
751 If True, the handler function will receive any string
752 arguments as dbus.UTF8String objects (a subclass of str
753 guaranteed to be UTF-8). If False (default) it will receive
754 any string arguments as dbus.String objects (a subclass of
755 unicode).
756 `byte_arrays` : bool
757 If True, the handler function will receive any byte-array
758 arguments as dbus.ByteArray objects (a subclass of str).
759 If False (default) it will receive any byte-array
760 arguments as a dbus.Array of dbus.Byte (subclasses of:
761 a list of ints).
762 `sender_keyword` : str
763 If not None (the default), the handler function will receive
764 the unique name of the sending endpoint as a keyword
765 argument with this name
766 `destination_keyword` : str
767 If not None (the default), the handler function will receive
768 the bus name of the destination (or None if the signal is a
769 broadcast, as is usual) as a keyword argument with this name.
770 `interface_keyword` : str
771 If not None (the default), the handler function will receive
772 the signal interface as a keyword argument with this name.
773 `member_keyword` : str
774 If not None (the default), the handler function will receive
775 the signal name as a keyword argument with this name.
776 `path_keyword` : str
777 If not None (the default), the handler function will receive
778 the object-path of the sending object as a keyword argument
779 with this name
780 `message_keyword` : str
781 If not None (the default), the handler function will receive
782 the `dbus.lowlevel.SignalMessage` as a keyword argument with
783 this name.
784 `arg...` : unicode or UTF-8 str
785 If there are additional keyword parameters of the form
786 ``arg``\ *n*, only call the handler_function for signals
787 where the *n*\ th argument is the value given for that
788 keyword parameter. As of this time only string arguments
789 can be matched.
791 if not dbus_interface:
792 dbus_interface = self._dbus_interface
794 return self._obj.connect_to_signal(signal_name, handler_function, dbus_interface, **keywords)
796 def __getattr__(self, member, **keywords):
797 # FIXME: this syntax is bizarre.
798 if (keywords.has_key('dbus_interface')):
799 _dbus_interface = keywords['dbus_interface']
800 else:
801 _dbus_interface = self._dbus_interface
803 # I have no idea what's going on here. -smcv
804 if member == '__call__':
805 return object.__call__
806 else:
807 ret = self._obj.__getattr__(member, dbus_interface=_dbus_interface)
808 return ret
810 def __repr__(self):
811 return '<Interface %r implementing %r at %#x>'%(
812 self._obj, self._dbus_interface, id(self))
813 __str__ = __repr__
816 _dbus_bindings_warning = DeprecationWarning("""\
817 The dbus_bindings module is deprecated and will go away soon.
819 dbus-python 0.80 provides only a partial emulation of the old
820 dbus_bindings, which was never meant to be public API.
822 Most uses of dbus_bindings are applications catching the exception
823 dbus.dbus_bindings.DBusException. You should use dbus.DBusException
824 instead (this is compatible with all dbus-python versions since 0.40.2).
826 If you need additional public API, please contact the maintainers via
827 <dbus@lists.freedesktop.org>.
828 """)
830 class _DBusBindingsEmulation:
831 """A partial emulation of the dbus_bindings module."""
832 _module = None
833 def __str__(self):
834 return '_DBusBindingsEmulation()'
835 def __repr__(self):
836 return '_DBusBindingsEmulation()'
837 def __getattr__(self, attr):
838 if self._module is None:
839 from warnings import warn as _warn
840 _warn(_dbus_bindings_warning, DeprecationWarning, stacklevel=2)
842 import dbus.dbus_bindings as m
843 self._module = m
844 return getattr(self._module, attr)
846 dbus_bindings = _DBusBindingsEmulation()
847 """Deprecated, don't use."""