By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,035 Members | 1,984 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,035 IT Pros & Developers. It's quick & easy.

PyRun_String and related functions causing garbage when calling a parsed function from C.

P: n/a
Hi I'm getting extremely odd behavior. First of all, why isn't
PyEval_EvalCode documented anywhere? Anyway, I'm working on
blender's
python integration (it embeds python, as opposed to python embedding
it). I have a function that executes a string buffer of python code,
fetches a function from its global dictionary then calls it.

When the function code returns a local variable, PyObject_Call()
appears
to be returning garbage. Strangely this is only happening with
internal
blender types, yet try however I might I can't find any refcounting
errors to account for this. The initial implementation used the same
dictionary for the global and local dicts. I tried using separate
dicts, but then the function wasn't being called at all (or at least I
tested it by putting a "print "bleh"" in there, and it didn't work).
Also, when I printed the refcount of the garbage data, it was garbage
as
well (so the entire piece of memory is bad, not just the data
portion).

I've tested with both python 2.4 and 2.5. Mostly with 2.4. This bug
may be cropping up in other experimental blender python code as well.

Here's the code in the string buffer:
#BPYCONSTRAINT
from Blender import *
from Blender.Mathutils import *
print "d"
def doConstraint(inmat, tarmat, prop):
a = Matrix()
a.identity()
a = a * TranslationMatrix(Vector(0, 0, 0))
print "t"
a = tarmat
return inmat

print doConstraint(Matrix(), Matrix(), 0)

Here's the code that executes the string buffer:

PyObject *RunPython2( Text * text, PyObject * globaldict, PyObject
*localdict )
{
char *buf = NULL;

/* The script text is compiled to Python bytecode and saved at
text->compiled
* to speed-up execution if the user executes the script multiple times
*/

if( !text->compiled ) { // if it wasn't already compiled, do it
now
buf = txt_to_buf( text );

text->compiled =
Py_CompileString( buf, GetName( text ),
Py_file_input );

MEM_freeN( buf );

if( PyErr_Occurred( ) ) {
BPY_free_compiled_text( text );
return NULL;
}

}
return PyEval_EvalCode( text->compiled, globaldict, localdict );
}
.. . .and heres the (rather long, and somewhat in a debugging state)
function that calls the function in the script's global dictionary:

void BPY_pyconstraint_eval(bPythonConstraint *con, float obmat[][4],
short ownertype, void *ownerdata, float targetmat[][4])
{
PyObject *srcmat, *tarmat, *idprop;
PyObject *globals, *locals;
PyObject *gkey, *gval;
PyObject *retval;
MatrixObject *retmat;
Py_ssize_t ppos = 0;
int row, col;

if ( !con->text ) return;

globals = CreateGlobalDictionary();

srcmat = newMatrixObject( (float*)obmat, 4, 4, Py_NEW );
tarmat = newMatrixObject( (float*)targetmat, 4, 4, Py_NEW );
idprop = BPy_Wrap_IDProperty( NULL, &con->prop, NULL);

/* since I can't remember what the armature weakrefs do, I'll just
leave this here
commented out. Since this function was based on pydrivers.
if( !setup_armature_weakrefs()){
fprintf( stderr, "Oops - weakref dict setup\n");
return result;
}
*/
retval = RunPython2( con->text, globals, globals);

if (retval) {Py_XDECREF( retval );}

if ( retval == NULL ) {
BPY_Err_Handle(con->text->id.name);
ReleaseGlobalDictionary( globals );

/*free temp objects*/
Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
return;
}

/*Now for the fun part! Try and find the functions we need.*/
while ( PyDict_Next(globals, &ppos, &gkey, &gval) ) {
if ( PyString_Check(gkey) && strcmp(PyString_AsString(gkey),
"doConstraint")==0 ) {
if (PyFunction_Check(gval) ) {
retval = PyObject_CallObject(gval,
Py_BuildValue("OOO",
srcmat, tarmat, idprop));
Py_XDECREF( retval );
} else {
printf("ERROR: doConstraint is supposed to be a
function!\n");
}
break;
}
}

if (!retval) {
BPY_Err_Handle(con->text->id.name);
/*free temp objects*/
ReleaseGlobalDictionary( globals );

Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
return;
}

if (!PyObject_TypeCheck(retval, &matrix_Type)) {
printf("Error in pyconstraint: Wrong return type for a
pyconstraint!\n");
ReleaseGlobalDictionary( globals );

Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
Py_XDECREF( retval );
return;
}

retmat = (MatrixObject*) retval;
if (retmat->rowSize != 4 || retmat->colSize != 4) {
printf("Error in pyconstraint: Matrix is the wrong size!\n");
ReleaseGlobalDictionary( globals );

Py_XDECREF( idprop );
Py_XDECREF( srcmat );
Py_XDECREF( tarmat );
Py_XDECREF( retval );
return;
}

//this is the reverse of code taken from newMatrix().
for(row = 0; row < 4; row++) {
for(col = 0; col < 4; col++) {
if (retmat->wrapped) obmat[row][col] =
retmat->data.blend_data[row*4+col]; //[row][col];
else obmat[row][col] = retmat->data.py_data[row*4+col];
//[row][col];

}
}

/*clear globals*/
//ReleaseGlobalDictionary( globals );

/*free temp objects*/
//Py_XDECREF( idprop );
//Py_XDECREF( srcmat );
//Py_XDECREF( tarmat );
//Py_XDECREF( retval );
//PyDict_Clear(locals);
//Py_XDECREF(locals);
}

Joe

May 13 '07 #1
Share this Question
Share on Google+
1 Reply


P: n/a
En Sun, 13 May 2007 17:58:17 -0300, <jo****@gmail.comescribió:
Hi I'm getting extremely odd behavior. First of all, why isn't
PyEval_EvalCode documented anywhere? Anyway, I'm working on
blender's
python integration (it embeds python, as opposed to python embedding
it). I have a function that executes a string buffer of python code,
fetches a function from its global dictionary then calls it.
Why don't you use a documented function like PyRun_String or similar, as
in the subject line?
/*Now for the fun part! Try and find the functions we need.*/
while ( PyDict_Next(globals, &ppos, &gkey, &gval) ) {
if ( PyString_Check(gkey) && strcmp(PyString_AsString(gkey),
"doConstraint")==0 ) {
if (PyFunction_Check(gval) ) {
retval = PyObject_CallObject(gval,
Py_BuildValue("OOO",
srcmat, tarmat, idprop));
Py_XDECREF( retval );
} else {
printf("ERROR: doConstraint is supposed to be a
function!\n");
}
break;
}
}
I'd use PyDict_Get_Item_String (iterating over a dict just to locate a key
is rather silly).
And, if you are going to use the return value from PyObject_CallObject
(retval), don't decref it!!! (you even decref it twice).

--
Gabriel Genellina

May 14 '07 #2

This discussion thread is closed

Replies have been disabled for this discussion.