Plans for Sub-interpreters and Free Threading

Phil Thompson phil at riverbankcomputing.com
Wed Sep 10 16:39:09 BST 2025


I wanted to give a heads up about plans for adding support for 
sub-interpreters and free threading for SIP (and consequently PyQt). For 
the moment this is targeted at Python v3.15 due in about a year's time.

A little background...

SIP generates a Python extension module that implements bindings for a 
library. It also generates a sip extension module that is automatically 
imported by all generated extension modules. Its purpose is to 
coordinate certain resources between extension modules and to present a 
higher-level ABI (compared to the Python ABI) to those extension 
modules. In particular it allows extension modules to be written to 
Python's Stable ABI which means that extension modules built for one 
version of Python will run with any later version. When a new Python 
version is released it is only necessary to build the latest version of 
the sip module for it. Existing wheels continue to work. This is 
extremely important - at the moment a new release of Qt triggers the 
release of 40 PyQt-related wheels (8 projects supporting 5 platforms). 
Having to do this for all currently supported Python versions would mean 
200 wheels.

The sip ABI uses semantic versioning and two major versions are 
currently supported: v12 (used by PyQt5) and v13 (used by PyQt6). 
Introducing a new major version allows significant changes to be made 
without affecting the stability of existing packages. When v13 was 
introduced it was assumed that v12 would eventually be deprecated and 
removed (and consequently PyQt5 would no longer be supported). However 
new PyQt5 applications continue to be written and there are no plans to 
stop supporting it (to the extent that it is planned to add 
sub-interpreter and free threading support).

Another important thing about SIP is its age. It was originally written 
in 1998 for Python v1.5.1 and elements of the design and implementation 
of the sip module still reflect that. (Whereas the SIP code generator 
has been completely rewritten in recent years.) For example, modules use 
single-phase initialisation (multi-phase was added to Python v3.5) and 
the core wrapper types are defined statically (PyType_Spec was added to 
Python v3.2). These "new" features haven't offered anything particularly 
useful and (until recently) were not a pre-requisite for anything.

That all changes if sub-interpreters or free threading are to be 
supported. In the context of SIP, support for sub-interpreters is more 
important than free threading. This is because the changes needed for 
sub-interpreters are a subset of those needed for free threading and are 
better documented and understood. The work needed is effectively a 
re-write of the sip module and will be implemented as v14 of the sip 
ABI. However v14 won't be "officially" released until free threading is 
also supported. v14 will behave like v12 when so configured and v13 when 
so configured.

As mentioned, the target for v14 will be Python v3.15. This is because 
Python's Stable ABI will not support free threading until then (at the 
earliest) and PyQt will continue to use the Stable ABI (for practical 
rather than technical reasons). At that point releases of PyQt5 and 
PyQt6 will be made that use sip ABI v14 (and therefore support 
sub-interpreters and free threading). I think it's unreasonable to 
impose the churn of so much new code on existing applications who have 
no use of the new features so releases of PyQt using the older sip ABIs 
will continue to be made until Python v3.16 (October 2027) at the 
earliest. Exactly how this will work isn't clear at the moment - it 
depends on how current discussions around new wheel tags and their 
meanings go. After sip ABI v14 is deemed to be sufficiently mature (ie. 
by late 2027), support for older ABIs will be dropped completely. The 
period between v14 being released and it being deemed to be sufficiently 
mature will be at least 1 year.

The current state is that the sub-interpreter support is designed and 
about two-thirds implemented and tested. (In a nutshell, all static 
variables have been removed and all static data structures are now 
immutable.) The new code will be moved to the repo on GitHub when it is 
more stable.

Phil


More information about the PyQt mailing list