Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embedding Python in C/C++

For my senior project in Computer Science, I am making a puzzle video game that will teach people how to code in Python. The largest portion of the design involves creating engaging puzzles that the user can sort through. The puzzle design isn't the issue I have currently, however.

While my initial idea was to have each "problem" have an array of expected answers to check the user's answer against, the CS department head at my school (who runs the senior seminar) recommended I use embedded Python instead, he recommend both to challenge me, and to make it easier on the data to embed a simple interpreter that will check user code output against the expected output.

Fast-forward four weeks, and I've learned a lot about how Python actually works. I even got the interpreter to simple C strings as python code, things like print("hello") or print("hello/tworld"), so long as there is no white space in the C string.

That code looks like

#include "pch.h"
#include <iostream>
#include <string>
#include <fstream>
#include <Python.h>

void exec_pycode(const char* code);

int main()
{
    using namespace std;
    Py_Initialize();

    string input;

    cin >> input;
     /*Though the variable gets passed to a const char* definition,
    the pointer is constant over the character, because the pointer ALWAYS points
    to the same function*/
    char const *PyCode = input.data();

    exec_pycode(PyCode);        

    Py_Finalize();
    return EXIT_SUCCESS;    
}        

//The execution of python code as a simple string in C and interpreting in python
void exec_pycode(const char* code)
{
    Py_Initialize();
    PyRun_SimpleString(code);
    Py_Finalize();
}

My next step I decided was to get strings like print("hello world") white space included, readable as Python code.

I have tried to change the exec code function to look like

void exec_pycode(const char* code)
{
    Py_Initialize();
    const char *inFile = "FileName";
    PyObject *dict = PyDict_New();
    Py_CompileString(code, inFile, Py_file_input);
    PyRun_String(code, Py_file_input, dict, dict);

    Py_Finalize();
}

This compiles fine when the function is changed like this, but when I input any string, simple or with white space, the program exits with a return value of 0 with out printing any of the python code.

I am curious why this is occurring, whether I'm having issues converting the user input to an adequate C string to read as a Python code, or it is not understanding the declaration of Py_CompileString(const char *str, const char *filename, int start) or PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals), I have stared at this documentation, taken notes, diagrammed, and I still get the same exit condition.

I'm also wondering:

  1. If I'm declaring the dictionary for the Python string commands to read the code properly, or if it's
  2. If by having my Python file flags set to NULL in the simplified version instead of Py_CompileStrngFlags(...) or Py_RunStringFlags(...) that it's what's causing the return value of NULL issue I'm experiencing.
  3. If I'm even using the right function to run embedded Python with user input.
like image 230
Ryan Mueller Avatar asked Oct 15 '22 11:10

Ryan Mueller


1 Answers

There is no need for C tag in your program. Your problem is only related to the C++ code. First of all,

string input;

cin >> input;

reads one space-delimited word, not unlike scanf("%s", input); in C. You need to use

getline(cin, input);

The next problem is that the input.data() need not be zero-terminated. You must use input.c_str() instead.

Finally: you must always check the return value of each and every Python API function that you call. There are no allowed shortcuts.

like image 143