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

Documentation generated for frePPLe by  doxygen