PyGObject Migration Guide
pangocffi (and pangocairocffi) can be replaced by PyGObject, but there are several dependencies and API calls that need to be changed. The migration is worthwhile because PyGObject’s bindings are more complete than pangocffi’s, and it’s also maintained by more people. However there are a few drawbacks, like needing to replace cairocffi with Pycairo, which not everyone will be able to do.
pangocffi can continue to be used in the short term, but if it breaks in future versions of Python, cairocffi, and cffi, the project will have to be forked and fixed. In such an event, the LGPL 2.1 license must be respected.
This guide covers various details for switching to PyGObject, including:
Replacing system dependencies
Replacing Python packages
Replacing usages of cairocffi with Pycairo
Switching usages of pangocffi and pangocairocffi’s API to PyGObject
An example using PyGObject
Replacing System Dependencies
Which system dependencies to install will differ between Linux, macOS, Windows, etc.
To give some general guidance, here’s a before and after of the system dependencies specifically for Debian Trixie. Other systems might have different names for these dependencies.
Before the migration, pangocffi and pangocairocffi required these dependencies:
libcairo2libpango-1.0-0libpangocairo-1.0-0
To use Pango and PangoCairo with PyGObject, install these dependencies:
pkg-configlibcairo2-devlibpango1.0-devlibpangocairo-1.0-0libgirepository-2.0-dev
The -dev suffix is important because these will include bindings that PyGObject will use to interface with Pango and PangoCairo.
If the libraries above don’t work, see Getting Started with Pycairo and Getting Started with PyGObject for guidance on which additional libraries to install. Note that PyGObject’s guide might include extra dependencies that are irrelevant for using Pango and Pangocairo.
Replacing Python Packages
Before the migration, these were the Python packages necessary:
pip install cairocffi
pip install pangocffi
pip install pangocairocffi
After the migration, these are now packages to install instead:
pip install pycairo
pip install pygobject
pip install pygobject-stubs # Optional for type-hinting
Switching from cairocffi to Pycairo
cairocffi does not appear to work with PyGObject, but Pycairo does. Therefore cairocffi must be replaced with Pycairo.
cairocffi is meant to be a drop-in replacement for Pycairo, so it should be a matter of changing the import in a lot of places from one package to another:
# Before
import cairocffi as cairo
from cairocffi import ImageSurface
# After
import cairo
from cairo import ImageSurface
Type hinting also changes subtly:
# Before
my_function(
surface: cairo.surfaces.Surface,
context: cairo.context.Context
) -> None
# After
my_function(
surface: cairo.Surface,
context: cairo.Context
) -> None
There are some inconsistencies between cairocffi and PyCairo, so make sure to review the code for errors. For example, in Pycairo, matrices cannot be copied using .copy():
# Before, cairocffi.Matrix has a copy method
new_matrix = old_matrix.copy()
# After, Pycairo requires an explicit initialisation of a new Matrix
new_matrix = cairo.Matrix(
old_matrix.xx,
old_matrix.yx,
old_matrix.xy,
old_matrix.yy,
old_matrix.x0,
old_matrix.y0,
)
Switching from pangocffi and pangocairocffi’s API to PyGObject
There are a few differences between pangocffi’s and PyGObject’s implementation of API methods. Below are a few examples:
Imports
pangocffi was imported with:
import pangocffi
import pangocairocffi
PyGObject instead requires:
import gi
gi.require_version("Pango", "1.0")
gi.require_version("PangoCairo", "1.0")
from gi.repository import Pango # noqa: E402
from gi.repository import PangoCairo # noqa: E402
Getters and setters
pangocffi uses the property decorator pattern for implementing getter and setter methods:
my_width = layout.width
layout.width = 123
PyGObject however uses plain get_x and set_x for getter and setter methods:
my_width = layout.get_width()
layout.set_width(123)
Using Layout Markup
pangocffi’s Layout object has a method called apply_markup(...).
PyGObject calls the method set_markup(...) instead.
PyGObject API reference
There are likely many more differences not listed here. See the GNOME Python API for Pango and PangoCairo for more details on additional methods. For other GNOME libraries, see the GNOME Python API documentation.
Example
In case there are any installation issues, a functioning example has been created to use as a reference. The example runs in a in a Debian environment using Docker. This can be useful for troubleshooting any unexpected migration issues when switching from pangocffi to PyGObject.