Firstly it might happen by accident. I was briefly building python-flint wheels like this in CI and could have easily pushed the trigger to upload them to PyPI but decided not to distribute them yet. (Probably I would have done at least a bit of local testing if I was actually going to distribute them.)
Secondly, it is not about the “effort” of marking the module with Py_MOD_GIL_NOT_USED
. The purpose of Py_MOD_GIL_NOT_USED
is to distinguish whether or not the package actually is thread-safe without the GIL. Packages that are not will build but then not set the flag. The “effort” is making the package thread-safe which is many orders of magnitude harder than just setting a build flag and might even be structurally impossible for some packages.
Thirdly, people are going to want to install packages into a free-threaded build regardless of whether importing them disables free-threading. You can install my GIL-using extension modules into your free-threading build and use them sometimes but otherwise not:
# (hypothetically) uses GIL:
python my_script_using_python_flint.py
# benefits from free-threading:
python my_other_script.py
Note that it makes total sense to do this for another reason: python-flint already uses threads internally without any GIL so it can already give you that benefit if you just tell it how many threads to use:
from flint import ctx
ctx.threads = 10
# From here any python-flint operation can use
# up to 10 threads. This is done transparently
# without the user needing to manage threads.
Apparently I haven’t tested it properly yet so in principle it might be difficult for python-flint to run safely without the GIL. Hypothetically setting Py_MOD_GIL_NOT_USED
might mean that import flint
explodes your computer in a mushroom cloud of segfaults. If that is the case then there will certainly be no point in uploading extension modules marked with Py_MOD_GIL_NOT_USED
.
Hypothetically it might be so difficult to fix the thread-safety issues that it would be years before the Py_MOD_GIL_NOT_USED
flag could be set. There will however be people who will want to use python-flint with their free-threaded build of CPython regardless of whether it brings the GIL back on a per-process basis. Those people would say:
Why don’t you upload cp313t wheels without setting Py_MOD_GIL_NOT_USED
? We don’t mind if python-flint uses the GIL but we have free-threaded builds for other reasons and yet we still want to use python-flint sometimes.
If it seems odd to you that people will want that then remember that if you are like me and just spin up Python versions via pyenv any time you feel like then you are in a small minority of the overall Python userbase. I can happily switch between a free-threaded and a non-free-threaded Python any time I like but most Python users want to have one installation of Python.
As soon as Python 3.13 is released thousands upon thousands of people are going to download the Windows and MacOS installers and tick the “free-threading please” button. Those people are going to be very disappointed when they find that none of their favourite packages are available.
So yes, there may well be packages that upload wheels matching the free-threading ABI but that do not set the Py_MOD_GIL_NOT_USED
flag so that the GIL is then disabled at runtime. There are valid reasons why the flag cannot be set and there are also valid reasons to want to install a package that does not set the flag.
The warning about enabling the GIL that is printed now is useful while free-threading is considered experimental but longer term (e.g. Python 3.14) will likely need to be removed if the expectation is that users will use the free-threading build by default.
For clarification given my comments about python-flint I don’t expect that any of this applies in python-flint’s case. I think that the situation is going to be that there are some less often used operations that are not thread-safe and I am just going to document as such:
python-flint is thread-safe in a free-threaded build provided that you never mutate an object that is shared between multiple threads. Very few operations mutate objects so a complete list is …
That approach will work for python-flint because the unsafe operations are ones that most people will not use anyway. It means that we will upload wheels with the cp313t
ABI and Py_MOD_GIL_NOT_USED
flag set. If you happen to mutate a polynomial that is shared between threads then you may get a segfault or other corrupted data. If I was going to improve on this then I would firstly consider just making all objects immutable (basically deprecate non-thread-safe features).