From 18b6d25f7e4f0943b3592f3bb4f6ca5ed9c285d3 Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Fri, 19 Jun 2015 22:28:06 +0200
Subject: Add support for Python algorithm plugins

---
 src/PluginAlgorithm.cpp | 294 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 294 insertions(+)
 create mode 100644 src/PluginAlgorithm.cpp

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
new file mode 100644
index 0000000..df13f31
--- /dev/null
+++ b/src/PluginAlgorithm.cpp
@@ -0,0 +1,294 @@
+/*
+-----------------------------------------------------------------------
+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 "astra/PluginAlgorithm.h"
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/lexical_cast.hpp>
+#include <iostream>
+#include <fstream>
+#include <string>
+
+namespace astra {
+
+CPluginAlgorithm::CPluginAlgorithm(PyObject* pyclass){
+    instance = PyObject_CallObject(pyclass, NULL);
+}
+
+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) return false;
+    m_bIsInitialized = true;
+    Py_DECREF(retVal);
+    return m_bIsInitialized;
+}
+
+void CPluginAlgorithm::run(int _iNrIterations){
+    if(instance==NULL) return;
+    PyObject *retVal = PyObject_CallMethod(instance, "run", "i",_iNrIterations);
+    if(retVal==NULL) return;
+    Py_DECREF(retVal);
+}
+
+const char ps =
+#ifdef _WIN32
+                            '\\';
+#else
+                            '/';
+#endif
+
+std::vector<std::string> CPluginAlgorithmFactory::getPluginPathList(){
+    std::vector<std::string> list;
+    list.push_back("/etc/astra-toolbox");
+    PyObject *ret, *retb;
+    ret = PyObject_CallMethod(inspect,"getfile","O",astra);
+    if(ret!=NULL){
+        retb = PyObject_CallMethod(six,"b","O",ret);
+        Py_DECREF(ret);
+        if(retb!=NULL){
+            std::string astra_inst (PyBytes_AsString(retb));
+            Py_DECREF(retb);
+            ret = PyObject_CallMethod(ospath,"dirname","s",astra_inst.c_str());
+            if(ret!=NULL){
+                retb = PyObject_CallMethod(six,"b","O",ret);
+                Py_DECREF(ret);
+                if(retb!=NULL){
+                    list.push_back(std::string(PyBytes_AsString(retb)));
+                    Py_DECREF(retb);
+                }
+            }
+        }
+    }
+    ret = PyObject_CallMethod(ospath,"expanduser","s","~");
+    if(ret!=NULL){
+        retb = PyObject_CallMethod(six,"b","O",ret);
+        Py_DECREF(ret);
+        if(retb!=NULL){
+            list.push_back(std::string(PyBytes_AsString(retb)) + ps + ".astra-toolbox");
+            Py_DECREF(retb);
+        }
+    }
+    const char *envval = getenv("ASTRA_PLUGIN_PATH");
+    if(envval!=NULL){
+        list.push_back(std::string(envval));
+    }
+    return list;
+}
+
+CPluginAlgorithmFactory::CPluginAlgorithmFactory(){
+    Py_Initialize();
+    pluginDict = PyDict_New();
+    ospath = PyImport_ImportModule("os.path");
+    inspect = PyImport_ImportModule("inspect");
+    six = PyImport_ImportModule("six");
+    astra = PyImport_ImportModule("astra");
+    std::vector<std::string> fls = getPluginPathList();
+    std::vector<std::string> items;
+    for(unsigned int i=0;i<fls.size();i++){
+        std::ifstream fs ((fls[i]+ps+"plugins.txt").c_str());
+        if(!fs.is_open()) continue;
+        std::string line;
+        while (std::getline(fs,line)){
+            boost::split(items, line, boost::is_any_of(" "));
+            if(items.size()<2) continue;
+            PyObject *str = PyBytes_FromString(items[1].c_str());
+            PyDict_SetItemString(pluginDict,items[0].c_str(),str);
+            Py_DECREF(str);
+        }
+        fs.close();
+    }
+}
+
+CPluginAlgorithmFactory::~CPluginAlgorithmFactory(){
+    if(pluginDict!=NULL){
+        Py_DECREF(pluginDict);
+    }
+}
+
+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::registerPluginClass(std::string name, PyObject * className){
+    PyDict_SetItemString(pluginDict, name.c_str(), className);
+    return true;
+}
+
+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) 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) return NULL;
+    }
+    return pyclass;
+}
+
+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::string CPluginAlgorithmFactory::getHelp(std::string name){
+    PyObject *className = PyDict_GetItemString(pluginDict, name.c_str());
+    if(className==NULL) return "";
+    std::string str = std::string(PyBytes_AsString(className));
+    std::string ret = "";
+    PyObject *pyclass = getClassFromString(str);
+    if(pyclass==NULL) return "";
+    PyObject *module = PyImport_ImportModule("inspect");
+    if(module!=NULL){
+        PyObject *retVal = PyObject_CallMethod(module,"getdoc","O",pyclass);
+        if(retVal!=NULL){
+            PyObject *retb = PyObject_CallMethod(six,"b","O",retVal);
+            Py_DECREF(retVal);
+            if(retVal!=NULL){
+                ret = std::string(PyBytes_AsString(retb));
+                Py_DECREF(retb);
+            }
+        }
+        Py_DECREF(module);
+    }
+    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(boost::lexical_cast<double>(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(boost::lexical_cast<double>(vec[i])));
+        }
+        return veclist;
+    }
+    try{
+        return PyLong_FromLong(boost::lexical_cast<long>(str));
+    }catch(const boost::bad_lexical_cast &){
+        try{
+            return PyFloat_FromDouble(boost::lexical_cast<double>(str));
+        }catch(const boost::bad_lexical_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 = stringToPythonValue(subnode.getAttribute("value"));
+            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
\ No newline at end of file
-- 
cgit v1.2.3


From 4c9e432ae4581fdc110e9a9c45267227be1c7c31 Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Wed, 24 Jun 2015 20:43:05 +0200
Subject: Fix config to dict translation for array options

---
 src/PluginAlgorithm.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index df13f31..a27ce2c 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -275,7 +275,12 @@ PyObject* XMLNode2dict(XMLNode node){
     while(it!=nodes.end()){
         XMLNode subnode = *it;
         if(subnode.getName()=="Option"){
-            PyObject *obj = stringToPythonValue(subnode.getAttribute("value"));
+            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{
-- 
cgit v1.2.3


From edae78481cf0e9cbffe335de1e541821758c5da1 Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Wed, 24 Jun 2015 21:36:04 +0200
Subject: Log error when running Python plugin algorithm

---
 src/PluginAlgorithm.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index a27ce2c..7dcaf68 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -62,7 +62,7 @@ bool CPluginAlgorithm::initialize(const Config& _cfg){
 
 void CPluginAlgorithm::run(int _iNrIterations){
     if(instance==NULL) return;
-    PyObject *retVal = PyObject_CallMethod(instance, "run", "i",_iNrIterations);
+    PyObject *retVal = PyObject_CallMethod(instance, "astra_run", "i",_iNrIterations);
     if(retVal==NULL) return;
     Py_DECREF(retVal);
 }
-- 
cgit v1.2.3


From 2f871bc7068d6c87a7d950ae044ba66b0b8dcd3f Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Fri, 17 Jul 2015 12:05:46 +0200
Subject: Remove config text file loading for plugins

---
 src/PluginAlgorithm.cpp | 72 ++++---------------------------------------------
 1 file changed, 5 insertions(+), 67 deletions(-)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index 7dcaf68..8ba6631 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -67,79 +67,19 @@ void CPluginAlgorithm::run(int _iNrIterations){
     Py_DECREF(retVal);
 }
 
-const char ps =
-#ifdef _WIN32
-                            '\\';
-#else
-                            '/';
-#endif
-
-std::vector<std::string> CPluginAlgorithmFactory::getPluginPathList(){
-    std::vector<std::string> list;
-    list.push_back("/etc/astra-toolbox");
-    PyObject *ret, *retb;
-    ret = PyObject_CallMethod(inspect,"getfile","O",astra);
-    if(ret!=NULL){
-        retb = PyObject_CallMethod(six,"b","O",ret);
-        Py_DECREF(ret);
-        if(retb!=NULL){
-            std::string astra_inst (PyBytes_AsString(retb));
-            Py_DECREF(retb);
-            ret = PyObject_CallMethod(ospath,"dirname","s",astra_inst.c_str());
-            if(ret!=NULL){
-                retb = PyObject_CallMethod(six,"b","O",ret);
-                Py_DECREF(ret);
-                if(retb!=NULL){
-                    list.push_back(std::string(PyBytes_AsString(retb)));
-                    Py_DECREF(retb);
-                }
-            }
-        }
-    }
-    ret = PyObject_CallMethod(ospath,"expanduser","s","~");
-    if(ret!=NULL){
-        retb = PyObject_CallMethod(six,"b","O",ret);
-        Py_DECREF(ret);
-        if(retb!=NULL){
-            list.push_back(std::string(PyBytes_AsString(retb)) + ps + ".astra-toolbox");
-            Py_DECREF(retb);
-        }
-    }
-    const char *envval = getenv("ASTRA_PLUGIN_PATH");
-    if(envval!=NULL){
-        list.push_back(std::string(envval));
-    }
-    return list;
-}
-
 CPluginAlgorithmFactory::CPluginAlgorithmFactory(){
     Py_Initialize();
     pluginDict = PyDict_New();
-    ospath = PyImport_ImportModule("os.path");
     inspect = PyImport_ImportModule("inspect");
     six = PyImport_ImportModule("six");
-    astra = PyImport_ImportModule("astra");
-    std::vector<std::string> fls = getPluginPathList();
-    std::vector<std::string> items;
-    for(unsigned int i=0;i<fls.size();i++){
-        std::ifstream fs ((fls[i]+ps+"plugins.txt").c_str());
-        if(!fs.is_open()) continue;
-        std::string line;
-        while (std::getline(fs,line)){
-            boost::split(items, line, boost::is_any_of(" "));
-            if(items.size()<2) continue;
-            PyObject *str = PyBytes_FromString(items[1].c_str());
-            PyDict_SetItemString(pluginDict,items[0].c_str(),str);
-            Py_DECREF(str);
-        }
-        fs.close();
-    }
 }
 
 CPluginAlgorithmFactory::~CPluginAlgorithmFactory(){
     if(pluginDict!=NULL){
         Py_DECREF(pluginDict);
     }
+    if(inspect!=NULL) Py_DECREF(inspect);
+    if(six!=NULL) Py_DECREF(six);
 }
 
 bool CPluginAlgorithmFactory::registerPlugin(std::string name, std::string className){
@@ -198,18 +138,16 @@ std::string CPluginAlgorithmFactory::getHelp(std::string name){
     std::string ret = "";
     PyObject *pyclass = getClassFromString(str);
     if(pyclass==NULL) return "";
-    PyObject *module = PyImport_ImportModule("inspect");
-    if(module!=NULL){
-        PyObject *retVal = PyObject_CallMethod(module,"getdoc","O",pyclass);
+    if(inspect!=NULL && six!=NULL){
+        PyObject *retVal = PyObject_CallMethod(inspect,"getdoc","O",pyclass);
         if(retVal!=NULL){
             PyObject *retb = PyObject_CallMethod(six,"b","O",retVal);
             Py_DECREF(retVal);
-            if(retVal!=NULL){
+            if(retb!=NULL){
                 ret = std::string(PyBytes_AsString(retb));
                 Py_DECREF(retb);
             }
         }
-        Py_DECREF(module);
     }
     Py_DECREF(pyclass);
     return ret;
-- 
cgit v1.2.3


From 3d136b7c819b0b142ad056bf01c8c1191eea9ba0 Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Fri, 17 Jul 2015 16:22:05 +0200
Subject: Fix numpy lapack loading when running in Matlab

---
 src/Globals.cpp         |  3 +++
 src/PluginAlgorithm.cpp | 29 +++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

(limited to 'src')

diff --git a/src/Globals.cpp b/src/Globals.cpp
index 813f9c9..904a459 100644
--- a/src/Globals.cpp
+++ b/src/Globals.cpp
@@ -28,5 +28,8 @@ $Id$
 
 #include "astra/Globals.h"
 
+namespace astra{
+    bool running_in_matlab=false;
+}
 // nothing to see here :)
 
diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index 8ba6631..c26ee3f 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -67,8 +67,37 @@ void CPluginAlgorithm::run(int _iNrIterations){
     Py_DECREF(retVal);
 }
 
+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(){
     Py_Initialize();
+#ifndef _MSC_VER
+    if(astra::running_in_matlab) fixLapackLoading();
+#endif
     pluginDict = PyDict_New();
     inspect = PyImport_ImportModule("inspect");
     six = PyImport_ImportModule("six");
-- 
cgit v1.2.3


From ef9eb1dc7eb494e87f728af7caff8e5291cf320c Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Mon, 20 Jul 2015 10:34:55 +0200
Subject: Also log Python errors when importing and creating Python plugins

---
 src/PluginAlgorithm.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index c26ee3f..a118f54 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -29,6 +29,7 @@ $Id$
 #ifdef ASTRA_PYTHON
 
 #include "astra/PluginAlgorithm.h"
+#include "astra/Logging.h"
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/split.hpp>
 #include <boost/lexical_cast.hpp>
@@ -38,8 +39,53 @@ $Id$
 
 namespace astra {
 
+
+void logPythonError(){
+    if(PyErr_Occurred()){
+        PyObject *ptype, *pvalue, *ptraceback;
+        PyErr_Fetch(&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(){
@@ -148,6 +194,8 @@ CPluginAlgorithm * CPluginAlgorithmFactory::getPlugin(std::string name){
         if(pyclass!=NULL){
             alg = new CPluginAlgorithm(pyclass);
             Py_DECREF(pyclass);
+        }else{
+            logPythonError();
         }
     }else{
         alg = new CPluginAlgorithm(className);
-- 
cgit v1.2.3


From 37abc22cf8d26fa3f7e282a1ee50a2a129d5a295 Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Mon, 20 Jul 2015 11:26:39 +0200
Subject: Always log Python errors when importing/creating plugins

---
 src/PluginAlgorithm.cpp | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index a118f54..d6cf731 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -173,13 +173,19 @@ 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) return NULL;
+    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) return NULL;
+        if(pyclass==NULL){
+            logPythonError();
+            return NULL;
+        }
     }
     return pyclass;
 }
@@ -194,8 +200,6 @@ CPluginAlgorithm * CPluginAlgorithmFactory::getPlugin(std::string name){
         if(pyclass!=NULL){
             alg = new CPluginAlgorithm(pyclass);
             Py_DECREF(pyclass);
-        }else{
-            logPythonError();
         }
     }else{
         alg = new CPluginAlgorithm(className);
-- 
cgit v1.2.3


From d91b51f6d58003de84a9d6dd8189fceba0e81a5a Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Mon, 20 Jul 2015 14:07:21 +0200
Subject: Allow registering plugins without explicit name, and fix exception
 handling when running in Matlab

---
 src/PluginAlgorithm.cpp | 95 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 76 insertions(+), 19 deletions(-)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index d6cf731..7f7ff61 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -100,7 +100,10 @@ bool CPluginAlgorithm::initialize(const Config& _cfg){
     PyObject *cfgDict = XMLNode2dict(_cfg.self);
     PyObject *retVal = PyObject_CallMethod(instance, "astra_init", "O",cfgDict);
     Py_DECREF(cfgDict);
-    if(retVal==NULL) return false;
+    if(retVal==NULL){
+        logPythonError();
+        return false;
+    }
     m_bIsInitialized = true;
     Py_DECREF(retVal);
     return m_bIsInitialized;
@@ -108,8 +111,11 @@ bool CPluginAlgorithm::initialize(const Config& _cfg){
 
 void CPluginAlgorithm::run(int _iNrIterations){
     if(instance==NULL) return;
-    PyObject *retVal = PyObject_CallMethod(instance, "astra_run", "i",_iNrIterations);
-    if(retVal==NULL) return;
+    PyObject *retVal = PyObject_CallMethod(instance, "run", "i",_iNrIterations);
+    if(retVal==NULL){
+        logPythonError();
+        return;
+    }
     Py_DECREF(retVal);
 }
 
@@ -157,18 +163,6 @@ CPluginAlgorithmFactory::~CPluginAlgorithmFactory(){
     if(six!=NULL) Py_DECREF(six);
 }
 
-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::registerPluginClass(std::string name, PyObject * className){
-    PyDict_SetItemString(pluginDict, name.c_str(), className);
-    return true;
-}
-
 PyObject * getClassFromString(std::string str){
     std::vector<std::string> items;
     boost::split(items, str, boost::is_any_of("."));
@@ -190,6 +184,43 @@ PyObject * getClassFromString(std::string str){
     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;
@@ -212,12 +243,34 @@ PyObject * CPluginAlgorithmFactory::getRegistered(){
     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 * keyb = PyObject_Bytes(key);
+        PyObject * valb = PyObject_Bytes(value);
+        ret[PyBytes_AsString(keyb)] = PyBytes_AsString(valb);
+        Py_DECREF(keyb);
+        Py_DECREF(valb);
+    }
+    return ret;
+}
+
 std::string CPluginAlgorithmFactory::getHelp(std::string name){
     PyObject *className = PyDict_GetItemString(pluginDict, name.c_str());
-    if(className==NULL) return "";
-    std::string str = std::string(PyBytes_AsString(className));
+    if(className==NULL){
+        ASTRA_ERROR("Plugin %s not found!",name.c_str());
+        return "";
+    }
     std::string ret = "";
-    PyObject *pyclass = getClassFromString(str);
+    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);
@@ -228,9 +281,13 @@ std::string CPluginAlgorithmFactory::getHelp(std::string name){
                 ret = std::string(PyBytes_AsString(retb));
                 Py_DECREF(retb);
             }
+        }else{
+            logPythonError();
         }
     }
-    Py_DECREF(pyclass);
+    if(PyBytes_Check(className)){
+        Py_DECREF(pyclass);
+    }
     return ret;
 }
 
-- 
cgit v1.2.3


From 3808967cfaa6beb9d93d2035ebc72fa010fdab11 Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Mon, 20 Jul 2015 16:41:55 +0200
Subject: Normalize Python exceptions (needed for some)

---
 src/PluginAlgorithm.cpp | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index 7f7ff61..56c4e4d 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -44,6 +44,7 @@ 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;
-- 
cgit v1.2.3


From dc3bed557603d4735ddc20961c28e5e868fc315c Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Tue, 21 Jul 2015 11:44:29 +0200
Subject: Clear Python error when plugin is not find in getHelp

---
 src/PluginAlgorithm.cpp | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index 56c4e4d..5c779fd 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -262,6 +262,7 @@ 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 = "";
-- 
cgit v1.2.3


From 645122f4b365ce44849afda2ed8a711ae649ed76 Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Tue, 21 Jul 2015 13:56:18 +0200
Subject: Fix 'get_registered' in Matlab with Python 3

---
 src/PluginAlgorithm.cpp | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index 5c779fd..5d6d733 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -249,11 +249,24 @@ std::map<std::string, std::string> CPluginAlgorithmFactory::getRegisteredMap(){
     PyObject *key, *value;
     Py_ssize_t pos = 0;
     while (PyDict_Next(pluginDict, &pos, &key, &value)) {
-        PyObject * keyb = PyObject_Bytes(key);
-        PyObject * valb = PyObject_Bytes(value);
-        ret[PyBytes_AsString(keyb)] = PyBytes_AsString(valb);
-        Py_DECREF(keyb);
-        Py_DECREF(valb);
+        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;
 }
-- 
cgit v1.2.3


From ab980d9f088c0f4e28d61b94c32788c30a9c4cb9 Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Wed, 5 Aug 2015 16:26:01 +0200
Subject: Fix get_help for classes without docstring

---
 src/PluginAlgorithm.cpp | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index 5d6d733..4066e30 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -290,12 +290,14 @@ std::string CPluginAlgorithmFactory::getHelp(std::string name){
     if(inspect!=NULL && six!=NULL){
         PyObject *retVal = PyObject_CallMethod(inspect,"getdoc","O",pyclass);
         if(retVal!=NULL){
-            PyObject *retb = PyObject_CallMethod(six,"b","O",retVal);
-            Py_DECREF(retVal);
-            if(retb!=NULL){
-                ret = std::string(PyBytes_AsString(retb));
-                Py_DECREF(retb);
+            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();
         }
-- 
cgit v1.2.3


From 0d5947a0e8e7d6f86c7591a96d877dfe14b187e4 Mon Sep 17 00:00:00 2001
From: "Daniel M. Pelt" <D.M.Pelt@cwi.nl>
Date: Mon, 10 Aug 2015 17:08:34 +0200
Subject: Ensure we have acquired the GIL before calling Python plugin 'run'
 method

---
 src/PluginAlgorithm.cpp | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index 4066e30..e79c77b 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -112,12 +112,14 @@ bool CPluginAlgorithm::initialize(const Config& _cfg){
 
 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();
-        return;
+    }else{
+        Py_DECREF(retVal);
     }
-    Py_DECREF(retVal);
+    PyGILState_Release(state);
 }
 
 void fixLapackLoading(){
@@ -147,7 +149,10 @@ void fixLapackLoading(){
 }
 
 CPluginAlgorithmFactory::CPluginAlgorithmFactory(){
-    Py_Initialize();
+    if(!Py_IsInitialized()){
+        Py_Initialize();
+        PyEval_InitThreads();
+    }
 #ifndef _MSC_VER
     if(astra::running_in_matlab) fixLapackLoading();
 #endif
-- 
cgit v1.2.3


From 07c31b932078544205d61551edd4a66f69be30ae Mon Sep 17 00:00:00 2001
From: Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>
Date: Wed, 2 Dec 2015 11:25:59 +0100
Subject: Avoid unnecessary include in header

---
 src/PluginAlgorithm.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
index e79c77b..8f7dfc5 100644
--- a/src/PluginAlgorithm.cpp
+++ b/src/PluginAlgorithm.cpp
@@ -37,9 +37,13 @@ $Id$
 #include <fstream>
 #include <string>
 
+#include <Python.h>
+#include "bytesobject.h"
+
 namespace astra {
 
 
+
 void logPythonError(){
     if(PyErr_Occurred()){
         PyObject *ptype, *pvalue, *ptraceback;
@@ -394,4 +398,4 @@ PyObject* XMLNode2dict(XMLNode node){
 }
 
 }
-#endif
\ No newline at end of file
+#endif
-- 
cgit v1.2.3