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: 1315 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2010-07-17 18:08:53 +0200 (Sat, 17 Jul 2010) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007-2010 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
Documentation generated for frePPLe by
