00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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 const MetaClass* CommandPython::metadata2;
00048
00049 DECLARE_EXPORT PyObject *PythonInterpreter::module = NULL;
00050 DECLARE_EXPORT string PythonInterpreter::encoding;
00051
00052
00053 void CommandPython::execute()
00054 {
00055
00056 if (getVerbose())
00057 {
00058 logger << "Start executing python ";
00059 if (!cmd.empty()) logger << "command";
00060 if (!filename.empty()) logger << "file";
00061 logger << " at " << Date::now() << endl;
00062 }
00063 Timer t;
00064
00065
00066 string c;
00067 if (!cmd.empty())
00068
00069 c = cmd + "\n";
00070 else if (!filename.empty())
00071 {
00072
00073
00074
00075
00076
00077
00078 c = filename;
00079 for (string::size_type pos = c.find_first_of("'", 0);
00080 pos < string::npos;
00081 pos = c.find_first_of("'", pos))
00082 {
00083 c.replace(pos,1,"\\'",2);
00084 pos+=2;
00085 }
00086 c = "execfile(ur'" + c + "')\n";
00087 }
00088 else throw DataException("Python command without statement or filename");
00089
00090
00091 PythonInterpreter::execute(c.c_str());
00092
00093
00094 if (getVerbose()) logger << "Finished executing python at "
00095 << Date::now() << " : " << t << endl;
00096 }
00097
00098
00099 void PythonInterpreter::initialize()
00100 {
00101
00102 Py_InitializeEx(0);
00103
00104 PyEval_InitThreads();
00105 module = Py_InitModule3("frepple", NULL, "Access to the frePPLe library");
00106 if (!module)
00107 {
00108 PyEval_ReleaseLock();
00109 throw RuntimeException("Can't initialize Python interpreter");
00110 }
00111
00112
00113 PyDateTime_IMPORT;
00114
00115
00116 int nok = 0;
00117 PythonLogicException = PyErr_NewException("frepple.LogicException", NULL, NULL);
00118 Py_IncRef(PythonLogicException);
00119 nok += PyModule_AddObject(module, "LogicException", PythonLogicException);
00120 PythonDataException = PyErr_NewException("frepple.DataException", NULL, NULL);
00121 Py_IncRef(PythonDataException);
00122 nok += PyModule_AddObject(module, "DataException", PythonDataException);
00123 PythonRuntimeException = PyErr_NewException("frepple.RuntimeException", NULL, NULL);
00124 Py_IncRef(PythonRuntimeException);
00125 nok += PyModule_AddObject(module, "RuntimeException", PythonRuntimeException);
00126
00127
00128 nok += PyModule_AddStringConstant(module, "version", PACKAGE_VERSION);
00129
00130
00131 registerGlobalMethod("log", python_log, METH_VARARGS,
00132 "Prints a string to the frePPLe log file.", false);
00133 PyRun_SimpleString(
00134 "import frepple, sys\n"
00135 "class redirect:\n"
00136 "\tdef write(self,str):\n"
00137 "\t\tfrepple.log(str)\n"
00138 "sys.stdout = redirect()\n"
00139 "sys.stderr = redirect()"
00140 );
00141
00142
00143 PyObject* localemodule = PyImport_ImportModule("locale");
00144 if (!localemodule)
00145 throw RuntimeException("Can't import 'locale' Python module");
00146 else
00147 {
00148 PyObject* moduledict = PyModule_GetDict(localemodule);
00149 PyObject* func = PyDict_GetItemString(moduledict, "getpreferredencoding");
00150 if (!func)
00151 throw RuntimeException("Can't find 'getpreferredencoding' Python function");
00152 PyObject* retval = PyEval_CallObject(func, NULL);
00153 if (retval)
00154 {
00155 encoding = PyString_AsString(retval);
00156 Py_XDECREF(retval);
00157 }
00158 Py_XDECREF(localemodule);
00159 }
00160
00161
00162 PyEval_ReleaseLock();
00163
00164
00165 if (nok) throw RuntimeException("Can't initialize Python interpreter");
00166 }
00167
00168
00169 DECLARE_EXPORT void PythonInterpreter::addThread()
00170 {
00171
00172 PyThreadState * myThreadState = PyGILState_GetThisThreadState();
00173 if (myThreadState) return;
00174
00175
00176 PyThreadState *tcur = PyThreadState_New(PyInterpreterState_Head());
00177 if (!tcur) throw RuntimeException("Can't create new thread state");
00178
00179
00180 PyEval_RestoreThread(tcur);
00181 PyEval_ReleaseLock();
00182 }
00183
00184
00185 DECLARE_EXPORT void PythonInterpreter::deleteThread()
00186 {
00187
00188 PyThreadState * tcur = PyGILState_GetThisThreadState();
00189 if (!tcur) return;
00190
00191
00192 PyEval_RestoreThread(tcur);
00193 PyThreadState_Clear(tcur);
00194 PyThreadState_DeleteCurrent();
00195 }
00196
00197
00198 DECLARE_EXPORT void PythonInterpreter::execute(const char* cmd)
00199 {
00200
00201
00202 PyThreadState *myThreadState = PyGILState_GetThisThreadState();
00203 if (!myThreadState)
00204 throw RuntimeException("No Python thread state for this thread");
00205 PyEval_RestoreThread(myThreadState);
00206
00207
00208 PyObject *m = PyImport_AddModule("__main__");
00209 if (!m)
00210 {
00211
00212 PyEval_ReleaseLock();
00213 throw RuntimeException("Can't initialize Python interpreter");
00214 }
00215 PyObject *d = PyModule_GetDict(m);
00216 if (!d)
00217 {
00218
00219 PyEval_ReleaseLock();
00220 throw RuntimeException("Can't initialize Python interpreter");
00221 }
00222
00223
00224
00225 PyObject *v = PyRun_String(cmd, Py_file_input, d, d);
00226 if (!v)
00227 {
00228
00229 PyErr_Print();
00230
00231 PyEval_ReleaseLock();
00232 throw RuntimeException("Error executing Python command");
00233 }
00234 Py_DECREF(v);
00235 if (Py_FlushLine()) PyErr_Clear();
00236
00237
00238 PyEval_ReleaseLock();
00239 }
00240
00241
00242 DECLARE_EXPORT void PythonInterpreter::registerGlobalMethod(
00243 const char* name, PyCFunction method, int flags, const char* doc, bool lock
00244 )
00245 {
00246
00247
00248
00249 string *leakingName = new string(name);
00250 string *leakingDoc = new string(doc);
00251 PyMethodDef *newMethod = new PyMethodDef;
00252 newMethod->ml_name = leakingName->c_str();
00253 newMethod->ml_meth = method;
00254 newMethod->ml_flags = flags;
00255 newMethod->ml_doc = leakingDoc->c_str();
00256
00257
00258 if (lock)
00259 {
00260 PyThreadState *myThreadState = PyGILState_GetThisThreadState();
00261 if (!Py_IsInitialized() || !myThreadState)
00262 throw RuntimeException("Python isn't initialized correctly");
00263 PyEval_RestoreThread(myThreadState);
00264 }
00265
00266
00267 PyObject* mod = PyString_FromString("frepple");
00268 if (!mod)
00269 {
00270 if (lock) PyEval_ReleaseLock();
00271 throw RuntimeException("Error registering a new Python method");
00272 }
00273 PyObject* func = PyCFunction_NewEx(newMethod, NULL, mod);
00274 Py_DECREF(mod);
00275 if (!func)
00276 {
00277 if (lock) PyEval_ReleaseLock();
00278 throw RuntimeException("Error registering a new Python method");
00279 }
00280
00281
00282 PyObject* moduledict = PyModule_GetDict(module);
00283 if (!moduledict)
00284 {
00285 Py_DECREF(func);
00286 if (lock) PyEval_ReleaseLock();
00287 throw RuntimeException("Error registering a new Python method");
00288 }
00289 if (PyDict_SetItemString(moduledict ,leakingName->c_str(), func) < 0)
00290 {
00291 Py_DECREF(func);
00292 if (lock) PyEval_ReleaseLock();
00293 throw RuntimeException("Error registering a new Python method");
00294 }
00295 Py_DECREF(func);
00296
00297
00298 if (lock) PyEval_ReleaseLock();
00299 }
00300
00301
00302 DECLARE_EXPORT void PythonInterpreter::registerGlobalMethod
00303 (const char* c, PyCFunctionWithKeywords f, int i, const char* d)
00304 {
00305 registerGlobalMethod(c, reinterpret_cast<PyCFunction>(f), i | METH_KEYWORDS, d);
00306 }
00307
00308
00309 PyObject* PythonInterpreter::python_log(PyObject *self, PyObject *args)
00310 {
00311
00312 char *data;
00313 int ok = PyArg_ParseTuple(args, "s", &data);
00314 if (!ok) return NULL;
00315
00316
00317 logger << data;
00318 logger.flush();
00319
00320
00321 return Py_BuildValue("");
00322
00323 }
00324
00325
00326 const PyTypeObject PythonType::PyTypeObjectTemplate =
00327 {
00328 PyObject_HEAD_INIT(NULL)
00329 0,
00330 "frepple.unspecified",
00331 0,
00332 0,
00333 0,
00334 0,
00335 0,
00336 0,
00337 0,
00338 0,
00339 0,
00340 0,
00341 0,
00342 0,
00343 0,
00344 0,
00345 0,
00346 0,
00347 0,
00348 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00349 "std doc",
00350 0,
00351 0,
00352 0,
00353 0,
00354 0,
00355 0,
00356 0,
00357 0,
00358 0,
00359 0,
00360 0,
00361 0,
00362 0,
00363 0,
00364 0,
00365 0,
00366 0,
00367 0,
00368 };
00369
00370
00371 DECLARE_EXPORT PythonObject::PythonObject(const Date& d)
00372 {
00373 PyDateTime_IMPORT;
00374
00375
00376
00377
00378
00379
00380
00381 time_t ticks = d.getTicks();
00382 #ifdef HAVE_LOCALTIME_R
00383 struct tm t;
00384 localtime_r(&ticks, &t);
00385 #else
00386 struct tm t = *localtime(&ticks);
00387 #endif
00388 obj = PyDateTime_FromDateAndTime(t.tm_year+1900, t.tm_mon+1, t.tm_mday,
00389 t.tm_hour, t.tm_min, t.tm_sec, 0);
00390 }
00391
00392
00393 DECLARE_EXPORT Date PythonObject::getDate() const
00394 {
00395 PyDateTime_IMPORT;
00396 if (PyDateTime_Check(obj))
00397 return Date(
00398 PyDateTime_GET_YEAR(obj),
00399 PyDateTime_GET_MONTH(obj),
00400 PyDateTime_GET_DAY(obj),
00401 PyDateTime_DATE_GET_HOUR(obj),
00402 PyDateTime_DATE_GET_MINUTE(obj),
00403 PyDateTime_DATE_GET_SECOND(obj)
00404 );
00405 else if (PyDate_Check(obj))
00406 return Date(
00407 PyDateTime_GET_YEAR(obj),
00408 PyDateTime_GET_MONTH(obj),
00409 PyDateTime_GET_DAY(obj)
00410 );
00411 else if (PyString_Check(obj))
00412 {
00413 if (PyUnicode_Check(obj))
00414 {
00415
00416 const_cast<PyObject*&>(obj) =
00417 PyUnicode_AsEncodedString(obj, PythonInterpreter::getPythonEncoding(), "ignore");
00418 }
00419 return Date(PyString_AsString(PyObject_Str(obj)));
00420 }
00421 else
00422 throw DataException(
00423 "Invalid data type. Expecting datetime.date, datetime.datetime or string"
00424 );
00425 }
00426
00427
00428 DECLARE_EXPORT PythonObject::PythonObject(Object* p)
00429 {
00430 if (!p)
00431 {
00432 obj = Py_None;
00433 Py_INCREF(obj);
00434 }
00435 else if (p->getType().factoryPythonProxy)
00436 obj = reinterpret_cast<PyObject*>(p->getType().factoryPythonProxy(p));
00437 else if (p->getType().category->factoryPythonProxy)
00438 obj = reinterpret_cast<PyObject*>(p->getType().category->factoryPythonProxy(p));
00439 else
00440 throw LogicException("Can't create a Python proxy for " + p->getType().type);
00441 }
00442
00443
00444 DECLARE_EXPORT PythonType::PythonType(size_t base_size, const type_info* tp)
00445 : methods(NULL), cppClass(tp)
00446 {
00447
00448 memcpy(&table, &PyTypeObjectTemplate, sizeof(PyTypeObject));
00449 table.tp_basicsize = base_size;
00450 }
00451
00452
00453 DECLARE_EXPORT void PythonType::addMethod
00454 (const char* method_name, PyCFunction f, int flags, const char* doc )
00455 {
00456
00457 if (methods) throw LogicException("Too late to add a method");
00458
00459
00460 PyMethodDef m;
00461 m.ml_name = method_name;
00462 m.ml_meth = f;
00463 m.ml_flags = flags;
00464 m.ml_doc = doc;
00465 methodvector.push_back(m);
00466 }
00467
00468
00469 DECLARE_EXPORT void PythonType::addMethod
00470 (const char* c, PyCFunctionWithKeywords f, int i, const char* d)
00471 {
00472 addMethod(c, reinterpret_cast<PyCFunction>(f), i | METH_KEYWORDS, d);
00473 }
00474
00475
00476 DECLARE_EXPORT int PythonType::typeReady(PyObject* m)
00477 {
00478
00479 if (!methodvector.empty())
00480 {
00481 addMethod(NULL, static_cast<PyCFunction>(NULL), 0, NULL);
00482 methods = new PyMethodDef[methodvector.size()];
00483 int j = 0;
00484 for(vector<PyMethodDef>::iterator i = methodvector.begin(); i != methodvector.end(); i++ )
00485 methods[j++] = *i;
00486 table.tp_methods = methods;
00487 }
00488
00489
00490 if (PyType_Ready(&table) < 0)
00491 throw RuntimeException("Can't register python type " + name);
00492 Py_INCREF(&table);
00493
00494 return PyModule_AddObject(m, const_cast<char*>(name.c_str()) + 8, reinterpret_cast<PyObject*>(&table));
00495 }
00496
00497
00498 DECLARE_EXPORT void PythonType::evalException()
00499 {
00500
00501 try {throw;}
00502 catch (DataException e)
00503 { PyErr_SetString(PythonDataException, e.what()); }
00504 catch (LogicException e)
00505 { PyErr_SetString(PythonLogicException, e.what()); }
00506 catch (RuntimeException e)
00507 { PyErr_SetString(PythonRuntimeException, e.what()); }
00508 catch (exception e)
00509 { PyErr_SetString(PyExc_Exception, e.what()); }
00510 catch (...)
00511 { PyErr_SetString(PyExc_Exception, "Unidentified exception"); }
00512 }
00513
00514
00515 extern "C" DECLARE_EXPORT PyObject* getattro_handler(PyObject *self, PyObject *name)
00516 {
00517 try
00518 {
00519 if (!PyString_Check(name))
00520 {
00521 PyErr_Format(PyExc_TypeError,
00522 "attribute name must be string, not '%s'",
00523 name->ob_type->tp_name);
00524 return NULL;
00525 }
00526 PyObject* result = static_cast<PythonExtensionBase*>(self)->getattro(Attribute(PyString_AsString(name)));
00527
00528 if (result) return result;
00529
00530 if (PyErr_Occurred()) return NULL;
00531
00532
00533
00534
00535
00536 return PyObject_GenericGetAttr(self,name);
00537 }
00538 catch (...)
00539 {
00540 PythonType::evalException();
00541 return NULL;
00542 }
00543 }
00544
00545
00546 extern "C" DECLARE_EXPORT int setattro_handler(PyObject *self, PyObject *name, PyObject *value)
00547 {
00548 try
00549 {
00550
00551 if (!PyString_Check(name))
00552 {
00553 PyErr_Format(PyExc_TypeError,
00554 "attribute name must be string, not '%s'",
00555 name->ob_type->tp_name);
00556 return -1;
00557 }
00558 PythonObject field(value);
00559
00560
00561 int result = static_cast<PythonExtensionBase*>(self)->setattro(Attribute(PyString_AsString(name)), field);
00562
00563
00564 if (!result) return 0;
00565 PyErr_Format(PyExc_AttributeError,
00566 "attribute '%s' on '%s' can't be updated",
00567 PyString_AsString(name), self->ob_type->tp_name);
00568 return -1;
00569 }
00570 catch (...)
00571 {
00572 PythonType::evalException();
00573 return -1;
00574 }
00575 }
00576
00577
00578 extern "C" DECLARE_EXPORT int compare_handler(PyObject *self, PyObject *other)
00579 {
00580 try
00581 {
00582 return static_cast<PythonExtensionBase*>(self)->compare(other);
00583 }
00584 catch (...)
00585 {
00586 PythonType::evalException();
00587 return -1;
00588 }
00589 }
00590
00591
00592 extern "C" DECLARE_EXPORT PyObject* iternext_handler(PyObject *self)
00593 {
00594 try
00595 {
00596 return static_cast<PythonExtensionBase*>(self)->iternext();
00597 }
00598 catch (...)
00599 {
00600 PythonType::evalException();
00601 return NULL;
00602 }
00603 }
00604
00605
00606 extern "C" DECLARE_EXPORT PyObject* call_handler(PyObject* self, PyObject* args, PyObject* kwds)
00607 {
00608 try
00609 {
00610 return static_cast<PythonExtensionBase*>(self)->call(args, kwds);
00611 }
00612 catch (...)
00613 {
00614 PythonType::evalException();
00615 return NULL;
00616 }
00617 }
00618
00619
00620 extern "C" DECLARE_EXPORT PyObject* str_handler(PyObject* self)
00621 {
00622 try
00623 {
00624 return static_cast<PythonExtensionBase*>(self)->str();
00625 }
00626 catch (...)
00627 {
00628 PythonType::evalException();
00629 return NULL;
00630 }
00631 }
00632
00633 }
00634 }