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 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 from __future__
import generators
26 __all__
= ('Bus', 'SystemBus', 'SessionBus', 'StarterBus', 'Interface')
27 __docformat__
= 'reStructuredText'
30 UTF8String
= _dbus_bindings
.UTF8String
31 DBusException
= _dbus_bindings
.DBusException
32 BusImplementation
= _dbus_bindings
.BusImplementation
38 from dbus
.proxies
import ProxyObject
, BUS_DAEMON_NAME
, BUS_DAEMON_PATH
, \
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
,
56 """(_NAME_OWNER_CHANGE_MATCH % sender) matches relevant NameOwnerChange
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,
74 self
._conn
_weakref
= weakref
.ref(conn
)
76 self
._interface
= dbus_interface
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
)
84 self
.sender_unique
= sender
85 self
._utf
8_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
96 self
._int
_args
_match
= None
98 self
._int
_args
_match
= {}
100 if not kwarg
.startswith('arg'):
101 raise TypeError('SignalMatch: unknown keyword argument %s'
104 index
= int(kwarg
[3:])
106 raise TypeError('SignalMatch: unknown keyword argument %s'
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
)
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)
141 if sender
!= self
._sender
:
142 #logger.debug('No match: sender %r is not %r', sender, self._sender)
144 if object_path
!= self
._path
:
145 #logger.debug('No match: path %r is not %r', object_path, self._path)
147 if dbus_interface
!= self
._interface
:
148 #logger.debug('No match: interface %r is not %r', dbus_interface, self._interface)
150 if member
!= self
._member
:
151 #logger.debug('No match: member %r is not %r', member, self._member)
153 if kwargs
!= self
._args
_match
:
154 #logger.debug('No match: args %r are not %r', kwargs, self._args_match)
158 def maybe_handle_message(self
, message
):
159 #logger.debug('%r: Considering whether I match %r %r', self, message,
160 #message.get_args_list())
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)
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)
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)
182 if self
._interface
not in (None, message
.get_interface()):
183 #logger.debug('%r: not the desired interface', self)
185 if self
._path
not in (None, message
.get_path()):
186 #logger.debug('%r: not the desired path', self)
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
._utf
8_strings
or not self
._byte
_arrays
:
193 args
= message
.get_args_list(utf8_strings
=self
._utf
8_strings
,
194 byte_arrays
=self
._byte
_arrays
)
195 #logger.debug('%r: extracted signal arguments', self)
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)
215 #logger.debug('%r: removing', self)
216 conn
= self
._conn
_weakref
()
217 # do nothing if the connection has already vanished
219 #logger.debug('%r: removing from connection %r', self, conn)
220 conn
.remove_signal_receiver(self
, self
._member
,
221 self
._interface
, self
._sender
,
226 class Bus(BusImplementation
):
227 """A connection to a DBus daemon.
229 One of three possible standard buses, the SESSION, SYSTEM,
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`.
257 `bus_type` : cls.TYPE_SESSION, cls.TYPE_SYSTEM or cls.TYPE_STARTER
258 Connect to the appropriate bus
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
267 - There is currently no way to connect this class to a custom
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
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
:
287 elif bus_type
== cls
.TYPE_STARTER
:
288 subclass
= StarterBus
290 raise ValueError('invalid bus_type %s' % bus_type
)
292 bus
= _dbus_bindings
.BusImplementation
.__new
__(subclass
, bus_type
,
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
312 bus
.add_message_filter(bus
.__class
__._signal
_func
)
315 cls
._shared
_instances
[bus_type
] = bus
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.
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.
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.
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.
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 follow_name_owner_changes
=False):
373 """Return a local proxy for the given remote object.
375 Method calls on the proxy are translated into method calls on the
379 `named_service` : str
380 A bus name (either the unique name or a well-known name)
381 of the application owning the object
383 The object path of the desired object
385 If true (default), attempt to introspect the remote
386 object to find out supported methods and their signatures
387 `follow_name_owner_changes` : bool
388 If the object path is a well-known name and this parameter
389 is false (default), resolve the well-known name to the unique
390 name of its current owner and bind to that instead; if the
391 ownership of the well-known name changes in future,
392 keep communicating with the original owner.
393 This is necessary if the D-Bus API used is stateful.
395 If the object path is a well-known name and this parameter
396 is true, whenever the well-known name changes ownership in
397 future, bind to the new owner, if any.
399 If the given object path is a unique name, this parameter
402 :Returns: a `dbus.proxies.ProxyObject`
403 :Raises `DBusException`: if resolving the well-known name to a
406 if follow_name_owner_changes
:
407 self
._require
_main
_loop
() # we don't get the signals otherwise
408 return self
.ProxyObjectClass(self
, named_service
, object_path
,
409 introspect
=introspect
,
410 follow_name_owner_changes
=follow_name_owner_changes
)
412 def add_signal_receiver(self
, handler_function
,
418 """Arrange for the given function to be called when a signal matching
419 the parameters is received.
422 `handler_function` : callable
423 The function to be called. Its positional arguments will
424 be the arguments of the signal. By default it will receive
425 no keyword arguments, but see the description of
426 the optional keyword arguments below.
428 The signal name; None (the default) matches all names
429 `dbus_interface` : str
430 The D-Bus interface name with which to qualify the signal;
431 None (the default) matches all interface names
432 `named_service` : str
433 A bus name for the sender, which will be resolved to a
434 unique name if it is not already; None (the default) matches
437 The object path of the object which must have emitted the
438 signal; None (the default) matches any object path
440 `utf8_strings` : bool
441 If True, the handler function will receive any string
442 arguments as dbus.UTF8String objects (a subclass of str
443 guaranteed to be UTF-8). If False (default) it will receive
444 any string arguments as dbus.String objects (a subclass of
447 If True, the handler function will receive any byte-array
448 arguments as dbus.ByteArray objects (a subclass of str).
449 If False (default) it will receive any byte-array
450 arguments as a dbus.Array of dbus.Byte (subclasses of:
452 `sender_keyword` : str
453 If not None (the default), the handler function will receive
454 the unique name of the sending endpoint as a keyword
455 argument with this name.
456 `destination_keyword` : str
457 If not None (the default), the handler function will receive
458 the bus name of the destination (or None if the signal is a
459 broadcast, as is usual) as a keyword argument with this name.
460 `interface_keyword` : str
461 If not None (the default), the handler function will receive
462 the signal interface as a keyword argument with this name.
463 `member_keyword` : str
464 If not None (the default), the handler function will receive
465 the signal name as a keyword argument with this name.
467 If not None (the default), the handler function will receive
468 the object-path of the sending object as a keyword argument
470 `message_keyword` : str
471 If not None (the default), the handler function will receive
472 the `dbus.lowlevel.SignalMessage` as a keyword argument with
474 `arg...` : unicode or UTF-8 str
475 If there are additional keyword parameters of the form
476 ``arg``\ *n*, match only signals where the *n*\ th argument
477 is the value given for that keyword parameter. As of this
478 time only string arguments can be matched (in particular,
479 object paths and signatures can't).
481 self
._require
_main
_loop
()
483 match
= SignalMatch(self
, named_service
, path
, dbus_interface
,
484 signal_name
, handler_function
, **keywords
)
485 by_interface
= self
._signal
_recipients
_by
_object
_path
.setdefault(path
,
487 by_member
= by_interface
.setdefault(dbus_interface
, {})
488 matches
= by_member
.setdefault(signal_name
, [])
489 # The bus daemon is special - its unique-name is org.freedesktop.DBus
490 # rather than starting with :
491 if (named_service
is not None and named_service
[:1] != ':'
492 and named_service
!= BUS_DAEMON_NAME
):
493 notification
= self
._signal
_sender
_matches
.setdefault(named_service
,
496 self
.add_match_string(_NAME_OWNER_CHANGE_MATCH
% named_service
)
497 notification
.append(match
)
498 # make sure nobody is currently manipulating the list
499 self
._signals
_lock
.acquire()
501 matches
.append(match
)
503 self
._signals
_lock
.release()
504 self
.add_match_string(str(match
))
507 def _iter_easy_matches(self
, path
, dbus_interface
, member
):
509 path_keys
= (None, path
)
512 if dbus_interface
is not None:
513 interface_keys
= (None, dbus_interface
)
515 interface_keys
= (None,)
516 if member
is not None:
517 member_keys
= (None, member
)
519 member_keys
= (None,)
521 for path
in path_keys
:
522 by_interface
= self
._signal
_recipients
_by
_object
_path
.get(path
,
524 if by_interface
is None:
526 for dbus_interface
in interface_keys
:
527 by_member
= by_interface
.get(dbus_interface
, None)
528 if by_member
is None:
530 for member
in member_keys
:
531 matches
= by_member
.get(member
, None)
537 def _remove_name_owner_changed_for_match(self
, named_service
, match
):
538 notification
= self
._signal
_sender
_matches
.get(named_service
, False)
541 notification
.remove(match
)
545 self
.remove_match_string(_NAME_OWNER_CHANGE_MATCH
548 def remove_signal_receiver(self
, handler_or_match
,
554 #logger.debug('%r: removing signal receiver %r: member=%s, '
555 #'iface=%s, sender=%s, path=%s, kwargs=%r',
556 #self, handler_or_match, signal_name,
557 #dbus_interface, named_service, path, keywords)
558 #logger.debug('%r', self._signal_recipients_by_object_path)
559 by_interface
= self
._signal
_recipients
_by
_object
_path
.get(path
, None)
560 if by_interface
is None:
562 by_member
= by_interface
.get(dbus_interface
, None)
563 if by_member
is None:
565 matches
= by_member
.get(signal_name
, None)
568 self
._signals
_lock
.acquire()
569 #logger.debug(matches)
572 for match
in matches
:
573 if (handler_or_match
is match
574 or match
.matches_removal_spec(named_service
,
580 #logger.debug('Removing match string: %s', match)
581 self
.remove_match_string(str(match
))
582 self
._remove
_name
_owner
_changed
_for
_match
(named_service
,
586 by_member
[signal_name
] = new
588 self
._signals
_lock
.release()
590 def _signal_func(self
, message
):
591 """D-Bus filter function. Handle signals by dispatching to Python
592 callbacks kept in the match-rule tree.
595 #logger.debug('Incoming message %r with args %r', message,
596 #message.get_args_list())
598 if (message
.get_type() != _dbus_bindings
.MESSAGE_TYPE_SIGNAL
):
599 return _dbus_bindings
.HANDLER_RESULT_NOT_YET_HANDLED
601 # If it's NameOwnerChanged, we'll need to update our
602 # sender well-known name -> sender unique name mappings
603 if (message
.is_signal(BUS_DAEMON_NAME
, 'NameOwnerChanged')
604 and message
.has_path(BUS_DAEMON_PATH
)):
605 name
, unused
, new
= message
.get_args_list()
606 for match
in self
._signal
_sender
_matches
.get(name
, (None,))[1:]:
607 match
.sender_unique
= new
609 # See if anyone else wants to know
610 dbus_interface
= message
.get_interface()
611 path
= message
.get_path()
612 signal_name
= message
.get_member()
614 ret
= _dbus_bindings
.HANDLER_RESULT_NOT_YET_HANDLED
615 for match
in self
._iter
_easy
_matches
(path
, dbus_interface
,
617 if match
.maybe_handle_message(message
):
618 ret
= _dbus_bindings
.HANDLER_RESULT_HANDLED
622 if self
._bus
_type
== self
.TYPE_SESSION
:
624 elif self
._bus
_type
== self
.TYPE_SYSTEM
:
626 elif self
._bus
_type
== self
.TYPE_STARTER
:
629 raise AssertionError('Unable to represent unknown bus type.')
631 return '<dbus.Bus on %s at %#x>' % (name
, id(self
))
635 # FIXME: Drop the subclasses here? I can't think why we'd ever want
637 class SystemBus(Bus
):
638 """The system-wide message bus."""
639 def __new__(cls
, private
=False, mainloop
=None):
640 """Return a connection to the system bus.
644 If true, never return an existing shared instance, but instead
645 return a private connection.
646 `mainloop` : dbus.mainloop.NativeMainLoop
647 The main loop to use. The default is to use the default
648 main loop if one has been set up, or raise an exception
651 return Bus
.__new
__(cls
, Bus
.TYPE_SYSTEM
, mainloop
=mainloop
,
654 class SessionBus(Bus
):
655 """The session (current login) message bus."""
656 def __new__(cls
, private
=False, mainloop
=None):
657 """Return a connection to the session bus.
661 If true, never return an existing shared instance, but instead
662 return a private connection.
663 `mainloop` : dbus.mainloop.NativeMainLoop
664 The main loop to use. The default is to use the default
665 main loop if one has been set up, or raise an exception
668 return Bus
.__new
__(cls
, Bus
.TYPE_SESSION
, private
=private
,
671 class StarterBus(Bus
):
672 """The bus that activated this process (only valid if
673 this process was launched by DBus activation).
675 def __new__(cls
, private
=False, mainloop
=None):
676 """Return a connection to the bus that activated this process.
680 If true, never return an existing shared instance, but instead
681 return a private connection.
682 `mainloop` : dbus.mainloop.NativeMainLoop
683 The main loop to use. The default is to use the default
684 main loop if one has been set up, or raise an exception
687 return Bus
.__new
__(cls
, Bus
.TYPE_STARTER
, private
=private
,
691 """An interface into a remote object.
693 An Interface can be used to wrap ProxyObjects
694 so that calls can be routed to their correct
698 def __init__(self
, object, dbus_interface
):
699 """Construct a proxy for the given interface on the given object.
702 `object` : `dbus.proxies.ProxyObject`
704 `dbus_interface` : str
705 An interface the `object` implements
708 self
._dbus
_interface
= dbus_interface
710 __dbus_object_path__
= property (lambda self
: self
._obj
.__dbus
_object
_path
__,
712 "The D-Bus object path of the "
715 def connect_to_signal(self
, signal_name
, handler_function
, dbus_interface
= None, **keywords
):
716 """Arrange for a function to be called when the given signal is
721 The name of the signal
722 `handler_function` : callable
723 A function to be called when the signal is emitted by the
724 remote object. It will receive the signal's arguments
725 as its positional arguments.
726 `dbus_interface` : str
727 Optional interface with which to qualify the signal name.
728 The default is to use the interface this Interface represents.
729 (FIXME: deprecate this? Violates least astonishment)
731 `utf8_strings` : bool
732 If True, the handler function will receive any string
733 arguments as dbus.UTF8String objects (a subclass of str
734 guaranteed to be UTF-8). If False (default) it will receive
735 any string arguments as dbus.String objects (a subclass of
738 If True, the handler function will receive any byte-array
739 arguments as dbus.ByteArray objects (a subclass of str).
740 If False (default) it will receive any byte-array
741 arguments as a dbus.Array of dbus.Byte (subclasses of:
743 `sender_keyword` : str
744 If not None (the default), the handler function will receive
745 the unique name of the sending endpoint as a keyword
746 argument with this name
747 `destination_keyword` : str
748 If not None (the default), the handler function will receive
749 the bus name of the destination (or None if the signal is a
750 broadcast, as is usual) as a keyword argument with this name.
751 `interface_keyword` : str
752 If not None (the default), the handler function will receive
753 the signal interface as a keyword argument with this name.
754 `member_keyword` : str
755 If not None (the default), the handler function will receive
756 the signal name as a keyword argument with this name.
758 If not None (the default), the handler function will receive
759 the object-path of the sending object as a keyword argument
761 `message_keyword` : str
762 If not None (the default), the handler function will receive
763 the `dbus.lowlevel.SignalMessage` as a keyword argument with
765 `arg...` : unicode or UTF-8 str
766 If there are additional keyword parameters of the form
767 ``arg``\ *n*, only call the handler_function for signals
768 where the *n*\ th argument is the value given for that
769 keyword parameter. As of this time only string arguments
772 if not dbus_interface
:
773 dbus_interface
= self
._dbus
_interface
775 return self
._obj
.connect_to_signal(signal_name
, handler_function
, dbus_interface
, **keywords
)
777 def __getattr__(self
, member
, **keywords
):
778 # FIXME: this syntax is bizarre.
779 if (keywords
.has_key('dbus_interface')):
780 _dbus_interface
= keywords
['dbus_interface']
782 _dbus_interface
= self
._dbus
_interface
784 # I have no idea what's going on here. -smcv
785 if member
== '__call__':
786 return object.__call
__
788 ret
= self
._obj
.__getattr
__(member
, dbus_interface
=_dbus_interface
)
791 def get_dbus_method(self
, member
, dbus_interface
=None):
792 """Return a proxy method representing the given D-Bus method. The
793 returned proxy method can be called in the usual way. For instance, ::
795 iface.get_dbus_method("Foo")(123)
803 getattr(iface, "Foo")(123)
805 However, using `get_dbus_method` is the only way to call D-Bus
806 methods with certain awkward names - if the author of a service
807 implements a method called ``connect_to_signal`` or even
808 ``__getattr__``, you'll need to use `get_dbus_method` to call them.
810 For services which follow the D-Bus convention of CamelCaseMethodNames
811 this won't be a problem.
813 if dbus_interface
is None:
814 dbus_interface
= self
._dbus
_interface
815 return self
._obj
.get_dbus_method(member
, dbus_interface
=dbus_interface
)
818 return '<Interface %r implementing %r at %#x>'%(
819 self
._obj
, self
._dbus
_interface
, id(self
))
823 _dbus_bindings_warning
= DeprecationWarning("""\
824 The dbus_bindings module is deprecated and will go away soon.
826 dbus-python 0.80 provides only a partial emulation of the old
827 dbus_bindings, which was never meant to be public API.
829 Most uses of dbus_bindings are applications catching the exception
830 dbus.dbus_bindings.DBusException. You should use dbus.DBusException
831 instead (this is compatible with all dbus-python versions since 0.40.2).
833 If you need additional public API, please contact the maintainers via
834 <dbus@lists.freedesktop.org>.
837 if 'DBUS_PYTHON_NO_DEPRECATED' not in os
.environ
:
839 class _DBusBindingsEmulation
:
840 """A partial emulation of the dbus_bindings module."""
843 return '_DBusBindingsEmulation()'
845 return '_DBusBindingsEmulation()'
846 def __getattr__(self
, attr
):
847 if self
._module
is None:
848 from warnings
import warn
as _warn
849 _warn(_dbus_bindings_warning
, DeprecationWarning, stacklevel
=2)
851 import dbus
.dbus_bindings
as m
853 return getattr(self
._module
, attr
)
855 dbus_bindings
= _DBusBindingsEmulation()
856 """Deprecated, don't use."""