2

I run a Python script from a C++ program using PyRun_SimpleFile. I defined a custom module (using PyImport_AppendInittab, as done here), so it can be imported in my Python script and some C++ code gets executed by the Python script when functions from this module are used, this is done through a callback PyObject* MyFunction(PyObject *self, PyObject *args) being invoked by Python interpreter.

I want to know the current script file name and line number within the callback function being invoked.

I could not find any way to retrieve this. Is this possible?

Note: This question is definitely not a duplicate of How to get the caller's method name in the called method?. I'm trying to retrieve file name and line number from C++ code executing and later executed by a Python script.

7
  • why not pass it as parameter? Commented Oct 13, 2020 at 11:34
  • @idclev463035818: Because the script calls many functions, and they have their own parameters, adding file name and line number would polute the original script. This is meant for debugging, so the idea is to make it work with my script without having to modify it. This is not an argument for a specific embedded function, it's some information I'd like to retrieve for any embedded function being called. Commented Oct 13, 2020 at 12:11
  • There is a way using PyEval_GetFrame and then digging through that object's members, but you might as well ask Python to do it for you: How to get the caller's method name in the called method? Commented Oct 13, 2020 at 12:50
  • @Botje: I tried PyEval_GetFrame()->f_lineno;but this is always evaluated to 1...and also I coulf not find the path the the .py file being interpreted here. Commented Oct 13, 2020 at 13:29
  • I was not able to check, but you probably need the parent frame, as PyEval_GetFrame is the frame for your native function. Commented Oct 13, 2020 at 13:31

1 Answer 1

1

You will need PyTraceBack_Here.

You can take a look at a traceback object's implementation here

Here is an example printig the traceback created by PyTraceBack_Here

#include <Python.h>

PyObject * mymodule_meth_test(PyObject * self) {
    PyTraceBack_Here(PyEval_GetFrame());
    PyObject * exc;
    PyObject * val;
    PyObject * tb;
    PyErr_Fetch(&exc, &val, &tb);
    PyTraceBack_Print(tb, PySys_GetObject("stderr"));
    Py_RETURN_NONE;
}

PyMethodDef module_methods[] = {
    {"test", (PyCFunction)mymodule_meth_test, METH_NOARGS, NULL},
    {},
};

PyModuleDef module_def = {PyModuleDef_HEAD_INIT, "mymodule", NULL, -1, module_methods};

extern "C" PyObject * PyInit_mymodule() {
    PyObject * module = PyModule_Create(&module_def);
    return module;
}

From the tb object you should be able to extract the filename and line number. It is an ordinary PyObject you can pass it to a python script or inspect it.

Here is how to extract the values without taking care of the refcounts:

    int line = PyLong_AsLong(PyObject_GetAttrString(PyObject_GetAttrString(tb, "tb_frame"), "f_lineno"));
    const char * filename = PyUnicode_AsUTF8(PyObject_GetAttrString(PyObject_GetAttrString(PyObject_GetAttrString(tb, "tb_frame"), "f_code"), "co_filename"));
Sign up to request clarification or add additional context in comments.

12 Comments

Thanks. Could you please elaborate how to retrieve file name and line number from this? I tried to call PyTraceBack_Here on result of PyEval_GetFrame but this constantly leaves f_lineno set to 1.
changed the code, this code is missing error and refcount handling.
THis works fine for line number. But file name is "C", while I execute my script through PyRun_SimpleFile.
Looks like "C" means I'm currently executing some C code, I tried to use PyFrame_GetBack to get the caller frame info hoping to be back to the Python file itself, but that was unsuccessful (it returns NULL).
OK, that actually works. It's just that I was passing PyRun_SimpleFile second parameter as UTF-8....and then, filename ended up being "C" instead of "C:\\....\\myfile.py"!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.