WhatsThis update
[mussa.git] / py / python.cpp
index fe2364eb529df5c44b24ae95bfd1381a841a5108..cc7dfdc52224e47a2b42da8cbb825d48d0065e06 100644 (file)
@@ -9,31 +9,60 @@ namespace py = boost::python;
 #include <boost/algorithm/string/classification.hpp>
 namespace alg = boost::algorithm;
 
+
 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()
 {
   try {
-    // add our mussa module to our environment
-    PyImport_AppendInittab("mussa", &initmussa);
+    // 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__"))))
     );
+    // setting the main_namespace must come before any calls to run or eval
     main_namespace = main_module.attr("__dict__");
-    // FIXME: this really should be a configuration file?
-    run("import __main__\n"
-        "import mussa\n"
-        "import webbrowser\n");
+    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();
   }
 }
 
+py::object MussaPython::get_namespace()
+{
+  if (main_namespace.ptr() == Py_None) {
+    init_interpreter();
+  }
+  return main_namespace;
+}
+
 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)
     )));
@@ -45,7 +74,7 @@ void MussaPython::run(std::string code)
 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)
     )));
@@ -58,7 +87,26 @@ py::object MussaPython::eval(std::string code)
 }
 
 
-void MussaPython::interpreter(FILE *fp)
+void MussaPython::interpreter() 
+{
+  try {
+    run("import sys\n"
+        "sys.argv = ['Mussa']\n"
+        "banner='Welcome to Mussa'\n"
+        "try:\n"
+        "  from IPython.Shell import IPShellEmbed\n"
+        "  ipshell = IPShellEmbed(banner=banner)\n"
+        "  ipshell()\n"
+        "except ImportError, e:\n"
+        "  import code\n"
+        "  code.interact(banner, local=globals())\n"
+        "print 'exiting interpreter'\n"
+    );
+  } catch (py::error_already_set e) {
+    PyErr_Print();
+  }
+}
+void MussaPython::simple_interpreter(FILE *fp)
 {
   try {
     PyRun_InteractiveLoop(fp, "mussa");
@@ -73,7 +121,7 @@ py::object MussaPython::operator[](std::string name)
   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();
@@ -85,8 +133,16 @@ py::object MussaPython::operator[](std::string name)
 }
 
 //! return a reference to a single mussa python interpreter
-MussaPython& get_py()
+MussaPython *get_py_ptr()
 {
-  static MussaPython py;
+  static MussaPython *py;
+  if (!py) {
+    py = new MussaPython;
+  }
   return py;
-}
\ No newline at end of file
+}
+
+MussaPython &get_py()
+{
+  return *get_py_ptr();
+}