separate pytwrpper from predictorWrappery
authorPeng Li <seudut@gmail.com>
Mon, 23 Jul 2018 11:37:19 +0000 (19:37 +0800)
committerPeng Li <seudut@gmail.com>
Mon, 23 Jul 2018 11:45:58 +0000 (19:45 +0800)
include/PredictorWrapper.h
include/PyWrapper.cpp [new file with mode: 0644]
include/PyWrapper.h [new file with mode: 0644]
include/SharedPtr.h
python/model.pkl [deleted file]
src/Engine.cpp
src/MultiTracker.cpp
src/PredictorWrapper.cpp
src/PyWrapper.cpp [new file with mode: 0644]
test/TestPredictor.cpp

index c41a8bc..18ea862 100644 (file)
@@ -14,18 +14,14 @@ namespace suanzi {
     class PredictorWrapper
     {
     public:
-        static PredictorWrapperPtr create(const std::string& python_dir, const std::string& model_dir); // model.pkl file
+        PredictorWrapper(const std::string& module="predictor", const std::string& pydir = "./python");
         ~PredictorWrapper(){}
         void dump();
         double predict(int index, const std::vector<double>& f);
+        bool load(const std::string& fname); // load pkl file
 
     private:
-        PredictorWrapper(const std::string& py_dir, const std::string& fname);
-        static PredictorWrapperWPtr instance;
-
-        PY_FUN dump_func;
-        PY_FUN predict_func;
-
+        boost::python::object m_module;
     };
 
 }
diff --git a/include/PyWrapper.cpp b/include/PyWrapper.cpp
new file mode 100644 (file)
index 0000000..6319940
--- /dev/null
@@ -0,0 +1,2 @@
+#include 
+
diff --git a/include/PyWrapper.h b/include/PyWrapper.h
new file mode 100644 (file)
index 0000000..24323cc
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _PY_WRAPPER_H_
+#define _PY_WRAPPER_H_
+
+#include <boost/python.hpp>
+#include "SharedPtr.h"
+#include <string>
+
+namespace suanzi {
+
+TK_DECLARE_PTR(PyWrapper);
+class PyWrapper 
+{
+public:
+    static PyWrapperPtr getInstance(const std::string& pydir); // get Python Interprete
+    virtual ~PyWrapper();
+    boost::python::object import(const std::string& module);
+    void exec(const std::string& cmd);
+    static std::string parse_python_exception();
+
+private:
+    PyWrapper(const std::string& python_dir);
+    boost::python::object main_namespace;
+    boost::python::object main_module;
+};
+
+}
+
+
+#endif // _PY_WRAPPER_H_
index 9b13584..8c2c303 100644 (file)
@@ -6,7 +6,7 @@
 #define  TK_DECLARE_PTR(className) \
     class className; \
     typedef std::shared_ptr<className> className##Ptr; \
-    typedef std::weak_ptr<className> className##WPtr;
+    typedef std::weak_ptr<className> className##WPtr
 #endif
 
 #endif /* _SHARED_PTR_H_ */
