Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 24, 2025

Plan: Add free-threading support to numpy_quaternion

  • Explore repository structure and understand the codebase
  • Build and test the package to verify current state
  • Add GIL-disabled support to src/numpy_quaternion.c
    • Add #ifdef Py_GIL_DISABLED guard with PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED) after module creation NULL check in PyInit_numpy_quaternion
  • Update .github/workflows/build.yml to enable free-threaded builds
    • Add CIBW_ENABLE: "cpython-freethreading" to build_wheels job env block
  • Verify changes build and tests still pass
  • Run code review
  • Run CodeQL security checks
  • Complete PR with summary and follow-up checklist

This will mark the extension as safe for free-threaded CPython builds and enable cibuildwheel to build free-threaded wheels.

Original prompt

Summary

Make the numpy_quaternion C extension explicitly declare itself safe for free-threaded CPython builds and update CI so cibuildwheel builds free-threaded wheels.

Why

  • On free-threaded CPython (GIL disabled), C extensions must explicitly indicate they do not need the GIL. Without that, importing the extension will cause the runtime to re-enable the GIL and print a warning.
  • The extension in this repo uses single-phase initialization (PyModule_Create in PyInit_numpy_quaternion). The recommended change is to call PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED) guarded by #ifdef Py_GIL_DISABLED.
  • The repo uses cibuildwheel in GitHub Actions; enabling free-threaded wheel builds requires adding CIBW_ENABLE=cpython-freethreading to the build_wheels job environment.

Changes to make (explicit)

  1. src/numpy_quaternion.c
  • Insert the following guarded call immediately after the module object is created and its NULL-check in PyInit_numpy_quaternion (the existing code does module = PyModule_Create(&moduledef); then if (module==NULL) { INITERROR; }). Add the snippet right after that check:

#ifdef Py_GIL_DISABLED
/* Indicate this extension does NOT require the GIL in free-threaded builds. */
PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED);
#endif

  • No other functional changes to this file. Keep the guard so the code still compiles on regular (GIL-enabled) builds.
  1. .github/workflows/build.yml
  • In the build_wheels job, add CIBW_ENABLE: "cpython-freethreading" to the env block so cibuildwheel will build free-threaded wheels where supported.

Additional notes (for reviewers / follow-ups)

  • This PR only marks the extension as GIL-optional. A runtime claim of safety requires the code to actually be thread-safe. I reviewed the repository and noted these places that may need follow-up work:
    • pyquaternion_get_vec and pyquaternion_get_components return numpy arrays that directly point to fields inside a PyQuaternion instance. Returning such views could be unsafe if another thread concurrently mutates the quaternion. Consider returning copies or document requiring synchronization, or use critical-section macros.
    • Audit for borrowed-reference usage (PyList_GetItem, PyDict_GetItem, PyDict_Next, PyCell_GET, PyWeakref_GetObject, etc.) and replace with strong-reference variants or guard with critical sections where necessary.
    • Ensure PyObject_Malloc is not used for non-Python-object buffers (use PyMem_* for buffers) and avoid direct struct-field access to Python internals without protection.
    • The free-threaded build currently does not support the limited C API / stable ABI. Ensure packaging does not publish py_limited_api wheels for free-threaded interpreters (if applicable).

What to include in PR

  • One commit on a feature branch named feat/freethreading-support with the two file edits described above.
  • PR description summarizing both code insertion and CI change, and a short checklist of follow-up auditing items (views into extension memory, borrowed refs, allocators).

Testing

  • Run CI and confirm cibuildwheel produces free-threaded wheels (they’ll have the "t" marker). Confirm import in a free-threaded interpreter does not re-enable the GIL with a warning.
  • Run unit tests under free-threaded wheels or on a free-threaded Python build and run concurrency-focused tests.

Please create the branch, apply the changes, and open a pull request against main with the title:

"Mark numpy_quaternion as free-threading safe and enable cibuildwheel free-threaded builds"

Include the PR body with a short summary of the change, the two files modified, and the follow-up checklist.

Repository: moble/quaternion

This pull request was created as a result of the following prompt from Copilot chat.

Summary

Make the numpy_quaternion C extension explicitly declare itself safe for free-threaded CPython builds and update CI so cibuildwheel builds free-threaded wheels.

Why

  • On free-threaded CPython (GIL disabled), C extensions must explicitly indicate they do not need the GIL. Without that, importing the extension will cause the runtime to re-enable the GIL and print a warning.
  • The extension in this repo uses single-phase initialization (PyModule_Create in PyInit_numpy_quaternion). The recommended change is to call PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED) guarded by #ifdef Py_GIL_DISABLED.
  • The repo uses cibuildwheel in GitHub Actions; enabling free-threaded wheel builds requires adding CIBW_ENABLE=cpython-freethreading to the build_wheels job environment.

Changes to make (explicit)

  1. src/numpy_quaternion.c
  • Insert the following guarded call immediately after the module object is created and its NULL-check in PyInit_numpy_quaternion (the existing code does module = PyModule_Create(&moduledef); then if (module==NULL) { INITERROR; }). Add the snippet right after that check:

#ifdef Py_GIL_DISABLED
/* Indicate this extension does NOT require the GIL in free-threaded builds. */
PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED);
#endif

  • No other functional changes to this file. Keep the guard so the code still compiles on regular (GIL-enabled) builds.
  1. .github/workflows/build.yml
  • In the build_wheels job, add CIBW_ENABLE: "cpython-freethreading" to the env block so cibuildwheel will build free-threaded wheels where supported.

Additional notes (for reviewers / follow-ups)

  • This PR only marks the extension as GIL-optional. A runtime claim of safety requires the code to actually be thread-safe. I reviewed the repository and noted these places that may need follow-up work:
    • pyquaternion_get_vec and pyquaternion_get_components return numpy arrays that directly point to fields inside a PyQuaternion instance. Returning such views could be unsafe if another thread concurrently mutates the quaternion. Consider returning copies or document requiring synchronization, or use critical-section macros.
    • Audit for borrowed-reference usage (PyList_GetItem, PyDict_GetItem, PyDict_Next, PyCell_GET, PyWeakref_GetObject, etc.) and replace with strong-reference variants or guard with critical sections where necessary.
    • Ensure PyObject_Malloc is not used for non-Python-object buffers (use PyMem_* for buffers) and avoid direct struct-field access to Python internals without protection.
    • The free-threaded build currently does not support the limited C API / stable ABI. Ensure packaging does not publish py_limited_api wheels for free-threaded interpreters (if applicable).

What to include in PR

  • One commit on a feature branch named feat/freethreading-support with the two file edits described above.
  • PR description summarizing both code insertion and CI change, and a short checklist of follow-up auditing items (views into extension memory, borrowed refs, allocators).

Testing

  • Run CI and confirm cibuildwheel produces free-threaded wheels (they’ll have the "t" marker). Confirm import in a free-threaded interpreter does not re-enable the GIL with a warning.
  • Run unit tests under free-threaded wheels or on a free-threaded Python build and run concurrency-focused tests.

Please create the branch, apply the changes, and open a pull request against main with the title:

"Mark numpy_quaternion as free-threading safe and enable cibuildwheel free-threaded builds"

Include the PR body with a short summary of the change, the two files modified, and the follow-up checklist.

Repository: moble/quaternion


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants