Problem with C-API

J

John Dean

Hi

I spent the whole of yesterday trying the get the following C code to
execute

PyRun_String("def title();", Py_file_input, dict, dict);
PyRun_String("\treturn 'Foo Bar'", Py_file_input, dict, dict);
PyRun_String("x = title()", Py_file_input, dict, dict);
PyObject * result = PyRun_String("print x", Py_file_input, dict, dict);
printf( "The result is %s\n", PyObject_AsString( result );

Each line throws an error.

Could somebody tell what is wrong with the above code.

Here below is the output from my test app

Starting Test ......

The file "testtitle" is open for reading

The variable codeStrings contains

Line 0 def title()
Line 1 return "Foo Bar"

The variable scriptText contains

def title()
return "Foo Bar"

The variable tempList contains

Line 0 testtitle
Line 1 title

Module Name is testtitle

Function Name is title

The variable functionCode contains

def title()
return "Foo Bar"

Python initialized successfully

Module object successfully created

Dict object successfully created

Failed to create a Result object.

The title of the this task is <nil>
 
D

Diez B. Roggisch

John said:
Hi

I spent the whole of yesterday trying the get the following C code to
execute

PyRun_String("def title();", Py_file_input, dict, dict);
^^^^^^^^^^^

Try using a colon here....
PyRun_String("\treturn 'Foo Bar'", Py_file_input, dict, dict);
PyRun_String("x = title()", Py_file_input, dict, dict);
PyObject * result = PyRun_String("print x", Py_file_input, dict, dict);
printf( "The result is %s\n", PyObject_AsString( result );


Overall it seems to me that ther must be a better way to do such a thing -
even in C. AFAIK it supports multiline-stringliterals. Why don't you do
something like this:

script = "\
def foo():\n\
return 'FooBar'\n\
x = title()\n\
print x\n"

And then read that script line by line, feeding it to the parser. Or maybe
the parser even groks that string at once - don't know that.


Diez
 
D

Duncan Booth

John said:
PyRun_String("def title();", Py_file_input, dict, dict);
PyRun_String("\treturn 'Foo Bar'", Py_file_input, dict, dict);
PyRun_String("x = title()", Py_file_input, dict, dict);
PyObject * result = PyRun_String("print x", Py_file_input, dict, dict);
printf( "The result is %s\n", PyObject_AsString( result );

Each line throws an error.

Please don't paraphrase your code when asking questions such as this. The
code above doesn't even compile (unmatched parentheses) so any response
must be a guess as to which parts were wrong in your original code and
which errors you introduced just for the posting.

Each call to PyRun_String is independant. You seem to think you can call
the function with part of your source code and then continue with more of
the source in another call. You cannot.

Try concatenating the lines together to at least make complete statements.
Also make sure to handle the result from every call to PyRun_String: check
it for null, if it is null you should format and print the error message.

The following is your code rewritten as a working program. When you run it,
it will tell you about the syntax error in your Python code. Fix that and
you will see your program output.

#include <python.h>

void run() {
PyObject *dict = PyDict_New();
PyObject *result;
if (dict==NULL) {
PyErr_Print();
return;
}

result = PyRun_String("def title();\n\treturn 'Foo Bar'\n",
Py_file_input, dict, dict);
if (result==NULL) {
PyErr_Print();
return;
} else {
Py_DECREF(result);
}

result = PyRun_String("x = title()", Py_file_input, dict, dict);
if (result==NULL) {
PyErr_Print();
return;
} else {
Py_DECREF(result);
}

result = PyRun_String("print x", Py_file_input, dict, dict);
if (result==NULL) {
PyErr_Print();
return;
} else {
PyObject *rString = PyObject_Str(result);
if (rString==NULL) {
Py_DECREF(result);
PyErr_Print();
return;
}

printf( "The result is %s\n", PyString_AsString(rString));
Py_DECREF(rString);
Py_DECREF(result);
}
}

int main(int argc, char **argv) {
Py_Initialize();
run();
}
 
J

John Dean

Hi Duncan

Your version of the app works apart from this part

.....
.....

else {
PyObject *rString = PyObject_Str(result);
if (rString==NULL) {
Py_DECREF(result);
PyErr_Print();
return;
}

printf( "The result is %s\n", PyString_AsString(rString));
Py_DECREF(rString);
Py_DECREF(result);
}
}

The result of the printf state is: "The result is None"


result = PyRun_String("print x", Py_file_input, dict, dict);

The above line of code displays the value returned from the title()
function. My problem is I need to be able to cature the return value because
in the real application it will be displayed in a Process Log Widget. Also
the real scripts will be much longer.

I have not had a problem writing Python extensions, but when it comes to
embedded Python I just see how to get my code to work.

Any further help would be greatly appreciated
 
J

John Dean

Hi

Duncan's example worked to a point. The line PyRun_String( "print x",
Py_file_input, dict, dict); print out the contents of x, but I don't want to
print x out. I want to be able to grab whateven the variable x contains so
that I can pass it on for further processing by the C++ application.

BTW this is only a test case. The real scripts are much bigger. I must say
the documentation is not of much help and there are no books or articles
covering embedding Python in any detail. What there is is very much out of
date.
 
F

Fredrik Lundh

John said:
Duncan's example worked to a point. The line PyRun_String( "print x",
Py_file_input, dict, dict); print out the contents of x, but I don't want to
print x out. I want to be able to grab whateven the variable x contains so
that I can pass it on for further processing by the C++ application.

