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