Because of weird library ordering issues, my test case that tested
running python code was looking for compiled in python modules that
weren't available yet it wouldn't link properly.
I solved this by making it possible to provide a list of what
compiled-in python extensions should be initialized when you launch
the interpreter, so the mussagl program, which does have all the right
components linked in is what is specifying what modules should be
provided to the python interpreter.
Now I just need to fix the build system so you can compile mussa without
all this python crud if needed.
And maybe decide how to launch the gui from a stanard python interpreter.
optimized ${QT_QTCORE_LIBRARY}
debug ${QT_QTCORE_LIBRARY_DEBUG}
)
optimized ${QT_QTCORE_LIBRARY}
debug ${QT_QTCORE_LIBRARY_DEBUG}
)
- SET(STATIC_PYTHON_TARGETS "")
- SET(SHARED_PYTHON_TARGETS "")
-
+ GET_MUSSA_COMPILE_FLAGS(PY_CFLAGS)
+ GET_MUSSA_LINK_FLAGS(PY_LDFLAGS)
+
+ # configure static core python library
ADD_LIBRARY(mussa_py STATIC ${SOURCES})
ADD_LIBRARY(mussa_py STATIC ${SOURCES})
- SET(${STATIC_PYTHON_TARGETS} "${${STATIC_PYTHON_TARGETS}} mussa_py")
+ SET_TARGET_PROPERTIES(mussa_py PROPERTIES
+ COMPILE_FLAGS "${PY_CFLAGS}"
+ LINK_FLAGS "${PY_LDFLAGS}")
+
+ # configure core (shared) python module
ADD_LIBRARY(mussa MODULE ${SOURCES})
ADD_LIBRARY(mussa MODULE ${SOURCES})
- SET(${SHARED_PYTHON_TARGETS} "${${SHARED_PYTHON_TARGETS}} mussa")
+ SET_TARGET_PROPERTIES(mussa PROPERTIES
+ PREFIX ""
+ COMPILE_FLAGS "${PY_CFLAGS}"
+ LINK_FLAGS "${PY_LDFLAGS}")
TARGET_LINK_LIBRARIES(mussa
${MUSSA_LIBRARIES}
)
TARGET_LINK_LIBRARIES(mussa
${MUSSA_LIBRARIES}
)
+ # configure static gui python library
ADD_LIBRARY(mussaqui_py STATIC ${QUI_SOURCES})
ADD_LIBRARY(mussaqui_py STATIC ${QUI_SOURCES})
- SET(${STATIC_PYTHON_TARGETS} "${${STATIC_PYTHON_TARGETS}} mussaqui_py")
- # ADD_LIBRARY(mussaqui MODULE ${QUI_SOURCES})
- # SET(${SHARED_PYTHON_TARGETS} "${${SHARED_PYTHON_TARGETS}} mussaqui")
+ SET_TARGET_PROPERTIES(mussa_py PROPERTIES
+ COMPILE_FLAGS "${PY_CFLAGS}"
+ LINK_FLAGS "${PY_LDFLAGS}")
+
+ # configure gui (shared) python library
+ #ADD_LIBRARY(mussaqui MODULE ${QUI_SOURCES})
+ #SET_TARGET_PROPERTIES(mussaqui PROPERTIES
+ # PREFIX ""
+ # COMPILE_FLAGS "${PY_CFLAGS}"
+ # LINK_FLAGS "${PY_LDFLAGS}")
#TARGET_LINK_LIBRARIES(mussaqui
# mussa_qui
# ${MUSSA_LIBRARIES}
#TARGET_LINK_LIBRARIES(mussaqui
# mussa_qui
# ${MUSSA_LIBRARIES}
# debug ${QT_QTOPENGL_LIBRARY_DEBUG}
# )
# debug ${QT_QTOPENGL_LIBRARY_DEBUG}
# )
- # don't put the "lib" prefix infront of our shared modules
- SET_TARGET_PROPERTIES(${SHARED_PYTHON_TARGETS}
- PROPERTIES
- PREFIX ""
- )
- GET_MUSSA_COMPILE_FLAGS(PY_CFLAGS)
- GET_MUSSA_LINK_FLAGS(PY_LDFLAGS)
SET_SOURCE_FILES_PROPERTIES(
${SOURCES}
${QUI_SOURCES}
SET_SOURCE_FILES_PROPERTIES(
${SOURCES}
${QUI_SOURCES}
#include <boost/algorithm/string/classification.hpp>
namespace alg = boost::algorithm;
#include <boost/algorithm/string/classification.hpp>
namespace alg = boost::algorithm;
MussaPython::MussaPython()
MussaPython::MussaPython()
+{
+}
+
+void MussaPython::add_module(const std::string &name, python_module_init initfunc)
+{
+ python_modules.push_back( module_item(name, initfunc) );
+}
+
+void MussaPython::AppendInittab(const module_item &item)
+{
+ PyImport_AppendInittab(const_cast<char *>(item.first.c_str()), item.second);
+}
+
+void MussaPython::init_interpreter()
- // add our mussa module to our environment
- PyImport_AppendInittab("mussa", &initmussa);
- PyImport_AppendInittab("mussaqui", &initmussaqui);
+ // add any compiled in modules to our environment
+ for_each(python_modules.begin(), python_modules.end(), AppendInittab);
// go ahead and finish initalizing python
Py_Initialize();
// get reference to the global namespace
py::object main_module(
(py::handle<>(py::borrowed(PyImport_AddModule("__main__"))))
);
// go ahead and finish initalizing python
Py_Initialize();
// get reference to the global namespace
py::object main_module(
(py::handle<>(py::borrowed(PyImport_AddModule("__main__"))))
);
+ // setting the main_namespace must come before any calls to run or eval
main_namespace = main_module.attr("__dict__");
main_namespace = main_module.attr("__dict__");
- // FIXME: this really should be a configuration file?
- run("import __main__\n"
- "import mussa\n"
- "import mussaqui");
+ run("import __main__\n");
+ // import modules that were added to us into the interpreter
+ for(module_list::const_iterator item = python_modules.begin();
+ item != python_modules.end();
+ ++item)
+ {
+ std::string code("import " + item->first);
+ run(code);
+ }
} catch (py::error_already_set e) {
PyErr_Print();
}
}
} catch (py::error_already_set e) {
PyErr_Print();
}
}
+py::object MussaPython::get_namespace()
+{
+ if (main_namespace.ptr() == Py_None) {
+ init_interpreter();
+ }
+ return main_namespace;
+}
+
void MussaPython::run(std::string code)
{
try {
void MussaPython::run(std::string code)
{
try {
- PyObject *global_ptr = main_namespace.ptr();
+ PyObject *global_ptr = get_namespace().ptr();
py::object result( py::handle<>(
(PyRun_String(code.c_str(), Py_file_input, global_ptr, global_ptr)
)));
py::object result( py::handle<>(
(PyRun_String(code.c_str(), Py_file_input, global_ptr, global_ptr)
)));
py::object MussaPython::eval(std::string code)
{
try {
py::object MussaPython::eval(std::string code)
{
try {
- PyObject *global_ptr = main_namespace.ptr();
+ PyObject *global_ptr = get_namespace().ptr();
py::object result( py::handle<>(
(PyRun_String(code.c_str(), Py_eval_input, global_ptr, global_ptr)
)));
py::object result( py::handle<>(
(PyRun_String(code.c_str(), Py_eval_input, global_ptr, global_ptr)
)));
string_vector split_name;
alg::split(split_name, name, alg::is_any_of("."));
string_vector split_name;
alg::split(split_name, name, alg::is_any_of("."));
- py::object lookup = main_namespace["__main__"];
+ py::object lookup = get_namespace()["__main__"];
for (string_vector::const_iterator name_i = split_name.begin();
name_i != split_name.end();
for (string_vector::const_iterator name_i = split_name.begin();
name_i != split_name.end();
}
//! return a reference to a single mussa python interpreter
}
//! return a reference to a single mussa python interpreter
{
static MussaPython *py;
if (!py) {
py = new MussaPython;
}
{
static MussaPython *py;
if (!py) {
py = new MussaPython;
}
}
\ No newline at end of file
}
\ No newline at end of file
#define _MUSSA_PYTHON_HPP_
#include <boost/python.hpp>
#include <string>
#define _MUSSA_PYTHON_HPP_
#include <boost/python.hpp>
#include <string>
-
-extern "C" void initmussa();
-extern "C" void initmussaqui();
+#include <list>
+#include <utility>
//! Create a singleton class to manage our reference to the python interpreter
class MussaPython {
public:
//! Create a singleton class to manage our reference to the python interpreter
class MussaPython {
public:
+ typedef void (*python_module_init)(void);
+ //! initalize interpreter
+ void init_interpreter();
+ //! add a python module that was statically compiled into this executable
+ void add_module(const std::string& name, python_module_init);
+ //! return main python namespace(initializing the interpreter if needed)
+ boost::python::object get_namespace();
//! pass multi-statement code block to the python interpreter
void run(std::string);
//! pass single expression to the python interpreter and return the result
//! pass multi-statement code block to the python interpreter
void run(std::string);
//! pass single expression to the python interpreter and return the result
void simple_interpreter(FILE *fp=stdin);
//! return an object in the python namespace
boost::python::object operator[](std::string);
void simple_interpreter(FILE *fp=stdin);
//! return an object in the python namespace
boost::python::object operator[](std::string);
+ typedef std::pair<std::string, python_module_init> module_item;
+ typedef std::list<module_item> module_list;
+ module_list python_modules;
boost::python::object main_namespace;
boost::python::object main_namespace;
+
+ static void AppendInittab(const module_item &item);
};
//! return a reference to a single mussa python interpreter
};
//! return a reference to a single mussa python interpreter
#endif // _MUSSA_PYTHON_HPP_
#endif // _MUSSA_PYTHON_HPP_
BOOST_AUTO_TEST_CASE( execute_python )
{
BOOST_AUTO_TEST_CASE( execute_python )
{
- get_py().run("x = 3");
- int x = py::extract<int>(get_py().eval("x"));
+ get_py()->run("x = 3");
+ int x = py::extract<int>(get_py()->eval("x"));
BOOST_CHECK_EQUAL(x, 3);
}
BOOST_AUTO_TEST_CASE( lookup_python )
{
BOOST_CHECK_EQUAL(x, 3);
}
BOOST_AUTO_TEST_CASE( lookup_python )
{
- get_py().run("import os");
- py::object splitext = get_py()["os.path.splitext"];
+ get_py()->run("import os");
+ py::object splitext = (*get_py())["os.path.splitext"];
py::object result = splitext("/home/diane/foo.txt");
std::string ext = py::extract<std::string>(result[1]);
BOOST_CHECK_EQUAL(ext, ".txt");
py::object result = splitext("/home/diane/foo.txt");
std::string ext = py::extract<std::string>(result[1]);
BOOST_CHECK_EQUAL(ext, ".txt");
- get_py().run("from os.path import splitext");
- py::object splitext2 = get_py()["splitext"];
+ get_py()->run("from os.path import splitext");
+ py::object splitext2 = (*get_py())["splitext"];
py::object result2 = splitext("/home/diane/bar.txt");
std::string ext2 = py::extract<std::string>(result2[1]);
BOOST_CHECK_EQUAL(ext, ext2);
py::object result2 = splitext("/home/diane/bar.txt");
std::string ext2 = py::extract<std::string>(result2[1]);
BOOST_CHECK_EQUAL(ext, ext2);
#ifdef USE_PYTHON
#include "py/python.hpp"
#ifdef USE_PYTHON
#include "py/python.hpp"
+extern "C" void initmussa();
+extern "C" void initmussaqui();
#endif
#include "qui/MussaWindow.hpp"
#endif
#include "qui/MussaWindow.hpp"
// allow the user to keep the interpreter open even after
// closing all the windows
app.setQuitOnLastWindowClosed(false);
// allow the user to keep the interpreter open even after
// closing all the windows
app.setQuitOnLastWindowClosed(false);
- const InterpreterThread *interp = thread.create_interpreter();
+ InterpreterThread *interp = thread.create_interpreter();
+ if (!interp) {
+ std::cerr << "Unable to initialize interpeter thread" << std::endl;
+ return 1;
+ }
+ MussaPython *py = interp->get_py();
+ if (!py) {
+ std::cerr << "Unable to initialize python interpreter" << std::endl;
+ return 1;
+ }
+ py->add_module("mussa", &initmussa);
+ py->add_module("mussaqui", &initmussaqui);
// quit when the interpreter exits
QObject::connect(interp, SIGNAL(finished()),
&app, SLOT(quit()));
// quit when the interpreter exits
QObject::connect(interp, SIGNAL(finished()),
&app, SLOT(quit()));
app.exec();
} else
#endif /* USE_PYTHON */
app.exec();
} else
#endif /* USE_PYTHON */
void InterpreterThread::run()
{
void InterpreterThread::run()
{
- get_py().interpreter();
+ ::get_py()->interpreter();
+}
+
+MussaPython *InterpreterThread::get_py()
+{
+ return ::get_py();
}
InterpreterThread::InterpreterThread()
}
InterpreterThread::InterpreterThread()
class InterpreterThread : public QThread {
Q_OBJECT
public:
void run();
class InterpreterThread : public QThread {
Q_OBJECT
public:
void run();
private:
//! only let ThreadManager create this object.
InterpreterThread();
private:
//! only let ThreadManager create this object.
InterpreterThread();
-const InterpreterThread *ThreadManager::create_interpreter() {
-
+InterpreterThread *ThreadManager::create_interpreter()
+{
static QMutex interpreter_lock;
static InterpreterThread *interpreter_thread;
if (interpreter_lock.tryLock()) {
// we're the first thread
interpreter_thread = new InterpreterThread();
static QMutex interpreter_lock;
static InterpreterThread *interpreter_thread;
if (interpreter_lock.tryLock()) {
// we're the first thread
interpreter_thread = new InterpreterThread();
- interpreter_thread->start();
- return interpreter_thread;
// someone already started a copy of the interpreter
// someone already started a copy of the interpreter
+ return interpreter_thread;
}
GuiProxy *ThreadManager::get_gui_proxy()
}
GuiProxy *ThreadManager::get_gui_proxy()
{
public:
//! make a python interpreter
{
public:
//! make a python interpreter
- const InterpreterThread *create_interpreter();
+ InterpreterThread *create_interpreter();
static GuiProxy *get_gui_proxy();
private:
ThreadManager();
static GuiProxy *get_gui_proxy();
private:
ThreadManager();