Accessing members on PyCodeObject and PyThreadState with different versions of (c)python is tricky.
I need to access PyCodeObject->co_name/co_filename and PyThreadState->c_tracefunc. But as the layout of the underlying structs change with each version, it would be nice to have a better API.
e.g. there is PyFrame_GetLineNumber() but not PyCode_GetName(). And I need a to check if tracing is active so something like PyThreadState_IsTraceing() or PyEval_GetTrace() (matching PyEval_SetTrace())
Each function would only be very few lines of code.
Or is there a better way to do this?
(I’m adding some debugger capabilities to an app that runs an embedded python. It loads whatever python version is installed on the system, so I need something that is not changing all the time.)
These are available at the Python layer: PyObject_GetAttrString(code_object, "co_name") or PyObject_CallNoArgs(PySys_GetObject("gettrace")), plus a bunch of lines for error handling.
If there are reasons to add dedicated C functions for these, they could be added individually. Typical reasons would be performance or protection against the user removing gettrace from sys.
That’s not where the cost is for CPython. Adding API also means we need to support the API, and the concept behind it, for a very long time.
Even with the API, if you’re writing a debugger you’ll need to adapt it to new versions of Python. For example, you’ll probably want to see PEP 669 monitoring hooks, but sys.gettrace probably won’t see those.
Using Python API will be easier in this respect: you get AttributeError rather than undefined C symbols.