summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/linux/Makefile.in2
-rw-r--r--include/astra/AstraObjectFactory.h7
-rw-r--r--include/astra/PluginAlgorithm.h57
-rw-r--r--matlab/mex/astra_mex_plugin_c.cpp18
-rw-r--r--python/astra/plugin_c.pyx17
-rw-r--r--python/astra/src/PythonPluginAlgorithm.cpp402
-rw-r--r--python/astra/src/PythonPluginAlgorithm.h89
-rw-r--r--python/builder.py4
-rw-r--r--src/PluginAlgorithm.cpp367
9 files changed, 544 insertions, 419 deletions
diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in
index 3018674..d5644bc 100644
--- a/build/linux/Makefile.in
+++ b/build/linux/Makefile.in
@@ -62,8 +62,6 @@ PYCPPFLAGS := $(CPPFLAGS)
PYCPPFLAGS += -I../include
PYLDFLAGS = $(LDFLAGS)
PYLDFLAGS += -L$(abs_top_builddir)/.libs
-LIBS += -l$(PYLIBVER)
-LDFLAGS += -L$(PYLIBDIR)
endif
# This is below where PYCPPFLAGS copies CPPFLAGS. The python code is built
diff --git a/include/astra/AstraObjectFactory.h b/include/astra/AstraObjectFactory.h
index 325989e..6af9cd8 100644
--- a/include/astra/AstraObjectFactory.h
+++ b/include/astra/AstraObjectFactory.h
@@ -155,8 +155,11 @@ class _AstraExport CAlgorithmFactory : public CAstraObjectFactory<CAlgorithm, Al
template <>
inline CAlgorithm* CAstraObjectFactory<CAlgorithm, AlgorithmTypeList>::findPlugin(std::string _sType)
{
- CPluginAlgorithmFactory *fac = CPluginAlgorithmFactory::getSingletonPtr();
- return fac->getPlugin(_sType);
+ CPluginAlgorithmFactory *fac = CPluginAlgorithmFactory::getFactory();
+ if (fac)
+ return fac->getPlugin(_sType);
+ else
+ return 0;
}
#endif
diff --git a/include/astra/PluginAlgorithm.h b/include/astra/PluginAlgorithm.h
index 667e813..cbd80fc 100644
--- a/include/astra/PluginAlgorithm.h
+++ b/include/astra/PluginAlgorithm.h
@@ -29,62 +29,37 @@ $Id$
#ifndef _INC_ASTRA_PLUGINALGORITHM
#define _INC_ASTRA_PLUGINALGORITHM
-#ifdef ASTRA_PYTHON
-
-#include "astra/Algorithm.h"
-#include "astra/Singleton.h"
-#include "astra/XMLDocument.h"
-#include "astra/XMLNode.h"
-
-// Slightly hackish forward declaration of PyObject
-struct _object;
-typedef _object PyObject;
+#include "astra/Globals.h"
+#include <map>
+#include <string>
namespace astra {
-class _AstraExport CPluginAlgorithm : public CAlgorithm {
-
-public:
-
- CPluginAlgorithm(PyObject* pyclass);
- ~CPluginAlgorithm();
-
- bool initialize(const Config& _cfg);
- void run(int _iNrIterations);
-
-private:
- PyObject * instance;
-};
+class CAlgorithm;
-class _AstraExport CPluginAlgorithmFactory : public Singleton<CPluginAlgorithmFactory> {
+class _AstraExport CPluginAlgorithmFactory {
public:
+ CPluginAlgorithmFactory() { }
+ virtual ~CPluginAlgorithmFactory() { }
- CPluginAlgorithmFactory();
- ~CPluginAlgorithmFactory();
+ virtual CAlgorithm * getPlugin(const std::string &name) = 0;
- CPluginAlgorithm * getPlugin(std::string name);
+ virtual bool registerPlugin(std::string name, std::string className) = 0;
+ virtual bool registerPlugin(std::string className) = 0;
- bool registerPlugin(std::string name, std::string className);
- bool registerPlugin(std::string className);
- bool registerPluginClass(std::string name, PyObject * className);
- bool registerPluginClass(PyObject * className);
+ virtual std::map<std::string, std::string> getRegisteredMap() = 0;
- PyObject * getRegistered();
- std::map<std::string, std::string> getRegisteredMap();
-
- std::string getHelp(std::string name);
+ virtual std::string getHelp(const std::string &name) = 0;
+
+ static void registerFactory(CPluginAlgorithmFactory *factory) { m_factory = factory; }
+ static CPluginAlgorithmFactory* getFactory() { return m_factory; }
private:
- PyObject * pluginDict;
- PyObject *inspect, *six;
+ static CPluginAlgorithmFactory *m_factory;
};
-PyObject* XMLNode2dict(XMLNode node);
-
}
#endif
-
-#endif
diff --git a/matlab/mex/astra_mex_plugin_c.cpp b/matlab/mex/astra_mex_plugin_c.cpp
index 177fcf4..0dc0edf 100644
--- a/matlab/mex/astra_mex_plugin_c.cpp
+++ b/matlab/mex/astra_mex_plugin_c.cpp
@@ -48,7 +48,11 @@ using namespace astra;
*/
void astra_mex_plugin_get_registered(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
- astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getSingletonPtr();
+ astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getFactory();
+ if (!fact) {
+ mexPrintf("Plugin support not initialized.");
+ return;
+ }
std::map<std::string, std::string> mp = fact->getRegisteredMap();
for(std::map<std::string,std::string>::iterator it=mp.begin();it!=mp.end();it++){
mexPrintf("%s: %s\n",it->first.c_str(), it->second.c_str());
@@ -62,9 +66,13 @@ void astra_mex_plugin_get_registered(int nlhs, mxArray* plhs[], int nrhs, const
*/
void astra_mex_plugin_register(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
+ astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getFactory();
+ if (!fact) {
+ mexPrintf("Plugin support not initialized.");
+ return;
+ }
if (2 <= nrhs) {
string class_name = mexToString(prhs[1]);
- astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getSingletonPtr();
fact->registerPlugin(class_name);
}else{
mexPrintf("astra_mex_plugin('register', class_name);\n");
@@ -78,9 +86,13 @@ void astra_mex_plugin_register(int nlhs, mxArray* plhs[], int nrhs, const mxArra
*/
void astra_mex_plugin_get_help(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
+ astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getFactory();
+ if (!fact) {
+ mexPrintf("Plugin support not initialized.");
+ return;
+ }
if (2 <= nrhs) {
string name = mexToString(prhs[1]);
- astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getSingletonPtr();
mexPrintf((fact->getHelp(name)+"\n").c_str());
}else{
mexPrintf("astra_mex_plugin('get_help', name);\n");
diff --git a/python/astra/plugin_c.pyx b/python/astra/plugin_c.pyx
index 8d6816b..775ccd4 100644
--- a/python/astra/plugin_c.pyx
+++ b/python/astra/plugin_c.pyx
@@ -32,21 +32,25 @@ import inspect
from libcpp.string cimport string
from libcpp cimport bool
-cdef CPluginAlgorithmFactory *fact = getSingletonPtr()
+cdef CPythonPluginAlgorithmFactory *fact = getSingletonPtr()
from . import utils
-cdef extern from "astra/PluginAlgorithm.h" namespace "astra":
- cdef cppclass CPluginAlgorithmFactory:
+cdef extern from "src/PythonPluginAlgorithm.h" namespace "astra":
+ cdef cppclass CPythonPluginAlgorithmFactory:
bool registerPlugin(string className)
bool registerPlugin(string name, string className)
bool registerPluginClass(object className)
bool registerPluginClass(string name, object className)
object getRegistered()
- string getHelp(string name)
+ string getHelp(string &name)
+
+cdef extern from "src/PythonPluginAlgorithm.h" namespace "astra::CPythonPluginAlgorithmFactory":
+ cdef CPythonPluginAlgorithmFactory* getSingletonPtr()
cdef extern from "astra/PluginAlgorithm.h" namespace "astra::CPluginAlgorithmFactory":
- cdef CPluginAlgorithmFactory* getSingletonPtr()
+ # NB: Using wrong pointer type here for convenience
+ cdef void registerFactory(CPythonPluginAlgorithmFactory *)
def register(className, name=None):
if inspect.isclass(className):
@@ -65,3 +69,6 @@ def get_registered():
def get_help(name):
return utils.wrap_from_bytes(fact.getHelp(six.b(name)))
+
+# Register python plugin factory with astra
+registerFactory(fact)
diff --git a/python/astra/src/PythonPluginAlgorithm.cpp b/python/astra/src/PythonPluginAlgorithm.cpp
new file mode 100644
index 0000000..1ea858d
--- /dev/null
+++ b/python/astra/src/PythonPluginAlgorithm.cpp
@@ -0,0 +1,402 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+ 2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+The ASTRA Toolbox is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_PYTHON
+
+#include "PythonPluginAlgorithm.h"
+
+#include "astra/Logging.h"
+#include "astra/Utilities.h"
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#include <Python.h>
+#include "bytesobject.h"
+
+namespace astra {
+
+
+
+void logPythonError(){
+ if(PyErr_Occurred()){
+ PyObject *ptype, *pvalue, *ptraceback;
+ PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+ PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
+ PyObject *traceback = PyImport_ImportModule("traceback");
+ if(traceback!=NULL){
+ PyObject *exc;
+ if(ptraceback==NULL){
+ exc = PyObject_CallMethod(traceback,"format_exception_only","OO",ptype, pvalue);
+ }else{
+ exc = PyObject_CallMethod(traceback,"format_exception","OOO",ptype, pvalue, ptraceback);
+ }
+ if(exc!=NULL){
+ PyObject *six = PyImport_ImportModule("six");
+ if(six!=NULL){
+ PyObject *iter = PyObject_GetIter(exc);
+ if(iter!=NULL){
+ PyObject *line;
+ std::string errStr = "";
+ while(line = PyIter_Next(iter)){
+ PyObject *retb = PyObject_CallMethod(six,"b","O",line);
+ if(retb!=NULL){
+ errStr += std::string(PyBytes_AsString(retb));
+ Py_DECREF(retb);
+ }
+ Py_DECREF(line);
+ }
+ ASTRA_ERROR("%s",errStr.c_str());
+ Py_DECREF(iter);
+ }
+ Py_DECREF(six);
+ }
+ Py_DECREF(exc);
+ }
+ Py_DECREF(traceback);
+ }
+ if(ptype!=NULL) Py_DECREF(ptype);
+ if(pvalue!=NULL) Py_DECREF(pvalue);
+ if(ptraceback!=NULL) Py_DECREF(ptraceback);
+ }
+}
+
+
+CPluginAlgorithm::CPluginAlgorithm(PyObject* pyclass){
+ instance = PyObject_CallObject(pyclass, NULL);
+ if(instance==NULL) logPythonError();
+}
+
+CPluginAlgorithm::~CPluginAlgorithm(){
+ if(instance!=NULL){
+ Py_DECREF(instance);
+ instance = NULL;
+ }
+}
+
+bool CPluginAlgorithm::initialize(const Config& _cfg){
+ if(instance==NULL) return false;
+ PyObject *cfgDict = XMLNode2dict(_cfg.self);
+ PyObject *retVal = PyObject_CallMethod(instance, "astra_init", "O",cfgDict);
+ Py_DECREF(cfgDict);
+ if(retVal==NULL){
+ logPythonError();
+ return false;
+ }
+ m_bIsInitialized = true;
+ Py_DECREF(retVal);
+ return m_bIsInitialized;
+}
+
+void CPluginAlgorithm::run(int _iNrIterations){
+ if(instance==NULL) return;
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject *retVal = PyObject_CallMethod(instance, "run", "i",_iNrIterations);
+ if(retVal==NULL){
+ logPythonError();
+ }else{
+ Py_DECREF(retVal);
+ }
+ PyGILState_Release(state);
+}
+
+void fixLapackLoading(){
+ // When running in Matlab, we need to force numpy
+ // to use its internal lapack library instead of
+ // Matlab's MKL library to avoid errors. To do this,
+ // we set Python's dlopen flags to RTLD_NOW|RTLD_DEEPBIND
+ // and import 'numpy.linalg.lapack_lite' here. We reset
+ // Python's dlopen flags afterwards.
+ PyObject *sys = PyImport_ImportModule("sys");
+ if(sys!=NULL){
+ PyObject *curFlags = PyObject_CallMethod(sys,"getdlopenflags",NULL);
+ if(curFlags!=NULL){
+ PyObject *retVal = PyObject_CallMethod(sys, "setdlopenflags", "i",10);
+ if(retVal!=NULL){
+ PyObject *lapack = PyImport_ImportModule("numpy.linalg.lapack_lite");
+ if(lapack!=NULL){
+ Py_DECREF(lapack);
+ }
+ PyObject_CallMethod(sys, "setdlopenflags", "O",curFlags);
+ Py_DECREF(retVal);
+ }
+ Py_DECREF(curFlags);
+ }
+ Py_DECREF(sys);
+ }
+}
+
+CPythonPluginAlgorithmFactory::CPythonPluginAlgorithmFactory(){
+ if(!Py_IsInitialized()){
+ Py_Initialize();
+ PyEval_InitThreads();
+ }
+#ifndef _MSC_VER
+ if(astra::running_in_matlab) fixLapackLoading();
+#endif
+ pluginDict = PyDict_New();
+ inspect = PyImport_ImportModule("inspect");
+ six = PyImport_ImportModule("six");
+}
+
+CPythonPluginAlgorithmFactory::~CPythonPluginAlgorithmFactory(){
+ if(pluginDict!=NULL){
+ Py_DECREF(pluginDict);
+ }
+ if(inspect!=NULL) Py_DECREF(inspect);
+ if(six!=NULL) Py_DECREF(six);
+}
+
+PyObject * getClassFromString(std::string str){
+ std::vector<std::string> items;
+ boost::split(items, str, boost::is_any_of("."));
+ PyObject *pyclass = PyImport_ImportModule(items[0].c_str());
+ if(pyclass==NULL){
+ logPythonError();
+ return NULL;
+ }
+ PyObject *submod = pyclass;
+ for(unsigned int i=1;i<items.size();i++){
+ submod = PyObject_GetAttrString(submod,items[i].c_str());
+ Py_DECREF(pyclass);
+ pyclass = submod;
+ if(pyclass==NULL){
+ logPythonError();
+ return NULL;
+ }
+ }
+ return pyclass;
+}
+
+bool CPythonPluginAlgorithmFactory::registerPlugin(std::string name, std::string className){
+ PyObject *str = PyBytes_FromString(className.c_str());
+ PyDict_SetItemString(pluginDict, name.c_str(), str);
+ Py_DECREF(str);
+ return true;
+}
+
+bool CPythonPluginAlgorithmFactory::registerPlugin(std::string className){
+ PyObject *pyclass = getClassFromString(className);
+ if(pyclass==NULL) return false;
+ bool ret = registerPluginClass(pyclass);
+ Py_DECREF(pyclass);
+ return ret;
+}
+
+bool CPythonPluginAlgorithmFactory::registerPluginClass(std::string name, PyObject * className){
+ PyDict_SetItemString(pluginDict, name.c_str(), className);
+ return true;
+}
+
+bool CPythonPluginAlgorithmFactory::registerPluginClass(PyObject * className){
+ PyObject *astra_name = PyObject_GetAttrString(className,"astra_name");
+ if(astra_name==NULL){
+ logPythonError();
+ return false;
+ }
+ PyObject *retb = PyObject_CallMethod(six,"b","O",astra_name);
+ if(retb!=NULL){
+ PyDict_SetItemString(pluginDict,PyBytes_AsString(retb),className);
+ Py_DECREF(retb);
+ }else{
+ logPythonError();
+ }
+ Py_DECREF(astra_name);
+ return true;
+}
+
+CAlgorithm * CPythonPluginAlgorithmFactory::getPlugin(const std::string &name){
+ PyObject *className = PyDict_GetItemString(pluginDict, name.c_str());
+ if(className==NULL) return NULL;
+ CPluginAlgorithm *alg = NULL;
+ if(PyBytes_Check(className)){
+ std::string str = std::string(PyBytes_AsString(className));
+ PyObject *pyclass = getClassFromString(str);
+ if(pyclass!=NULL){
+ alg = new CPluginAlgorithm(pyclass);
+ Py_DECREF(pyclass);
+ }
+ }else{
+ alg = new CPluginAlgorithm(className);
+ }
+ return alg;
+}
+
+PyObject * CPythonPluginAlgorithmFactory::getRegistered(){
+ Py_INCREF(pluginDict);
+ return pluginDict;
+}
+
+std::map<std::string, std::string> CPythonPluginAlgorithmFactory::getRegisteredMap(){
+ std::map<std::string, std::string> ret;
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pluginDict, &pos, &key, &value)) {
+ PyObject *keystr = PyObject_Str(key);
+ if(keystr!=NULL){
+ PyObject *valstr = PyObject_Str(value);
+ if(valstr!=NULL){
+ PyObject * keyb = PyObject_CallMethod(six,"b","O",keystr);
+ if(keyb!=NULL){
+ PyObject * valb = PyObject_CallMethod(six,"b","O",valstr);
+ if(valb!=NULL){
+ ret[PyBytes_AsString(keyb)] = PyBytes_AsString(valb);
+ Py_DECREF(valb);
+ }
+ Py_DECREF(keyb);
+ }
+ Py_DECREF(valstr);
+ }
+ Py_DECREF(keystr);
+ }
+ logPythonError();
+ }
+ return ret;
+}
+
+std::string CPythonPluginAlgorithmFactory::getHelp(const std::string &name){
+ PyObject *className = PyDict_GetItemString(pluginDict, name.c_str());
+ if(className==NULL){
+ ASTRA_ERROR("Plugin %s not found!",name.c_str());
+ PyErr_Clear();
+ return "";
+ }
+ std::string ret = "";
+ PyObject *pyclass;
+ if(PyBytes_Check(className)){
+ std::string str = std::string(PyBytes_AsString(className));
+ pyclass = getClassFromString(str);
+ }else{
+ pyclass = className;
+ }
+ if(pyclass==NULL) return "";
+ if(inspect!=NULL && six!=NULL){
+ PyObject *retVal = PyObject_CallMethod(inspect,"getdoc","O",pyclass);
+ if(retVal!=NULL){
+ if(retVal!=Py_None){
+ PyObject *retb = PyObject_CallMethod(six,"b","O",retVal);
+ if(retb!=NULL){
+ ret = std::string(PyBytes_AsString(retb));
+ Py_DECREF(retb);
+ }
+ }
+ Py_DECREF(retVal);
+ }else{
+ logPythonError();
+ }
+ }
+ if(PyBytes_Check(className)){
+ Py_DECREF(pyclass);
+ }
+ return ret;
+}
+
+DEFINE_SINGLETON(CPythonPluginAlgorithmFactory);
+
+#if PY_MAJOR_VERSION >= 3
+PyObject * pyStringFromString(std::string str){
+ return PyUnicode_FromString(str.c_str());
+}
+#else
+PyObject * pyStringFromString(std::string str){
+ return PyBytes_FromString(str.c_str());
+}
+#endif
+
+PyObject* stringToPythonValue(std::string str){
+ if(str.find(";")!=std::string::npos){
+ std::vector<std::string> rows, row;
+ boost::split(rows, str, boost::is_any_of(";"));
+ PyObject *mat = PyList_New(rows.size());
+ for(unsigned int i=0; i<rows.size(); i++){
+ boost::split(row, rows[i], boost::is_any_of(","));
+ PyObject *rowlist = PyList_New(row.size());
+ for(unsigned int j=0;j<row.size();j++){
+ PyList_SetItem(rowlist, j, PyFloat_FromDouble(StringUtil::stringToDouble(row[j])));
+ }
+ PyList_SetItem(mat, i, rowlist);
+ }
+ return mat;
+ }
+ if(str.find(",")!=std::string::npos){
+ std::vector<std::string> vec;
+ boost::split(vec, str, boost::is_any_of(","));
+ PyObject *veclist = PyList_New(vec.size());
+ for(unsigned int i=0;i<vec.size();i++){
+ PyList_SetItem(veclist, i, PyFloat_FromDouble(StringUtil::stringToDouble(vec[i])));
+ }
+ return veclist;
+ }
+ try{
+ return PyLong_FromLong(StringUtil::stringToInt(str));
+ }catch(const StringUtil::bad_cast &){
+ try{
+ return PyFloat_FromDouble(StringUtil::stringToDouble(str));
+ }catch(const StringUtil::bad_cast &){
+ return pyStringFromString(str);
+ }
+ }
+}
+
+PyObject* XMLNode2dict(XMLNode node){
+ PyObject *dct = PyDict_New();
+ PyObject *opts = PyDict_New();
+ if(node.hasAttribute("type")){
+ PyObject *obj = pyStringFromString(node.getAttribute("type").c_str());
+ PyDict_SetItemString(dct, "type", obj);
+ Py_DECREF(obj);
+ }
+ std::list<XMLNode> nodes = node.getNodes();
+ std::list<XMLNode>::iterator it = nodes.begin();
+ while(it!=nodes.end()){
+ XMLNode subnode = *it;
+ if(subnode.getName()=="Option"){
+ PyObject *obj;
+ if(subnode.hasAttribute("value")){
+ obj = stringToPythonValue(subnode.getAttribute("value"));
+ }else{
+ obj = stringToPythonValue(subnode.getContent());
+ }
+ PyDict_SetItemString(opts, subnode.getAttribute("key").c_str(), obj);
+ Py_DECREF(obj);
+ }else{
+ PyObject *obj = stringToPythonValue(subnode.getContent());
+ PyDict_SetItemString(dct, subnode.getName().c_str(), obj);
+ Py_DECREF(obj);
+ }
+ ++it;
+ }
+ PyDict_SetItemString(dct, "options", opts);
+ Py_DECREF(opts);
+ return dct;
+}
+
+}
+#endif
diff --git a/python/astra/src/PythonPluginAlgorithm.h b/python/astra/src/PythonPluginAlgorithm.h
new file mode 100644
index 0000000..0b1309e
--- /dev/null
+++ b/python/astra/src/PythonPluginAlgorithm.h
@@ -0,0 +1,89 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+ 2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+The ASTRA Toolbox is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_PYTHONPLUGINALGORITHM
+#define _INC_PYTHONPLUGINALGORITHM
+
+#ifdef ASTRA_PYTHON
+
+#include "astra/Algorithm.h"
+#include "astra/Singleton.h"
+#include "astra/XMLDocument.h"
+#include "astra/XMLNode.h"
+#include "astra/PluginAlgorithm.h"
+
+#include <Python.h>
+
+namespace astra {
+class CPluginAlgorithm : public CAlgorithm {
+
+public:
+
+ CPluginAlgorithm(PyObject* pyclass);
+ ~CPluginAlgorithm();
+
+ bool initialize(const Config& _cfg);
+ void run(int _iNrIterations);
+
+private:
+ PyObject * instance;
+
+};
+
+class CPythonPluginAlgorithmFactory : public CPluginAlgorithmFactory, public Singleton<CPythonPluginAlgorithmFactory> {
+
+public:
+
+ CPythonPluginAlgorithmFactory();
+ virtual ~CPythonPluginAlgorithmFactory();
+
+ virtual CAlgorithm * getPlugin(const std::string &name);
+
+ virtual bool registerPlugin(std::string name, std::string className);
+ virtual bool registerPlugin(std::string className);
+ bool registerPluginClass(std::string name, PyObject * className);
+ bool registerPluginClass(PyObject * className);
+
+ PyObject * getRegistered();
+ virtual std::map<std::string, std::string> getRegisteredMap();
+
+ virtual std::string getHelp(const std::string &name);
+
+private:
+ PyObject * pluginDict;
+ PyObject *inspect, *six;
+};
+
+PyObject* XMLNode2dict(XMLNode node);
+
+}
+
+
+#endif
+
+#endif
diff --git a/python/builder.py b/python/builder.py
index 018b26b..9a77ecc 100644
--- a/python/builder.py
+++ b/python/builder.py
@@ -70,6 +70,10 @@ ext_modules = [ ]
ext_modules = cythonize("astra/*.pyx", language_level=2)
cmdclass = { 'build_ext': build_ext }
+for m in ext_modules:
+ if m.name == 'astra.plugin_c':
+ m.sources.append('astra/src/PythonPluginAlgorithm.cpp')
+
setup (name = 'PyASTRAToolbox',
version = '1.7.1',
description = 'Python interface to the ASTRA-Toolbox',
diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index 9fc511a..1bcfbdb 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -26,376 +26,11 @@ along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
$Id$
*/
-#ifdef ASTRA_PYTHON
-
#include "astra/PluginAlgorithm.h"
-#include "astra/Logging.h"
-#include "astra/Utilities.h"
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/split.hpp>
-#include <iostream>
-#include <fstream>
-#include <string>
-
-#include <Python.h>
-#include "bytesobject.h"
namespace astra {
+CPluginAlgorithmFactory *CPluginAlgorithmFactory::m_factory = 0;
-
-void logPythonError(){
- if(PyErr_Occurred()){
- PyObject *ptype, *pvalue, *ptraceback;
- PyErr_Fetch(&ptype, &pvalue, &ptraceback);
- PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
- PyObject *traceback = PyImport_ImportModule("traceback");
- if(traceback!=NULL){
- PyObject *exc;
- if(ptraceback==NULL){
- exc = PyObject_CallMethod(traceback,"format_exception_only","OO",ptype, pvalue);
- }else{
- exc = PyObject_CallMethod(traceback,"format_exception","OOO",ptype, pvalue, ptraceback);
- }
- if(exc!=NULL){
- PyObject *six = PyImport_ImportModule("six");
- if(six!=NULL){
- PyObject *iter = PyObject_GetIter(exc);
- if(iter!=NULL){
- PyObject *line;
- std::string errStr = "";
- while(line = PyIter_Next(iter)){
- PyObject *retb = PyObject_CallMethod(six,"b","O",line);
- if(retb!=NULL){
- errStr += std::string(PyBytes_AsString(retb));
- Py_DECREF(retb);
- }
- Py_DECREF(line);
- }
- ASTRA_ERROR("%s",errStr.c_str());
- Py_DECREF(iter);
- }
- Py_DECREF(six);
- }
- Py_DECREF(exc);
- }
- Py_DECREF(traceback);
- }
- if(ptype!=NULL) Py_DECREF(ptype);
- if(pvalue!=NULL) Py_DECREF(pvalue);
- if(ptraceback!=NULL) Py_DECREF(ptraceback);
- }
-}
-
-
-CPluginAlgorithm::CPluginAlgorithm(PyObject* pyclass){
- instance = PyObject_CallObject(pyclass, NULL);
- if(instance==NULL) logPythonError();
-}
-
-CPluginAlgorithm::~CPluginAlgorithm(){
- if(instance!=NULL){
- Py_DECREF(instance);
- instance = NULL;
- }
-}
-
-bool CPluginAlgorithm::initialize(const Config& _cfg){
- if(instance==NULL) return false;
- PyObject *cfgDict = XMLNode2dict(_cfg.self);
- PyObject *retVal = PyObject_CallMethod(instance, "astra_init", "O",cfgDict);
- Py_DECREF(cfgDict);
- if(retVal==NULL){
- logPythonError();
- return false;
- }
- m_bIsInitialized = true;
- Py_DECREF(retVal);
- return m_bIsInitialized;
-}
-
-void CPluginAlgorithm::run(int _iNrIterations){
- if(instance==NULL) return;
- PyGILState_STATE state = PyGILState_Ensure();
- PyObject *retVal = PyObject_CallMethod(instance, "run", "i",_iNrIterations);
- if(retVal==NULL){
- logPythonError();
- }else{
- Py_DECREF(retVal);
- }
- PyGILState_Release(state);
}
-void fixLapackLoading(){
- // When running in Matlab, we need to force numpy
- // to use its internal lapack library instead of
- // Matlab's MKL library to avoid errors. To do this,
- // we set Python's dlopen flags to RTLD_NOW|RTLD_DEEPBIND
- // and import 'numpy.linalg.lapack_lite' here. We reset
- // Python's dlopen flags afterwards.
- PyObject *sys = PyImport_ImportModule("sys");
- if(sys!=NULL){
- PyObject *curFlags = PyObject_CallMethod(sys,"getdlopenflags",NULL);
- if(curFlags!=NULL){
- PyObject *retVal = PyObject_CallMethod(sys, "setdlopenflags", "i",10);
- if(retVal!=NULL){
- PyObject *lapack = PyImport_ImportModule("numpy.linalg.lapack_lite");
- if(lapack!=NULL){
- Py_DECREF(lapack);
- }
- PyObject_CallMethod(sys, "setdlopenflags", "O",curFlags);
- Py_DECREF(retVal);
- }
- Py_DECREF(curFlags);
- }
- Py_DECREF(sys);
- }
-}
-
-CPluginAlgorithmFactory::CPluginAlgorithmFactory(){
- if(!Py_IsInitialized()){
- Py_Initialize();
- PyEval_InitThreads();
- }
-#ifndef _MSC_VER
- if(astra::running_in_matlab) fixLapackLoading();
-#endif
- pluginDict = PyDict_New();
- inspect = PyImport_ImportModule("inspect");
- six = PyImport_ImportModule("six");
-}
-
-CPluginAlgorithmFactory::~CPluginAlgorithmFactory(){
- if(pluginDict!=NULL){
- Py_DECREF(pluginDict);
- }
- if(inspect!=NULL) Py_DECREF(inspect);
- if(six!=NULL) Py_DECREF(six);
-}
-
-PyObject * getClassFromString(std::string str){
- std::vector<std::string> items;
- boost::split(items, str, boost::is_any_of("."));
- PyObject *pyclass = PyImport_ImportModule(items[0].c_str());
- if(pyclass==NULL){
- logPythonError();
- return NULL;
- }
- PyObject *submod = pyclass;
- for(unsigned int i=1;i<items.size();i++){
- submod = PyObject_GetAttrString(submod,items[i].c_str());
- Py_DECREF(pyclass);
- pyclass = submod;
- if(pyclass==NULL){
- logPythonError();
- return NULL;
- }
- }
- return pyclass;
-}
-
-bool CPluginAlgorithmFactory::registerPlugin(std::string name, std::string className){
- PyObject *str = PyBytes_FromString(className.c_str());
- PyDict_SetItemString(pluginDict, name.c_str(), str);
- Py_DECREF(str);
- return true;
-}
-
-bool CPluginAlgorithmFactory::registerPlugin(std::string className){
- PyObject *pyclass = getClassFromString(className);
- if(pyclass==NULL) return false;
- bool ret = registerPluginClass(pyclass);
- Py_DECREF(pyclass);
- return ret;
-}
-
-bool CPluginAlgorithmFactory::registerPluginClass(std::string name, PyObject * className){
- PyDict_SetItemString(pluginDict, name.c_str(), className);
- return true;
-}
-
-bool CPluginAlgorithmFactory::registerPluginClass(PyObject * className){
- PyObject *astra_name = PyObject_GetAttrString(className,"astra_name");
- if(astra_name==NULL){
- logPythonError();
- return false;
- }
- PyObject *retb = PyObject_CallMethod(six,"b","O",astra_name);
- if(retb!=NULL){
- PyDict_SetItemString(pluginDict,PyBytes_AsString(retb),className);
- Py_DECREF(retb);
- }else{
- logPythonError();
- }
- Py_DECREF(astra_name);
- return true;
-}
-
-CPluginAlgorithm * CPluginAlgorithmFactory::getPlugin(std::string name){
- PyObject *className = PyDict_GetItemString(pluginDict, name.c_str());
- if(className==NULL) return NULL;
- CPluginAlgorithm *alg = NULL;
- if(PyBytes_Check(className)){
- std::string str = std::string(PyBytes_AsString(className));
- PyObject *pyclass = getClassFromString(str);
- if(pyclass!=NULL){
- alg = new CPluginAlgorithm(pyclass);
- Py_DECREF(pyclass);
- }
- }else{
- alg = new CPluginAlgorithm(className);
- }
- return alg;
-}
-
-PyObject * CPluginAlgorithmFactory::getRegistered(){
- Py_INCREF(pluginDict);
- return pluginDict;
-}
-
-std::map<std::string, std::string> CPluginAlgorithmFactory::getRegisteredMap(){
- std::map<std::string, std::string> ret;
- PyObject *key, *value;
- Py_ssize_t pos = 0;
- while (PyDict_Next(pluginDict, &pos, &key, &value)) {
- PyObject *keystr = PyObject_Str(key);
- if(keystr!=NULL){
- PyObject *valstr = PyObject_Str(value);
- if(valstr!=NULL){
- PyObject * keyb = PyObject_CallMethod(six,"b","O",keystr);
- if(keyb!=NULL){
- PyObject * valb = PyObject_CallMethod(six,"b","O",valstr);
- if(valb!=NULL){
- ret[PyBytes_AsString(keyb)] = PyBytes_AsString(valb);
- Py_DECREF(valb);
- }
- Py_DECREF(keyb);
- }
- Py_DECREF(valstr);
- }
- Py_DECREF(keystr);
- }
- logPythonError();
- }
- return ret;
-}
-
-std::string CPluginAlgorithmFactory::getHelp(std::string name){
- PyObject *className = PyDict_GetItemString(pluginDict, name.c_str());
- if(className==NULL){
- ASTRA_ERROR("Plugin %s not found!",name.c_str());
- PyErr_Clear();
- return "";
- }
- std::string ret = "";
- PyObject *pyclass;
- if(PyBytes_Check(className)){
- std::string str = std::string(PyBytes_AsString(className));
- pyclass = getClassFromString(str);
- }else{
- pyclass = className;
- }
- if(pyclass==NULL) return "";
- if(inspect!=NULL && six!=NULL){
- PyObject *retVal = PyObject_CallMethod(inspect,"getdoc","O",pyclass);
- if(retVal!=NULL){
- if(retVal!=Py_None){
- PyObject *retb = PyObject_CallMethod(six,"b","O",retVal);
- if(retb!=NULL){
- ret = std::string(PyBytes_AsString(retb));
- Py_DECREF(retb);
- }
- }
- Py_DECREF(retVal);
- }else{
- logPythonError();
- }
- }
- if(PyBytes_Check(className)){
- Py_DECREF(pyclass);
- }
- return ret;
-}
-
-DEFINE_SINGLETON(CPluginAlgorithmFactory);
-
-#if PY_MAJOR_VERSION >= 3
-PyObject * pyStringFromString(std::string str){
- return PyUnicode_FromString(str.c_str());
-}
-#else
-PyObject * pyStringFromString(std::string str){
- return PyBytes_FromString(str.c_str());
-}
-#endif
-
-PyObject* stringToPythonValue(std::string str){
- if(str.find(";")!=std::string::npos){
- std::vector<std::string> rows, row;
- boost::split(rows, str, boost::is_any_of(";"));
- PyObject *mat = PyList_New(rows.size());
- for(unsigned int i=0; i<rows.size(); i++){
- boost::split(row, rows[i], boost::is_any_of(","));
- PyObject *rowlist = PyList_New(row.size());
- for(unsigned int j=0;j<row.size();j++){
- PyList_SetItem(rowlist, j, PyFloat_FromDouble(StringUtil::stringToDouble(row[j])));
- }
- PyList_SetItem(mat, i, rowlist);
- }
- return mat;
- }
- if(str.find(",")!=std::string::npos){
- std::vector<std::string> vec;
- boost::split(vec, str, boost::is_any_of(","));
- PyObject *veclist = PyList_New(vec.size());
- for(unsigned int i=0;i<vec.size();i++){
- PyList_SetItem(veclist, i, PyFloat_FromDouble(StringUtil::stringToDouble(vec[i])));
- }
- return veclist;
- }
- try{
- return PyLong_FromLong(StringUtil::stringToInt(str));
- }catch(const StringUtil::bad_cast &){
- try{
- return PyFloat_FromDouble(StringUtil::stringToDouble(str));
- }catch(const StringUtil::bad_cast &){
- return pyStringFromString(str);
- }
- }
-}
-
-PyObject* XMLNode2dict(XMLNode node){
- PyObject *dct = PyDict_New();
- PyObject *opts = PyDict_New();
- if(node.hasAttribute("type")){
- PyObject *obj = pyStringFromString(node.getAttribute("type").c_str());
- PyDict_SetItemString(dct, "type", obj);
- Py_DECREF(obj);
- }
- std::list<XMLNode> nodes = node.getNodes();
- std::list<XMLNode>::iterator it = nodes.begin();
- while(it!=nodes.end()){
- XMLNode subnode = *it;
- if(subnode.getName()=="Option"){
- PyObject *obj;
- if(subnode.hasAttribute("value")){
- obj = stringToPythonValue(subnode.getAttribute("value"));
- }else{
- obj = stringToPythonValue(subnode.getContent());
- }
- PyDict_SetItemString(opts, subnode.getAttribute("key").c_str(), obj);
- Py_DECREF(obj);
- }else{
- PyObject *obj = stringToPythonValue(subnode.getContent());
- PyDict_SetItemString(dct, subnode.getName().c_str(), obj);
- Py_DECREF(obj);
- }
- ++it;
- }
- PyDict_SetItemString(dct, "options", opts);
- Py_DECREF(opts);
- return dct;
-}
-
-}
-#endif