Using GSettings with Python/PyGObject

This morning I began tinkering with GSettings in Python, the new configuration settings API used in GNOME 3 (replaced GConf). I am using PyGObject, the new GLib/GObject/GIO bindings (replaced PyGTK). Here is the example program I used to get my feet wet along with a short tutorial.

Keep in mind that I've been tinkering with the GSettings API for all of a few hours. Please feel free to comment on this post if I have provided incorrect information.

GSettings in a Nutshell

For those who aren't familiar with GConf, GSettings is high-level API for application settings. Where and how the actual data is stored is dependent upon the platform (dconf in GNOME 3, the registery in Windows, etc). In other words, an application does not need to know where or how the data is stored, just how to access that data and recieve a notification if and when the data changes.

If this is all news to you, take some time to explore the various application settings on your system using the dconf-editor command.

The GSettings API Documentation

Like the rest of the PyGObject modules, the GSettings C API is used as the reference documentation for Python. Simply follow the guidelines set forth in the Introspection Porting page to understand how the C API translates to Python.

Create a GSettings Schema

The first step is to create a schema to define the application's configuration settings. An XML format file is compiled into a compact, binary form for GSettings. You can read about the details under the "Description" section of the GSettings API. If you favor learning by example, read on...

The XML schema file must have a .gschema.xml file extension. My example program, called gsettings-example-py, uses the following XML schema.

apps.gsettings-example-py.gschema.xml

<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
  <schema id="apps.gsettings-example-py" path="/apps/gsettings-example-py/">
    <key type="b" name="my-setting">
      <default>false</default>
      <summary>My boolean setting</summary>
      <description>This is an example of a boolean setting.</description>
    </key>
  </schema>
</schemalist>

See more example schemas from other applications in your /usr/share/glib-2.0/schemas/ directory and refer to the XML schema description in the GSettings API.

In order for GSettings to use the application's schema, it must be copied to the /usr/share/glib-2.0/schemas/ directory and then that directory should be compiled by glib-compile-schemas.

(as root)

cp apps.gsettings-example-py.gschema.xml /usr/share/glib-2.0/schemas/
glib-compile-schemas /usr/share/glib-2.0/schemas/

After the schema for the application has been compiled it should show up in the dconf-editor as shown below.

So there it is. Keep the Configuration Editor open so you can see how settings are kept in sync between applications in the next section.

Python Code

The Python code consists of a Gtk.Window with a single Gtk.CheckBox packed into it. The Gio.Settings object provides the interface with GSettings.

The application changes the my-setting setting in the callback for the check button's "toggled" signal. When that happens the change should also be reflected in the Configuration Editor (you need to give the Configuration Editor focus to see the change).

The application also connected a callback on the "changed::my-setting" signal to update the check button when the my-setting setting is changed outside of the application. In other words, if the setting is changed using the Configuration Editor, the change is mirrored in the application.

from gi.repository import Gio, Gtk

class App(object):
    BASE_KEY = "apps.gsettings-example-py"
    def __init__(self):
        # setup a check button and associate it with a GSettings key
        settings = Gio.Settings.new(self.BASE_KEY)
        check_button = Gtk.CheckButton("This is my boolean setting")
        check_button.set_active(settings.get_boolean("my-setting"))
        settings.connect("changed::my-setting", self.on_my_setting_changed, check_button)
        check_button.connect('toggled', self.on_check_button_toggled, settings)
        
        # main window
        window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL)
        window.set_title('GSettings Example')
        window.set_border_width(24)
        window.connect_after('destroy', self.on_window_destroy)
        window.add(check_button)
        window.show_all()
        Gtk.main()
    
    def on_my_setting_changed(self, settings, key, check_button):
        check_button.set_active(settings.get_boolean("my-setting"))
        
    def on_check_button_toggled(self, button, settings):
        settings.set_boolean("my-setting", button.get_active())
                                  
    def on_window_destroy(self, widget, data=None):
        Gtk.main_quit()

if __name__ == "__main__":
    app = App()