Search code examples
pythoncpython-c-api

How to print the object returned by PyRun_String?


I would like to know how to use the return of Pyrun_String.

I already tried to use PyUnicode_DATA and PyObject_Str.

if (!(pstr = PyRun_String("a = 1", Py_single_input, pGlobal, pdict)))
    exit(printf("Error while running string\n"));


// I tried this

PyObject *pstr = PyObject_Str(pstr);

void* test = PyUnicode_DATA(pstr);
printf("%s\n", (char*)test);


// or this

if (!PyArg_Parse(pstr, "s", &cstr))
    exit(printf("Bad result type\n"));
printf("%s\n", cstr);

Solution

  • You can use PyObject_Repr() to get a string representation of the object (like Python's repr()) and then pass it to PyUnicode_AsUTF8() to get an UTF-8 encoded C string. Don't forget to check with PyUnicode_Check() first.

    Working example:

    #include <stdio.h>
    #include <Python.h>
    
    int main(int argc, char **argv) {
            if (argc != 2) {
                    fprintf(stderr, "Usage: %s PYTHON_CODE\n", argv[0]);
                    return 1;
            }
    
            Py_Initialize();
            PyObject *dict = PyDict_New();
            PyObject *pstr;
    
            if (!(pstr = PyRun_String(argv[1], Py_single_input, dict, dict))) {
                    fputs("PyRun_String failed\n", stderr);
                    return 1;
            }
    
            PyObject *rep = PyObject_Repr(pstr);
    
            if (!PyUnicode_Check(rep)) {
                    fputs("repr is not unicode (this should not happen!)\n", stderr);
                    return 1;
            }
    
            const char *str_rep = PyUnicode_AsUTF8(rep);
            puts(str_rep);
    }
    

    Example output:

    $ ./x 'a = 1'
    None
    $ ./x '(1,2,3)'
    (1, 2, 3)
    None
    $ ./x 'x = {"a": 1}; x; x["a"]'
    {'a': 1}
    1
    None
    

    You always end up with an additional None because that's the "return value" of the whole script.