Run an python method from C++

Craig Ringer craig at postnewspapers.com.au
Wed Dec 1 08:00:18 CET 2004


On Wed, 2004-12-01 at 06:59, Mark Doberenz wrote:

>         pyRunFile =PyRun_File(pythonFileP,filename,Py_file_input,globals,globals);
>         runMethod = PyObject_CallMethod(pyRunFile,"proc1","s","Blah");

> --- It's crashing when I try to do the PyObject_CallMethod.

(I'm going to assume 'crashing' means 'segmentation fault' as you have
given no more detailed information, such as the error message or the
backtrace...)

Have you checked to ensure that pyRunFile is not NULL?

According to the documentation, PyRun_File:
"Returns the result of executing the code as a Python object, or NULL if
an exception was raised."

So you MUST check for and handle a NULL value.

Separately, I don't think what you're doing with PyRunFile makes much
sense. If you want to return the class, you need to do so explicitly
with

return dc

at the end of your Python script.

It might be worth using PyMapping_GetAttrString() to retrieve it out of
the global namespace after your script runs, rather than trying to
return it, though.

I've been working with the Python/C API for a bit now, and I'm still
finding it pretty hard going, so I understand your difficulties. There's
actually another major bug in your code that you'll run into sooner or
later. Try running a script that just contains:

import sys
sys.exit(1)

and you'll see what I mean.

To work around that and the difficulty of getting the exception text
from the Python interpreter, I generate a small Python program as a C++
string, then PyRun_String() it. That program performs some setup and
then execfile()s the real Python program inside a try block. I'll
include the block I use below. I'm using a Qt-based C++ app, so it's all
done with QString, but the concept is the same. If you're not familar
with Qt, QString::arg() works pretty similarly to Python's % string
substitution.

fileDir is the directory the file to be run is stored in, and fileName
is the path to to the script file to run.

QString cm = QString("import sys,StringIO,traceback\n");
cm        += QString("sys.path[0] = \"%1\"\n").arg(fileDir);
cm        += QString("try:\n");
cm        += QString("    execfile(\"%1\")\n").arg(fileName);
cm        += QString("except SystemExit:\n");
cm        += QString("    pass\n");
// Capture the text of any other exception that's raised by the interpreter
// into a StringIO buffer for later extraction.
cm        += QString("except Exception, err:\n");
cm        += QString("    f=StringIO.StringIO()\n");
cm        += QString("    traceback.print_exc(file=f)\n");
cm        += QString("    errorMsg = f.getvalue()\n");
cm        += QString("    del(f)\n");
// We re-raise the exception so the return value of PyRun_String reflects
// the fact that an exception has ocurred.
cm        += QString("    raise\n");

// Get the thing as a char*
char* python_wrapper = cm.latin1().data();


When I later need to retrieve an exception (after I run this with
PyRun_String) I get to it with (error checking omitted):

PyObject* errorMsgPyStr = PyMapping_GetItemString(globals, "errorMsg")
QString errorMsg = PyString_AsString(errorMsgPyStr);

(I'd love to be told there's a nicer way to do this).

This could easily be the wrong way to go about things, buggy, or just
stupid, so be warned. It does work well here, however.

I would be interested in knowing how to tell Python what encoding is
used for program text passed using PyRun_String() if anybody knows.

--
Craig Ringer




More information about the Python-list mailing list