[pygtk] Can't run PyGTK more than once from embedded Python
Patrick K. O'Brien
pobrien at orbtech.com
Tue Jan 10 05:26:29 WST 2006
Romain Behar wrote:
>
> Why running the script using:
>
> PyRun_String(my_script, 0, 0, 0);
>
> or:
>
> PyObject* main_module =
> PyImport_AddModule("__main__");
> PyObject* main_dict = PyModule_GetDict(main_module);
> PyRun_String(my_script, 0, main_dict, main_dict);
>
> does nothing? The script runs and ends, but printed
> messages don't show in the console and PyGTK windows
> don't open. Is that what you call "using different
> namespaces"?
Here is a pile of code that represents the extent to which I was able to
create a decent environment for executing Python scripts. I wouldn't
hold this up as the best code in the world, but it might help you out:
int PythonInit()
{
if (!Py_IsInitialized())
{
Py_Initialize(); // No-op if already initialized.
// Allow subinterpreters.
PyEval_InitThreads();
/// Start a subinterpreter.
Py_NewInterpreter();
}
return(GOOD);
}
int PythonClose()
{
if (Py_IsInitialized())
Py_Finalize();
return(GOOD);
}
// Set a flag saying that we need to reset the environment.
void PythonNewProgramInit()
{
mRunReset = true;
}
// Create a fresh environment within which to execute test script code.
int PythonReset()
{
if (!Py_IsInitialized())
{
PythonInit();
}
else
{
Py_EndInterpreter(PyThreadState_Get());
Py_NewInterpreter();
}
return(GOOD);
}
// PythonTrace is a C function that will be called by Python for every event
// that takes place in its code evaluation loop. Basically, this
function will
// get called each time Python executes another line of code. The
arguments are
// required by Python, but we don't do anything with them.
//
// This is a hack wherein we tap into Python's debugging capabilities so
that we
// can keep the app GUI alive without resorting to threading. This will
allow
// us to stop the execution of any Python code appearing in a file, with one
// important exception: this gimic cannot protect against an infinite loop
// coded as a single line of Python, such as:
//
// while True: pass
//
static int PythonTrace(PyObject *obj, PyFrameObject *frame, int what,
PyObject *arg)
{
ptheApp->PeekAndPump();
return 0;
}
// Run the Python code, typically extracted from a TE file.
int PythonRunCodeString(LPCSTR apstrCode)
{
int errorCode = 0;
char *cstrTmp = NULL;
PyObject *pmod, *pdict, *pstr;
PythonInit(); // No-op if already initialized.
if (mRunReset)
{
PythonReset();
mRunReset = false;
}
// Get the main Python dictionary to use as global and local namespace.
pmod = PyImport_ImportModule("__main__");
pdict = PyModule_GetDict(pmod);
Py_DECREF(pmod);
try
{
// Set default return code value - assume success.
errorCode = GOOD;
cstrTmp = (char*)malloc(strlen(apstrCode)+1);
if (!cstrTmp)
return(MALLOC_ERROR);
strcpy(cstrTmp,apstrCode);
// Run the Python script using the main dictionary as the global and
// local namespace. This form of PyRun allows us to catch Python
// errors (PyRun_SimpleString does not).
// Tap into Python's debugging mode to keep the app GUI alive.
PyEval_SetTrace(PythonTrace, NULL);
// Keep track of the fact that we are now running code from a TE file.
mRunningCode = true;
// Run the Python code that was in the file.
pstr = PyRun_String(cstrTmp, Py_file_input, pdict, pdict);
// Set this back to false since we only want PythonStop to stop Python
// when it is running code that came from a file.
mRunningCode = false;
// Stop tracing every single line of Python code.
PyEval_SetTrace(NULL, NULL);
free(cstrTmp);
if (PyErr_Occurred())
{
ptheApp->DebugAddLine(ptheApp->DEBUG_INFO_MSG,"The following error
occured in the Python script:");
// Print a Python traceback to stderr.
// If you call PyErr_Print() when there was NOT an error
// you will cause a fatal error, so don't do it.
PyErr_Print();
errorCode = SCRIPT_EXECUTION_ERROR;
}
else
{
Py_DECREF(pstr);
}
return(errorCode);
}
catch (...)
{
return(SCRIPT_EXECUTION_ERROR);
}
}
// Send a keyboard interrupt to stop Python while it is running a script.
int PythonStop()
{
if (mRunningCode)
{
PyErr_SetInterrupt();
}
return(GOOD);
}
Hope that helps. I removed some proprietary bits and pieces, so please
test before using any of this code as is. :-)
--
Patrick K. O'Brien
Orbtech http://www.orbtech.com
Schevo http://www.schevo.org
Louie http://louie.berlios.de
More information about the pygtk
mailing list