There are newly documented restrictions on tp_traverse: gh-123241: Document restrictions for `tp_traverse` implementations by colesbury · Pull Request #142272 · python/cpython · GitHub
The traversal function must not have any side effects. It must not modify the reference counts of any Python objects nor create or destroy any Python objects.
This primarily means you can’t use functions that return new references, or ones that raise (new) exceptions. (Basically, the kind of functions we’re trying to add nowadays.)
But you also can’t use any C API function, unless it guarantees that it has no side effects. I don’t think we guarantee that for anything.
You typically don’t need to do much in tp_traverse. But, both current PEPs for a free-threading stable ABI (PEP 803 & PEP 809) require some newer APIs for module state and PEP 697 layouts (instance structs that don’t include PyObject).
So, I’d like to add variants for existing functions that are usable in this context – they’d:
- never set an exception (on failure, only return
NULL) - return borrowed references
- do not have “internal” side effects (for example, call a “normal C API function and then DECREF the result)
For the first two I’d normally name the functions with _NoError and _Borrow suffixes, but, perhaps that’s included in “safe to use in GC callbacks”. Would _GCSafe work?
PyObject_GetTypeData_GCSafe(doesn’t set exceptions)PyObject_GetItemData_GCSafe(ditto)PyType_GetModuleState_GCSafe(ditto)PyModule_GetState_GCSafe(ditto)PyModule_GetToken_GCSafe(ditto)PyType_GetBaseByToken_GCSafe(doesn’t set exceptions & returns borrowed ref)PyType_GetModule_GCSafe(ditto)PyType_GetModuleByToken_GCSafe(ditto)
Additionally, document Py_TYPE & Py_SIZE as GC-safe.
Does that make sense?