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