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