#include #include "PythonInterpreter.h" #include #include #include #include #include using namespace boost::python; class PythonInterpreterImpl { public: PythonInterpreterImpl(); ~PythonInterpreterImpl(); public: object loadObjectInstance(CString fileSpec, CString className) const throw(InstanceException); private: CString pythonError() const; }; typedef SingletonHolder< PythonInterpreterImpl, CreateUsingNew > PythonInterpreter; PythonInterpreterImpl::PythonInterpreterImpl() { Py_Initialize(); std::cout << "Loaded Python Interpreter" << std::endl; } PythonInterpreterImpl::~PythonInterpreterImpl() { Py_Finalize(); std::cout << "Unloaded Python Interpreter" << std::endl; } std::string PythonInterpreterImpl::pythonError() const { PyObject* errType(NULL); PyObject* errValue(NULL); PyObject* errTraceback(NULL); PyErr_Fetch(&errType, &errValue, &errTraceback); if (NULL == errValue) { return "Unknown Python Error"; } handle<> errHandle(errValue); str errObj(errHandle); char *errMsg = extract< char* >(errObj); return errMsg; } object PythonInterpreterImpl::loadObjectInstance(CString fileSpec, CString className) const throw (InstanceException) { handle<> main_module(borrowed( PyImport_ImportModule(const_cast< char* >("__main__")) )); handle<> main_namespace(borrowed( PyModule_GetDict(main_module.get()) )); FILE *fp(fopen(fileSpec.ptr(), "r")); if(NULL == fp) { std::ostrstream msg; msg << "Could not open file \"" << fileSpec << "\", " << strerror(errno) << '\0'; throw InstanceException(msg); } PyObject* runFileResult = PyRun_File(fp, const_cast< char* >(fileSpec.ptr()), Py_file_input, main_namespace.get(), main_namespace.get()); fclose(fp); if(NULL == runFileResult) { std::ostrstream msg; msg << "Error loading \"" << fileSpec << "\": Python Err: " << pythonError() << '\0'; throw InstanceException(msg); } std::strstream funcName; funcName << className << "()" << '\0'; PyObject *instance = PyRun_String ( funcName.str(), Py_eval_input, main_namespace.get(), main_namespace.get()); if(NULL == instance) { std::ostrstream msg; msg << "Error instantiating " << funcName.str() << ": Python Err:" << pythonError() << '\0'; throw InstanceException(msg); } handle<> returnObj(instance); return object(returnObj); } // This class is exported to Python via the wrapper below: class SimpleObject { public: SimpleObject() { std::cout << "SimpleObject default constructor" << std::endl; } virtual ~SimpleObject() { std::cout << "SimpleObject destructor" << std::endl; } virtual CString override() throw (std::exception) = 0; }; class SimpleObject_callback : public SimpleObject { public: SimpleObject_callback(PyObject* self) : m_self(self) {} CString override() { char* str = call_method< char* >(m_self, "override"); return str; } CString SimpleObject_override() { return "You should override this yourself"; } private: PyObject* const m_self; }; struct cstring_to_str { static PyObject* convert(CString const& inputStr) { return PyString_FromString(inputStr.ptr()); } }; BOOST_PYTHON_MODULE(my_module) { class_< SimpleObject, SimpleObject_callback, boost::noncopyable >("SimpleObject") .def("override", &SimpleObject_callback::SimpleObject_override) to_python_converter(); } /* #Python file returned by the _testPythonFile() function: import my_module class DerivedObject(cdm_python.SimpleObject): def override(self): return "DerivedValue" */ void UnitTestLoadObjectFromFile() { object derivedObjectBase(PythonInterpreter::Instance().loadObjectInstance(_testPythonFile(), "DerivedObject")); SimpleObject* derivedObjectPtr = extract< SimpleObject* >(derivedObjectBase); CPPUNIT_ASSERT(NULL != derivedObjectPtr); CPPUNIT_ASSERT_EQUAL(CString("DerivedValue"), derivedObjectPtr->override()); }