Tim Richardson
Tim Richardson

Reputation: 7251

How to choose and use a python3 dbus library to replace a dbus-send call

Using ubuntu 20.10

I want to write a python script to process the output of this shell command:

dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.GetInhibitors

I don't know anything about coding dbus. The first place to start was I hoped a good python library.

I learn this about the apparently canonical library: "dbus-python is a legacy API, built with a deprecated dbus-glib library, and involving a lot of type-guessing (despite "explicit is better than implicit" and "resist the temptation to guess") (from https://wiki.python.org/moin/DbusExamples)

The library https://pypi.org/project/dbus-next/ promises a pure python implementation: "Zero dependencies and pure Python 3." It is not mentioned on the wiki page mentioned above, but it looks like a healthy project. However it seems that the pure python approach requires me to use the asyncio version. I think this is overkill for my needs.

I tried using dasbus but I can't install the necessary libraries, at least not in a virtual env. Despite installing the system package python3-gi, I get errors "no module named gi" and trying to install PyGObject fails because "no package 'cairo' found" ... and ERROR: failed building wheel for pycairo.

So at this point, I have a library which is old and not recommended, a library with dependency difficulties and a library which seems to force me to use asyncio.

I now understand why the php script I am trying to re-write in python executed a shell command and dealt with the ugly output.

On top of that, I think I have worked out these points:

I need the SessionBus

The "path" is "/org/gnome/SessionManager" The "interface" is org.gnome.SessionManager I want to "call" the "member" GetInhibitors

I find async a bit of overkill since this is a shell script but if this is only way I can avoid a C dependency, I will deal with it.

Which library should I use?

Upvotes: 4

Views: 4403

Answers (2)

Niko Fohr
Niko Fohr

Reputation: 34018

First, how to do what you wanted with two popular easy-to-install python-only MIT licenced packages

jeepney

Here's how you could use jeepney for the task:

from jeepney import DBusAddress, new_method_call
from jeepney.io.blocking import open_dbus_connection

proxy = DBusAddress('/org/gnome/SessionManager',
                            bus_name='org.gnome.SessionManager',
                            interface='org.gnome.SessionManager')

connection = open_dbus_connection(bus='SESSION')

msg = new_method_call(proxy, 'GetInhibitors')

reply = connection.send_and_get_reply(msg)
print(reply.body[0])

dbus-next

And here is how the same could be done in dbus-next. I'm not an expert on the asyncio stuff, but this seems to work even if your code is non-async (synchronous):

import asyncio
from dbus_next.aio import MessageBus
from dbus_next.message import Message

async def main():
    bus = await MessageBus().connect()
    msg = Message(destination='org.gnome.SessionManager',
        path='/org/gnome/SessionManager',
        interface='org.gnome.SessionManager',
        member='GetInhibitors')
    return await bus.call(msg)
    

reply = asyncio.run(main())
print(reply.body[0])

What are all my options?

There are plenty of options. Some of them are easy to install, and some are not.

Packages which are "hard" to install

I tested installability by running python -m pip install <packagename> inside a fresh virtual environment, inside a fresh Ubuntu 22.04 installation. These packages did not install (as they have additional dependencies):

  • dbus-python which relies on the original dbus implementation and libdbus.
  • pydbus, which relies on PyGObject (aka. PyGI with import name gi). Installs, but raises Exceptions on runtime for missing gi module.
  • dasbus, which relies on PyGObject, and is basically continuation of (the abandoned) pydbus project. Installs, but raises Exceptions on runtime for missing gi module.
  • pystemd which provides Cython wrappers for libsystemd.

Packages which are easy to install

  • jeepney, which is pure python, zero dependency implementation using the socket standard library module. It is also MIT licenced. (docs)
  • dbus-next (which you found already), is an another pure python, zero dependency implementation using the socket standard library module. That is, when you use the MessageBus from the async dbus_next.aio subpackage (The MessageBus in the dbus_next.glib part requires PyGObject). Dbus-next is MIT licenced. (docs)
  • sdbus which relies on libsystemd. This is not pure python but had some C-files in the repo. Not sure if the install will always be painless :) It's licenced under LGPL-2.1 & GPL-2.0.
  • dbussy much smaller project which is basically ctypes wrapper around libdbus-1.so.3 (and it requires that to be available on the system). This shared library is basically part of every system running dbus-daemon (and using dbus). Some dislike libdbus (threading problems? at least the Internet says so). LGPL-2.1 licenced.
  • pysdbus a tiny project, like dbussy, but depends on availability of the shared library libsystemd.so.0 on the system. That should be available in any system running systemd (which makes most of the popular distros). LGPL-2.1 licenced.

Out of these, current days the

  • jeepney has about 850000 downloads / day
  • dbus-next about 1250 downloads / day
  • sdbus about 100 downloads / day
  • dbussy 20 / day

and pysdbus is not listed in PyPI. So jeepney really seems to be most popular choice, perhaps because of easy installation. It is not optimized for speed, though. Having said that, the above code examples, when ran multiple times, take roughly 2 ms with jeepney and 3 ms with dbus-next.


  • There's also txdbus which is really only for usage with twisted (it even installs twisted as dependency).
  • Also perhaps worth mentioning that a Ubuntu 22.04 installation comes with jeepney, dbus (python-dbus) and gi (PyGObject) installed. That does not help with virtual environments, or projects that are supposed to be installed as dependencies (inside venv), though.

Upvotes: 6

ukBaz
ukBaz

Reputation: 8014

pydbus is a very capable library that allows me to build things quickly and simply although the repo isn't necessarily that active.

I've only used dbus-next library a few times and it does have various *_sync methods if you don't want to do things asynchronously.

Upvotes: 1

Related Questions