18

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.

Mike Pennington
  • 41,899
  • 19
  • 136
  • 174
Sion Sheevok
  • 4,057
  • 2
  • 21
  • 37

7 Answers7

15

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.

mozzbozz
  • 3,052
  • 5
  • 31
  • 44
user1208182
  • 161
  • 1
  • 3
  • 2
    Works for me, but with small modification: FILE *file = _Py_fopen( "test.py", "r+" ); PyRun_SimpleFile(file, "test.py"); This should be marked as the answer. – MasterMind Sep 03 '14 at 15:14
  • 1
    @MasterMind: The OP of the answer obviously wanted to call the `_Py_fopen_obj`-function instead of the `_Py_fopen`-function. I edited the answer accordingly (so the code from the answer should now work out of the box). Your solution seems to be easier / more lightweight though. For some reason, both solutions *only* worked if I had declared the `const char*` filepath-variable **after** the `Py_Initialize()`-function or if I directly put in the string like you did in your example. (to be honest: The Python C++ wrapper is a pain and could be so much simpler) – mozzbozz Nov 11 '14 at 15:54
13

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.

sambha
  • 1,333
  • 3
  • 17
  • 30
5

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.

Jack Kelly
  • 18,264
  • 2
  • 56
  • 81
  • Well, that's where I'm running into trouble. I know the C runtime is different. I'm using Visual Studio 2010 and I'm quite certain most Python binaries are built with Visual Studio 2008. I've been trying to build the Stackless Python 3.1 source, but I'm not entirely sure which libraries, DLLs, and headers are needed. Not to mention there are some issues regarding some of the extension modules not building due to missing files. The provided batch file to build them depends on several other missing files, like having SVN installed. – Sion Sheevok Sep 10 '10 at 20:37
  • @Sion: Unfortunately, there's nothing more I can really offer besides saying "check the docs" and "good luck". I don't have access to a Windows development machine, let alone VS2010. Is there any way to write a small wrapper for the relevant parts of stdio that's built with the correct visual studio version? – Jack Kelly Sep 10 '10 at 22:21
  • The help is appreciated none the less, though at this point even the same compiler and runtime have had no effect on solving the issue. I may very well have to try and contact the developers or other Python gurus directly. – Sion Sheevok Sep 11 '10 at 18:55
  • Good catch with the differing runtimes, a common problem on Windoze, with mix and match compilers. – Matt Joiner Sep 12 '10 at 08:18
  • Different runtimes was my issue when trying to do this with 2.7. I was calling fopen which used one runtime. Python was then taking the FILE* and using with a DIFFERENT runtime, causing a crash. _Py_fopen not available in 2.7 – Tom Quarendon Mar 04 '16 at 11:39
3

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?

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • Aye, I did not build the Stackless Python 3.1 library my self. I'd read that the issue could very well be the use of FILE*s from different runtimes, thus why the workaround was to allow the Python library to create the FILE* and return it for use as an argument to the function. So then, have I no option but to acquire the source and build Stackless Python 3.1 myself? – Sion Sheevok Sep 06 '10 at 23:03
  • If you can build your C code, then you shouldn't have any difficulty with the Stackless code. – Ned Batchelder Sep 07 '10 at 00:28
0

If you built your test with VC 2010, you will definitely have problems - VC9 (VS 2008) and VC10 (VS 2010) have mutually incompatible support DLLs that are usually required (implement printf, file i/o and that sort of thing). You cannot mix them if they include the standard libraries, which the python build does.

You always have the option of using gcc (e.g. Cygwin or mingw) or downloading Visual Studio 2008 express, which should work fine for experimentation into python embedding. I have used both with the standard Python 2.7.6 build.

CPD
  • 43
  • 3
0

And what about this solution:

Py_SetProgramName(argv[0]);
Py_Initialize();
PyRun_SimpleString("execfile(\"ex30.py\")");
Py_Finalize();

Where ex30.py it the name of the python script I am running.

newandlost
  • 935
  • 2
  • 10
  • 21
0

The below code will execute the test.py module. Python will search the module in the path set. So the path should be handled first.

Py_Initialize();

string path = "Python Scripts/";

//Set the path
PyRun_SimpleString("import sys");
string str = "sys.path.append('" + path + "')";
PyRun_SimpleString(str.c_str());

//Dont use test.py as it actually searches sub module test>>py
PyObject * moduleName = PyUnicode_FromString("test");
PyObject * pluginModule = PyImport_Import(moduleName);

if (pluginModule == nullptr)
{
    PyErr_Print();
    return "";
}

//Do the executions here

//clean up
Py_DECREF(moduleName);
Py_DECREF(pluginModule);
Py_DECREF(transformFunc);
Py_DECREF(result);

Py_Finalize();