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

Documentation generated for frePPLe by  doxygen