Introspection
Network Manager
Create a Service
GObject Introspection
In previous posts, I have looked at using the python-dbus to communicate with other processes, essentially using it the same way we use the dbus-send command.
There is another way to create DBus messages. It's a bit more complicated than python-dbus, and it depends upon Gnome, but it's also more robust and perhaps better maintained.
Using Gobject Introspection replacement for python-dbus is described several places, but the best example is here. Python-dbus as a separate bindings project has also suffered with complaints of "lightly maintained," and an awkward method of exposing properties that has been unfixed for years.
These examples only work for clients. Gnome Bug #656330 shows that services cannot yet use PyGI.
Here's an example notification using Pygi instead of Python-DBus. It's based on this blog post by Martin Pitt, but expanded a bit to show all the variables I can figure out....
1) Header and load gi
#!/usr/bin/env python3 import gi.repository from gi.repository import Gio, GLib
2) Connect to the DBus Session Bus
Documentation: http://developer.gnome.org/gio/2.29/GDBusConnection.html
session_bus = Gio.BusType.SESSION cancellable = None connection = Gio.bus_get_sync(session_bus, cancellable)
3) Create (but don't send) the DBus message header
Documentation: http://developer.gnome.org/gio/2.29/GDBusProxy.html
proxy_property = 0 interface_properties_array = None destination = 'org.freedesktop.Notifications' path = '/org/freedesktop/Notifications' interface = destination notify = Gio.DBusProxy.new_sync( connection, proxy_property, interface_properties_array, destination, path, interface, cancellable)
4) Create (but don't send) the DBus message data
The order is determined by arg order of the Notification system
Documentation: http://developer.gnome.org/notification-spec/#protocol
application_name = 'test' title = 'Hello World!' body_text = 'Subtext' id_num_to_replace = 0 actions_list = [] hints_dict = {} display_milliseconds = 5000 icon = 'gtk-ok' # Can use full path, too '/usr/share/icons/Humanity/actions/' args = GLib.Variant('(susssasa{sv}i)', ( application_name, id_num_to_replace, icon, title, body_text, actions_list, hints_dict, display_milliseconds))
5) Send the DBus message header and data to the notification service
Documentation: http://developer.gnome.org/gio/2.29/GDBusProxy.html
method = 'Notify' timeout = -1 result = notify.call_sync(method, args, proxy_property, timeout, cancellable)
6) (Optional) Convert the result value from a Uint32 to a python integer
id = result.unpack()[0] print(id)
Play with it a bit, and you will quickly see how the pieces work together.
Here is a different, original example DBus client using introspection and this askubuntu question. You can see this is a modified and simplified version of the above example:
#!/usr/bin/env python3 import gi.repository from gi.repository import Gio, GLib # Create the DBus message destination = 'org.freedesktop.NetworkManager' path = '/org/freedesktop/NetworkManager' interface = 'org.freedesktop.DBus.Introspectable' method = 'Introspect' args = None answer_fmt = GLib.VariantType.new ('(v)') proxy_prpty = Gio.DBusCallFlags.NONE timeout = -1 cancellable = None # Connect to DBus, send the DBus message, and receive the reply bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) reply = bus.call_sync(destination, path, interface, method, args, answer_fmt, proxy_prpty, timeout, cancellable) # Convert the result value to a formatted python element print(reply.unpack()[0])
Here is a final DBus client example, getting the properties of the current Network Manager connection
#!/usr/bin/env python3 import gi.repository from gi.repository import Gio, GLib # Create the DBus message destination = 'org.freedesktop.NetworkManager' path = '/org/freedesktop/NetworkManager/ActiveConnection/19' interface = 'org.freedesktop.DBus.Properties' method = 'GetAll' args = GLib.Variant('(ss)', ('org.freedesktop.NetworkManager.Connection.Active', 'None')) answer_fmt = GLib.VariantType.new ('(v)') proxy_prpty = Gio.DBusCallFlags.NONE timeout = -1 cancellable = None # Connect to DBus, send the DBus message, and receive the reply bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) reply = bus.call_sync(destination, path, interface, method, args, answer_fmt, proxy_prpty, timeout, cancellable) # Convert the result value to a useful python object and print [print(item[0], item[1]) for item in result.unpack()[0].items()]
As you can see from this example, dbus communication is actually pretty easy using GLib: Assign the nine variables, turn the crank, and unpack the result.