a better approach is to combine embedding and extending, and let the em-
bedded code use your extension to talk to your program.

if you want your program to access x, let the embedded script do

import myapp
myapp.write(x)

since you know how to extend Python, implementing write should be trivial.

if you insist on picking out variables from the embedded script, you can use
the same approach as when you want to pull out variables from code you've
exec'ed: run the code in a namespace dictionary, and extract the data from
the dictionary after you've run the code. i.e.

g = {}
exec code in g
x = g["x"]

becomes

PyObject *g, *x;
g = PyDict_New();
PyDict_SetItemString(g, "__builtins__", PyEval_GetBuiltins());
PyRun_String(mycode, Py_file_input, g, NULL);
x = PyDict_GetItemString(g, "x");
Py_DECREF(g);

(the SetItemString call is probably not needed in all cases)
BTW this is only a test case. The real scripts are much bigger. I must say
the documentation is not of much help and there are no books or articles
covering embedding Python in any detail. What there is is very much out of
date.

well, I'm getting a bit tired of all this "if it's not published within the last
few weeks, it's out of date" nonsense that people keep using as an excuse
for procrastination. The Python C API is very stable, and the embedding
and extending basics haven't changed a bit in a decade.

and "no books" is also wrong; ORA's "Programming Python" spends some
40 pages on embedding only (including examples on how to extract stuff
from module namespaces). I'm pretty sure it's not the only one.

</F>
 
D

Duncan Booth

John said:
Hi Duncan

Your version of the app works apart from this part

....
....

else {
PyObject *rString = PyObject_Str(result);
if (rString==NULL) {
Py_DECREF(result);
PyErr_Print();
return;
}

printf( "The result is %s\n", PyString_AsString(rString));
Py_DECREF(rString);
Py_DECREF(result);
}
}

The result of the printf state is: "The result is None"

Yes, what did you expect it to be? The result from executing the Python
code was the value None.
result = PyRun_String("print x", Py_file_input, dict, dict);

The above line of code displays the value returned from the title()
function. My problem is I need to be able to cature the return value
because in the real application it will be displayed in a Process Log
Widget. Also the real scripts will be much longer.

I have not had a problem writing Python extensions, but when it comes
to embedded Python I just see how to get my code to work.

Any further help would be greatly appreciated
If you want the value of x, then pick it out of the dictionary:

{
PyObject *x = PyDict_GetItemString(dict, "x");
PyObject *rString = PyObject_Str(x);
printf( "x is %s\n", PyString_AsString(rString));
Py_DECREF(rString);
Py_DECREF(x);
}
Py_DECREF(dict); // I forgot this one in my original code.

If you want to embed Python though you really should look at Pyrex. Using
Pyrex you can all but forget about the Python api, write a Pyrex function
which is callable directly from C: it calls the Python code and returns the
C values you want as a result. Also it will handle all the error checking
and reference counting automatically.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,602
Members
45,183
Latest member
OrderGlycoEase

Latest Threads

Top