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 #include "frepple/utils.h"
00034
00035 namespace frepple
00036 {
00037 namespace utils
00038 {
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 class PythonInterpreter
00141 {
00142 public:
00143
00144 static void initialize();
00145
00146
00147 static DECLARE_EXPORT void execute(const char*);
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 static DECLARE_EXPORT void registerGlobalMethod(
00158 const char*, PyCFunction, int, const char*, bool = true
00159 );
00160
00161
00162 static DECLARE_EXPORT void registerGlobalMethod
00163 (const char*, PyCFunctionWithKeywords, int, const char*);
00164
00165
00166 static PyObject* getModule() { return module; }
00167
00168
00169 static const char* getPythonEncoding() { return encoding.c_str(); }
00170
00171
00172
00173
00174
00175
00176
00177 static DECLARE_EXPORT void addThread();
00178
00179
00180
00181
00182
00183
00184
00185 static DECLARE_EXPORT void deleteThread();
00186
00187 private:
00188
00189 static DECLARE_EXPORT PyObject *module;
00190
00191
00192
00193
00194 static DECLARE_EXPORT PyObject *python_log(PyObject*, PyObject*);
00195
00196
00197
00198
00199 static DECLARE_EXPORT string encoding;
00200 };
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 class CommandPython : public Command
00216 {
00217 private:
00218
00219 string cmd;
00220
00221
00222 string filename;
00223
00224 public:
00225
00226 void execute();
00227
00228
00229 string getDescription() const {return "Python interpreter";}
00230
00231
00232 explicit CommandPython() {}
00233
00234
00235 virtual ~CommandPython() {}
00236
00237
00238 void setCommandLine(const string& s) {cmd = s; filename.clear();}
00239
00240
00241 string getCommandLine() const {return cmd;}
00242
00243
00244 string getFileName() const {return filename;}
00245
00246
00247 void setFileName(const string& s) {filename = s; cmd.clear();}
00248
00249
00250 static const MetaClass *metadata2;
00251
00252
00253 static void processorXMLInstruction(const char *d)
00254 {PythonInterpreter::execute(d);}
00255 };
00256
00257
00258
00259 extern DECLARE_EXPORT PyObject* PythonLogicException;
00260
00261
00262 extern DECLARE_EXPORT PyObject* PythonDataException;
00263
00264
00265 extern DECLARE_EXPORT PyObject* PythonRuntimeException;
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 class PythonObject : public DataElement
00298 {
00299 private:
00300 PyObject* obj;
00301
00302 public:
00303
00304 explicit PythonObject() : obj(Py_None) {Py_INCREF(obj);}
00305
00306
00307
00308
00309 PythonObject(PyObject* o) : obj(o) {}
00310
00311
00312 operator PyObject*() const {return obj;}
00313
00314
00315 operator bool() const {return obj != NULL;}
00316
00317
00318 PythonObject& operator = (const PythonObject& o) { obj = o.obj; return *this; }
00319
00320
00321
00322
00323 bool check(const PythonType& c) const
00324 {
00325 return obj ?
00326 PyObject_TypeCheck(obj, c.type_object()) :
00327 false;
00328 }
00329
00330
00331 inline string getString() const
00332 {
00333 if (obj == Py_None) return string();
00334 if (PyUnicode_Check(obj))
00335 {
00336
00337 const_cast<PyObject*&>(obj) =
00338 PyUnicode_AsEncodedString(obj, PythonInterpreter::getPythonEncoding(), "ignore");
00339 }
00340 return PyString_AsString(PyObject_Str(obj));
00341 }
00342
00343
00344 unsigned long getUnsignedLong() const
00345 {
00346 if (obj == Py_None) return 0;
00347 if (PyString_Check(obj))
00348 {
00349 PyObject* t = PyFloat_FromString(obj, NULL);
00350 if (!t) throw DataException("Invalid number");
00351 double x = PyFloat_AS_DOUBLE(t);
00352 Py_DECREF(t);
00353 if (x < 0 || x > ULONG_MAX)
00354 throw DataException("Invalid number");
00355 return static_cast<unsigned long>(x);
00356 }
00357 return PyLong_AsUnsignedLong(obj);
00358 }
00359
00360
00361
00362 DECLARE_EXPORT Date getDate() const;
00363
00364
00365 inline double getDouble() const
00366 {
00367 if (obj == Py_None) return 0;
00368 if (PyString_Check(obj))
00369 {
00370 PyObject* t = PyFloat_FromString(obj, NULL);
00371 if (!t) throw DataException("Invalid number");
00372 double x = PyFloat_AS_DOUBLE(t);
00373 Py_DECREF(t);
00374 return x;
00375 }
00376 return PyFloat_AsDouble(obj);
00377 }
00378
00379
00380 inline int getInt() const
00381 {
00382 if (PyString_Check(obj))
00383 {
00384 PyObject* t = PyFloat_FromString(obj, NULL);
00385 if (!t) throw DataException("Invalid number");
00386 double x = PyFloat_AS_DOUBLE(t);
00387 Py_DECREF(t);
00388 if (x < INT_MIN || x > INT_MAX)
00389 throw DataException("Invalid number");
00390 return static_cast<int>(x);
00391 }
00392 int result = PyInt_AsLong(obj);
00393 if (result == -1 && PyErr_Occurred())
00394 throw DataException("Invalid number");
00395 return result;
00396 }
00397
00398
00399 inline long getLong() const
00400 {
00401 if (PyString_Check(obj))
00402 {
00403 PyObject* t = PyFloat_FromString(obj, NULL);
00404 if (!t) throw DataException("Invalid number");
00405 double x = PyFloat_AS_DOUBLE(t);
00406 Py_DECREF(t);
00407 if (x < LONG_MIN || x > LONG_MIN)
00408 throw DataException("Invalid number");
00409 return static_cast<long>(x);
00410 }
00411 int result = PyInt_AsLong(obj);
00412 if (result == -1 && PyErr_Occurred())
00413 throw DataException("Invalid number");
00414 return result;
00415 }
00416
00417
00418 inline bool getBool() const
00419 {
00420 return PyObject_IsTrue(obj) ? true : false;
00421 }
00422
00423
00424
00425
00426
00427 TimePeriod getTimeperiod() const
00428 {
00429 if (PyString_Check(obj))
00430 {
00431 if (PyUnicode_Check(obj))
00432 {
00433
00434 const_cast<PyObject*&>(obj) =
00435 PyUnicode_AsEncodedString(obj, PythonInterpreter::getPythonEncoding(), "ignore");
00436 }
00437 return TimePeriod(PyString_AsString(PyObject_Str(obj)));
00438 }
00439 int result = PyInt_AsLong(obj);
00440 if (result == -1 && PyErr_Occurred())
00441 throw DataException("Invalid number");
00442 return result;
00443 }
00444
00445
00446
00447
00448
00449 DECLARE_EXPORT PythonObject(Object* p);
00450
00451
00452 inline PythonObject(const string& val)
00453 {
00454 if (val.empty())
00455 {
00456 obj = Py_None;
00457 Py_INCREF(obj);
00458 }
00459 else
00460 obj = PyString_FromString(val.c_str());
00461 }
00462
00463
00464 inline PythonObject(const double val)
00465 {
00466 obj = PyFloat_FromDouble(val);
00467 }
00468
00469
00470 inline PythonObject(const int val)
00471 {
00472 obj = PyInt_FromLong(val);
00473 }
00474
00475
00476 inline PythonObject(const long val)
00477 {
00478 obj = PyLong_FromLong(val);
00479 }
00480
00481
00482 inline PythonObject(const unsigned long val)
00483 {
00484 obj = PyLong_FromUnsignedLong(val);
00485 }
00486
00487
00488 inline PythonObject(const bool val)
00489 {
00490 obj = val ? Py_True : Py_False;
00491 Py_INCREF(obj);
00492 }
00493
00494
00495
00496 inline PythonObject(const TimePeriod val)
00497 {
00498
00499 obj = PyLong_FromLong(val);
00500 }
00501
00502
00503 DECLARE_EXPORT PythonObject(const Date& val);
00504 };
00505
00506
00507
00508 class PythonAttributeList : public AttributeList
00509 {
00510 private:
00511 PyObject* kwds;
00512 PythonObject result;
00513
00514 public:
00515 PythonAttributeList(PyObject* a) : kwds(a) {}
00516
00517 virtual const DataElement* get(const Keyword& k) const
00518 {
00519 if (!kwds)
00520 {
00521 const_cast<PythonAttributeList*>(this)->result = PythonObject();
00522 return &result;
00523 }
00524 PyObject* val = PyDict_GetItemString(kwds,k.getName().c_str());
00525 const_cast<PythonAttributeList*>(this)->result = PythonObject(val);
00526 return &result;
00527 }
00528 };
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 class PythonExtensionBase : public PyObject
00547 {
00548 public:
00549
00550 PythonExtensionBase() {}
00551
00552
00553 virtual ~PythonExtensionBase() {}
00554
00555
00556
00557
00558
00559 virtual PyObject* getattro(const Attribute& attr)
00560 {
00561 PyErr_SetString(PythonLogicException, "Missing method 'getattro'");
00562 return NULL;
00563 }
00564
00565
00566
00567
00568
00569 virtual int setattro(const Attribute& attr, const PythonObject& field)
00570 {
00571 PyErr_SetString(PythonLogicException, "Missing method 'setattro'");
00572 return -1;
00573 }
00574
00575
00576
00577
00578
00579 virtual int compare(const PythonObject& other)
00580 {
00581 PyErr_SetString(PythonLogicException, "Missing method 'compare'");
00582 return -1;
00583 }
00584
00585
00586
00587
00588
00589 virtual PyObject* iternext()
00590 {
00591 PyErr_SetString(PythonLogicException, "Missing method 'iternext'");
00592 return NULL;
00593 }
00594
00595
00596
00597
00598
00599 virtual PyObject* call(const PythonObject& args, const PythonObject& kwds)
00600 {
00601 PyErr_SetString(PythonLogicException, "Missing method 'call'");
00602 return NULL;
00603 }
00604
00605
00606
00607
00608
00609 virtual PyObject* str()
00610 {
00611 PyErr_SetString(PythonLogicException, "Missing method 'str'");
00612 return NULL;
00613 }
00614
00615 protected:
00616 DECLARE_EXPORT static vector<PythonType*> table;
00617 };
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 template<class T>
00631 class PythonExtension: public PythonExtensionBase, public NonCopyable
00632 {
00633 public:
00634
00635 explicit PythonExtension()
00636 {
00637 PyObject_Init(this, getType().type_object());
00638 }
00639
00640
00641 virtual ~PythonExtension() {}
00642
00643
00644 static PythonType& getType()
00645 {
00646 static PythonType* cachedTypePtr = NULL;
00647 if (cachedTypePtr) return *cachedTypePtr;
00648
00649
00650 for (vector<PythonType*>::const_iterator i = table.begin(); i != table.end(); ++i)
00651 if (**i==typeid(T))
00652 {
00653
00654 cachedTypePtr = *i;
00655 return *cachedTypePtr;
00656 }
00657
00658
00659 cachedTypePtr = new PythonType(sizeof(T), &typeid(T));
00660 cachedTypePtr->supportdealloc( deallocator );
00661 table.push_back(cachedTypePtr);
00662 return *cachedTypePtr;
00663 }
00664
00665
00666
00667
00668
00669 static void deallocator(PyObject* o) {delete static_cast<T*>(o);}
00670
00671 protected:
00672
00673
00674
00675
00676
00677 static PyObject* toXML(PyObject* self, PyObject* args)
00678 {
00679 try
00680 {
00681
00682 Object *o = static_cast<T*>(self)->obj;
00683 if (!o) throw LogicException("Can't generate a XML representation");
00684
00685
00686 PyObject *filearg = NULL;
00687 if (PyArg_UnpackTuple(args, "toXML", 0, 1, &filearg))
00688 {
00689 ostringstream ch;
00690 XMLOutput x(ch);
00691
00692 o->writeElement(&x, *(o->getType().category->typetag));
00693
00694 if (filearg)
00695 {
00696 if (PyFile_Check(filearg))
00697 {
00698
00699 return PyFile_WriteString(ch.str().c_str(), filearg) ?
00700 NULL :
00701 Py_BuildValue("");
00702 }
00703 else
00704
00705 throw LogicException("Expecting a file argument");
00706 }
00707 else
00708
00709 return PythonObject(ch.str());
00710 }
00711 }
00712 catch(...)
00713 {
00714 PythonType::evalException();
00715 return NULL;
00716 }
00717 throw LogicException("Unreachable code reached");
00718 }
00719 };
00720
00721
00722
00723
00724 template <class ME, class PROXY>
00725 class FreppleCategory : public PythonExtension< FreppleCategory<ME,PROXY> >
00726 {
00727 public:
00728
00729 static int initialize(PyObject* m)
00730 {
00731
00732 PythonType& x = PythonExtension< FreppleCategory<ME,PROXY> >::getType();
00733 x.setName(PROXY::metadata->type);
00734 x.setDoc("frePPLe " + PROXY::metadata->type);
00735 x.supportgetattro();
00736 x.supportsetattro();
00737 x.supportstr();
00738 x.supportcompare();
00739 x.supportcreate(create);
00740 const_cast<MetaCategory*>(PROXY::metadata)->factoryPythonProxy = proxy;
00741 return x.typeReady(m);
00742 }
00743
00744 static PyObject* proxy(Object* p) {
00745 return static_cast<PyObject*>(new ME(static_cast<PROXY*>(p)));
00746 }
00747
00748
00749 FreppleCategory(PROXY* x = NULL) : obj(x) {}
00750
00751 public:
00752 PROXY* obj;
00753
00754 private:
00755 virtual PyObject* getattro(const Attribute&) = 0;
00756
00757 virtual int setattro(const Attribute&, const PythonObject&) = 0;
00758
00759
00760 PyObject* str()
00761 {
00762 return PythonObject(obj ? obj->getName() : "None");
00763 }
00764
00765
00766 int compare(const PythonObject& other)
00767 {
00768 if (!obj || !other.check(ME::getType()))
00769 {
00770
00771 PyErr_SetString(PythonDataException, "Wrong type in comparison");
00772 return -1;
00773 }
00774 PROXY* y = static_cast<ME*>(static_cast<PyObject*>(other))->obj;
00775 return obj->getName().compare(y->getName());
00776 }
00777
00778 static PyObject* create(PyTypeObject* pytype, PyObject* args, PyObject* kwds)
00779 {
00780 try
00781 {
00782
00783 PythonAttributeList atts(kwds);
00784 Object* x = PROXY::reader(PROXY::metadata,atts);
00785
00786
00787 PythonExtensionBase* pr = static_cast<PythonExtensionBase*>(static_cast<PyObject*>(*(new PythonObject(x))));
00788
00789
00790 PyObject *key, *value;
00791 Py_ssize_t pos = 0;
00792 while (PyDict_Next(kwds, &pos, &key, &value))
00793 {
00794 PythonObject field(value);
00795 Attribute attr(PyString_AsString(key));
00796 if (!attr.isA(Tags::tag_name) && !attr.isA(Tags::tag_type) && !attr.isA(Tags::tag_action))
00797 {
00798 int result = pr->setattro(attr, field);
00799 if (result)
00800 PyErr_Format(PyExc_AttributeError,
00801 "attribute '%s' on '%s' can't be updated",
00802 PyString_AsString(key), pr->ob_type->tp_name);
00803 }
00804 };
00805 return pr;
00806
00807 }
00808 catch (...)
00809 {
00810 PythonType::evalException();
00811 return NULL;
00812 }
00813 }
00814 };
00815
00816
00817
00818 template <class ME, class BASE, class PROXY>
00819 class FreppleClass : public PythonExtension< FreppleClass<ME,BASE,PROXY> >
00820 {
00821 public:
00822 static int initialize(PyObject* m)
00823 {
00824
00825 PythonType& x = PythonExtension< FreppleClass<ME,BASE,PROXY> >::getType();
00826 x.setName(PROXY::metadata->type);
00827 x.setDoc("frePPLe " + PROXY::metadata->type);
00828 x.supportgetattro();
00829 x.supportsetattro();
00830 x.supportstr();
00831 x.supportcompare();
00832 x.supportcreate(create);
00833 x.setBase(BASE::getType());
00834 x.addMethod("toXML", ME::toXML, METH_VARARGS, "return a XML representation");
00835 const_cast<MetaClass*>(PROXY::metadata)->factoryPythonProxy = proxy;
00836 return x.typeReady(m);
00837 }
00838
00839 static PyObject* proxy(Object* p) {return static_cast<PyObject*>(new ME(static_cast<PROXY*>(p)));}
00840
00841 FreppleClass(PROXY* p= NULL) : obj(p) {}
00842
00843
00844 int compare(const PythonObject& other)
00845 {
00846 if (!obj || !other.check(BASE::getType()))
00847 {
00848
00849 PyErr_SetString(PythonDataException, "Wrong type in comparison");
00850 return -1;
00851 }
00852 BASE* y = static_cast<BASE*>(static_cast<PyObject*>(other));
00853 return obj->getName().compare(y->obj->getName());
00854 }
00855
00856
00857 PyObject* str()
00858 {
00859 return PythonObject(obj ? obj->getName() : "None");
00860 }
00861
00862
00863 static PyObject* create(PyTypeObject* pytype, PyObject* args, PyObject* kwds)
00864 {
00865 try
00866 {
00867
00868 PythonAttributeList atts(kwds);
00869 Object* x = PROXY::reader(PROXY::metadata,atts);
00870
00871
00872 PythonExtensionBase* pr = static_cast<PythonExtensionBase*>(static_cast<PyObject*>(*(new PythonObject(x))));
00873
00874
00875 PyObject *key, *value;
00876 Py_ssize_t pos = 0;
00877 while (PyDict_Next(kwds, &pos, &key, &value))
00878 {
00879 PythonObject field(value);
00880 Attribute attr(PyString_AsString(key));
00881 if (!attr.isA(Tags::tag_name) && !attr.isA(Tags::tag_type) && !attr.isA(Tags::tag_action))
00882 {
00883 int result = pr->setattro(attr, field);
00884 if (result)
00885 PyErr_Format(PyExc_AttributeError,
00886 "attribute '%s' on '%s' can't be updated",
00887 PyString_AsString(key), pr->ob_type->tp_name);
00888 }
00889 };
00890 return pr;
00891
00892 }
00893 catch (...)
00894 {
00895 PythonType::evalException();
00896 return NULL;
00897 }
00898 }
00899
00900 public:
00901 PROXY* obj;
00902
00903 private:
00904 virtual PyObject* getattro(const Attribute&) = 0;
00905
00906 virtual int setattro(const Attribute&, const PythonObject&) = 0;
00907
00908 };
00909
00910
00911
00912 template <class ME, class ITERCLASS, class DATACLASS, class PROXYCLASS>
00913 class FreppleIterator : public PythonExtension<ME>
00914 {
00915 public:
00916 static int initialize(PyObject* m)
00917 {
00918
00919 PythonType& x = PythonExtension<ME>::getType();
00920 x.setName(DATACLASS::metadata->type + "Iterator");
00921 x.setDoc("frePPLe iterator for " + DATACLASS::metadata->type);
00922 x.supportiter();
00923 return x.typeReady(m);
00924 }
00925
00926 FreppleIterator() : i(DATACLASS::begin()) {}
00927
00928 template <class OTHER> FreppleIterator(const OTHER *o) : i(o) {}
00929
00930 static PyObject* create(PyObject* self, PyObject* args)
00931 {return new ME();}
00932
00933 private:
00934 ITERCLASS i;
00935
00936 virtual PyObject* iternext()
00937 {
00938 if (i == DATACLASS::end()) return NULL;
00939 PyObject* result = PythonObject(&*i);
00940 ++i;
00941 return result;
00942 }
00943 };
00944
00945 }
00946 }