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 traceback
import print_exc
40 from dbus
.proxies
import ProxyObject
, BUS_DAEMON_NAME
, BUS_DAEMON_PATH
, \
46 import dummy_thread
as thread
48 logger
= logging
.getLogger('dbus._dbus')
49 BUS_DAEMON_NAME
= 'org.freedesktop.DBus'
50 BUS_DAEMON_PATH
= '/org/freedesktop/DBus'
51 BUS_DAEMON_IFACE
= BUS_DAEMON_NAME
53 _NAME_OWNER_CHANGE_MATCH
= ("type='signal',sender='%s',"
54 "interface='%s',member='NameOwnerChanged',"
55 "path='%s',arg0='%%s'"
56 % (BUS_DAEMON_NAME
, BUS_DAEMON_IFACE
,
58 """(_NAME_OWNER_CHANGE_MATCH % sender) matches relevant NameOwnerChange
62 class SignalMatch(object):
63 __slots__
= ('sender_unique', '_member', '_interface', '_sender',
64 '_path', '_handler', '_args_match', '_rule',
65 '_utf8_strings', '_byte_arrays', '_conn_weakref',
66 '_destination_keyword', '_interface_keyword',
67 '_message_keyword', '_member_keyword',
68 '_sender_keyword', '_path_keyword', '_int_args_match')
70 def __init__(self
, conn
, sender
, object_path
, dbus_interface
,
71 member
, handler
, utf8_strings
=False, byte_arrays
=False,
72 sender_keyword
=None, path_keyword
=None,
73 interface_keyword
=None, member_keyword
=None,
74 message_keyword
=None, destination_keyword
=None,
76 if member
is not None:
77 _dbus_bindings
.validate_member_name(member
)
78 if dbus_interface
is not None:
79 _dbus_bindings
.validate_interface_name(dbus_interface
)
80 if sender
is not None:
81 _dbus_bindings
.validate_bus_name(sender
)
82 if object_path
is not None:
83 _dbus_bindings
.validate_object_path(object_path
)
85 self
._conn
_weakref
= weakref
.ref(conn
)
87 self
._interface
= dbus_interface
89 self
._path
= object_path
90 self
._handler
= handler
91 if (sender
is not None and sender
[:1] != ':'
92 and sender
!= BUS_DAEMON_NAME
):
93 self
.sender_unique
= conn
.get_object(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
).GetNameOwner(sender
, dbus_interface
=BUS_DAEMON_IFACE
)
95 self
.sender_unique
= sender
96 self
._utf
8_strings
= utf8_strings
97 self
._byte
_arrays
= byte_arrays
98 self
._sender
_keyword
= sender_keyword
99 self
._path
_keyword
= path_keyword
100 self
._member
_keyword
= member_keyword
101 self
._interface
_keyword
= interface_keyword
102 self
._message
_keyword
= message_keyword
103 self
._destination
_keyword
= destination_keyword
105 self
._args
_match
= kwargs
107 self
._int
_args
_match
= None
109 self
._int
_args
_match
= {}
111 if not kwarg
.startswith('arg'):
112 raise TypeError('SignalMatch: unknown keyword argument %s'
115 index
= int(kwarg
[3:])
117 raise TypeError('SignalMatch: unknown keyword argument %s'
119 if index
< 0 or index
> 63:
120 raise TypeError('SignalMatch: arg match index must be in '
121 'range(64), not %d' % index
)
122 self
._int
_args
_match
[index
] = kwargs
[kwarg
]
124 # we're always going to have to calculate the match rule for
125 # the Bus's benefit, so this constructor might as well do the work
126 rule
= ["type='signal'"]
127 if self
._sender
is not None:
128 rule
.append("sender='%s'" % self
._sender
)
129 if self
._path
is not None:
130 rule
.append("path='%s'" % self
._path
)
131 if self
._interface
is not None:
132 rule
.append("interface='%s'" % self
._interface
)
133 if self
._member
is not None:
134 rule
.append("member='%s'" % self
._member
)
135 for kwarg
, value
in kwargs
.iteritems():
136 rule
.append("%s='%s'" % (kwarg
, value
))
138 self
._rule
= ','.join(rule
)
144 return ('<%s at %x "%s" on conn %r>'
145 % (self
.__class
__, id(self
), self
._rule
, self
._conn
_weakref
()))
147 def matches_removal_spec(self
, sender
, object_path
,
148 dbus_interface
, member
, handler
, **kwargs
):
149 if handler
not in (None, self
._handler
):
151 if sender
!= self
._sender
:
153 if object_path
!= self
._path
:
155 if dbus_interface
!= self
._interface
:
157 if member
!= self
._member
:
159 if kwargs
!= self
._args
_match
:
163 def maybe_handle_message(self
, message
):
166 # these haven't been checked yet by the match tree
167 if self
.sender_unique
not in (None, message
.get_sender()):
169 if self
._int
_args
_match
is not None:
170 # extracting args with utf8_strings and byte_arrays is less work
171 args
= message
.get_args_list(utf8_strings
=True, byte_arrays
=True)
172 for index
, value
in self
._int
_args
_match
.iteritems():
173 if (index
>= len(args
)
174 or not isinstance(args
[index
], UTF8String
)
175 or args
[index
] != value
):
178 # these have likely already been checked by the match tree
179 if self
._member
not in (None, message
.get_member()):
181 if self
._interface
not in (None, message
.get_interface()):
183 if self
._path
not in (None, message
.get_path()):
187 # minor optimization: if we already extracted the args with the
188 # right calling convention to do the args match, don't bother
190 if args
is None or not self
._utf
8_strings
or not self
._byte
_arrays
:
191 args
= message
.get_args_list(utf8_strings
=self
._utf
8_strings
,
192 byte_arrays
=self
._byte
_arrays
)
194 if self
._sender
_keyword
is not None:
195 kwargs
[self
._sender
_keyword
] = message
.get_sender()
196 if self
._destination
_keyword
is not None:
197 kwargs
[self
._destination
_keyword
] = message
.get_destination()
198 if self
._path
_keyword
is not None:
199 kwargs
[self
._path
_keyword
] = message
.get_path()
200 if self
._member
_keyword
is not None:
201 kwargs
[self
._member
_keyword
] = message
.get_member()
202 if self
._interface
_keyword
is not None:
203 kwargs
[self
._interface
_keyword
] = message
.get_interface()
204 if self
._message
_keyword
is not None:
205 kwargs
[self
._message
_keyword
] = message
206 self
._handler
(*args
, **kwargs
)
208 # FIXME: need to decide whether dbus-python uses logging, or
209 # stderr, or what, and make it consistent
210 sys
.stderr
.write('Exception in handler for D-Bus signal:\n')
216 #logger.debug('%r: removing', self)
217 conn
= self
._conn
_weakref
()
218 # do nothing if the connection has already vanished
220 #logger.debug('%r: removing from connection %r', self, conn)
221 conn
.remove_signal_receiver(self
, self
._member
,
222 self
._interface
, self
._sender
,
227 class Bus(BusImplementation
):
228 """A connection to a DBus daemon.
230 One of three possible standard buses, the SESSION, SYSTEM,
234 TYPE_SESSION
= _dbus_bindings
.BUS_SESSION
235 """Represents a session bus (same as the global dbus.BUS_SESSION)"""
237 TYPE_SYSTEM
= _dbus_bindings
.BUS_SYSTEM
238 """Represents the system bus (same as the global dbus.BUS_SYSTEM)"""
240 TYPE_STARTER
= _dbus_bindings
.BUS_STARTER
241 """Represents the bus that started this service by activation (same as
242 the global dbus.BUS_STARTER)"""
244 ProxyObjectClass
= ProxyObject
246 START_REPLY_SUCCESS
= _dbus_bindings
.DBUS_START_REPLY_SUCCESS
247 START_REPLY_ALREADY_RUNNING
= _dbus_bindings
.DBUS_START_REPLY_ALREADY_RUNNING
249 _shared_instances
= {}
251 def __new__(cls
, bus_type
=TYPE_SESSION
, private
=False, mainloop
=None):
252 """Constructor, returning an existing instance where appropriate.
254 The returned instance is actually always an instance of `SessionBus`,
255 `SystemBus` or `StarterBus`.
258 `bus_type` : cls.TYPE_SESSION, cls.TYPE_SYSTEM or cls.TYPE_STARTER
259 Connect to the appropriate bus
261 If true, never return an existing shared instance, but instead
262 return a private connection
263 `mainloop` : dbus.mainloop.NativeMainLoop
264 The main loop to use. The default is to use the default
265 main loop if one has been set up, or raise an exception
268 - There is currently no way to connect this class to a custom
270 - Some of this functionality should be available on
271 peer-to-peer D-Bus connections too.
272 :Changed: in dbus-python 0.80:
273 converted from a wrapper around a Connection to a Connection
276 if (not private
and bus_type
in cls
._shared
_instances
):
277 return cls
._shared
_instances
[bus_type
]
279 # this is a bit odd, but we create instances of the subtypes
280 # so we can return the shared instances if someone tries to
281 # construct one of them (otherwise we'd eg try and return an
282 # instance of Bus from __new__ in SessionBus). why are there
283 # three ways to construct this class? we just don't know.
284 if bus_type
== cls
.TYPE_SESSION
:
285 subclass
= SessionBus
286 elif bus_type
== cls
.TYPE_SYSTEM
:
288 elif bus_type
== cls
.TYPE_STARTER
:
289 subclass
= StarterBus
291 raise ValueError('invalid bus_type %s' % bus_type
)
293 bus
= _dbus_bindings
.BusImplementation
.__new
__(subclass
, bus_type
,
296 bus
._bus
_type
= bus_type
297 # _bus_names is used by dbus.service.BusName!
298 bus
._bus
_names
= weakref
.WeakValueDictionary()
300 bus
._signal
_recipients
_by
_object
_path
= {}
301 """Map from object path to dict mapping dbus_interface to dict
302 mapping member to list of SignalMatch objects."""
304 bus
._signal
_sender
_matches
= {}
305 """Map from sender well-known name to list of match rules for all
306 signal handlers that match on sender well-known name."""
308 bus
._signals
_lock
= thread
.allocate_lock()
309 """Lock used to protect signal data structures if doing two
310 removals at the same time (everything else is atomic, thanks to
313 bus
.add_message_filter(bus
.__class
__._signal
_func
)
316 cls
._shared
_instances
[bus_type
] = bus
322 if self
.__class
__._shared
_instances
[t
] is self
:
323 del self
.__class
__._shared
_instances
[t
]
324 BusImplementation
.close(self
)
326 def get_connection(self
):
327 """(Deprecated - in new code, just use self)
329 Return self, for backwards compatibility with earlier dbus-python
330 versions where Bus was not a subclass of Connection.
333 _connection
= property(get_connection
, None, None,
334 """self._connection == self, for backwards
335 compatibility with earlier dbus-python versions
336 where Bus was not a subclass of Connection.""")
338 def get_session(private
=False):
339 """Static method that returns a connection to the session bus.
343 If true, do not return a shared connection.
345 return SessionBus(private
=private
)
347 get_session
= staticmethod(get_session
)
349 def get_system(private
=False):
350 """Static method that returns a connection to the system bus.
354 If true, do not return a shared connection.
356 return SystemBus(private
=private
)
358 get_system
= staticmethod(get_system
)
361 def get_starter(private
=False):
362 """Static method that returns a connection to the starter bus.
366 If true, do not return a shared connection.
368 return StarterBus(private
=private
)
370 get_starter
= staticmethod(get_starter
)
372 def get_object(self
, named_service
, object_path
, introspect
=True,
373 follow_name_owner_changes
=False):
374 """Return a local proxy for the given remote object.
376 Method calls on the proxy are translated into method calls on the
380 `named_service` : str
381 A bus name (either the unique name or a well-known name)
382 of the application owning the object
384 The object path of the desired object
386 If true (default), attempt to introspect the remote
387 object to find out supported methods and their signatures
388 `follow_name_owner_changes` : bool
389 If the object path is a well-known name and this parameter
390 is false (default), resolve the well-known name to the unique
391 name of its current owner and bind to that instead; if the
392 ownership of the well-known name changes in future,
393 keep communicating with the original owner.
394 This is necessary if the D-Bus API used is stateful.
396 If the object path is a well-known name and this parameter
397 is true, whenever the well-known name changes ownership in
398 future, bind to the new owner, if any.
400 If the given object path is a unique name, this parameter
403 :Returns: a `dbus.proxies.ProxyObject`
404 :Raises `DBusException`: if resolving the well-known name to a
407 if follow_name_owner_changes
:
408 self
._require
_main
_loop
() # we don't get the signals otherwise
409 return self
.ProxyObjectClass(self
, named_service
, object_path
,
410 introspect
=introspect
,
411 follow_name_owner_changes
=follow_name_owner_changes
)
413 def add_signal_receiver(self
, handler_function
,
419 """Arrange for the given function to be called when a signal matching
420 the parameters is received.
423 `handler_function` : callable
424 The function to be called. Its positional arguments will
425 be the arguments of the signal. By default it will receive
426 no keyword arguments, but see the description of
427 the optional keyword arguments below.
429 The signal name; None (the default) matches all names
430 `dbus_interface` : str
431 The D-Bus interface name with which to qualify the signal;
432 None (the default) matches all interface names
433 `named_service` : str
434 A bus name for the sender, which will be resolved to a
435 unique name if it is not already; None (the default) matches
438 The object path of the object which must have emitted the
439 signal; None (the default) matches any object path
441 `utf8_strings` : bool
442 If True, the handler function will receive any string
443 arguments as dbus.UTF8String objects (a subclass of str
444 guaranteed to be UTF-8). If False (default) it will receive
445 any string arguments as dbus.String objects (a subclass of
448 If True, the handler function will receive any byte-array
449 arguments as dbus.ByteArray objects (a subclass of str).
450 If False (default) it will receive any byte-array
451 arguments as a dbus.Array of dbus.Byte (subclasses of:
453 `sender_keyword` : str
454 If not None (the default), the handler function will receive
455 the unique name of the sending endpoint as a keyword
456 argument with this name.
457 `destination_keyword` : str
458 If not None (the default), the handler function will receive
459 the bus name of the destination (or None if the signal is a
460 broadcast, as is usual) as a keyword argument with this name.
461 `interface_keyword` : str
462 If not None (the default), the handler function will receive
463 the signal interface as a keyword argument with this name.
464 `member_keyword` : str
465 If not None (the default), the handler function will receive
466 the signal name as a keyword argument with this name.
468 If not None (the default), the handler function will receive
469 the object-path of the sending object as a keyword argument
471 `message_keyword` : str
472 If not None (the default), the handler function will receive
473 the `dbus.lowlevel.SignalMessage` as a keyword argument with
475 `arg...` : unicode or UTF-8 str
476 If there are additional keyword parameters of the form
477 ``arg``\ *n*, match only signals where the *n*\ th argument
478 is the value given for that keyword parameter. As of this
479 time only string arguments can be matched (in particular,
480 object paths and signatures can't).
482 self
._require
_main
_loop
()
484 match
= SignalMatch(self
, named_service
, path
, dbus_interface
,
485 signal_name
, handler_function
, **keywords
)
486 by_interface
= self
._signal
_recipients
_by
_object
_path
.setdefault(path
,
488 by_member
= by_interface
.setdefault(dbus_interface
, {})
489 matches
= by_member
.setdefault(signal_name
, [])
490 # The bus daemon is special - its unique-name is org.freedesktop.DBus
491 # rather than starting with :
492 if (named_service
is not None and named_service
[:1] != ':'
493 and named_service
!= BUS_DAEMON_NAME
):
494 notification
= self
._signal
_sender
_matches
.setdefault(named_service
,
497 self
.add_match_string(_NAME_OWNER_CHANGE_MATCH
% named_service
)
498 notification
.append(match
)
499 # make sure nobody is currently manipulating the list
500 self
._signals
_lock
.acquire()
502 matches
.append(match
)
504 self
._signals
_lock
.release()
505 self
.add_match_string(str(match
))
508 def _iter_easy_matches(self
, path
, dbus_interface
, member
):
510 path_keys
= (None, path
)
513 if dbus_interface
is not None:
514 interface_keys
= (None, dbus_interface
)
516 interface_keys
= (None,)
517 if member
is not None:
518 member_keys
= (None, member
)
520 member_keys
= (None,)
522 for path
in path_keys
:
523 by_interface
= self
._signal
_recipients
_by
_object
_path
.get(path
,
525 if by_interface
is None:
527 for dbus_interface
in interface_keys
:
528 by_member
= by_interface
.get(dbus_interface
, None)
529 if by_member
is None:
531 for member
in member_keys
:
532 matches
= by_member
.get(member
, None)
538 def _remove_name_owner_changed_for_match(self
, named_service
, match
):
539 notification
= self
._signal
_sender
_matches
.get(named_service
, False)
542 notification
.remove(match
)
546 self
.remove_match_string(_NAME_OWNER_CHANGE_MATCH
549 def remove_signal_receiver(self
, handler_or_match
,
555 #logger.debug('%r: removing signal receiver %r: member=%s, '
556 #'iface=%s, sender=%s, path=%s, kwargs=%r',
557 #self, handler_or_match, signal_name,
558 #dbus_interface, named_service, path, keywords)
559 #logger.debug('%r', self._signal_recipients_by_object_path)
560 by_interface
= self
._signal
_recipients
_by
_object
_path
.get(path
, None)
561 if by_interface
is None:
563 by_member
= by_interface
.get(dbus_interface
, None)
564 if by_member
is None:
566 matches
= by_member
.get(signal_name
, None)
569 self
._signals
_lock
.acquire()
570 #logger.debug(matches)
573 for match
in matches
:
574 if (handler_or_match
is match
575 or match
.matches_removal_spec(named_service
,
581 #logger.debug('Removing match string: %s', match)
582 self
.remove_match_string(str(match
))
583 self
._remove
_name
_owner
_changed
_for
_match
(named_service
,
587 by_member
[signal_name
] = new
589 self
._signals
_lock
.release()
591 def _signal_func(self
, message
):
592 """D-Bus filter function. Handle signals by dispatching to Python
593 callbacks kept in the match-rule tree.
596 #logger.debug('Incoming message %r with args %r', message,
597 #message.get_args_list())
599 if (message
.get_type() != _dbus_bindings
.MESSAGE_TYPE_SIGNAL
):
600 return _dbus_bindings
.HANDLER_RESULT_NOT_YET_HANDLED
602 # If it's NameOwnerChanged, we'll need to update our
603 # sender well-known name -> sender unique name mappings
604 if (message
.is_signal(BUS_DAEMON_NAME
, 'NameOwnerChanged')
605 and message
.has_path(BUS_DAEMON_PATH
)):
606 name
, unused
, new
= message
.get_args_list()
607 for match
in self
._signal
_sender
_matches
.get(name
, (None,))[1:]:
608 match
.sender_unique
= new
610 # See if anyone else wants to know
611 dbus_interface
= message
.get_interface()
612 path
= message
.get_path()
613 signal_name
= message
.get_member()
615 ret
= _dbus_bindings
.HANDLER_RESULT_NOT_YET_HANDLED
616 for match
in self
._iter
_easy
_matches
(path
, dbus_interface
,
618 if match
.maybe_handle_message(message
):
619 ret
= _dbus_bindings
.HANDLER_RESULT_HANDLED
623 if self
._bus
_type
== self
.TYPE_SESSION
:
625 elif self
._bus
_type
== self
.TYPE_SYSTEM
:
627 elif self
._bus
_type
== self
.TYPE_STARTER
:
630 raise AssertionError('Unable to represent unknown bus type.')
632 return '<dbus.Bus on %s at %#x>' % (name
, id(self
))
636 # FIXME: Drop the subclasses here? I can't think why we'd ever want
638 class SystemBus(Bus
):
639 """The system-wide message bus."""
640 def __new__(cls
, private
=False, mainloop
=None):
641 """Return a connection to the system bus.
645 If true, never return an existing shared instance, but instead
646 return a private connection.
647 `mainloop` : dbus.mainloop.NativeMainLoop
648 The main loop to use. The default is to use the default
649 main loop if one has been set up, or raise an exception
652 return Bus
.__new
__(cls
, Bus
.TYPE_SYSTEM
, mainloop
=mainloop
,
655 class SessionBus(Bus
):
656 """The session (current login) message bus."""
657 def __new__(cls
, private
=False, mainloop
=None):
658 """Return a connection to the session bus.
662 If true, never return an existing shared instance, but instead
663 return a private connection.
664 `mainloop` : dbus.mainloop.NativeMainLoop
665 The main loop to use. The default is to use the default
666 main loop if one has been set up, or raise an exception
669 return Bus
.__new
__(cls
, Bus
.TYPE_SESSION
, private
=private
,
672 class StarterBus(Bus
):
673 """The bus that activated this process (only valid if
674 this process was launched by DBus activation).
676 def __new__(cls
, private
=False, mainloop
=None):
677 """Return a connection to the bus that activated this process.
681 If true, never return an existing shared instance, but instead
682 return a private connection.
683 `mainloop` : dbus.mainloop.NativeMainLoop
684 The main loop to use. The default is to use the default
685 main loop if one has been set up, or raise an exception
688 return Bus
.__new
__(cls
, Bus
.TYPE_STARTER
, private
=private
,
692 """An interface into a remote object.
694 An Interface can be used to wrap ProxyObjects
695 so that calls can be routed to their correct
699 def __init__(self
, object, dbus_interface
):
700 """Construct a proxy for the given interface on the given object.
703 `object` : `dbus.proxies.ProxyObject`
705 `dbus_interface` : str
706 An interface the `object` implements
709 self
._dbus
_interface
= dbus_interface
711 __dbus_object_path__
= property (lambda self
: self
._obj
.__dbus
_object
_path
__,
713 "The D-Bus object path of the "
716 def connect_to_signal(self
, signal_name
, handler_function
, dbus_interface
= None, **keywords
):
717 """Arrange for a function to be called when the given signal is
722 The name of the signal
723 `handler_function` : callable
724 A function to be called when the signal is emitted by the
725 remote object. It will receive the signal's arguments
726 as its positional arguments.
727 `dbus_interface` : str
728 Optional interface with which to qualify the signal name.
729 The default is to use the interface this Interface represents.
730 (FIXME: deprecate this? Violates least astonishment)
732 `utf8_strings` : bool
733 If True, the handler function will receive any string
734 arguments as dbus.UTF8String objects (a subclass of str
735 guaranteed to be UTF-8). If False (default) it will receive
736 any string arguments as dbus.String objects (a subclass of
739 If True, the handler function will receive any byte-array
740 arguments as dbus.ByteArray objects (a subclass of str).
741 If False (default) it will receive any byte-array
742 arguments as a dbus.Array of dbus.Byte (subclasses of:
744 `sender_keyword` : str
745 If not None (the default), the handler function will receive
746 the unique name of the sending endpoint as a keyword
747 argument with this name
748 `destination_keyword` : str
749 If not None (the default), the handler function will receive
750 the bus name of the destination (or None if the signal is a
751 broadcast, as is usual) as a keyword argument with this name.
752 `interface_keyword` : str
753 If not None (the default), the handler function will receive
754 the signal interface as a keyword argument with this name.
755 `member_keyword` : str
756 If not None (the default), the handler function will receive
757 the signal name as a keyword argument with this name.
759 If not None (the default), the handler function will receive
760 the object-path of the sending object as a keyword argument
762 `message_keyword` : str
763 If not None (the default), the handler function will receive
764 the `dbus.lowlevel.SignalMessage` as a keyword argument with
766 `arg...` : unicode or UTF-8 str
767 If there are additional keyword parameters of the form
768 ``arg``\ *n*, only call the handler_function for signals
769 where the *n*\ th argument is the value given for that
770 keyword parameter. As of this time only string arguments
773 if not dbus_interface
:
774 dbus_interface
= self
._dbus
_interface
776 return self
._obj
.connect_to_signal(signal_name
, handler_function
, dbus_interface
, **keywords
)
778 def __getattr__(self
, member
, **keywords
):
779 # FIXME: this syntax is bizarre.
780 if (keywords
.has_key('dbus_interface')):
781 _dbus_interface
= keywords
['dbus_interface']
783 _dbus_interface
= self
._dbus
_interface
785 # I have no idea what's going on here. -smcv
786 if member
== '__call__':
787 return object.__call
__
789 ret
= self
._obj
.__getattr
__(member
, dbus_interface
=_dbus_interface
)
792 def get_dbus_method(self
, member
, dbus_interface
=None):
793 """Return a proxy method representing the given D-Bus method. The
794 returned proxy method can be called in the usual way. For instance, ::
796 iface.get_dbus_method("Foo")(123)
804 getattr(iface, "Foo")(123)
806 However, using `get_dbus_method` is the only way to call D-Bus
807 methods with certain awkward names - if the author of a service
808 implements a method called ``connect_to_signal`` or even
809 ``__getattr__``, you'll need to use `get_dbus_method` to call them.
811 For services which follow the D-Bus convention of CamelCaseMethodNames
812 this won't be a problem.
814 if dbus_interface
is None:
815 dbus_interface
= self
._dbus
_interface
816 return self
._obj
.get_dbus_method(member
, dbus_interface
=dbus_interface
)
819 return '<Interface %r implementing %r at %#x>'%(
820 self
._obj
, self
._dbus
_interface
, id(self
))
824 _dbus_bindings_warning
= DeprecationWarning("""\
825 The dbus_bindings module is deprecated and will go away soon.
827 dbus-python 0.80 provides only a partial emulation of the old
828 dbus_bindings, which was never meant to be public API.
830 Most uses of dbus_bindings are applications catching the exception
831 dbus.dbus_bindings.DBusException. You should use dbus.DBusException
832 instead (this is compatible with all dbus-python versions since 0.40.2).
834 If you need additional public API, please contact the maintainers via
835 <dbus@lists.freedesktop.org>.
838 if 'DBUS_PYTHON_NO_DEPRECATED' not in os
.environ
:
840 class _DBusBindingsEmulation
:
841 """A partial emulation of the dbus_bindings module."""
844 return '_DBusBindingsEmulation()'
846 return '_DBusBindingsEmulation()'
847 def __getattr__(self
, attr
):
848 if self
._module
is None:
849 from warnings
import warn
as _warn
850 _warn(_dbus_bindings_warning
, DeprecationWarning, stacklevel
=2)
852 import dbus
.dbus_bindings
as m
854 return getattr(self
._module
, attr
)
856 dbus_bindings
= _DBusBindingsEmulation()
857 """Deprecated, don't use."""