pythonutils.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.9.1/src/utils/pythonutils.cpp $
00003   version : $LastChangedRevision: 1656 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2012-03-27 19:05:34 +0200 (Tue, 27 Mar 2012) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007-2012 by Johan De Taeye, frePPLe bvba                 *
00010  *                                                                         *
00011  * This library is free software; you can redistribute it and/or modify it *
00012  * under the terms of the GNU Lesser General Public License as published   *
00013  * by the Free Software Foundation; either version 2.1 of the License, or  *
00014  * (at your option) any later version.                                     *
00015  *                                                                         *
00016  * This library is distributed in the hope that it will be useful,         *
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
00019  * General Public License for more details.                                *
00020  *                                                                         *
00021  * You should have received a copy of the GNU Lesser General Public        *
00022  * License along with this library; if not, write to the Free Software     *
00023  * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 *
00024  * USA                                                                     *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 /** @file pythonutils.cpp
00029   * @brief Reusable functions for python functionality.
00030   *
00031   * The structure of the C++ wrappers around the C Python API is heavily
00032   * inspired on the design of PyCXX.<br>
00033   * More information can be found on http://cxx.sourceforge.net
00034   */
00035 
00036 #define FREPPLE_CORE
00037 #include "frepple/utils.h"
00038 
00039 namespace frepple
00040 {
00041 namespace utils
00042 {
00043 
00044 DECLARE_EXPORT PyObject* PythonLogicException = NULL;
00045 DECLARE_EXPORT PyObject* PythonDataException = NULL;
00046 DECLARE_EXPORT PyObject* PythonRuntimeException = NULL;
00047 
00048 DECLARE_EXPORT PyObject *PythonInterpreter::module = NULL;
00049 DECLARE_EXPORT string PythonInterpreter::encoding;
00050 DECLARE_EXPORT PyThreadState* PythonInterpreter::mainThreadState = NULL;
00051 
00052 
00053 DECLARE_EXPORT void PythonInterpreter::initialize(int argc, char *argv[])
00054 {
00055   // Initialize the Python interpreter in case we are embedding it in frePPLe.
00056   if(!Py_IsInitialized())
00057   {
00058     Py_InitializeEx(0);   // The arg 0 indicates that the interpreter doesn't
00059     // implement its own signal handler
00060     // Pass the command line arguments to Python as well
00061 #if PY_VERSION_HEX > 0x02060600
00062     if (argc>0) PySys_SetArgvEx(argc, argv, 0);
00063 #endif
00064     // Initializes threads
00065     PyEval_InitThreads();
00066     mainThreadState = PyEval_SaveThread();
00067   }
00068 
00069   // Capture global lock
00070   PyGILState_STATE state = PyGILState_Ensure();
00071 
00072   // Create the frePPLe module
00073   module = Py_InitModule3("frepple", NULL, "Access to the frePPLe library");
00074   if (!module)
00075   {
00076     PyGILState_Release(state);
00077     throw RuntimeException("Can't initialize Python interpreter");
00078   }
00079 
00080   // Make the datetime types available
00081   PyDateTime_IMPORT;
00082 
00083   // Create python exception types
00084   int nok = 0;
00085   PythonLogicException = PyErr_NewException("frepple.LogicException", NULL, NULL);
00086   Py_IncRef(PythonLogicException);
00087   nok += PyModule_AddObject(module, "LogicException", PythonLogicException);
00088   PythonDataException = PyErr_NewException("frepple.DataException", NULL, NULL);
00089   Py_IncRef(PythonDataException);
00090   nok += PyModule_AddObject(module, "DataException", PythonDataException);
00091   PythonRuntimeException = PyErr_NewException("frepple.RuntimeException", NULL, NULL);
00092   Py_IncRef(PythonRuntimeException);
00093   nok += PyModule_AddObject(module, "RuntimeException", PythonRuntimeException);
00094 
00095   // Add a string constant for the version
00096   nok += PyModule_AddStringConstant(module, "version", PACKAGE_VERSION);
00097 
00098   // Redirect the stderr and stdout streams of Python
00099   registerGlobalMethod("log", python_log, METH_VARARGS,
00100       "Prints a string to the frePPLe log file.", false);
00101   PyRun_SimpleString(
00102     "import frepple, sys\n"
00103     "class redirect:\n"
00104     "\tdef write(self,str):\n"
00105     "\t\tfrepple.log(str)\n"
00106     "sys.stdout = redirect()\n"
00107     "sys.stderr = redirect()"
00108   );
00109 
00110   // Get the preferred Python locale
00111   PyObject* localemodule = PyImport_ImportModule("locale");
00112   if (!localemodule)
00113   {
00114     PyGILState_Release(state);
00115     throw RuntimeException("Can't import 'locale' Python module");
00116   }
00117   else
00118   {
00119     PyObject* moduledict = PyModule_GetDict(localemodule);
00120     PyObject* func = PyDict_GetItemString(moduledict, "getpreferredencoding");
00121     if (!func)
00122     {
00123       PyGILState_Release(state);
00124       throw RuntimeException("Can't find 'getpreferredencoding' Python function");
00125     }
00126     PyObject* retval = PyEval_CallObject(func, NULL);
00127     if (retval)
00128     {
00129       encoding =  PyString_AsString(retval);
00130       Py_XDECREF(retval);
00131     }
00132     Py_XDECREF(localemodule);
00133   }
00134 
00135   // Release the lock
00136   PyGILState_Release(state);
00137 
00138   // A final check...
00139   if (nok) throw RuntimeException("Can't initialize Python interpreter");
00140 }
00141 
00142 
00143 DECLARE_EXPORT void PythonInterpreter::finalize()
00144 {
00145   // Only valid if this is an embedded interpreter
00146   if (!mainThreadState) return;
00147 
00148   // Swap to the main thread and exit
00149   PyEval_AcquireLock();
00150   PyEval_RestoreThread(mainThreadState);
00151   Py_Finalize();
00152 }
00153 
00154 
00155 DECLARE_EXPORT void PythonInterpreter::addThread()
00156 {
00157   // Check whether the thread already has a Python state
00158   PyThreadState * myThreadState = PyGILState_GetThisThreadState();
00159   if (myThreadState) return;
00160 
00161   // Create a new state
00162   PyThreadState *tcur = PyThreadState_New(PyInterpreterState_Head());
00163   if (!tcur) throw RuntimeException("Can't create new thread state");
00164 
00165   // Make the new state current
00166   PyEval_RestoreThread(tcur);
00167   PyEval_ReleaseLock();
00168 }
00169 
00170 
00171 DECLARE_EXPORT void PythonInterpreter::deleteThread()
00172 {
00173   // Check whether the thread already has a Python state
00174   PyThreadState * tcur = PyGILState_GetThisThreadState();
00175   if (!tcur) return;
00176 
00177   // Delete the current Python thread state
00178   PyEval_RestoreThread(tcur);
00179   PyThreadState_Clear(tcur);
00180   PyThreadState_DeleteCurrent(); // This releases the GIL too!
00181 }
00182 
00183 
00184 DECLARE_EXPORT void PythonInterpreter::execute(const char* cmd)
00185 {
00186   // Capture global lock
00187   PyGILState_STATE state = PyGILState_Ensure();
00188 
00189   // Execute the command
00190   PyObject *m = PyImport_AddModule("__main__");
00191   if (!m)
00192   {
00193     // Release the global Python lock
00194     PyGILState_Release(state);
00195     throw RuntimeException("Can't initialize Python interpreter");
00196   }
00197   PyObject *d = PyModule_GetDict(m);
00198   if (!d)
00199   {
00200     // Release the global Python lock
00201     PyGILState_Release(state);
00202     throw RuntimeException("Can't initialize Python interpreter");
00203   }
00204 
00205   // Execute the Python code. Note that during the call the Python lock can be
00206   // temporarily released.
00207   PyObject *v = PyRun_String(cmd, Py_file_input, d, d);
00208   if (!v)
00209   {
00210     // Print the error message
00211     PyErr_Print();
00212     // Release the global Python lock
00213     PyGILState_Release(state);
00214     throw RuntimeException("Error executing Python command");
00215   }
00216   Py_DECREF(v);
00217   if (Py_FlushLine()) PyErr_Clear();
00218 
00219   // Release the global Python lock
00220   PyGILState_Release(state);
00221 }
00222 
00223 
00224 DECLARE_EXPORT void PythonInterpreter::executeFile(string filename)
00225 {
00226   // A file to be executed.
00227   // We build an equivalent python command rather than using the
00228   // PyRun_File function. On windows different versions of the
00229   // VC compiler have a different structure for FILE, thus making it
00230   // impossible to use a lib compiled in python version x when compiling
00231   // under version y.  Quite ugly... :-( :-( :-(
00232   for (string::size_type pos = filename.find_first_of("'", 0);
00233       pos < string::npos;
00234       pos = filename.find_first_of("'", pos))
00235   {
00236     filename.replace(pos,1,"\\'",2); // Replacing ' with \'
00237     pos+=2;
00238   }
00239   string cmd = "execfile(ur'" + filename + "')\n";
00240   execute(cmd.c_str());
00241 }
00242 
00243 
00244 DECLARE_EXPORT void PythonInterpreter::registerGlobalMethod(
00245   const char* name, PyCFunction method, int flags, const char* doc, bool lock
00246 )
00247 {
00248   // Define a new method object.
00249   // We need are leaking the memory allocated for it to assure the data
00250   // are available at all times to Python.
00251   string *leakingName = new string(name);
00252   string *leakingDoc = new string(doc);
00253   PyMethodDef *newMethod = new PyMethodDef;
00254   newMethod->ml_name = leakingName->c_str();
00255   newMethod->ml_meth = method;
00256   newMethod->ml_flags = flags;
00257   newMethod->ml_doc = leakingDoc->c_str();
00258 
00259   // Lock the interpreter
00260   PyGILState_STATE state;
00261   if (lock) state = PyGILState_Ensure();
00262 
00263   // Register a new C function in Python
00264   PyObject* mod = PyString_FromString("frepple");
00265   if (!mod)
00266   {
00267     if (lock) PyGILState_Release(state);;
00268     throw RuntimeException("Error registering a new Python method");
00269   }
00270   PyObject* func = PyCFunction_NewEx(newMethod, NULL, mod);
00271   Py_DECREF(mod);
00272   if (!func)
00273   {
00274     if (lock) PyGILState_Release(state);
00275     throw RuntimeException("Error registering a new Python method");
00276   }
00277 
00278   // Add the method to the module dictionary
00279   PyObject* moduledict = PyModule_GetDict(module);
00280   if (!moduledict)
00281   {
00282     Py_DECREF(func);
00283     if (lock) PyGILState_Release(state);
00284     throw RuntimeException("Error registering a new Python method");
00285   }
00286   if (PyDict_SetItemString(moduledict ,leakingName->c_str(), func) < 0)
00287   {
00288     Py_DECREF(func);
00289     if (lock) PyGILState_Release(state);
00290     throw RuntimeException("Error registering a new Python method");
00291   }
00292   Py_DECREF(func);
00293 
00294   // Release the interpeter
00295   if (lock) PyGILState_Release(state);
00296 }
00297 
00298 
00299 DECLARE_EXPORT void PythonInterpreter::registerGlobalMethod
00300 (const char* c, PyCFunctionWithKeywords f, int i, const char* d, bool b)
00301 {
00302   registerGlobalMethod(c, reinterpret_cast<PyCFunction>(f), i | METH_KEYWORDS, d, b);
00303 }
00304 
00305 
00306 PyObject* PythonInterpreter::python_log(PyObject *self, PyObject *args)
00307 {
00308   // Pick up arguments
00309   char *data;
00310   int ok = PyArg_ParseTuple(args, "s:log", &data);
00311   if (!ok) return NULL;
00312 
00313   // Print and flush the output stream
00314   logger << data;
00315   logger.flush();
00316 
00317   // Return code
00318   return Py_BuildValue("");  // Safer than using Py_None, which is not
00319   // portable across compilers
00320 }
00321 
00322 
00323 const PyTypeObject PythonType::PyTypeObjectTemplate =
00324 {
00325   PyObject_HEAD_INIT(NULL)
00326   0,  /* ob_size */
00327   "frepple.unspecified",  /* WILL BE UPDATED tp_name */
00328   0,  /* WILL BE UPDATED tp_basicsize */
00329   0,  /* tp_itemsize */
00330   0,  /* CAN BE UPDATED tp_dealloc */
00331   0,  /* tp_print */
00332   0,  /* tp_getattr */
00333   0,  /* tp_setattr */
00334   0,  /* CAN BE UPDATED tp_compare */
00335   0,  /* tp_repr */
00336   0,  /* tp_as_number */
00337   0,  /* tp_as_sequence */
00338   0,  /* tp_as_mapping */
00339   reinterpret_cast<hashfunc>(_Py_HashPointer),  /* tp_hash */
00340   0,  /* CAN BE UPDATED tp_call */
00341   0,  /* CAN BE UPDATED tp_str */
00342   0,  /* CAN BE UPDATED tp_getattro */
00343   0,  /* CAN BE UPDATED tp_setattro */
00344   0,  /* tp_as_buffer */
00345   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
00346   "std doc", /* CAN BE UPDATED  tp_doc */
00347   0,  /* tp_traverse */
00348   0,  /* tp_clear */
00349   0,  /* tp_richcompare */
00350   0,  /* tp_weaklistoffset */
00351   0,  /* CAN BE UPDATED tp_iter */
00352   0,  /* CAN BE UPDATED tp_iternext */
00353   0,  /* tp_methods */
00354   0,  /* tp_members */
00355   0,  /* tp_getset */
00356   0,  /* tp_base */
00357   0,  /* tp_dict */
00358   0,  /* tp_descr_get */
00359   0,  /* tp_descr_set */
00360   0,  /* tp_dictoffset */
00361   0,  /* tp_init */
00362   0,  /* tp_alloc */
00363   0,  /* CAN BE UPDATED tp_new */
00364   0,  /* tp_free */
00365 };
00366 
00367 
00368 DECLARE_EXPORT PythonObject::PythonObject(const Date& d)
00369 {
00370   PyDateTime_IMPORT;
00371   // The standard library function localtime() is not re-entrant: the same
00372   // static structure is used for all calls. In a multi-threaded environment
00373   // the function is not to be used.
00374   // The POSIX standard defines a re-entrant version of the function:
00375   // localtime_r.
00376   // Visual C++ 6.0 and Borland 5.5 are missing it, but provide a thread-safe
00377   // variant without changing the function semantics.
00378   time_t ticks = d.getTicks();
00379 #ifdef HAVE_LOCALTIME_R
00380   struct tm t;
00381   localtime_r(&ticks, &t);
00382 #else
00383   struct tm t = *localtime(&ticks);
00384 #endif
00385   obj = PyDateTime_FromDateAndTime(t.tm_year+1900, t.tm_mon+1, t.tm_mday,
00386       t.tm_hour, t.tm_min, t.tm_sec, 0);
00387 }
00388 
00389 
00390 DECLARE_EXPORT Date PythonObject::getDate() const
00391 {
00392   PyDateTime_IMPORT;
00393   if (PyDateTime_Check(obj))
00394     return Date(
00395         PyDateTime_GET_YEAR(obj),
00396         PyDateTime_GET_MONTH(obj),
00397         PyDateTime_GET_DAY(obj),
00398         PyDateTime_DATE_GET_HOUR(obj),
00399         PyDateTime_DATE_GET_MINUTE(obj),
00400         PyDateTime_DATE_GET_SECOND(obj)
00401         );
00402   else if (PyDate_Check(obj))
00403     return Date(
00404         PyDateTime_GET_YEAR(obj),
00405         PyDateTime_GET_MONTH(obj),
00406         PyDateTime_GET_DAY(obj)
00407         );
00408   else if (PyString_Check(obj))
00409   {
00410     if (PyUnicode_Check(obj))
00411     {
00412       // Replace the unicode object with a string encoded in the correct locale
00413       const_cast<PyObject*&>(obj) =
00414         PyUnicode_AsEncodedString(obj, PythonInterpreter::getPythonEncoding(), "ignore");
00415     }
00416     return Date(PyString_AsString(PyObject_Str(obj)));
00417   }
00418   else
00419     throw DataException(
00420       "Invalid data type. Expecting datetime.date, datetime.datetime or string"
00421     );
00422 }
00423 
00424 
00425 DECLARE_EXPORT PythonObject::PythonObject(Object* p)
00426 {
00427   obj = p ? static_cast<PyObject*>(p) : Py_None;
00428   Py_INCREF(obj);
00429 }
00430 
00431 
00432 DECLARE_EXPORT PythonType::PythonType(size_t base_size, const type_info* tp)
00433   : cppClass(tp)
00434 {
00435   // Allocate a new type object if it doesn't exist yet.
00436   // We copy from a template type definition.
00437   table = new PyTypeObject(PyTypeObjectTemplate);
00438   table->tp_basicsize = base_size;
00439 }
00440 
00441 
00442 DECLARE_EXPORT PythonType* PythonExtensionBase::registerPythonType(int size, const type_info *t)
00443 {
00444   // Scan the types already registered
00445   for (vector<PythonType*>::const_iterator i = table.begin(); i != table.end(); ++i)
00446     if (**i==*t) return *i;
00447 
00448   // Not found in the vector, so create a new one
00449   PythonType *cachedTypePtr = new PythonType(size, t);
00450   table.push_back(cachedTypePtr);
00451   return cachedTypePtr;
00452 }
00453 
00454 
00455 DECLARE_EXPORT PyObject* Object::toXML(PyObject* self, PyObject* args)
00456 {
00457   try
00458   {
00459     // Parse the argument
00460     PyObject *filearg = NULL;
00461     if (PyArg_UnpackTuple(args, "toXML", 0, 1, &filearg))
00462     {
00463       ostringstream ch;
00464       XMLOutput x(ch);
00465       // Create the XML string.
00466       // The next call only works if the self argument is effectively an
00467       // instance of the Object base class! We don't check this.
00468       static_cast<Object*>(self)->writeElement
00469       (&x, *(static_cast<Object*>(self)->getType().category->typetag));
00470       // Write the output...
00471       if (filearg)
00472       {
00473         if (PyFile_Check(filearg))
00474         {
00475           // ... to a file
00476           return PyFile_WriteString(ch.str().c_str(), filearg) ?
00477               NULL : // Error writing to the file
00478               Py_BuildValue("");
00479         }
00480         else
00481           // The argument is not a file
00482           throw LogicException("Expecting a file argument");
00483       }
00484       else
00485         // ... to a string
00486         return PythonObject(ch.str());
00487     }
00488   }
00489   catch(...)
00490   {
00491     PythonType::evalException();
00492     return NULL;
00493   }
00494   throw LogicException("Unreachable code reached");
00495 }
00496 
00497 
00498 DECLARE_EXPORT void PythonType::addMethod
00499 (const char* method_name, PyCFunction f, int flags, const char* doc )
00500 {
00501   unsigned short i = 0;
00502 
00503   // Create a method table array
00504   if (!table->tp_methods)
00505     // Allocate a first block
00506     table->tp_methods = new PyMethodDef[methodArraySize];
00507   else
00508   {
00509     // Find the first non-empty method record
00510     while (table->tp_methods[i].ml_name) i++;
00511     if (i % methodArraySize == methodArraySize - 1)
00512     {
00513       // Allocation of a bigger buffer is required
00514       PyMethodDef* tmp = new PyMethodDef[i + 1 + methodArraySize];
00515       for(unsigned short j = 0; j < i; j++)
00516         tmp[j] = table->tp_methods[j];
00517       delete [] table->tp_methods;
00518       table->tp_methods = tmp;
00519     }
00520   }
00521 
00522   // Populate a method definition struct
00523   table->tp_methods[i].ml_name = method_name;
00524   table->tp_methods[i].ml_meth = f;
00525   table->tp_methods[i].ml_flags = flags;
00526   table->tp_methods[i].ml_doc = doc;
00527 
00528   // Append an empty terminator record
00529   table->tp_methods[++i].ml_name = NULL;
00530   table->tp_methods[i].ml_meth = NULL;
00531   table->tp_methods[i].ml_flags = 0;
00532   table->tp_methods[i].ml_doc = NULL;
00533 }
00534 
00535 
00536 DECLARE_EXPORT void PythonType::addMethod
00537 (const char* c, PyCFunctionWithKeywords f, int i, const char* d)
00538 {
00539   addMethod(c, reinterpret_cast<PyCFunction>(f), i | METH_KEYWORDS, d);
00540 }
00541 
00542 
00543 DECLARE_EXPORT int PythonType::typeReady()
00544 {
00545   // Register the new type in the module
00546   PyGILState_STATE state = PyGILState_Ensure();
00547   if (PyType_Ready(table) < 0)
00548   {
00549     PyGILState_Release(state);
00550     throw RuntimeException(string("Can't register python type ") + table->tp_name);
00551   }
00552   Py_INCREF(table);
00553   int result = PyModule_AddObject(
00554       PythonInterpreter::getModule(),
00555       table->tp_name + 8, // Note: +8 is to skip the "frepple." characters in the name
00556       reinterpret_cast<PyObject*>(table)
00557       );
00558   PyGILState_Release(state);
00559   return result;
00560 }
00561 
00562 
00563 DECLARE_EXPORT void PythonType::evalException()
00564 {
00565   // Rethrowing the exception to catch its type better
00566   try {throw;}
00567   catch (const DataException& e)
00568   {PyErr_SetString(PythonDataException, e.what());}
00569   catch (const LogicException& e)
00570   {PyErr_SetString(PythonLogicException, e.what());}
00571   catch (const RuntimeException& e)
00572   {PyErr_SetString(PythonRuntimeException, e.what());}
00573   catch (const exception& e)
00574   {PyErr_SetString(PyExc_Exception, e.what());}
00575   catch (...)
00576   {PyErr_SetString(PyExc_Exception, "Unidentified exception");}
00577 }
00578 
00579 
00580 DECLARE_EXPORT PythonFunction::PythonFunction(const string& n)
00581 {
00582   if (n.empty())
00583   {
00584     // Resetting to NULL when the string is empty
00585     func = NULL;
00586     return;
00587   }
00588 
00589   // Find the Python function
00590   PyGILState_STATE pythonstate = PyGILState_Ensure();
00591   func = PyRun_String(n.c_str(), Py_eval_input,
00592       PyEval_GetGlobals(), PyEval_GetLocals() );
00593   if (!func)
00594   {
00595     PyGILState_Release(pythonstate);
00596     throw DataException("Python function '" + n + "' not defined");
00597   }
00598   if (!PyCallable_Check(func))
00599   {
00600     PyGILState_Release(pythonstate);
00601     throw DataException("Python object '" + n + "' is not a function");
00602   }
00603   Py_INCREF(func);
00604 
00605   // Store the Python function
00606   PyGILState_Release(pythonstate);
00607 }
00608 
00609 
00610 DECLARE_EXPORT PythonFunction::PythonFunction(PyObject* p)
00611 {
00612   if (!p || p == Py_None)
00613   {
00614     // Resetting to null
00615     func = NULL;
00616     return;
00617   }
00618 
00619   if (!PyCallable_Check(p))
00620   {
00621     // It's not a callable object. Interprete it as a function name and
00622     // look it up.
00623     string n = PythonObject(p).getString();
00624     PyGILState_STATE pythonstate = PyGILState_Ensure();
00625     p = PyRun_String(n.c_str(), Py_eval_input,
00626         PyEval_GetGlobals(), PyEval_GetLocals() );
00627     if (!p)
00628     {
00629       PyGILState_Release(pythonstate);
00630       throw DataException("Python function '" + n + "' not defined");
00631     }
00632     if (!PyCallable_Check(p))
00633     {
00634       PyGILState_Release(pythonstate);
00635       throw DataException("Python object '" + n + "' is not a function");
00636     }
00637     PyGILState_Release(pythonstate);
00638   }
00639 
00640   // Store the Python function
00641   func = p;
00642   Py_INCREF(func);
00643 }
00644 
00645 
00646 DECLARE_EXPORT PythonObject PythonFunction::call() const
00647 {
00648   if (!func) return PythonObject();
00649   PyGILState_STATE pythonstate = PyGILState_Ensure();
00650   PyObject* result = PyEval_CallFunction(func, "()");
00651   if (!result)
00652   {
00653     logger << "Error: Exception caught when calling Python function '"
00654         << (func ? PyEval_GetFuncName(func) : "NULL") << "'" << endl;
00655     if (PyErr_Occurred()) PyErr_PrintEx(0);
00656   }
00657   PyGILState_Release(pythonstate);
00658   return PythonObject(result);
00659 }
00660 
00661 
00662 DECLARE_EXPORT PythonObject PythonFunction::call(const PyObject* p) const
00663 {
00664   if (!func) return PythonObject();
00665   PyGILState_STATE pythonstate = PyGILState_Ensure();
00666   PyObject* result = PyEval_CallFunction(func, "(O)", p);
00667   if (!result)
00668   {
00669     logger << "Error: Exception caught when calling Python function '"
00670         << (func ? PyEval_GetFuncName(func) : "NULL") << "'" << endl;
00671     if (PyErr_Occurred()) PyErr_PrintEx(0);
00672   }
00673   PyGILState_Release(pythonstate);
00674   return PythonObject(result);
00675 }
00676 
00677 
00678 DECLARE_EXPORT PythonObject PythonFunction::call(const PyObject* p, const PyObject* q) const
00679 {
00680   if (!func) return PythonObject();
00681   PyGILState_STATE pythonstate = PyGILState_Ensure();
00682   PyObject* result = PyEval_CallFunction(func, "(OO)", p, q);
00683   if (!result)
00684   {
00685     logger << "Error: Exception caught when calling Python function '"
00686         << (func ? PyEval_GetFuncName(func) : "NULL") << "'" << endl;
00687     if (PyErr_Occurred()) PyErr_PrintEx(0);
00688   }
00689   PyGILState_Release(pythonstate);
00690   return PythonObject(result);
00691 }
00692 
00693 
00694 extern "C" DECLARE_EXPORT PyObject* getattro_handler(PyObject *self, PyObject *name)
00695 {
00696   try
00697   {
00698     if (!PyString_Check(name))
00699     {
00700       PyErr_Format(PyExc_TypeError,
00701           "attribute name must be string, not '%s'",
00702           name->ob_type->tp_name);
00703       return NULL;
00704     }
00705     PyObject* result = static_cast<PythonExtensionBase*>(self)->getattro(Attribute(PyString_AsString(name)));
00706     // Exit 1: Normal
00707     if (result) return result;
00708     // Exit 2: Exception occurred
00709     if (PyErr_Occurred()) return NULL;
00710     // Exit 3: No error occurred but the attribute was not found.
00711     // Use the standard generic function to pick up  standard attributes
00712     // (such as __class__, __doc__, ...)
00713     // Note that this function also picks up attributes from base classes, but
00714     // we can't rely on that: any C++ exceptions are lost along the way...
00715     return PyObject_GenericGetAttr(self,name);
00716   }
00717   catch (...)
00718   {
00719     PythonType::evalException();
00720     return NULL;
00721   }
00722 }
00723 
00724 
00725 extern "C" DECLARE_EXPORT int setattro_handler(PyObject *self, PyObject *name, PyObject *value)
00726 {
00727   try
00728   {
00729     // Pick up the field name
00730     if (!PyString_Check(name))
00731     {
00732       PyErr_Format(PyExc_TypeError,
00733           "attribute name must be string, not '%s'",
00734           name->ob_type->tp_name);
00735       return -1;
00736     }
00737     PythonObject field(value);
00738 
00739     // Call the object to update the attribute
00740     int result = static_cast<PythonExtensionBase*>(self)->setattro(Attribute(PyString_AsString(name)), field);
00741 
00742     // Process 'OK' result
00743     if (!result) return 0;
00744 
00745     // Process 'not OK' result - set python error string if it isn't set yet
00746     if (!PyErr_Occurred())
00747       PyErr_Format(PyExc_AttributeError,
00748           "attribute '%s' on '%s' can't be updated",
00749           PyString_AsString(name), self->ob_type->tp_name);
00750     return -1;
00751   }
00752   catch (...)
00753   {
00754     PythonType::evalException();
00755     return -1;
00756   }
00757 }
00758 
00759 
00760 extern "C" DECLARE_EXPORT int compare_handler(PyObject *self, PyObject *other)
00761 {
00762   try
00763   {
00764     return static_cast<PythonExtensionBase*>(self)->compare(other);
00765   }
00766   catch (...)
00767   {
00768     PythonType::evalException();
00769     return -1;
00770   }
00771 }
00772 
00773 
00774 extern "C" DECLARE_EXPORT PyObject* iternext_handler(PyObject *self)
00775 {
00776   try
00777   {
00778     return static_cast<PythonExtensionBase*>(self)->iternext();
00779   }
00780   catch (...)
00781   {
00782     PythonType::evalException();
00783     return NULL;
00784   }
00785 }
00786 
00787 
00788 extern "C" DECLARE_EXPORT PyObject* call_handler(PyObject* self, PyObject* args, PyObject* kwds)
00789 {
00790   try
00791   {
00792     return static_cast<PythonExtensionBase*>(self)->call(args, kwds);
00793   }
00794   catch (...)
00795   {
00796     PythonType::evalException();
00797     return NULL;
00798   }
00799 }
00800 
00801 
00802 extern "C" DECLARE_EXPORT PyObject* str_handler(PyObject* self)
00803 {
00804   try
00805   {
00806     return static_cast<PythonExtensionBase*>(self)->str();
00807   }
00808   catch (...)
00809   {
00810     PythonType::evalException();
00811     return NULL;
00812   }
00813 }
00814 
00815 } // end namespace
00816 } // end namespace

Documentation generated for frePPLe by  doxygen