Posted to the python developer list but suggested I mail this here instead.
---
Hi, I'm writing because I'm working on a project where the user can
run scripts that don't reference a file but use internal application
text data.
Otherwise we are not doing anything tricky, only that the scripts
should each run independently (no cruft left from the previous scripts
namespace, sharing sys.modules etc is fine).
Something which is unclear to me even after looking over pythonrun.c
is the correct way to setup a namespace.
For years we have been doing this and it seemed to work fine...
PyObject *d = PyDict_New(); // new namespace
PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
PyDict_SetItemString(d, "__file__", PyString_FromString(filename));
// fake, avoids sys.argv[0] being used for warnings.
/* --- snip ---*/
PyEval_EvalCode(compiled_text, d, d);
Recently a developer reported a bug where pickle wasn't working, it
turns out that in a few places python expects the __main__ modules
namespace to match that if the running script: _pickle.c's
save_global() in this case
eg:
>>> spam = 10
>>> print(__import__("__main__").__dict__["spam"])
... 10
Once I found this was the problem it was simple to use __main__'s
namespace however there are still things that are not clear about
exactly how this should be done.
Simplified code...
PyObject *item, *dict= PyModule_GetDict(PyImport_AddModule("__main__"));
PyDict_Clear(dict);
PyDict_SetItemString(dict, "__builtins__", PyImport_AddModule("builtins"));
item = PyUnicode_FromString( "__main__" );
PyDict_SetItemString( dict, "__name__", item );
Py_DECREF(item);
PyDict_SetItemString(d, "__file__", PyString_FromString(filename));
// fake, avoids sys.argv[0] being used for warnings.
/* --- snip ---*/
PyEval_EvalCode(compiled_text, dict, dict);
Still this leaves me with the following questions...
- Whats the best way to manage the namespace for running multiple
scripts one after another? clear and initialize __main__'s dict each
time?, keep a copy and restore it after each run?
- should the original __main__ namespace be restored after running a script?
- pickle expects: __import__("__main__").__dict__ == ***the current
namespace***, is this apart of the python spec or just something
specific to pickle?
- PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins()) acts
differently to PyDict_SetItemString(dict, "__builtins__",
PyImport_AddModule("builtins")), using the PyEval_GetBuiltins() dict
adds every member of __builtins__ when running:
print(__import__("__main__").__dict__.keys()), rather then just
showing __builtins__.
--
- Campbell
I asked this question here a few days ago, and someone suggested I ask again,
providing all the code, so that it can be actually tried. So here it is, and I’m
still stumped.
Original post:
I have a problem with threading using the Python/C API. I have an extension that
implements a timer, and the C++ timer callback function calls a Python function.
The code looks like this:
// fetimer.cpp : Defines the exported functions for timer function.
#define_WIN32_WINNT 0x502
#include"stdafx.h"
#include"mmsystem.h"
#include"python.h"
#defineTARGET_RESOLUTION 1
UINT wTimerRes,fooval;
BOOL LEDflag,timeFlag;
BOOL timerActive = FALSE;
BOOL timerSet = FALSE;
BOOL funcsetFlag = FALSE;
BOOL modsetFlag = FALSE;
BOOL attrsetFlag = FALSE;
UINT wTimerID,timeval,setVal = 2000;
HANDLE porthandle;
TIMECAPS tc;
UINT userval,*pVal;
PyObject *mod, *attr, *pargs, *pres;
UINT SetTimerCallback( UINT wTimrID, UINT msInterval );
staticvoid CALLBACK PeriodicTimer(UINT wTimerID, UINT msg,
DWORD dwUser, DWORD dw1, DWORD dw2);
PyObject *ProcessTimer( void );
PyObject *pymod;
PyObject *pattr;
PyObject *foop;
staticvoid (*pFunc)(UINT wTimerID, UINT msg,
DWORD dwUser, DWORD dw1, DWORD dw2);
staticPyObject *timer_setup( PyObject *pSelf, PyObject *pArgs )
{
if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
}
wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
timeBeginPeriod(wTimerRes);
LEDflag = FALSE;
timeFlag = FALSE;
timerActive = FALSE;
userval = 123;
pVal = &userval;
Py_Initialize();
fooval = 0;
return Py_None;
}
staticPyObject *timer_start( PyObject *pSelf, PyObject *pArgs )
{
int tval = 2000;
if( timerActive ){
timeKillEvent( wTimerID );
}
if( timerSet ){
tval = setVal;
}
UINT retval = SetTimerCallback( wTimerID, tval );
timerActive = TRUE;
return Py_None;
}
UINT SetTimerCallback(UINT wTimrID, // sequencer data
UINT msInterval) // event interval
{
wTimerID = timeSetEvent(
msInterval, // delay
wTimerRes, // resolution (global variable)
(LPTIMECALLBACK)PeriodicTimer, // callback function
wTimrID, // user data
TIME_PERIODIC|TIME_CALLBACK_FUNCTION );
if(!wTimerID)
{
return 999;
}
else{
return 0;
}
}
staticvoid CALLBACK PeriodicTimer(UINT wTimerID, UINT msg,
DWORD dwUser, DWORD dw1, DWORD dw2)
{
PyGILState_STATE pgs;
pgs = PyGILState_Ensure();
if(attrsetFlag)
{
pres = PyObject_CallFunction(attr,NULL);
if( pres == NULL )printf("CallFunction failed!\n");
}
PyGILState_Release( pgs );
}
staticPyObject *timer_kill( PyObject *pSelf, PyObject *pArgs )
{
timeKillEvent( wTimerID );
timerSet = FALSE;
timerActive = FALSE;
return Py_None;
}
staticPyObject *timer_settime( PyObject *pSelf, PyObject *pArgs )
{
UINT t;
PyArg_ParseTuple( pArgs, "i", &t );
setVal = t;
timerSet = TRUE;
return Py_None;
}
staticPyObject *timer_setmodname( PyObject *pSelf, PyObject *pArgs )
{
char *b;
PyArg_ParseTuple( pArgs, "s", &b );
mod = PyImport_ImportModule(b);
if( mod == NULL )
{
printf("Could not import %s\n",b);
return Py_None;
}
modsetFlag = TRUE;
return Py_None;
}
staticPyObject *timer_setprocname( PyObject *pSelf, PyObject *pArgs )
{
char *b;
if( !modsetFlag )return Py_None;
PyArg_ParseTuple( pArgs, "s", &b );
attr = PyObject_GetAttrString(mod,b);
if( attr == NULL )
{
printf("Could not import %s\n",b);
return Py_None;
}
attrsetFlag = TRUE;
return Py_None;
}
staticPyMethodDef fetimer_methods[] = {
{"timer", timer_setup, METH_VARARGS, "blah"},
{"start", timer_start, METH_VARARGS, "start timer" },
{"kill", timer_kill, METH_VARARGS, "kill timer" },
{"settime", timer_settime, METH_VARARGS, "set timer" },
{"setmodname", timer_setmodname, METH_VARARGS, "set module name" },
{"setprocname", timer_setprocname, METH_VARARGS, "set procedure name" },
{NULL, NULL}
};
PyMODINIT_FUNC
initfetimer(void)
{
Py_InitModule("fetimer", fetimer_methods);
}
The Python code (Timetest3.py) that sets this up looks like this:
#Time Test 3.py
import fetimer
#import feserial
import time
Hit = 0
L = 0
fetimer.timer()
fetimer.settime(30)
fetimer.setmodname("Timeslice3")
fetimer.setprocname("Timetester")
#feserial.open(4)
#feserial.dtr(0)
print "\n Program Waiting for Time Slice"
fetimer.start()
while True:
time.sleep(0.010)
and the module Timeslice3.py looks like this:
#Timeslice3.py
def Timetester():
pass
The application should run by entering "python timetest3.py" at the command
prompt.
When I run this stuff, it works fine for hundreds, often even thousands, of
timer ticks (I’ve been testing with about thirty ticks per second, but it
doesn’t matter – it still crashes at ten or fewer ticks per second). Sometimes
it runs for only a few seconds, sometimes for ten minutes or so. But it always
eventually crashes Python. Usually it gives no error message. Sometimes, though,
it does give an error message, but not always the same one. I’ve noted three
that it has given in my testing so far:
Fatal Python Error: This thread state must be current when releasing
Fatal Python Error: PyThreadState_DeleteCurrent: no current tstate
Fatal Python Error: PyEval_SaveThread: NULL tstate
Can anybody help me make this code stable, so that it works all the time? I’m
using Python 2.6.5 under Windows Vista, but it crashes under Windows XP as well.
You are receiving this email because we wish you to use our cost-effective IT services.
We are a China based Custom Software Application Development provider. We offer full cycle custom software programming services, from product idea, software development to support and enhancement. We employ a large pool of software engineers coming from different backgrounds. We are able to balance product development efforts and project duration to your business needs.
Core Services:
Custom Application Development
Custom Software Development
iPhone Application Development
iPad Application Development
Mobile Application Development
Android Mobile Application Development
Soft Product Development
Game Design & Development
Game Testing & Quality Assurance
Cloud Computing
Solutions:
CRM Software Application Development
ERP Software Application Development
Enterprise Portal Solution
Sales Force Automation Solution
Game Design & Development
Knowledge Management Solution
Workflow Management Solution
SharePoint Development Services
Microsoft Online Services
Microsoft Azure Services
Best regards,
Gary
ITVIATSA Software Development
Contact: ibsoftware(a)yeah.net
Pls send address to larryremove123(a)msn.com for remove
I'm using PyDict_SetItemString to add a long from a C struct
into a Python dictionary. The full code is in the usn2dict
function in here:
http://svn.timgolden.me.uk/extensions/change-journal/_usn.c
but the sort of thing I'm talking about is this:
PyDict_SetItemString (
dict,
"RecordLength",
PyLong_FromLongLong (usn_record->RecordLength)
);
My understanding is that PyLong_FromLongLong passes its reference
to my function, which then passes it to PyDict_Set... which INCREFs
it. That means, I think, that my function should DECREF it before
exit since I'm only creating it to store it in the dict. Is that correct?
In other words, should my code really do this?
record_length = PyLong_FromLongLong (usn_record->RecordLength);
PyDict_SetItemString (dict, "RecordLength", record_length);
Py_DECREF (record_length)
Thanks
TJG
I have a problem with threading using the Python/C API. I have an extension that
implements a timer, and the C++ timer callback function calls a Python function.
The relevant code looks like this:
staticPyObject *timer_setmodname( PyObject *pSelf, PyObject *pArgs )
{
char *b;
PyArg_ParseTuple( pArgs, "s", &b );
mod = PyImport_ImportModule(b);
if( mod == NULL )
{
printf("Could not import %s\n",b);
return Py_None;
}
modsetFlag = TRUE;
return Py_None;
}
staticPyObject *timer_setprocname( PyObject *pSelf, PyObject *pArgs )
{
char *b;
if( !modsetFlag )return Py_None;
PyArg_ParseTuple( pArgs, "s", &b );
attr = PyObject_GetAttrString(mod,b);
if( attr == NULL )
{
printf("Could not import %s\n",b);
return Py_None;
}
attrsetFlag = TRUE;
return Py_None;
}
staticvoid CALLBACK PeriodicTimer(UINT wTimerID, UINT msg,
DWORD dwUser, DWORD dw1, DWORD dw2)
{
PyGILState_STATE pgs;
pgs = PyGILState_Ensure();
if(attrsetFlag)
{
pres = PyObject_CallFunction(attr,NULL);
if( pres == NULL )printf("CallFunction failed!\n");
}
PyGILState_Release( pgs );
}
The Python code that sets this up looks like this:
fetimer.setmodname("Timeslice3")
fetimer.setprocname("Timetester")
print "\n Program Waiting for Time Slice"
while True:
time.sleep(0.010)
and the module Timeslice3.py looks like this:
#Timeslice3.py
def Timetester():
pass
When I run this stuff, it works fine for hundreds, often even thousands, of
timer ticks (I’ve been testing with about thirty ticks per second, but it
doesn’t matter – it still crashes at ten or fewer ticks per second). Sometimes
it runs for only a few seconds, sometimes for ten minutes or so. But it always
eventually crashes Python. Usually it gives no error message. Sometimes, though,
it does give an error message, but not always the same one. I’ve noted three
that it has given in my testing so far:
Fatal Python Error: This thread state must be current when releasing
Fatal Python Error: PyThreadState_DeleteCurrent: no current tstate
Fatal Python Error: PyEval_SaveThread: NULL tstate
Can anybody help me make this code stable, so that it works all the time? I’m
using Python 2.6.5 under Windows Vista, but it crashes under Windows XP as well.