From 5be0cfdac0356ceb2cafc8d6aa5dbac71bf7c3c9 Mon Sep 17 00:00:00 2001 From: HugoFara Date: Tue, 11 Aug 2026 13:54:29 +0200 Subject: [PATCH] fix(packaging): stop shipping free-threaded wheels, declare 3.14 v2.5.0 published cp314t wheels. Those advertise free-threading, but _pyforefire declares no py::mod_gil_not_used(), so importing it makes the interpreter re-enable the GIL: the wheel promises something it then turns off. The core could not honour the promise anyway. There is not one mutex, atomic or lock guard in src/. SimulationParameters::GetInstance() is an unguarded lazy singleton, ForeFireAtom::instanceNRCount hands out object IDs through a non-atomic ++, FireDomain::propModelsTable is a process-wide array of 50 slots mutated at runtime, and FireNode keeps its scheme and smoothing settings in mutable statics. The binding never releases the GIL, which is what keeps all of this safe today. Also adds the 3.14 classifier, since non-free-threaded cp314 wheels do build and pass CI. --- pyproject.toml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e39015f..be4350e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering", "Operating System :: POSIX :: Linux", "Operating System :: MacOS :: MacOS X", @@ -82,7 +83,13 @@ regex = '''ff_version\s*=\s*"v?(?P\d+\.\d+\.\d+)"''' [tool.cibuildwheel] # 32-bit and musl targets have no usable NetCDF C++4 story, and PyPy cannot # load the pybind11 module built here. -skip = ["pp*", "*-musllinux_*", "*_i686", "*-win32"] +# cp314t is the free-threaded build. An extension that does not declare +# `py::mod_gil_not_used()` makes the interpreter re-enable the GIL on import, +# so such a wheel advertises free-threading while silently switching it off. +# _pyforefire makes no such declaration, and the C++ core keeps mutable global +# state (see FireDomain's model registries and SimulationParameters), so it is +# not safe to run without the GIL. Revisit only once that is addressed. +skip = ["pp*", "*-musllinux_*", "*_i686", "*-win32", "cp314t-*"] test-command = [ "python {project}/tests/python/test_wheel.py", "forefire -v",