2

From the official docs ;

#define PY_SSIZE_T_CLEAN
#include <Python.h>

int main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
    fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
    exit(1);
}
Py_SetProgramName(program);  /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
                   "print('Today is', ctime(time()))\n");
if (Py_FinalizeEx() < 0) {
    exit(120);
}
PyMem_RawFree(program);
return 0;
}

I successfully ran this piece. I am trying to get output of PyRun_SimpleString to a string variable, let's say

char string[50];

I went through the documentation but couldn't come up with a result. As far as I can tell there are multiple ways to achieve this tiny task and is in the orders of a couple of additional lines. I would appreciate a guidence or a workaround regarding this manner.

  • You seem to have taken the sample code in your question from [Python docs](https://docs.python.org/3/extending/embedding.html). The [next example](https://docs.python.org/3/extending/embedding.html#pure-embedding) on the same page explains this in detail. What specific information do you need? – Selcuk Jul 29 '20 at 23:40
  • As I stated at the beginning of original post, code is from official document pages already. Example at the next page points to a structure that calls a function from a script file with arguments and the rest. What I am trying to do is just to simply assign output of PyRun_SimpleString() to a char array so to speak to a string variable. –  Jul 29 '20 at 23:46
  • Why are you printing the output? You wouldn't use `printf` for this in C. Why would you use `print` in Python? – user2357112 Jul 30 '20 at 01:16

1 Answers1

0

I wish I had found a better way, but this way seems to work, (will update if I find a better solution):

If you defined a class in Python to catch sys.stdout writes:

import sys
class CatchOutErr:
    def __init__(self):
        self.value = ''
    def write(self, txt):
        self.value += txt
catchOutErr = CatchOutErr()
sys.stdout = catchOutErr
sys.stderr = catchOutErr

And you passed the value received from this handler to C++, converted to string, etc...

#include <Python.h>
#include <iostream>
#include <stdio.h>

int main(int argc, char *argv[])
{

    Py_Initialize();
    PyObject *pModule = PyImport_AddModule("__main__"); //create main module
    std::string stdOutErr = "import sys\nclass CatchOutErr:\n\tdef __init__(self):\n\t\tself.value = ''\n\tdef write(self, txt):\n\t\tself.value += txt\ncatchOutErr = CatchOutErr()\nsys.stdout = catchOutErr\nsys.stderr = catchOutErr\n";

    PyRun_SimpleString(stdOutErr.c_str()); //invoke code to redirect
    PyRun_SimpleString("from time import time,ctime\n"
                       "print('Today is', ctime(time()))\n");
    PyObject *catcher = PyObject_GetAttrString(pModule, "catchOutErr"); //get our catchOutErr created above
    PyObject *output = PyObject_GetAttrString(catcher,"value"); //get the stdout and stderr from our catchOutErr object
    std::string s = PyString_AsString(output);
    Py_DECREF(catcher);
    Py_DECREF(output);
    Py_DECREF(s);
    std::cout << s;
    return 0;
}

('Today is', 'Thu Jul 30 09:02:55 2020')

For Python3:

...
PyObject *output = PyObject_GetAttrString(catcher,"value"); //get the stdout and stderr from our catchOutErr object
PyObject *encodedData = PyUnicode_AsEncodedString(output, "ascii", NULL);
Py_DECREF(output);
Py_DECREF(encodedData);
char* buf;
Py_ssize_t len;
PyBytes_AsStringAndSize(encodedData, &buf, &len);
std::cout << std::string(buf) << std::endl;

Reference: https://stackoverflow.com/a/4307737/9238288 https://cpp.hotexamples.com/examples/-/-/PyUnicode_AsEncodedString/cpp-pyunicode_asencodedstring-function-examples.html

jackw11111
  • 1,457
  • 1
  • 17
  • 34
  • 1
    Thank you for the answer. Your approach seems to work from my end as well. –  Jul 31 '20 at 12:42