[C++-sig] Under what conditions would PyRun_SimpleFile return false?
Stefan Seefeld
seefeld at sympatico.ca
Thu Aug 17 17:39:09 CEST 2006
Blake Skinner wrote:
> PyRun_SimpleFile() doesn't seem to like me. First, passing a FILE* created by
> fopen() in Visual Studio 2005 caused a runtime error, but I found a work around:
>
> FILE* fp = PyFile_AsFile( PyFile_FromString(filename, "r") );
> PyRun_SimpleString(fp, filename);
I'm not sure what runtime error the above is a workaround for. There is some
ABI incompatibility between different versions of MSVC related to the FILE
structure, and one way to avoid tripping over that is not to hold FILE pointers
directly, but passing around python objects instead (PyFile_FromString to create
it and PyRun_File(PyFile_AsFile(...), ...) to use it).
> I'm mentioning this so you understand why I'm doing it in my code.
>
> This worked fine, until I tried to construct a class around boost python, here's
> the jist of it:
>
> // constructor, Initializes python, creates the main module and gets the
> // dictionary
> pyEngine::pyEngine()
> {
> Py_Initialize();
>
> // main module and main dictionary
> object main((
> handle<>(borrowed(PyImport_AddModule("__main__")))
> ));
> _main = main;
> _mdict = _main.attr("__dict__");
> }
>
> // destructor
> // finalizes python
> pyEngine::~pyEngine()
> {
> Py_Finalize();
Using Py_Finalize() doesn't work with current boost.python versions.
(Search the archives to find more context around that.)
> }
>
> //////////////////////////////////////////////////////////////////
> // methods
>
> // load a python module with the given filename
> bool pyEngine::LoadModule(char *filename)
> {
> // originally more condensed, the 'if's were added for debugging
> PyObject *py_file = PyFile_FromString(filename, "r");
> if (!py_file)
> {
> fprintf(stderr, "Unable to locate module (pyEngine)\n");
> return false;
> }
>
> FILE *fp = PyFile_AsFile( py_file );
> if (!fp)
> {
> fprintf(stderr, "PyFile_AsFile returned NULL\n");
> return false;
> }
>
> if (!(PyRun_SimpleFile(fp, filename) == 1))
> {
> fprintf(stderr, "PyRun_SimpleFile returned 0\n");
>
> return false;
> }
>
> return true;
> }
>
> ///////////////////////////////////////////////////////////////////////////////
>
>>From stderr I found that PyRun_SimpleFile was returning 0. I checked the
> documentation and it didn't mention what conditions that would happen for. I'll
> keep looking for it on my own and post if I solve it, but any help would be
> appreciated.
In general, if a python C API function returns 0 it has an exception set that you
should query via PyErr_Occured(), PyErr_Fetch(), and the like.
The current CVS version of boost.python (including the branch that will end up
as version 1.34 if ever that gets released some day) contains a boost::python::exec
and boost::python::exec_file function that should provide all you need. Here is
the code for the latter:
// Execute python source code from file filename.
// global and local are the global and local scopes respectively,
// used during execution.
object exec_file(str filename, object global, object local)
{
// should be 'char const *' but older python versions don't use 'const' yet.
char *f = python::extract<char *>(filename);
// Let python open the file to avoid potential binary incompatibilities.
PyObject *pyfile = PyFile_FromString(f, "r");
if (!pyfile) throw std::invalid_argument(std::string(f) + " : no such file");
python::handle<> file(pyfile);
PyObject* result = PyRun_File(PyFile_AsFile(file.get()),
f,
Py_file_input,
global.ptr(), local.ptr());
if (!result) throw_error_already_set();
return object(detail::new_reference(result));
}
You may want to borrow from it. As you can see, if the call to PyRun_File fails
(i.e. returns 0), an exception is thrown that captures (or allows a handler to capture)
the associated python exception.
HTH,
Stefan
--
...ich hab' noch einen Koffer in Berlin...
More information about the Cplusplus-sig
mailing list