pythonutils.cpp

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

Generated on 16 Apr 2010 for frePPLe by  doxygen 1.6.1