diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/pyinterp.cc | 143 | ||||
-rw-r--r-- | src/pyinterp.h | 58 | ||||
-rw-r--r-- | src/textual.cc | 4 |
3 files changed, 130 insertions, 75 deletions
diff --git a/src/pyinterp.cc b/src/pyinterp.cc index 3157079a..d733c40d 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -84,16 +84,56 @@ struct python_run python_run(python_interpreter_t * intepreter, const string& str, int input_mode) - : result(handle<>(borrowed(PyRun_String(str.c_str(), input_mode, - intepreter->main_nspace.ptr(), - intepreter->main_nspace.ptr())))) {} + : result + (handle<> + (borrowed + (PyRun_String(str.c_str(), input_mode, + intepreter->main_module->module_globals.ptr(), + intepreter->main_module->module_globals.ptr())))) {} operator object() { return result; } }; +python_module_t::python_module_t(const string& name) + : scope_t(), module_name(name), module_globals() +{ + import_module(name); +} + +python_module_t::python_module_t(const string& name, python::object obj) + : scope_t(), module_name(name), module_globals() +{ + module_object = obj; + module_globals = extract<dict>(module_object.attr("__dict__")); +} + +void python_module_t::import_module(const string& name, bool import_direct) +{ + object mod = python::import(name.c_str()); + if (! mod) + throw_(std::runtime_error, + _("Module import failed (couldn't find %1)") << name); + + dict globals = extract<dict>(mod.attr("__dict__")); + if (! globals) + throw_(std::runtime_error, + _("Module import failed (couldn't find %1)") << name); + + if (! import_direct) { + module_object = mod; + module_globals = globals; + } else { + // Import all top-level entries directly into the namespace + module_globals.update(mod.attr("__dict__")); + } +} + void python_interpreter_t::initialize() { + if (is_initialized) + return; + TRACE_START(python_init, 1, "Initialized Python"); try { @@ -104,15 +144,7 @@ void python_interpreter_t::initialize() hack_system_paths(); - main_module = python::import("__main__"); - if (! main_module) - throw_(std::runtime_error, - _("Python failed to initialize (couldn't find __main__)")); - - main_nspace = extract<dict>(main_module.attr("__dict__")); - if (! main_nspace) - throw_(std::runtime_error, - _("Python failed to initialize (couldn't find __dict__)")); + main_module = import_module("__main__"); python::detail::init_module("ledger", &initialize_for_python); @@ -170,28 +202,6 @@ void python_interpreter_t::hack_system_paths() #endif } -object python_interpreter_t::import_into_main(const string& str) -{ - if (! is_initialized) - initialize(); - - try { - object mod = python::import(str.c_str()); - if (! mod) - throw_(std::runtime_error, - _("Failed to import Python module %1") << str); - - // Import all top-level entries directly into the main namespace - main_nspace.update(mod.attr("__dict__")); - - return mod; - } - catch (const error_already_set&) { - PyErr_Print(); - } - return object(); -} - object python_interpreter_t::import_option(const string& str) { if (! is_initialized) @@ -229,13 +239,10 @@ object python_interpreter_t::import_option(const string& str) } try { - if (contains(str, ".py")) { - import_into_main(name); - } else { - object obj = python::import(python::str(name.c_str())); - main_nspace[name.c_str()] = obj; - return obj; - } + if (contains(str, ".py")) + main_module->import_module(name, true); + else + import_module(str); } catch (const error_already_set&) { PyErr_Print(); @@ -399,6 +406,40 @@ python_interpreter_t::lookup_option(const char * p) return NULL; } +expr_t::ptr_op_t python_module_t::lookup(const symbol_t::kind_t kind, + const string& name) +{ + switch (kind) { + case symbol_t::FUNCTION: + DEBUG("python.interp", "Python lookup: " << name); + if (module_globals.has_key(name.c_str())) { + if (python::object obj = module_globals.get(name.c_str())) { + if (PyModule_Check(obj.ptr())) { + shared_ptr<python_module_t> mod; + python_module_map_t::iterator i = + python_session->modules_map.find(obj.ptr()); + if (i == python_session->modules_map.end()) { + mod.reset(new python_module_t(name, obj)); + python_session->modules_map.insert + (python_module_map_t::value_type(obj.ptr(), mod)); + } else { + mod = (*i).second; + } + return expr_t::op_t::wrap_value(scope_value(mod.get())); + } else { + return WRAP_FUNCTOR(python_interpreter_t::functor_t(obj, name)); + } + } + } + break; + + default: + break; + } + + return NULL; +} + expr_t::ptr_op_t python_interpreter_t::lookup(const symbol_t::kind_t kind, const string& name) { @@ -408,28 +449,16 @@ expr_t::ptr_op_t python_interpreter_t::lookup(const symbol_t::kind_t kind, switch (kind) { case symbol_t::FUNCTION: - if (option_t<python_interpreter_t> * handler = lookup_option(name.c_str())) - return MAKE_OPT_FUNCTOR(python_interpreter_t, handler); - - if (is_initialized && main_nspace.has_key(name.c_str())) { - DEBUG("python.interp", "Python lookup: " << name); - - if (python::object obj = main_nspace.get(name.c_str())) - return WRAP_FUNCTOR(functor_t(obj, name)); - } + if (is_initialized) + return main_module->lookup(kind, name); break; case symbol_t::OPTION: { if (option_t<python_interpreter_t> * handler = lookup_option(name.c_str())) return MAKE_OPT_HANDLER(python_interpreter_t, handler); - string option_name(string("option_") + name); - if (is_initialized && main_nspace.has_key(option_name.c_str())) { - DEBUG("python.interp", "Python lookup option: " << option_name); - - if (python::object obj = main_nspace.get(option_name.c_str())) - return WRAP_FUNCTOR(functor_t(obj, option_name)); - } + if (is_initialized) + return main_module->lookup(symbol_t::FUNCTION, string("option_") + name); break; } diff --git a/src/pyinterp.h b/src/pyinterp.h index c3397840..8699f69d 100644 --- a/src/pyinterp.h +++ b/src/pyinterp.h @@ -38,21 +38,52 @@ namespace ledger { +class python_module_t : public scope_t, public noncopyable +{ +public: + string module_name; + python::object module_object; + python::dict module_globals; + + explicit python_module_t(const string& name); + explicit python_module_t(const string& name, python::object obj); + + void import_module(const string& name, bool import_direct = false); + + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); + + void define_global(const string& name, python::object obj) { + module_globals[name] = obj; + } + + virtual string description() { + return module_name; + } +}; + +typedef std::map<PyObject *, shared_ptr<python_module_t> > python_module_map_t; + class python_interpreter_t : public session_t { public: - python::object main_module; - python::dict main_nspace; - bool is_initialized; + bool is_initialized; - python_interpreter_t() - : session_t(), main_nspace(), is_initialized(false) { + shared_ptr<python_module_t> main_module; + python_module_map_t modules_map; + + shared_ptr<python_module_t> import_module(const string& name) { + shared_ptr<python_module_t> mod(new python_module_t(name)); + if (name != "__main__") + main_module->define_global(name, mod->module_object); + return mod; + } + + python_interpreter_t() : session_t(), is_initialized(false) { TRACE_CTOR(python_interpreter_t, ""); } - virtual ~python_interpreter_t() { TRACE_DTOR(python_interpreter_t); - if (is_initialized) Py_Finalize(); } @@ -60,7 +91,6 @@ public: void initialize(); void hack_system_paths(); - python::object import_into_main(const string& name); python::object import_option(const string& name); enum py_eval_mode_t { @@ -69,14 +99,10 @@ public: PY_EVAL_MULTI }; - python::object eval(std::istream& in, - py_eval_mode_t mode = PY_EVAL_EXPR); - python::object eval(const string& str, - py_eval_mode_t mode = PY_EVAL_EXPR); - python::object eval(const char * c_str, - py_eval_mode_t mode = PY_EVAL_EXPR) { - string str(c_str); - return eval(str, mode); + python::object eval(std::istream& in, py_eval_mode_t mode = PY_EVAL_EXPR); + python::object eval(const string& str, py_eval_mode_t mode = PY_EVAL_EXPR); + python::object eval(const char * c_str, py_eval_mode_t mode = PY_EVAL_EXPR) { + return eval(string(c_str), mode); } value_t python_command(call_scope_t& scope); diff --git a/src/textual.cc b/src/textual.cc index a4e03435..95635184 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -1156,8 +1156,8 @@ void instance_t::python_directive(char * line) if (! python_session->is_initialized) python_session->initialize(); - python_session->main_nspace["journal"] = - python::object(python::ptr(context.journal)); + python_session->main_module->define_global + ("journal", python::object(python::ptr(context.journal))); python_session->eval(script.str(), python_interpreter_t::PY_EVAL_MULTI); } #endif // HAVE_BOOST_PYTHON |