Why has `_PyThread_CurrentExceptions` disappeared from the exported symbols (but `_PyThread_CurrentFrames` is still there)?

I was trying to make sense of C API: Remove private C API functions (move them to the internal C API) · Issue #106320 · python/cpython · GitHub and the reason why the _PyThread_CurrentExceptions symbol seem to have disappeared from 3.13. We rely on this function to retrieve the current exceptions from all the running threads in our Cython extension. With the symbol gone we get

ImportError: dlopen(extension.cpython-313-darwin.so, 0x0002): symbol not found in flat namespace '__PyThread_CurrentExceptions'

Looking at the symbols exported by the Python library I get

❯ nm -g libpython3.13.dylib | grep _PyThread_Current
00000000001df738 T __PyThread_CurrentFrames

So I was wondering whether it is expected that _PyThread_CurrentExceptions is no longer available from symbols, whilst _PyThread_CurrentFrames still is.

As per the What’s New entry, please open an issue to request a public C API and add “cc: @vstinner”.

On Python 3.13, you can call sys._current_exceptions() in C which wraps the internal _PyThread_CurrentExceptions() function. Tell me if you need help to write code to call the function. It works on Python 3.12 and older: see sys._current_exceptions() documentation.

So I was wondering whether it is expected that _PyThread_CurrentExceptions is no longer available from symbols, whilst _PyThread_CurrentFrames still is.

mod_wsgi uses _PyThread_CurrentFrames() which triggered to restore the function in Python 3.13 alpha 2:

Thanks @vstinner!

mod_wsgi uses _PyThread_CurrentFrames() which triggered to restore the function in Python 3.13 alpha 2

I see, so the other function was added back. I currently have the sys._current_exceptions() “workaround” in place to fix my issue, but it would be nice if _PyThread_CurrentExceptions could be exposed again, mostly for performance issues (for context, this would be for an exception profiler, so we would like to be as efficient as possible in retrieving the information we are after). Do you reckon this could be possible?

Do you have a microbenchmark showing that calling the sys function is way slower than calling the C function directly on Python 3.12?

I don’t, but I would expect that calling via Python would be in general more expensive than a direct call, and we really strive to shave off as much overhead as possible, so whatever we can save we’d take it.

I suggest to actually measure with a benchmark, rather than guessing :wink:

If you import the sys._current_exceptions function only once, calling the function should have no overhead compared to calling directly the underlying _PyThread_CurrentExceptions() function.