Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the Python/C API crash on PyRun_SimpleFile?

I've been experimenting with embedding different scripting languages in a C++ application, currently I'm trying Stackless Python 3.1. I've tried several tutorials and examples, what few I can find, to try and run a simple script from an application.

Py_Initialize();

FILE* PythonScriptFile = fopen("Python Scripts/Test.py", "r");
if(PythonScriptFile)
{
    PyRun_SimpleFile(PythonScriptFile, "Python Scripts/Test.py");
    fclose(PythonScriptFile);
}

Py_Finalize();

For some odd reason, running this piece of code results in an access violation at:

    PyRun_SimpleFile(PythonScriptFile, "Python Scripts/Test.py");

I've searched online for others with a similar problem and found only one. Their only solution was a workaround that only seems possible in an older version of Python: Creating a python file object and returning the FILE* from that python file object into PyRun_SimpleFile. Such function calls are not available however, the Python 3.1 API creates file objects from a file descriptor and returns file descriptors, but the PyRun_SimpleFile function still requires a FILE*.

I'm at a loss as to how to run any scripts from file, short of loading the entire file into memory manually and running it as a giant string, certainly not a practical solution.

What gives? How can I accomplish this task if the API has an internal error?

Update: I've managed to build Stackless Python 3.1 from the source and yet the crash remains completely unchanged, despite using the same C runtime library. Both my project and the Stackless Python 3.1 source are built with Visual Studio 2010's C++ compiler and C runtime. I no longer have any inkling as to what might solve this problem, short of modifying Python to use a file name and not a FILE*. Another terrible workaround.

like image 516
Sion Sheevok Avatar asked Sep 06 '10 22:09

Sion Sheevok


4 Answers

This works for me on Python 3:

 PyObject *obj = Py_BuildValue("s", "test.py");
 FILE *file = _Py_fopen_obj(obj, "r+");
 if(file != NULL) {
     PyRun_SimpleFile(file, "test.py");
 }

I hope It would be useful.

like image 111
user1208182 Avatar answered Sep 25 '22 16:09

user1208182


I was getting a similar crash & did the below:

   PyObject* PyFileObject = PyFile_FromString("test.py", "r");
   PyRun_SimpleFileEx(PyFile_AsFile(PyFileObject), "test.py", 1);

Note that this was in python 2.7 though. I don't know if the API has changed in 3.x.

like image 36
sambha Avatar answered Sep 28 '22 16:09

sambha


Your code works correctly on my installed version of Python 2.6. I also built stackless 3.1.2 from source and it worked correctly. This was with g++ 4.4.3 on Ubuntu 10.04. If you're on windows, you might want to check that both stackless and your code are built against the same C runtime.

like image 5
Jack Kelly Avatar answered Sep 28 '22 16:09

Jack Kelly


This sounds like a problem of mismatched APIs. If your code and the Python runtime were compiled with different compilers, or even different compiler options, then accessing the FILE* could result in an access violation. Can you double-check that you've build your C code properly?

You mention that you're embedding Python into your C++ application. Keep in mind that Python is C code, compiled as C code. Perhaps that is the source of the problem?

like image 3
Ned Batchelder Avatar answered Sep 28 '22 16:09

Ned Batchelder