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'
32 UTF8String
= _dbus_bindings
.UTF8String
33 DBusException
= _dbus_bindings
.DBusException
34 BusImplementation
= _dbus_bindings
.BusImplementation
39 from dbus
.proxies
import ProxyObject
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 """Return a local proxy for the given remote object.
374 Method calls on the proxy are translated into method calls on the
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
385 `named_service` : str
386 A bus name (either the unique name or a well-known name)
387 of the application owning the object
389 The object path of the desired object
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
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
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
416 The object path of the desired object
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
425 if named_service
[:1] == ':' or named_service
== BUS_DAEMON_NAME
:
426 unique
= named_service
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
)
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
,
443 """Arrange for the given function to be called when a signal matching
444 the parameters is received.
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.
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
462 The object path of the object which must have emitted the
463 signal; None (the default) matches any object path
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
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:
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.
492 If not None (the default), the handler function will receive
493 the object-path of the sending object as a keyword argument
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
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
,
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()
525 matches
.append(match
)
527 self
._signals
_lock
.release()
528 self
.add_match_string(str(match
))
531 def _iter_easy_matches(self
, path
, dbus_interface
, member
):
533 path_keys
= (None, path
)
536 if dbus_interface
is not None:
537 interface_keys
= (None, dbus_interface
)
539 interface_keys
= (None,)
540 if member
is not None:
541 member_keys
= (None, member
)
543 member_keys
= (None,)
545 for path
in path_keys
:
546 by_interface
= self
._signal
_recipients
_by
_object
_path
.get(path
,
548 if by_interface
is None:
550 for dbus_interface
in interface_keys
:
551 by_member
= by_interface
.get(dbus_interface
, None)
552 if by_member
is None:
554 for member
in member_keys
:
555 matches
= by_member
.get(member
, None)
561 def _remove_name_owner_changed_for_match(self
, named_service
, match
):
562 notification
= self
._signal
_sender
_matches
.get(named_service
, False)
565 notification
.remove(match
)
569 self
.remove_match_string(_NAME_OWNER_CHANGE_MATCH
572 def remove_signal_receiver(self
, handler_or_match
,
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:
586 by_member
= by_interface
.get(dbus_interface
, None)
587 if by_member
is None:
589 matches
= by_member
.get(signal_name
, None)
592 self
._signals
_lock
.acquire()
593 #logger.debug(matches)
596 for match
in matches
:
597 if (handler_or_match
is match
598 or match
.matches_removal_spec(named_service
,
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
,
610 by_member
[signal_name
] = new
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
,
641 if match
.maybe_handle_message(message
):
642 ret
= _dbus_bindings
.HANDLER_RESULT_HANDLED
646 if self
._bus
_type
== self
.TYPE_SESSION
:
648 elif self
._bus
_type
== self
.TYPE_SYSTEM
:
650 elif self
._bus
_type
== self
.TYPE_STARTER
:
653 raise AssertionError('Unable to represent unknown bus type.')
655 return '<dbus.Bus on %s at %#x>' % (name
, id(self
))
659 # FIXME: Drop the subclasses here? I can't think why we'd ever want
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.
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
675 return Bus
.__new
__(cls
, Bus
.TYPE_SYSTEM
, mainloop
=mainloop
,
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.
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
692 return Bus
.__new
__(cls
, Bus
.TYPE_SESSION
, private
=private
,
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.
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
711 return Bus
.__new
__(cls
, Bus
.TYPE_STARTER
, private
=private
,
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
722 def __init__(self
, object, dbus_interface
):
723 """Construct a proxy for the given interface on the given object.
726 `object` : `dbus.proxies.ProxyObject`
728 `dbus_interface` : str
729 An interface the `object` implements
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
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)
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
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:
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.
777 If not None (the default), the handler function will receive
778 the object-path of the sending object as a keyword argument
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
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
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']
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
__
807 ret
= self
._obj
.__getattr
__(member
, dbus_interface
=_dbus_interface
)
811 return '<Interface %r implementing %r at %#x>'%(
812 self
._obj
, self
._dbus
_interface
, id(self
))
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>.
830 class _DBusBindingsEmulation
:
831 """A partial emulation of the dbus_bindings module."""
834 return '_DBusBindingsEmulation()'
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
844 return getattr(self
._module
, attr
)
846 dbus_bindings
= _DBusBindingsEmulation()
847 """Deprecated, don't use."""