diff --git a/python/model.pkl b/python/model.pkl
deleted file mode 100644 (file)
index e26d88b..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-(lp1
-ccopy_reg
-_reconstructor
-p2
-(csklearn.linear_model.logistic
-LogisticRegression
-p3
-c__builtin__
-object
-p4
-NtRp5
-(dp6
-S'warm_start'
-p7
-I00
-sS'C'
-F1
-sS'n_jobs'
-p8
-I1
-sS'verbose'
-p9
-I0
-sS'fit_intercept'
-p10
-I01
-sS'solver'
-p11
-S'liblinear'
-p12
-sS'classes_'
-p13
-cnumpy.core.multiarray
-_reconstruct
-p14
-(cnumpy
-ndarray
-p15
-(I0
-tS'b'
-tRp16
-(I1
-(L2L
-tcnumpy
-dtype
-p17
-(S'i4'
-I0
-I1
-tRp18
-(I3
-S'<'
-NNNI-1
-I-1
-I0
-tbI00
-S'\x00\x00\x00\x00\x01\x00\x00\x00'
-tbsS'n_iter_'
-p19
-g14
-(g15
-(I0
-tS'b'
-tRp20
-(I1
-(L1L
-tg17
-(S'i4'
-I0
-I1
-tRp21
-(I3
-S'<'
-NNNI-1
-I-1
-I0
-tbI00
-S'\x0b\x00\x00\x00'
-tbsS'intercept_scaling'
-p22
-I1
-sS'penalty'
-p23
-S'l2'
-p24
-sS'multi_class'
-p25
-S'ovr'
-p26
-sS'random_state'
-p27
-NsS'_sklearn_version'
-p28
-S'0.19.0'
-p29
-sS'dual'
-p30
-I00
-sS'tol'
-p31
-F0.0001
-sS'coef_'
-p32
-g14
-(g15
-(I0
-tS'b'
-tRp33
-(I1
-(L1L
-L8L
-tg17
-(S'f8'
-I0
-I1
-tRp34
-(I3
-S'<'
-NNNI-1
-I-1
-I0
-tbI00
-S'\xe2\x06dQ\xb5\xd1\x11@\xb4\x06\x1c.{`\xfb?\xea}\x1c\xea \xb7\xbb?TQz6\x17\r\xdc\xbfc}J\xd5\xfb\x81\x0c@\x92\xe9\xf7\r/\xa3\xf4\xbf\xf5\xc9mcQ\xfe\x01\xc0:\xa9`\xd4\xd3\xfb\xf7\xbf'
-tbsS'intercept_'
-p35
-g14
-(g15
-(I0
-tS'b'
-tRp36
-(I1
-(L1L
-tg34
-I00
-S'\xee\xa1\x95\x9f\xd3\xeb}?'
-tbsS'max_iter'
-p37
-I100
-sS'class_weight'
-p38
-Nsbag2
-(g3
-g4
-NtRp39
-(dp40
-g7
-I00
-sS'C'
-F1
-sg8
-I1
-sg9
-I0
-sg10
-I01
-sg11
-g12
-sg13
-g14
-(g15
-(I0
-tS'b'
-tRp41
-(I1
-(L2L
-tg18
-I00
-S'\x00\x00\x00\x00\x01\x00\x00\x00'
-tbsg19
-g14
-(g15
-(I0
-tS'b'
-tRp42
-(I1
-(L1L
-tg21
-I00
-S'\x0c\x00\x00\x00'
-tbsg22
-I1
-sg23
-g24
-sg25
-g26
-sg27
-Nsg28
-g29
-sg30
-I00
-sg31
-F0.0001
-sg32
-g14
-(g15
-(I0
-tS'b'
-tRp43
-(I1
-(L1L
-L16L
-tg34
-I00
-S'4\xf7\\\xbf\xe6$\x0c@biKO\x01\x00\xf6?\xff\x82\x07*\xe9\xf7\xd2?\xb8\xe3\xd7|\x14O\xdf\xbfK<B\xd8\x97\x8b\x01@\xd0G8]\x0b\xb5\xef\xbf8\x1e\xd3\xafZ\xf5\x0b\xc0.\x8b\xd0\x9cm\xf2\xe7\xbf$\x89\xdfM-5\xfa?\x14`\x04C4\xc6\xe0?L\xc8I\xc1\xc5\xb1\xd5?\x96%\xb0\xca\xe6\xf3\xa9\xbf\xb7\x93B\x0eD\xe1\xf6?\xb2@k\xd5sK\xa6?r\x8bVe\xbb\xe1\xf7?\xcb\xaa\x86\n/\x9e\xda\xbf'
-tbsg35
-g14
-(g15
-(I0
-tS'b'
-tRp44
-(I1
-(L1L
-tg34
-I00
-S'\\\x8c\xb8\x7f`\xbe\xe1\xbf'
-tbsg37
-I100
-sg38
-Nsbag2
-(g3
-g4
-NtRp45
-(dp46
-g7
-I00
-sS'C'
-F1
-sg8
-I1
-sg9
-I0
-sg10
-I01
-sg11
-g12
-sg13
-g14
-(g15
-(I0
-tS'b'
-tRp47
-(I1
-(L2L
-tg18
-I00
-S'\x00\x00\x00\x00\x01\x00\x00\x00'
-tbsg19
-g14
-(g15
-(I0
-tS'b'
-tRp48
-(I1
-(L1L
-tg21
-I00
-S'\r\x00\x00\x00'
-tbsg22
-I1
-sg23
-g24
-sg25
-g26
-sg27
-Nsg28
-g29
-sg30
-I00
-sg31
-F0.0001
-sg32
-g14
-(g15
-(I0
-tS'b'
-tRp49
-(I1
-(L1L
-L24L
-tg34
-I00
-S'\xe2\xd9\xb1\xd9!\xc5\x08@\xb9\xbf\xc0T!\xde\xf5?\x0fvN\xa2%\xe2\xd1?\x80\xda\xe1n\xff\x8f\xe0\xbf\x8bu\xd5wq\xf4\xfe?o\x81k\x01\xff\x93\xec\xbf\xcdQ\xac\x13\x14\xc0\r\xc0\x84\xc2\x8f58\x98\xda\xbf\xab\x87.\xe6-G\xf0?\x90\xb6wI\x10\xb8\xe2?\x19v\xe3\x0e>S\xd5?\x10\x00\xaf\xd6!\xa7\x81?\xb7\xbe\xa9,\xb0k\xec?\xf7\x18\x82?\xf8\xa6\xc2\xbfU\xe8Ni\xf2\xa2\xfa?\xff\x84E\xf7!\x98\xdf\xbf\xbb\x91N=\x86\xfd\xf1?\xd7/\xef\xb4\xb3\xc2\xe0?\x0c\x96\x13\x04Al\xd4?\xa4\xd3a\x12\x1d\xce\xc1\xbf\xd2(9\xcd\x9dh\xef?H /\xedC\xcf\xda?J\n\xa1\x1fD\x98\xc1?m%\xc3&\xaa;\xdb?'
-tbsg35
-g14
-(g15
-(I0
-tS'b'
-tRp50
-(I1
-(L1L
-tg34
-I00
-S'\x80\x1d\xf1\xf3(\x89\xe3\xbf'
-tbsg37
-I100
-sg38
-Nsbag2
-(g3
-g4
-NtRp51
-(dp52
-g7
-I00
-sS'C'
-F1
-sg8
-I1
-sg9
-I0
-sg10
-I01
-sg11
-g12
-sg13
-g14
-(g15
-(I0
-tS'b'
-tRp53
-(I1
-(L2L
-tg18
-I00
-S'\x00\x00\x00\x00\x01\x00\x00\x00'
-tbsg19
-g14
-(g15
-(I0
-tS'b'
-tRp54
-(I1
-(L1L
-tg21
-I00
-S'\r\x00\x00\x00'
-tbsg22
-I1
-sg23
-g24
-sg25
-g26
-sg27
-Nsg28
-g29
-sg30
-I00
-sg31
-F0.0001
-sg32
-g14
-(g15
-(I0
-tS'b'
-tRp55
-(I1
-(L1L
-L32L
-tg34
-I00
-S'N+\xd0R\xed\x8f\x06@\xe0\x9f\xab\xc1\x16\x8f\xf4?\xbe+\xed&\xea\r\xd0?\xb6\xfc,\x074\x8b\xe2\xbf\x8f>f\x8e\xa3\x07\x01@\xe7lu\xbbn\x9b\xf1\xbf>[@s\xc7:\x0e\xc0\x86"\xb8\xaa,\xdb\x85?\xec\xddMJ)\x1a\xea?\xec*\xe1\xfc.\xc5\xd4?\t\xef,\xd8\xf41\xd4?J[\'\x8fP\x14\xab\xbf\x8fA\xea\xd8\xf0b\xe6?3\x8a|\t1\x1c\xc1\xbfn6\xdf\x96\xc6\xe2\xfa?&\x04\x82\x14\x1f5\xdb\xbf\xcc+\x18\xfa\x9f\x0b\xea?\xc6\x1c\xcf\xec\xcf\xa0\xd8?\n\xa5\xbe\xb2\xd7\x1c\xd4?\x82c M\x85\xf6\xbb\xbf\x1b\xb6\x17\x972"\xe1?U\x90/\x04\x8f\xdb\xd2?\x93\xceVv\xe2\x9f\x9c?$p\x16#o\x93\xd7?\x0e\x1a\xfe=\xe7\xc3\xea?h\xfa\xee\xd04y\xdf?\xf8\xad\xff\x86\xf0\xc4\xd1?\xa4N\xb3<87\xb4?\xb8\xc9\xce@\xdc(\xc4?HSA\x9b\xd1I\xcb?g\n\xd9tn\x10\xd0?t\x9db\x95u\xd0\xdc?'
-tbsg35
-g14
-(g15
-(I0
-tS'b'
-tRp56
-(I1
-(L1L
-tg34
-I00
-S'\xbc;\xceA\xf6\xc7\xe2\xbf'
-tbsg37
-I100
-sg38
-Nsbag2
-(g3
-g4
-NtRp57
-(dp58
-g7
-I00
-sS'C'
-F1
-sg8
-I1
-sg9
-I0
-sg10
-I01
-sg11
-g12
-sg13
-g14
-(g15
-(I0
-tS'b'
-tRp59
-(I1
-(L2L
-tg18
-I00
-S'\x00\x00\x00\x00\x01\x00\x00\x00'
-tbsg19
-g14
-(g15
-(I0
-tS'b'
-tRp60
-(I1
-(L1L
-tg21
-I00
-S'\x0e\x00\x00\x00'
-tbsg22
-I1
-sg23
-g24
-sg25
-g26
-sg27
-Nsg28
-g29
-sg30
-I00
-sg31
-F0.0001
-sg32
-g14
-(g15
-(I0
-tS'b'
-tRp61
-(I1
-(L1L
-L40L
-tg34
-I00
-S'\xd9\xfe\'\xeeW\xc4\x05@\x9f:b\xf1F\xa4\xf4?\xf28\xaf\xdc`\xd4\xc8?\xf5\xcb.\x85#\xa9\xe7\xbf6"e&G\xbb\x00@1\x833\xe4O\xa9\xf1\xbfEm\x1d\x8b\xb9\xdb\x0c\xc0\x83\xd6J\xe3Q|\xcd?\xa5\xd5?\x034"\xe5?\xd7d\x92\xaf\x8ev\xdc?\xe2U:|\xe0\xf9\xd1?\xcf>~0\xadm\xcb\xbf\x92D.n\xf6\'\xde?\x83\x90\x81\x07\xab\xa2\xd2\xbfn\x96L\x15W*\xfa?\xecC\xfaMtr\xdd\xbf4\r\xcew\x90\xad\xe7?\x10Wu\x18\x84"\xe2?\xe7m\xba\xb1pk\xd2?T\x84V\xe1V\x86\xbd\xbf\x82\x1b-\x0c\xb6H\xcf?\xe9F\x06{\x8dW\xc8?\xa5\xb5d\x0e\x1b\x11\xbe\xbf\x9f\xe4y4\xe5n\xd3?\xe0\xf8M\xb1\xff\xb5\xd9?)\xb1e\xc4\xb4\x02\xe0?\x04\xdb\x94\xe2\xfd\xa6\xd1?9\xa7\x04\x89\xff\x90\xbf?\xee\x8f\xab\x1d1\x1c\xc8\xbf&w\xf6X\xd0\x8f\xc1?\xf3\xdeI\xaa\xfc\x02\xb2?\xae\xbf\xa3Sj\xa0\xc1?\x83\xdb\xcf\rr\x0e\xec?\r\xe8\xb1k\xc9\x14\xe0?\x1b"j?o\xc8\xd2?\xdf9_W\xa7{\xcd?.\xbf&\xea\xa2\x1f\xda?\xbeno\xb3\xe8\xda\xb5?\x85&\xcbt\xd3r\xd0?\x04\xbb\xffur\xc1\xde?'
-tbsg35
-g14
-(g15
-(I0
-tS'b'
-tRp62
-(I1
-(L1L
-tg34
-I00
-S'\x90\xe2;h\x9e\xbf\xe2\xbf'
-tbsg37
-I100
-sg38
-Nsba.
\ No newline at end of file
index 1b7cca2..fbdf337 100644 (file)
@@ -29,7 +29,8 @@ EnginePtr Engine::create()
 
 Engine::Engine()
 {
-    detector = std::make_shared<Detector>();
+    //detector = std::make_shared<Detector>();
+    detector = DetectorPtr(new Detector());
 }
 
 Engine::~Engine()
index 138657e..bbfc6f3 100644 (file)
@@ -18,7 +18,8 @@ MultiTracker::MultiTracker(EngineWPtr e)
 : engine(e)
 {
     LOG_DEBUG(TAG, "init - loading model.pkl");
-    predictor = PredictorWrapper::create("./python", "./python/model.pkl");
+    predictor = PredictorWrapperPtr(new PredictorWrapper());
+    predictor->load("./resources/model.pkl");
     predictor->dump();
     this->descriptor = {Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9};
 }
index ebe7579..5559ddc 100644 (file)
@@ -3,6 +3,7 @@
 #include "Logger.h"
 #include <iostream>
 #include <thread>
+#include "PyWrapper.h"
 
 namespace py = boost::python;
 
@@ -10,12 +11,8 @@ using namespace std;
 using namespace suanzi;
 
 
-PredictorWrapperWPtr PredictorWrapper::instance;
-
 const static std::string TAG = "PredictorWrapper";
 
-static std::string parse_python_exception();
-
 template <class T>
 boost::python::list toPythonList(const std::vector<T>& v) {
     typename std::vector<T>::iterator iter;
@@ -26,114 +23,47 @@ boost::python::list toPythonList(const std::vector<T>& v) {
     return list;
 }
 
-PredictorWrapperPtr PredictorWrapper::create(const std::string& python_dir, const std::string& model_path)
-{
-    if (instance.lock()){
-        return PredictorWrapperPtr();
-    }
-    PredictorWrapperPtr ins (new PredictorWrapper(python_dir, model_path));
-    instance = ins;
-    return ins;
-}
+#define CALL_WITH_EXCEPTION(expr, ret_val)                      \
+    try{                                                        \
+        py::object py_ret = expr;                               \
+        ret_val = py::extract<decltype(ret_val)>(py_ret);       \
+    }catch(boost::python::error_already_set const &){           \
+        LOG_ERROR(TAG, PyWrapper::parse_python_exception());    \
+    }                                                           \
 
-void PredictorWrapper::dump()
+
+PredictorWrapper::PredictorWrapper(const string& module, const string& pydir)
 {
-    LOG_DEBUG(TAG, "dump");
-    std::string ss = "";
+    PyWrapperPtr interpreter = PyWrapper::getInstance(pydir);
     try{
-        py::object ret = this->dump_func();
-        ss = py::extract<std::string>(ret);
+        m_module = interpreter->import(module);
     } catch (boost::python::error_already_set const &){
-        std::string perror_str = parse_python_exception();
-        LOG_ERROR(TAG, "Error in Python: " + perror_str)
+        LOG_ERROR(TAG, PyWrapper::parse_python_exception());
     }
-    LOG_DEBUG(TAG, ss);
 }
 
-double PredictorWrapper::predict(int index, const std::vector<double>& ff)
+bool PredictorWrapper::load(const string& fname)
 {
-    LOG_DEBUG(TAG, "predict");
-    py::object ret;
-    try{
-        ret = this->predict_func(index, toPythonList(ff));
-    } catch (boost::python::error_already_set const &){
-        std::string perror_str = parse_python_exception();
-        LOG_ERROR(TAG, "Error in Python: " + perror_str)
-    }
-    double rr = py::extract<double>(ret);
-    LOG_DEBUG(TAG, "return: " + std::to_string(rr));
-    return rr; 
+    LOG_DEBUG(TAG, "load " + fname);
+    py::object func = m_module.attr("init");
+    string ret;
+    CALL_WITH_EXCEPTION(func(fname.c_str()), ret);
+    return true;
 }
 
-PredictorWrapper::PredictorWrapper(const std::string& py_dir, const std::string& model_path)
+void PredictorWrapper::dump()
 {
-    Py_Initialize();
-    try{
-        py::object main_module = py::import("__main__");
-        py::object main_namespace = main_module.attr("__dict__");
-        py::exec("import sys", main_namespace);
-        std::string cmd = "sys.path.insert(0, '" + py_dir + "')";
-        py::exec(cmd.c_str(), main_namespace);
-        py::exec("import signal", main_namespace);
-        py::exec("signal.signal(signal.SIGINT, signal.SIG_DFL)", main_namespace);
-        py::object predictor_mod = py::import("predictor");
-        py::object predictor_init = predictor_mod.attr("init");
-        dump_func = predictor_mod.attr("dump");
-        predict_func = predictor_mod.attr("predict");
-        predictor_init(model_path.c_str());
-    } catch (boost::python::error_already_set const &){
-        std::string perror_str = parse_python_exception();
-        LOG_ERROR(TAG, "Error in Python: " + perror_str)
-    }
+    LOG_DEBUG(TAG, "dump");
+    py::object func = m_module.attr("dump");
+    string ret = "";
+    CALL_WITH_EXCEPTION(func(), ret);
+    LOG_DEBUG(TAG, ret);
 }
 
-static std::string parse_python_exception(){  
-    PyObject *type_ptr = NULL, *value_ptr = NULL, *traceback_ptr = NULL;  
-    // Fetch the exception info from the Python C API  
-    PyErr_Fetch(&type_ptr, &value_ptr, &traceback_ptr);  
-  
-    // Fallback error  
-    std::string ret("Unfetchable Python error");  
-    // If the fetch got a type pointer, parse the type into the exception string  
-    if(type_ptr != NULL){  
-        py::handle<> h_type(type_ptr);  
-        py::str type_pstr(h_type);  
-        // Extract the string from the boost::python object  
-        py::extract<std::string> e_type_pstr(type_pstr);  
-        // If a valid string extraction is available, use it   
-        //  otherwise use fallback  
-        if(e_type_pstr.check())  
-            ret = e_type_pstr();  
-        else  
-            ret = "Unknown exception type";  
-    }  
-    // Do the same for the exception value (the stringification of the exception)  
-    if(value_ptr != NULL){  
-        py::handle<> h_val(value_ptr);  
-        py::str a(h_val);  
-        py::extract<std::string> returned(a);  
-        if(returned.check())  
-            ret +=  ": " + returned();  
-        else  
-            ret += std::string(": Unparseable Python error: ");  
-    }  
-    // Parse lines from the traceback using the Python traceback module  
-    if(traceback_ptr != NULL){  
-        py::handle<> h_tb(traceback_ptr);  
-        // Load the traceback module and the format_tb function  
-        py::object tb(py::import("traceback"));  
-        py::object fmt_tb(tb.attr("format_tb"));  
-        // Call format_tb to get a list of traceback strings  
-        py::object tb_list(fmt_tb(h_tb));  
-        // Join the traceback strings into a single string  
-        py::object tb_str(py::str("\n").join(tb_list));  
-        // Extract the string, check the extraction, and fallback in necessary  
-        py::extract<std::string> returned(tb_str);  
-        if(returned.check())  
-            ret += ": " + returned();  
-        else  
-            ret += std::string(": Unparseable Python traceback");  
-    }  
-    return ret;  
-}  
-
+double PredictorWrapper::predict(int index, const vector<double>& features)
+{
+    py::object func = m_module.attr("predict");
+    double rr = 0;
+    CALL_WITH_EXCEPTION(func(index, toPythonList(features)), rr);
+    return rr;
+}
diff --git a/src/PyWrapper.cpp b/src/PyWrapper.cpp
new file mode 100644 (file)
index 0000000..e19fe3d
--- /dev/null
@@ -0,0 +1,113 @@
+#include "PyWrapper.h"
+#include <string>
+#include <mutex>
+#include "Logger.h"
+
+namespace py = boost::python;
+using namespace std;
+using namespace suanzi;
+
+static const std::string TAG = "PyWrapper";
+
+PyWrapperPtr PyWrapper::getInstance(const string& pydir)
+{
+    LOG_DEBUG(TAG, "getInstance");
+    static PyWrapperPtr instance (new PyWrapper(pydir));
+    return instance;
+}
+
+PyWrapper::PyWrapper(const std::string& python_dir)
+{    
+    LOG_DEBUG(TAG, "Init Python interpreter");
+    Py_Initialize();
+    try{
+        main_module = py::import("__main__");
+        main_namespace = main_module.attr("__dict__");
+        py::exec("import sys", main_namespace);
+        std::string cmd = "sys.path.insert(0, '" + python_dir + "')";
+        py::exec(cmd.c_str(), main_namespace);
+        py::exec("import signal", main_namespace);
+        py::exec("signal.signal(signal.SIGINT, signal.SIG_DFL)", main_namespace);
+    } catch (boost::python::error_already_set const &){
+        LOG_ERROR(TAG, "Error in Python: " + parse_python_exception())
+    }
+}
+
+PyWrapper::~PyWrapper()
+{
+    Py_Finalize();
+    LOG_DEBUG(TAG, "DeInit Python interpreter");
+}
+
+py::object PyWrapper::import(const std::string& module)
+{
+    LOG_DEBUG(TAG, "import " + module);
+    py::object o;
+    try{
+        o = py::import(module.c_str());
+    } catch (boost::python::error_already_set const &){
+        LOG_ERROR(TAG, parse_python_exception());
+    }
+    return o;
+}
+
+void PyWrapper::exec(const std::string& cmd)
+{
+    try{
+        py::exec(cmd.c_str());
+    } catch(boost::python::error_already_set const &){
+        LOG_ERROR(TAG, parse_python_exception());
+    }
+}
+
+
+// refer to http://www.sigverse.org/wiki/en/index.php?Import%20and%20use%20of%20user%20defined%20python%20modules
+std::string PyWrapper::parse_python_exception(){  
+    PyObject *type_ptr = NULL, *value_ptr = NULL, *traceback_ptr = NULL;  
+    // Fetch the exception info from the Python C API  
+    PyErr_Fetch(&type_ptr, &value_ptr, &traceback_ptr);  
+  
+    // Fallback error  
+    std::string ret("Unfetchable Python error");  
+    // If the fetch got a type pointer, parse the type into the exception string  
+    if(type_ptr != NULL){  
+        py::handle<> h_type(type_ptr);  
+        py::str type_pstr(h_type);  
+        // Extract the string from the boost::python object  
+        py::extract<std::string> e_type_pstr(type_pstr);  
+        // If a valid string extraction is available, use it   
+        //  otherwise use fallback  
+        if(e_type_pstr.check())  
+            ret = e_type_pstr();  
+        else  
+            ret = "Unknown exception type";  
+    }  
+    // Do the same for the exception value (the stringification of the exception)  
+    if(value_ptr != NULL){  
+        py::handle<> h_val(value_ptr);  
+        py::str a(h_val);  
+        py::extract<std::string> returned(a);  
+        if(returned.check())  
+            ret +=  ": " + returned();  
+        else  
+            ret += std::string(": Unparseable Python error: ");  
+    }  
+    // Parse lines from the traceback using the Python traceback module  
+    if(traceback_ptr != NULL){  
+        py::handle<> h_tb(traceback_ptr);  
+        // Load the traceback module and the format_tb function  
+        py::object tb(py::import("traceback"));  
+        py::object fmt_tb(tb.attr("format_tb"));  
+        // Call format_tb to get a list of traceback strings  
+        py::object tb_list(fmt_tb(h_tb));  
+        // Join the traceback strings into a single string  
+        py::object tb_str(py::str("\n").join(tb_list));  
+        // Extract the string, check the extraction, and fallback in necessary  
+        py::extract<std::string> returned(tb_str);  
+        if(returned.check())  
+            ret += ": " + returned();  
+        else  
+            ret += std::string(": Unparseable Python traceback");  
+    }  
+    return ret;  
+}
index c6087f0..e3add17 100644 (file)
@@ -5,7 +5,8 @@ using namespace suanzi;
 
 TEST(Predictor, load)
 {
-    PredictorWrapperPtr predictor = PredictorWrapper::create("../python", "../python/model.pkl");
+    PredictorWrapperPtr predictor (new PredictorWrapper("predictor", "../python"));
+    predictor->load("../resources/model.pkl");
     predictor->dump();
     std::vector<double> ff (40, 1);
     double prob = predictor->predict(4, ff);