[capi-sig] Easy way to Return Value from 1 line of Embedded Python?

M.-A. Lemburg mal at egenix.com
Fri May 28 10:54:38 CEST 2010


Jerry Krinock wrote:
> In a C program I need to unpickle a Python pickle which is generated by someone's Python program.  A Python newbie, I was able to do this, but only by writing a little python script file and loading it as a module.  But reading from a script file is fragile, has lots of possible errors to handle as you can see below, and is silly since there's only one line of Python.
> 
> I'd therefore like to create the Python module from a string constant, as with PyRun_SimpleString(), instead of reading a file.  But I can't find a function like that which returns a value.  Or I just don't know how.
> 
> Certainly there must be a simpler way to do this...

You can compile the code into code object using Py_CompileString()
and then pass this to PyEval_EvalCode() for execution. This
will evaluate the code and return the resulting Python object.

In your case, it's probably easier to just load the pickle
module from C and call the loads() function directly rather
than going through an extra layer of Python code.

> Thank you,
> 
> Jerry Krinock
> 
> ***** somePython.py *****************************
> 
> #!/usr/bin/env python
> 
> from pickle import loads
> 
> def unpickle(x):
>     return loads(x)
> 
> 
> ***** My C "Proof of Concept" Function **********
> 
> #include <Python/Python.h>  // Running on Mac OS X
> 
> char* PythonUnpickle(char* pickle) {
>     PyObject *pName, *pModule, *pFunc;
>     PyObject *pArgs, *pValue;
>     char* unpickledString = NULL ;
>     
>     Py_Initialize();
>     PyRun_SimpleString("import sys"); 
>     PyRun_SimpleString("sys.path.append(\"/Users/jk/Documents/Programming/Python/\")"); 
>     
>     pName = PyString_FromString("somePython");
>      
>     pModule = PyImport_Import(pName);
>     Py_DECREF(pName);
>     
>     if (pModule != NULL) {
>         
>         pFunc = PyObject_GetAttrString(pModule, "unpickle");
>         /* pFunc is a new reference */
>         
>         if (pFunc && PyCallable_Check(pFunc)) {
>             pArgs = PyTuple_New(1);
>             
>             // Create the argument to unpickle()
>             pValue = PyString_FromString(pickle);
>             if (!pValue) {
>                 Py_DECREF(pArgs);
>                 Py_DECREF(pModule);
>                 fprintf(stderr, "Cannot convert argument\n");
>                 return NULL ;
>             }
>             // Set the argument into the pArgs tuple
>             PyTuple_SetItem(pArgs, 0, pValue);
>             
>             // Run the python unpickle() function, get result pValue
>             pValue = PyObject_CallObject(pFunc, pArgs) ;
>             Py_DECREF(pArgs) ;
>             // Convert the Python string pValue to a C string
>             if (pValue != NULL) {
>                 unpickledString = PyString_AsString(pValue) ;
>                 Py_DECREF(pValue);
>             }
>             else {
>                 Py_DECREF(pFunc);
>                 Py_DECREF(pModule);
>                 PyErr_Print();
>                 fprintf(stderr,"Call failed\n");
>                 return  NULL ;
>             }
>         }
>         else {
>             if (PyErr_Occurred())
>                 PyErr_Print();
>             fprintf(stderr, "Cannot find 'unpickle' function\n") ;
>         }
>         Py_XDECREF(pFunc);
>         
>         
>         Py_DECREF(pModule);
>     }
>     else {
>         PyErr_Print();
>         fprintf(stderr, "Failed to load python script file\n");
>     }
>     Py_Finalize() ;
>     
>     return unpickledString ;
> }


The string object you get from the Python function will only
be allocated while the interpreter is initialized.

In your example the unpickledString will point to unallocated
memory when the function returns. It is not even guaranteed
to still have the correct string data.

To correct this, you will have to get the pointer to the string
data, copy it to a buffer you allocate in your app and only
then finalize the interpreter.

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, May 28 2010)
>>> Python/Zope Consulting and Support ...        http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ...             http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/
________________________________________________________________________
2010-07-19: EuroPython 2010, Birmingham, UK                51 days to go

::: Try our new mxODBC.Connect Python Database Interface for free ! ::::


   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
    D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
           Registered at Amtsgericht Duesseldorf: HRB 46611
               http://www.egenix.com/company/contact/


More information about the capi-sig mailing list