1 /******************************************************************************
2 *
3 * MantaFlow fluid solver framework
4 * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
5 *
6 * This program is free software, distributed under the terms of the
7 * Apache License, Version 2.0
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Auto python registry
11 *
12 ******************************************************************************/
13
14 #include <string.h>
15 #include "pythonInclude.h"
16 #include "structmember.h"
17 #include "manta.h"
18
19 using namespace std;
20
21 const string gDefaultModuleName = "manta";
22
23 namespace Pb {
24
25 //******************************************************************************
26 // Custom object definition
27
28 struct Method {
MethodPb::Method29 Method(const string &n, const string &d, GenericFunction f) : name(n), doc(d), func(f)
30 {
31 }
32 string name, doc;
33 GenericFunction func;
34
defPb::Method35 PyMethodDef def()
36 {
37 PyMethodDef def = {&name[0], (PyCFunction)func, METH_VARARGS | METH_KEYWORDS, &doc[0]};
38 return def;
39 }
40 };
41 struct GetSet {
GetSetPb::GetSet42 GetSet() : getter(0), setter(0)
43 {
44 }
GetSetPb::GetSet45 GetSet(const string &n, const string &d, Getter g, Setter s)
46 : name(n), doc(d), getter(g), setter(s)
47 {
48 }
49 string name, doc;
50 Getter getter;
51 Setter setter;
52
defPb::GetSet53 PyGetSetDef def()
54 {
55 PyGetSetDef def = {&name[0], getter, setter, &doc[0], NULL};
56 return def;
57 }
58 };
59
60 struct ClassData {
61 string cName, pyName;
62 string cPureName, cTemplate;
63 InitFunc init;
64 PyTypeObject typeInfo;
65 PyNumberMethods numInfo;
66 // PySequenceMethods seqInfo;
67 vector<Method> methods;
68 map<string, GetSet> getset;
69 map<string, OperatorFunction> ops;
70 ClassData *baseclass;
71 string baseclassName;
72 Constructor constructor;
73
74 vector<PyMethodDef> genMethods;
75 vector<PyGetSetDef> genGetSet;
76 };
77
78 struct PbObject {
79 PyObject_HEAD Manta::PbClass *instance;
80 ClassData *classdef;
81 };
82
83 //******************************************************
84 // Internal wrapper class
85
86 //! Registers all classes and methods exposed to Python.
87 /*! This class is only used internally by Pb:: framwork.
88 * Please use the functionality of PbClass to lookup and translate pointers. */
89 class WrapperRegistry {
90 public:
91 static WrapperRegistry &instance();
92 void addClass(const std::string &name,
93 const std::string &internalName,
94 const std::string &baseclass);
95 void addEnumEntry(const std::string &name, int value);
96 void addExternalInitializer(InitFunc func);
97 void addMethod(const std::string &classname,
98 const std::string &methodname,
99 GenericFunction method);
100 void addOperator(const std::string &classname,
101 const std::string &methodname,
102 OperatorFunction method);
103 void addConstructor(const std::string &classname, Constructor method);
104 void addGetSet(const std::string &classname,
105 const std::string &property,
106 Getter getfunc,
107 Setter setfunc);
108 void addPythonPath(const std::string &path);
109 void addPythonCode(const std::string &file, const std::string &code);
110 PyObject *createPyObject(const std::string &classname,
111 const std::string &name,
112 Manta::PbArgs &args,
113 Manta::PbClass *parent);
114 void construct(const std::string &scriptname, const vector<string> &args);
115 void cleanup();
116 void renameObjects();
117 void runPreInit();
118 PyObject *initModule();
119 ClassData *lookup(const std::string &name);
120 bool canConvert(ClassData *from, ClassData *to);
121
122 private:
123 ClassData *getOrConstructClass(const string &name);
124 void registerBaseclasses();
125 void registerDummyTypes();
126 void registerMeta();
127 void addConstants(PyObject *module);
128 void registerOperators(ClassData *cls);
129 void addParentMethods(ClassData *cls, ClassData *base);
130 WrapperRegistry();
131 ~WrapperRegistry();
132 std::map<std::string, ClassData *> mClasses;
133 std::vector<ClassData *> mClassList;
134 std::vector<InitFunc> mExtInitializers;
135 std::vector<std::string> mPaths;
136 std::string mCode, mScriptName;
137 std::vector<std::string> args;
138 std::map<std::string, int> mEnumValues;
139 };
140
141 //******************************************************************************
142 // Callback functions
143
cbGetClass(PbObject * self,void * cl)144 PyObject *cbGetClass(PbObject *self, void *cl)
145 {
146 return Manta::toPy(self->classdef->cPureName);
147 }
148
cbGetTemplate(PbObject * self,void * cl)149 PyObject *cbGetTemplate(PbObject *self, void *cl)
150 {
151 return Manta::toPy(self->classdef->cTemplate);
152 }
153
cbGetCName(PbObject * self,void * cl)154 PyObject *cbGetCName(PbObject *self, void *cl)
155 {
156 return Manta::toPy(self->classdef->cName);
157 }
158
cbDealloc(PbObject * self)159 void cbDealloc(PbObject *self)
160 {
161 // cout << "dealloc " << self->instance->getName() << " " << self->classdef->cName << endl;
162 if (self->instance) {
163 #ifndef BLENDER
164 // don't delete top-level objects
165 if (self->instance->getParent() != self->instance)
166 delete self->instance;
167 #else
168 // in Blender we *have* to delete all objects
169 delete self->instance;
170 #endif
171 }
172 Py_TYPE(self)->tp_free((PyObject *)self);
173 }
174
cbNew(PyTypeObject * type,PyObject * args,PyObject * kwds)175 PyObject *cbNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
176 {
177 PbObject *self = (PbObject *)type->tp_alloc(type, 0);
178 if (self != NULL) {
179 // lookup and link classdef
180 self->classdef = WrapperRegistry::instance().lookup(type->tp_name);
181 self->instance = NULL;
182 // cout << "creating " << self->classdef->cName << endl;
183 }
184 else
185 errMsg("can't allocate new python class object");
186 return (PyObject *)self;
187 }
188
cbDisableConstructor(PyObject * self,PyObject * args,PyObject * kwds)189 int cbDisableConstructor(PyObject *self, PyObject *args, PyObject *kwds)
190 {
191 errMsg("Can't instantiate a class template without template arguments");
192 return -1;
193 }
194
PyInit_manta_main(void)195 PyMODINIT_FUNC PyInit_manta_main(void)
196 {
197 MantaEnsureRegistration();
198 #if PY_MAJOR_VERSION >= 3
199 return WrapperRegistry::instance().initModule();
200 #else
201 WrapperRegistry::instance().initModule();
202 #endif
203 }
204
205 //******************************************************
206 // WrapperRegistry
207
WrapperRegistry()208 WrapperRegistry::WrapperRegistry()
209 {
210 addClass("__modclass__", "__modclass__", "");
211 addClass("PbClass", "PbClass", "");
212 }
213
~WrapperRegistry()214 WrapperRegistry::~WrapperRegistry()
215 {
216 // Some static constructions may have called WrapperRegistry.instance() and added
217 // own classes, functions, etc. Ensure everything is cleaned up properly.
218 cleanup();
219 }
220
getOrConstructClass(const string & classname)221 ClassData *WrapperRegistry::getOrConstructClass(const string &classname)
222 {
223 map<string, ClassData *>::iterator it = mClasses.find(classname);
224
225 if (it != mClasses.end())
226 return it->second;
227 ClassData *data = new ClassData;
228 data->cName = classname;
229 data->cPureName = classname;
230 data->cTemplate = "";
231 size_t tplIdx = classname.find('<');
232 if (tplIdx != string::npos) {
233 data->cPureName = classname.substr(0, tplIdx);
234 data->cTemplate = classname.substr(tplIdx + 1, classname.find('>') - tplIdx - 1);
235 }
236 data->baseclass = NULL;
237 data->constructor = cbDisableConstructor;
238 mClasses[classname] = data;
239 mClassList.push_back(data);
240 return data;
241 }
242
replaceAll(string & source,string const & find,string const & replace)243 void replaceAll(string &source, string const &find, string const &replace)
244 {
245 for (string::size_type i = 0; (i = source.find(find, i)) != std::string::npos;) {
246 source.replace(i, find.length(), replace);
247 i += replace.length() - find.length() + 1;
248 }
249 }
250
addClass(const string & pyName,const string & internalName,const string & baseclass)251 void WrapperRegistry::addClass(const string &pyName,
252 const string &internalName,
253 const string &baseclass)
254 {
255 ClassData *data = getOrConstructClass(internalName);
256
257 // regularize python name
258 string pythonName = pyName;
259 replaceAll(pythonName, "<", "_");
260 replaceAll(pythonName, ">", "");
261 replaceAll(pythonName, ",", "_");
262
263 if (data->pyName.empty())
264 data->pyName = pythonName;
265 mClasses[pythonName] = data;
266 if (!baseclass.empty())
267 data->baseclassName = baseclass;
268 }
269
addEnumEntry(const string & name,int value)270 void WrapperRegistry::addEnumEntry(const string &name, int value)
271 {
272 /// Gather static definitions to add them as static python objects afterwards
273 if (mEnumValues.insert(std::make_pair(name, value)).second == false) {
274 errMsg("Enum entry '" + name + "' already existing...");
275 }
276 }
277
addExternalInitializer(InitFunc func)278 void WrapperRegistry::addExternalInitializer(InitFunc func)
279 {
280 mExtInitializers.push_back(func);
281 }
282
addPythonPath(const string & path)283 void WrapperRegistry::addPythonPath(const string &path)
284 {
285 mPaths.push_back(path);
286 }
287
addPythonCode(const string & file,const string & code)288 void WrapperRegistry::addPythonCode(const string &file, const string &code)
289 {
290 mCode += code + "\n";
291 }
292
addGetSet(const string & classname,const string & property,Getter getfunc,Setter setfunc)293 void WrapperRegistry::addGetSet(const string &classname,
294 const string &property,
295 Getter getfunc,
296 Setter setfunc)
297 {
298 ClassData *classdef = getOrConstructClass(classname);
299 GetSet &def = classdef->getset[property];
300 if (def.name.empty()) {
301 def.name = property;
302 def.doc = property;
303 }
304 if (getfunc)
305 def.getter = getfunc;
306 if (setfunc)
307 def.setter = setfunc;
308 }
309
addMethod(const string & classname,const string & methodname,GenericFunction func)310 void WrapperRegistry::addMethod(const string &classname,
311 const string &methodname,
312 GenericFunction func)
313 {
314 string aclass = classname;
315 if (aclass.empty())
316 aclass = "__modclass__";
317
318 ClassData *classdef = getOrConstructClass(aclass);
319 for (int i = 0; i < (int)classdef->methods.size(); i++)
320 if (classdef->methods[i].name == methodname)
321 return; // avoid duplicates
322 classdef->methods.push_back(Method(methodname, methodname, func));
323 }
324
addOperator(const string & classname,const string & methodname,OperatorFunction func)325 void WrapperRegistry::addOperator(const string &classname,
326 const string &methodname,
327 OperatorFunction func)
328 {
329 if (classname.empty())
330 errMsg("PYTHON operators have to be defined within classes.");
331
332 string op = methodname.substr(8);
333 ClassData *classdef = getOrConstructClass(classname);
334 classdef->ops[op] = func;
335 }
336
addConstructor(const string & classname,Constructor func)337 void WrapperRegistry::addConstructor(const string &classname, Constructor func)
338 {
339 ClassData *classdef = getOrConstructClass(classname);
340 classdef->constructor = func;
341 }
342
addParentMethods(ClassData * cur,ClassData * base)343 void WrapperRegistry::addParentMethods(ClassData *cur, ClassData *base)
344 {
345 if (base == 0)
346 return;
347
348 for (vector<Method>::iterator it = base->methods.begin(); it != base->methods.end(); ++it)
349 addMethod(cur->cName, it->name, it->func);
350
351 for (map<string, GetSet>::iterator it = base->getset.begin(); it != base->getset.end(); ++it)
352 addGetSet(cur->cName, it->first, it->second.getter, it->second.setter);
353
354 for (map<string, OperatorFunction>::iterator it = base->ops.begin(); it != base->ops.end(); ++it)
355 cur->ops[it->first] = it->second;
356
357 addParentMethods(cur, base->baseclass);
358 }
359
registerBaseclasses()360 void WrapperRegistry::registerBaseclasses()
361 {
362 for (int i = 0; i < (int)mClassList.size(); i++) {
363 string bname = mClassList[i]->baseclassName;
364 if (!bname.empty()) {
365 mClassList[i]->baseclass = lookup(bname);
366 if (!mClassList[i]->baseclass)
367 errMsg("Registering class '" + mClassList[i]->cName + "' : Base class '" + bname +
368 "' not found");
369 }
370 }
371
372 for (int i = 0; i < (int)mClassList.size(); i++) {
373 addParentMethods(mClassList[i], mClassList[i]->baseclass);
374 }
375 }
376
registerMeta()377 void WrapperRegistry::registerMeta()
378 {
379 for (int i = 0; i < (int)mClassList.size(); i++) {
380 mClassList[i]->getset["_class"] = GetSet("_class", "C class name", (Getter)cbGetClass, 0);
381 mClassList[i]->getset["_cname"] = GetSet("_cname", "Full C name", (Getter)cbGetCName, 0);
382 mClassList[i]->getset["_T"] = GetSet("_T", "C template argument", (Getter)cbGetTemplate, 0);
383 }
384 }
385
registerOperators(ClassData * cls)386 void WrapperRegistry::registerOperators(ClassData *cls)
387 {
388 PyNumberMethods &num = cls->numInfo;
389 for (map<string, OperatorFunction>::iterator it = cls->ops.begin(); it != cls->ops.end(); it++) {
390 const string &op = it->first;
391 OperatorFunction func = it->second;
392 if (op == "+=")
393 num.nb_inplace_add = func;
394 else if (op == "-=")
395 num.nb_inplace_subtract = func;
396 else if (op == "*=")
397 num.nb_inplace_multiply = func;
398 else if (op == "+")
399 num.nb_add = func;
400 else if (op == "-")
401 num.nb_subtract = func;
402 else if (op == "*")
403 num.nb_multiply = func;
404 #if PY_MAJOR_VERSION < 3
405 else if (op == "/=")
406 num.nb_inplace_divide = func;
407 else if (op == "/")
408 num.nb_divide = func;
409 #else
410 else if (op == "/=")
411 num.nb_inplace_true_divide = func;
412 else if (op == "/")
413 num.nb_true_divide = func;
414 #endif
415 else
416 errMsg("PYTHON operator " + op + " not supported");
417 }
418 }
419
registerDummyTypes()420 void WrapperRegistry::registerDummyTypes()
421 {
422 vector<string> add;
423 for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
424 string cName = (*it)->cName;
425 if (cName.find('<') != string::npos)
426 add.push_back(cName.substr(0, cName.find('<')));
427 }
428 for (int i = 0; i < (int)add.size(); i++)
429 addClass(add[i], add[i], "");
430 }
431
lookup(const string & name)432 ClassData *WrapperRegistry::lookup(const string &name)
433 {
434 for (map<string, ClassData *>::iterator it = mClasses.begin(); it != mClasses.end(); ++it) {
435 if (it->first == name || it->second->cName == name)
436 return it->second;
437 }
438 return NULL;
439 }
440
cleanup()441 void WrapperRegistry::cleanup()
442 {
443 for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
444 delete *it;
445 }
446 mClasses.clear();
447 mClassList.clear();
448 }
449
instance()450 WrapperRegistry &WrapperRegistry::instance()
451 {
452 static WrapperRegistry inst;
453 return inst;
454 }
455
canConvert(ClassData * from,ClassData * to)456 bool WrapperRegistry::canConvert(ClassData *from, ClassData *to)
457 {
458 if (from == to)
459 return true;
460 if (from->baseclass)
461 return canConvert(from->baseclass, to);
462 return false;
463 }
464
addConstants(PyObject * module)465 void WrapperRegistry::addConstants(PyObject *module)
466 {
467 // expose arguments
468 PyObject *list = PyList_New(args.size());
469 for (int i = 0; i < (int)args.size(); i++)
470 PyList_SET_ITEM(list, i, Manta::toPy(args[i]));
471 PyModule_AddObject(module, "args", list);
472 PyModule_AddObject(module, "SCENEFILE", Manta::toPy(mScriptName));
473
474 // expose compile flags
475 #ifdef DEBUG
476 PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(true));
477 #else
478 PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(false));
479 #endif
480 #ifdef MANTA_MT
481 PyModule_AddObject(module, "MT", Manta::toPy<bool>(true));
482 #else
483 PyModule_AddObject(module, "MT", Manta::toPy<bool>(false));
484 #endif
485 #ifdef GUI
486 PyModule_AddObject(module, "GUI", Manta::toPy<bool>(true));
487 #else
488 PyModule_AddObject(module, "GUI", Manta::toPy<bool>(false));
489 #endif
490 #if FLOATINGPOINT_PRECISION == 2
491 PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(true));
492 #else
493 PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(false));
494 #endif
495 // cuda off for now
496 PyModule_AddObject(module, "CUDA", Manta::toPy<bool>(false));
497
498 // expose enum entries
499 std::map<std::string, int>::iterator it;
500 for (it = mEnumValues.begin(); it != mEnumValues.end(); it++) {
501 PyModule_AddObject(module, it->first.c_str(), Manta::toPy(it->second));
502 // Alternative would be:
503 // e.g. PyModule_AddIntConstant(module, "FlagFluid", 1);
504 }
505 }
506
runPreInit()507 void WrapperRegistry::runPreInit()
508 {
509 // add python directories to path
510 PyObject *sys_path = PySys_GetObject((char *)"path");
511 for (size_t i = 0; i < mPaths.size(); i++) {
512 PyObject *path = Manta::toPy(mPaths[i]);
513 if (sys_path == NULL || path == NULL || PyList_Append(sys_path, path) < 0) {
514 errMsg("unable to set python path");
515 }
516 Py_DECREF(path);
517 }
518 if (!mCode.empty()) {
519 mCode = "from manta import *\n" + mCode;
520 PyRun_SimpleString(mCode.c_str());
521 }
522 }
523
createPyObject(const string & classname,const string & name,Manta::PbArgs & args,Manta::PbClass * parent)524 PyObject *WrapperRegistry::createPyObject(const string &classname,
525 const string &name,
526 Manta::PbArgs &args,
527 Manta::PbClass *parent)
528 {
529 ClassData *classdef = lookup(classname);
530 if (!classdef)
531 errMsg("Class " + classname + " doesn't exist.");
532
533 // create object
534 PyObject *obj = cbNew(&classdef->typeInfo, NULL, NULL);
535 PbObject *self = (PbObject *)obj;
536 PyObject *nkw = 0;
537
538 if (args.kwds())
539 nkw = PyDict_Copy(args.kwds());
540 else
541 nkw = PyDict_New();
542
543 PyObject *nocheck = Py_BuildValue("s", "yes");
544 PyDict_SetItemString(nkw, "nocheck", nocheck);
545 if (parent)
546 PyDict_SetItemString(nkw, "parent", parent->getPyObject());
547
548 // create instance
549 if (self->classdef->constructor(obj, args.linArgs(), nkw) < 0)
550 errMsg("error raised in constructor"); // assume condition is already set
551
552 Py_DECREF(nkw);
553 Py_DECREF(nocheck);
554 self->instance->setName(name);
555
556 return obj;
557 }
558
559 // prepare typeinfo and register python module
construct(const string & scriptname,const vector<string> & args)560 void WrapperRegistry::construct(const string &scriptname, const vector<string> &args)
561 {
562 mScriptName = scriptname;
563 this->args = args;
564
565 registerBaseclasses();
566 registerMeta();
567 registerDummyTypes();
568
569 // work around for certain gcc versions, cast to char*
570 PyImport_AppendInittab((char *)gDefaultModuleName.c_str(), PyInit_manta_main);
571 }
572
castPy(PyTypeObject * p)573 inline PyObject *castPy(PyTypeObject *p)
574 {
575 return reinterpret_cast<PyObject *>(static_cast<void *>(p));
576 }
577
initModule()578 PyObject *WrapperRegistry::initModule()
579 {
580 // generate and terminate all method lists
581 PyMethodDef sentinelFunc = {NULL, NULL, 0, NULL};
582 PyGetSetDef sentinelGetSet = {NULL, NULL, NULL, NULL, NULL};
583 for (int i = 0; i < (int)mClassList.size(); i++) {
584 ClassData *cls = mClassList[i];
585 cls->genMethods.clear();
586 cls->genGetSet.clear();
587 for (vector<Method>::iterator i2 = cls->methods.begin(); i2 != cls->methods.end(); ++i2)
588 cls->genMethods.push_back(i2->def());
589 for (map<string, GetSet>::iterator i2 = cls->getset.begin(); i2 != cls->getset.end(); ++i2)
590 cls->genGetSet.push_back(i2->second.def());
591
592 cls->genMethods.push_back(sentinelFunc);
593 cls->genGetSet.push_back(sentinelGetSet);
594 }
595
596 // prepare module info
597 #if PY_MAJOR_VERSION >= 3
598 static PyModuleDef MainModule = {PyModuleDef_HEAD_INIT,
599 gDefaultModuleName.c_str(),
600 "Bridge module to the C++ solver",
601 -1,
602 NULL,
603 NULL,
604 NULL,
605 NULL,
606 NULL};
607 // get generic methods (plugin functions)
608 MainModule.m_methods = &mClasses["__modclass__"]->genMethods[0];
609
610 // create module
611 PyObject *module = PyModule_Create(&MainModule);
612 #else
613 PyObject *module = Py_InitModule(gDefaultModuleName.c_str(),
614 &mClasses["__modclass__"]->genMethods[0]);
615 #endif
616 if (module == NULL)
617 return NULL;
618
619 // load classes
620 for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
621 ClassData &data = **it;
622 char *nameptr = (char *)data.pyName.c_str();
623
624 // define numeric substruct
625 PyNumberMethods *num = 0;
626 if (!data.ops.empty()) {
627 num = &data.numInfo;
628 memset(num, 0, sizeof(PyNumberMethods));
629 registerOperators(&data);
630 }
631
632 // define python classinfo
633 PyTypeObject t = {
634 PyVarObject_HEAD_INIT(NULL, 0)(char *) data.pyName.c_str(), // tp_name
635 sizeof(PbObject), // tp_basicsize
636 0, // tp_itemsize
637 (destructor)cbDealloc, // tp_dealloc
638 0, // tp_print
639 0, // tp_getattr
640 0, // tp_setattr
641 0, // tp_reserved
642 0, // tp_repr
643 num, // tp_as_number
644 0, // tp_as_sequence
645 0, // tp_as_mapping
646 0, // tp_hash
647 0, // tp_call
648 0, // tp_str
649 0, // tp_getattro
650 0, // tp_setattro
651 0, // tp_as_buffer
652 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
653 nameptr, // tp_doc
654 0, // tp_traverse
655 0, // tp_clear
656 0, // tp_richcompare
657 0, // tp_weaklistoffset
658 0, // tp_iter
659 0, // tp_iternext
660 &data.genMethods[0], // tp_methods
661 0, // tp_members
662 &data.genGetSet[0], // tp_getset
663 0, // tp_base
664 0, // tp_dict
665 0, // tp_descr_get
666 0, // tp_descr_set
667 0, // tp_dictoffset
668 (initproc)(data.constructor), // tp_init
669 0, // tp_alloc
670 cbNew // tp_new
671 };
672 data.typeInfo = t;
673
674 if (PyType_Ready(&data.typeInfo) < 0)
675 continue;
676
677 for (map<string, ClassData *>::iterator i2 = mClasses.begin(); i2 != mClasses.end(); ++i2) {
678 if (*it != i2->second)
679 continue;
680 // register all aliases
681 Py_INCREF(castPy(&data.typeInfo));
682 PyModule_AddObject(module, (char *)i2->first.c_str(), (PyObject *)&data.typeInfo);
683 }
684 }
685
686 // externals
687 for (vector<InitFunc>::iterator it = mExtInitializers.begin(); it != mExtInitializers.end();
688 ++it) {
689 (*it)(module);
690 }
691
692 addConstants(module);
693
694 return module;
695 }
696
697 //******************************************************
698 // Register members and exposed functions
699
setup(const std::string & filename,const std::vector<std::string> & args)700 void setup(const std::string &filename, const std::vector<std::string> &args)
701 {
702 WrapperRegistry::instance().construct(filename, args);
703 Py_Initialize();
704 WrapperRegistry::instance().runPreInit();
705 }
706
finalize()707 void finalize()
708 {
709 Py_Finalize();
710 WrapperRegistry::instance().cleanup();
711 }
712
canConvert(PyObject * obj,const string & classname)713 bool canConvert(PyObject *obj, const string &classname)
714 {
715 ClassData *from = ((PbObject *)obj)->classdef;
716 ClassData *dest = WrapperRegistry::instance().lookup(classname);
717 if (!dest)
718 errMsg("Classname '" + classname + "' is not registered.");
719 return WrapperRegistry::instance().canConvert(from, dest);
720 }
721
objFromPy(PyObject * obj)722 Manta::PbClass *objFromPy(PyObject *obj)
723 {
724 if (Py_TYPE(obj)->tp_dealloc != (destructor)cbDealloc) // not a manta object
725 return NULL;
726
727 return ((PbObject *)obj)->instance;
728 }
729
copyObject(Manta::PbClass * cls,const string & classname)730 PyObject *copyObject(Manta::PbClass *cls, const string &classname)
731 {
732 ClassData *classdef = WrapperRegistry::instance().lookup(classname);
733 assertMsg(classdef, "python class " + classname + " does not exist.");
734
735 // allocate new object
736 PbObject *obj = (PbObject *)classdef->typeInfo.tp_alloc(&(classdef->typeInfo), 0);
737 assertMsg(obj, "cannot allocate new python object");
738
739 obj->classdef = classdef;
740 cls->registerObject((PyObject *)obj, 0);
741
742 return cls->getPyObject();
743 }
744
createPy(const std::string & classname,const std::string & name,Manta::PbArgs & args,Manta::PbClass * parent)745 Manta::PbClass *createPy(const std::string &classname,
746 const std::string &name,
747 Manta::PbArgs &args,
748 Manta::PbClass *parent)
749 {
750 PyObject *obj = WrapperRegistry::instance().createPyObject(classname, name, args, parent);
751 return ((PbObject *)obj)->instance;
752 }
753
setReference(Manta::PbClass * cls,PyObject * obj)754 void setReference(Manta::PbClass *cls, PyObject *obj)
755 {
756 ((PbObject *)obj)->instance = cls;
757 }
758
Register(const string & className,const string & funcName,GenericFunction func)759 Register::Register(const string &className, const string &funcName, GenericFunction func)
760 {
761 WrapperRegistry::instance().addMethod(className, funcName, func);
762 }
Register(const string & className,const string & funcName,OperatorFunction func)763 Register::Register(const string &className, const string &funcName, OperatorFunction func)
764 {
765 WrapperRegistry::instance().addOperator(className, funcName, func);
766 }
Register(const string & className,const string & funcName,Constructor func)767 Register::Register(const string &className, const string &funcName, Constructor func)
768 {
769 WrapperRegistry::instance().addConstructor(className, func);
770 }
Register(const string & className,const string & property,Getter getter,Setter setter)771 Register::Register(const string &className, const string &property, Getter getter, Setter setter)
772 {
773 WrapperRegistry::instance().addGetSet(className, property, getter, setter);
774 }
Register(const string & className,const string & pyName,const string & baseClass)775 Register::Register(const string &className, const string &pyName, const string &baseClass)
776 {
777 WrapperRegistry::instance().addClass(pyName, className, baseClass);
778 }
Register(const string & name,const int value)779 Register::Register(const string &name, const int value)
780 {
781 WrapperRegistry::instance().addEnumEntry(name, value);
782 }
Register(const string & file,const string & pythonCode)783 Register::Register(const string &file, const string &pythonCode)
784 {
785 WrapperRegistry::instance().addPythonCode(file, pythonCode);
786 }
Register(InitFunc func)787 Register::Register(InitFunc func)
788 {
789 WrapperRegistry::instance().addExternalInitializer(func);
790 }
791
792 } // namespace Pb
793