1 """Module for high-level communication over the FreeDesktop.org Bus (DBus)
3 DBus allows you to share and access remote objects between processes
4 running on the desktop, and also to access system services (such as
7 To use DBus, first get a Bus object, which provides a connection to one
8 of a few standard dbus-daemon instances that might be running. From the
9 Bus you can get a RemoteService. A service is provided by an application or
10 process connected to the Bus, and represents a set of objects. Once you
11 have a RemoteService you can get a RemoteObject that implements a specific interface
12 (an interface is just a standard group of member functions). Then you can call
13 those member functions directly.
15 You can think of a complete method call as looking something like::
17 Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org')
19 This communicates over the SESSION Bus to the org.gnome.Evolution process to call the
20 Forward method of the /org/gnome/Evolution/Inbox object (which provides the
21 org.gnome.Evolution.MailFolder interface) with two string arguments.
23 For example, the dbus-daemon itself provides a service and some objects::
25 # Get a connection to the desktop-wide SESSION bus
26 bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
28 # Get the service provided by the dbus-daemon named org.freedesktop.DBus
29 dbus_service = bus.get_service('org.freedesktop.DBus')
31 # Get a reference to the desktop bus' standard object, denoted
32 # by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus
33 # implements the 'org.freedesktop.DBus' interface
34 dbus_object = dbus_service.get_object('/org/freedesktop/DBus',
35 'org.freedesktop.DBus')
37 # One of the member functions in the org.freedesktop.DBus interface
38 # is ListServices(), which provides a list of all the other services
39 # registered on this bus. Call it, and print the list.
40 print(dbus_object.ListServices())
43 __all__
= ('Bus', 'SystemBus', 'SessionBus', 'StarterBus', 'Interface',
44 # From exceptions (some originally from _dbus_bindings)
45 'DBusException', 'ConnectionError', 'MissingErrorHandlerException',
46 'MissingReplyHandlerException', 'ValidationException',
47 'IntrospectionParserException', 'UnknownMethodException',
48 'NameExistsException',
49 # proxies, matchrules are not public API, so exclude them
51 __docformat__
= 'reStructuredText'
58 from exceptions
import *
59 from matchrules
import *
62 """A connection to a DBus daemon.
64 One of three possible standard buses, the SESSION, SYSTEM,
67 TYPE_SESSION
= _dbus_bindings
.BUS_SESSION
68 TYPE_SYSTEM
= _dbus_bindings
.BUS_SYSTEM
69 TYPE_STARTER
= _dbus_bindings
.BUS_STARTER
71 """bus_type=[Bus.TYPE_SESSION | Bus.TYPE_SYSTEM | Bus.TYPE_STARTER]
74 ProxyObjectClass
= ProxyObject
76 START_REPLY_SUCCESS
= _dbus_bindings
.DBUS_START_REPLY_SUCCESS
77 START_REPLY_ALREADY_RUNNING
= _dbus_bindings
.DBUS_START_REPLY_ALREADY_RUNNING
79 _shared_instances
= weakref
.WeakValueDictionary()
81 def __new__(cls
, bus_type
=TYPE_SESSION
, use_default_mainloop
=True, private
=False):
82 """Constructor, returning an existing instance where appropriate.
84 The returned instance is actually always an instance of `SessionBus`,
85 `SystemBus` or `StarterBus`.
88 `bus_type` : cls.TYPE_SESSION, cls.TYPE_SYSTEM or cls.TYPE_STARTER
89 Connect to the appropriate bus
90 `use_default_mainloop` : bool
91 If true (default), automatically register the new connection
92 to be polled by the default main loop, if any
94 If true, never return an existing shared instance, but instead
95 return a private connection
97 if (not private
and bus_type
in cls
._shared
_instances
):
98 return cls
._shared
_instances
[bus_type
]
100 # this is a bit odd, but we create instances of the subtypes
101 # so we can return the shared instances if someone tries to
102 # construct one of them (otherwise we'd eg try and return an
103 # instance of Bus from __new__ in SessionBus). why are there
104 # three ways to construct this class? we just don't know.
105 if bus_type
== cls
.TYPE_SESSION
:
106 subclass
= SessionBus
107 elif bus_type
== cls
.TYPE_SYSTEM
:
109 elif bus_type
== cls
.TYPE_STARTER
:
110 subclass
= StarterBus
112 raise ValueError('invalid bus_type %s' % bus_type
)
114 bus
= object.__new
__(subclass
)
116 bus
._bus
_type
= bus_type
117 bus
._bus
_names
= weakref
.WeakValueDictionary()
118 bus
._match
_rule
_tree
= SignalMatchTree()
120 # FIXME: if you get a starter and a system/session bus connection
121 # in the same process, it's the same underlying connection that
122 # is returned by bus_get, but we initialise it twice
123 bus
._connection
= _dbus_bindings
.bus_get(bus_type
, private
)
124 bus
._connection
.add_filter(bus
._signal
_func
)
126 if use_default_mainloop
:
127 func
= getattr(dbus
, "_dbus_mainloop_setup_function", None)
132 cls
._shared
_instances
[bus_type
] = bus
136 def __init__(self
, *args
, **keywords
):
137 # do nothing here because this can get called multiple times on the
138 # same object if __new__ returns a shared instance
142 """Close the connection."""
143 self
._connection
.close()
145 def get_connection(self
):
146 """Return the underlying `_dbus_bindings.Connection`."""
147 return self
._connection
149 def get_session(private
=False):
150 """Static method that returns a connection to the session bus.
154 If true, do not return a shared connection.
156 return SessionBus(private
=private
)
158 get_session
= staticmethod(get_session
)
160 def get_system(private
=False):
161 """Static method that returns a connection to the system bus.
165 If true, do not return a shared connection.
167 return SystemBus(private
=private
)
169 get_system
= staticmethod(get_system
)
172 def get_starter(private
=False):
173 """Static method that returns a connection to the starter bus.
177 If true, do not return a shared connection.
179 return StarterBus(private
=private
)
181 get_starter
= staticmethod(get_starter
)
184 def get_object(self
, named_service
, object_path
):
185 """Return a local proxy for the given remote object.
187 Method calls on the proxy are translated into method calls on the
191 `named_service` : str
192 A bus name (either the unique name or a well-known name)
193 of the application owning the object
195 The object path of the desired object
196 :Returns: a `dbus.proxies.ProxyObject`
198 return self
.ProxyObjectClass(self
, named_service
, object_path
)
200 def _create_args_dict(self
, keywords
):
202 for (key
, value
) in keywords
.iteritems():
203 if key
.startswith('arg'):
211 args_dict
[num
] = value
213 raise TypeError("Invalid arg index %s"%snum
)
214 elif key
in ("sender_keyword", "path_keyword"):
217 raise TypeError("Unknown keyword %s"%(key))
221 def add_signal_receiver(self
, handler_function
,
227 """Arrange for the given function to be called when a signal matching
228 the parameters is emitted.
231 `handler_function` : callable
232 The function to be called.
234 The signal name; None (the default) matches all names
235 `dbus_interface` : str
236 The D-Bus interface name with which to qualify the signal;
237 None (the default) matches all interface names
238 `named_service` : str
239 A bus name for the sender, which will be resolved to a
240 unique name if it is not already; None (the default) matches
243 The object path of the object which must have emitted the
244 signal; None (the default) matches any object path
245 `sender_keyword` : str
246 If not None (the default), the handler function will receive
247 the unique name of the sending endpoint as a keyword
248 argument with this name
250 If not None (the default), the handler function will receive
251 the object-path of the sending object as a keyword argument
254 If there are additional keyword parameters of the form
255 ``arg``\ *n*, match only signals where the *n*\ th argument
256 is the value given for that keyword parameter
259 args_dict
= self
._create
_args
_dict
(keywords
)
261 if (named_service
and named_service
[0] != ':'):
262 bus_object
= self
.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
263 named_service
= bus_object
.GetNameOwner(named_service
, dbus_interface
='org.freedesktop.DBus')
265 match_rule
= SignalMatchRule(signal_name
, dbus_interface
, named_service
, path
)
267 for kw
in ("sender_keyword", "path_keyword"):
269 setattr(match_rule
, kw
, keywords
[kw
])
271 setattr(match_rule
, kw
, None)
274 match_rule
.add_args_match(args_dict
)
276 match_rule
.add_handler(handler_function
)
278 self
._match
_rule
_tree
.add(match_rule
)
280 _dbus_bindings
.bus_add_match(self
._connection
, repr(match_rule
))
282 def remove_signal_receiver(self
, handler_function
,
289 args_dict
= self
._create
_args
_dict
(keywords
)
291 if (named_service
and named_service
[0] != ':'):
292 bus_object
= self
.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
293 named_service
= bus_object
.GetNameOwner(named_service
, dbus_interface
='org.freedesktop.DBus')
295 match_rule
= SignalMatchRule(signal_name
, dbus_interface
, named_service
, path
)
298 match_rule
.add_args_match(args_dict
)
300 if (handler_function
):
301 match_rule
.add_handler(handler_function
)
303 self
._match
_rule
_tree
.remove(match_rule
)
305 #TODO we leak match rules in the lower level bindings. We need to ref count them
307 def get_unix_user(self
, named_service
):
308 """Get the numeric uid of the process which owns the given bus name
309 on the connected bus daemon.
312 `named_service` : str
313 A bus name (may be either a unique name or a well-known name)
315 return _dbus_bindings
.bus_get_unix_user(self
._connection
, named_service
)
317 def _signal_func(self
, connection
, message
):
318 if (message
.get_type() != _dbus_bindings
.MESSAGE_TYPE_SIGNAL
):
319 return _dbus_bindings
.HANDLER_RESULT_NOT_YET_HANDLED
321 dbus_interface
= message
.get_interface()
322 named_service
= message
.get_sender()
323 path
= message
.get_path()
324 signal_name
= message
.get_member()
326 match_rule
= SignalMatchRule(signal_name
, dbus_interface
, named_service
, path
)
328 self
._match
_rule
_tree
.exec_matches(match_rule
, message
)
330 def start_service_by_name(self
, named_service
):
331 """Start a service which will implement the given bus name on this
335 `named_service` : str
336 The well-known bus name for which an implementation is required
338 :Returns: A tuple of 2 elements. The first is always True, the second is
339 either START_REPLY_SUCCESS or START_REPLY_ALREADY_RUNNING.
341 :Raises DBusException: if the service could not be started.
343 return _dbus_bindings
.bus_start_service_by_name(self
._connection
, named_service
)
346 if self
._bus
_type
== self
.TYPE_SESSION
:
348 elif self
._bus
_type
== self
.TYPE_SYSTEM
:
350 elif self
._bus
_type
== self
.TYPE_STARTER
:
353 assert False, 'Unable to represent unknown bus type.'
355 return '<dbus.Bus on %s at %#x>' % (name
, id(self
))
359 # FIXME: Drop the subclasses here? I can't think why we'd ever want
361 class SystemBus(Bus
):
362 """The system-wide message bus."""
363 def __new__(cls
, use_default_mainloop
=True, private
=False):
364 """Return a connection to the system bus.
367 `use_default_mainloop` : bool
368 If true (default), automatically register the new connection
369 to be polled by the default main loop, if any
371 If true, never return an existing shared instance, but instead
372 return a private connection.
374 return Bus
.__new
__(cls
, Bus
.TYPE_SYSTEM
, use_default_mainloop
, private
)
376 class SessionBus(Bus
):
377 """The session (current login) message bus."""
378 def __new__(cls
, use_default_mainloop
=True, private
=False):
379 """Return a connection to the session bus.
382 `use_default_mainloop` : bool
383 If true (default), automatically register the new connection
384 to be polled by the default main loop, if any
386 If true, never return an existing shared instance, but instead
387 return a private connection.
389 return Bus
.__new
__(cls
, Bus
.TYPE_SESSION
, use_default_mainloop
, private
)
391 class StarterBus(Bus
):
392 """The bus that activated this process (only valid if
393 this process was launched by DBus activation).
395 def __new__(cls
, use_default_mainloop
=True, private
=False):
396 """Return a connection to the bus that activated this process.
399 `use_default_mainloop` : bool
400 If true (default), automatically register the new connection
401 to be polled by the default main loop, if any
403 If true, never return an existing shared instance, but instead
404 return a private connection.
406 return Bus
.__new
__(cls
, Bus
.TYPE_STARTER
, use_default_mainloop
, private
)
409 """An interface into a remote object.
411 An Interface can be used to wrap ProxyObjects
412 so that calls can be routed to their correct
416 def __init__(self
, object, dbus_interface
):
417 """Construct a proxy for the given interface on the given object.
420 `object` : `dbus.proxies.ProxyObject`
422 `dbus_interface` : str
423 An interface the `object` implements
426 self
._dbus
_interface
= dbus_interface
428 def connect_to_signal(self
, signal_name
, handler_function
, dbus_interface
= None, **keywords
):
429 """Arrange for a function to be called when the given signal is
434 The name of the signal
435 `handler_function` : callable
436 A function to be called (FIXME arguments?) when the signal
437 is emitted by the remote object.
438 `dbus_interface` : str
439 Optional interface with which to qualify the signal name.
440 The default is to use the interface this Interface represents.
441 `sender_keyword` : str
442 If not None (the default), the handler function will receive
443 the unique name of the sending endpoint as a keyword
444 argument with this name
446 If not None (the default), the handler function will receive
447 the object-path of the sending object as a keyword argument
450 If there are additional keyword parameters of the form
451 ``arg``\ *n*, match only signals where the *n*\ th argument
452 is the value given for that keyword parameter
454 if not dbus_interface
:
455 dbus_interface
= self
._dbus
_interface
457 self
._obj
.connect_to_signal(signal_name
, handler_function
, dbus_interface
, **keywords
)
459 def __getattr__(self
, member
, **keywords
):
460 # FIXME: this syntax is bizarre.
461 if (keywords
.has_key('dbus_interface')):
462 _dbus_interface
= keywords
['dbus_interface']
464 _dbus_interface
= self
._dbus
_interface
466 if member
== '__call__':
467 return object.__call
__
469 ret
= self
._obj
.__getattr
__(member
, dbus_interface
=_dbus_interface
)
473 return '<Interface %r implementing %r at %#x>'%(
474 self
._obj
, self
._dbus
_interface
, id(self
))