diff options
author | John Wiegley <johnw@newartisans.com> | 2009-02-24 19:48:14 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-02-24 19:48:14 -0400 |
commit | 0814c5a23f44120088b6139bb7bf1f934f1d1057 (patch) | |
tree | 1c2132245b93881b42b99aa0dd5b7c5d00aff2e0 /src | |
parent | 3598abf9d235c24618856d4e0d5092e818e6332e (diff) | |
download | fork-ledger-0814c5a23f44120088b6139bb7bf1f934f1d1057.tar.gz fork-ledger-0814c5a23f44120088b6139bb7bf1f934f1d1057.tar.bz2 fork-ledger-0814c5a23f44120088b6139bb7bf1f934f1d1057.zip |
Added a new level of Python integration
Diffstat (limited to 'src')
-rw-r--r-- | src/py_scope.cc | 21 | ||||
-rw-r--r-- | src/py_session.cc | 11 | ||||
-rw-r--r-- | src/pyinterp.cc | 98 | ||||
-rw-r--r-- | src/pyinterp.h | 33 | ||||
-rw-r--r-- | src/report.cc | 17 | ||||
-rw-r--r-- | src/report.h | 2 |
6 files changed, 141 insertions, 41 deletions
diff --git a/src/py_scope.cc b/src/py_scope.cc index 55f779d2..897e2a84 100644 --- a/src/py_scope.cc +++ b/src/py_scope.cc @@ -70,9 +70,28 @@ void export_scope() class_< scope_t, scope_wrapper, boost::noncopyable > ("Scope", no_init) .def("define", py_scope_define) .def("lookup", py_scope_lookup) - .def("resolve", &scope_t::resolve) .def("__getattr__", py_scope_getattr) ; + + class_< child_scope_t, bases<scope_t>, + boost::noncopyable > ("ChildScope") + .def(init<>()) + .def(init<scope_t&>()) + ; + + class_< symbol_scope_t, bases<child_scope_t>, + boost::noncopyable > ("SymbolScope") + .def(init<>()) + .def(init<scope_t&>()) + ; + + class_< call_scope_t, bases<child_scope_t>, + boost::noncopyable > ("CallScope", init<scope_t&>()) + ; + + class_< bind_scope_t, bases<child_scope_t>, + boost::noncopyable > ("BindScope", init<scope_t&, scope_t&>()) + ; } } // namespace ledger diff --git a/src/py_session.cc b/src/py_session.cc index 108dcc3c..df0c6dd8 100644 --- a/src/py_session.cc +++ b/src/py_session.cc @@ -46,14 +46,13 @@ using namespace boost::python; void export_session() { -#if 0 - class_< session_t > ("Session") + class_< session_t, bases<symbol_scope_t>, + shared_ptr<session_t>, boost::noncopyable > ("SessionBase") ; -#endif - //register_optional_to_python<amount_t>(); - - //implicitly_convertible<string, amount_t>(); + class_< python_interpreter_t, bases<session_t>, + shared_ptr<python_interpreter_t>, boost::noncopyable > ("Session") + ; #define EXC_TRANSLATE(type) \ register_exception_translator<type>(&exc_translate_ ## type); diff --git a/src/pyinterp.cc b/src/pyinterp.cc index 9782f3a0..33b3ca9b 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -41,13 +41,13 @@ void export_amount(); void export_balance(); void export_chain(); void export_commodity(); -void export_xact(); void export_expr(); void export_flags(); void export_format(); void export_global(); void export_item(); void export_journal(); +void export_post(); void export_report(); void export_scope(); void export_session(); @@ -55,7 +55,7 @@ void export_timelog(); void export_times(); void export_utils(); void export_value(); -void export_post(); +void export_xact(); void initialize_for_python() { @@ -63,13 +63,13 @@ void initialize_for_python() export_balance(); export_chain(); export_commodity(); - export_xact(); export_expr(); export_flags(); export_format(); export_global(); export_item(); export_journal(); + export_post(); export_report(); export_scope(); export_session(); @@ -77,7 +77,9 @@ void initialize_for_python() export_times(); export_utils(); export_value(); - export_post(); + export_xact(); + + scope().attr("session") = python_session; } struct python_run @@ -106,15 +108,53 @@ void python_interpreter_t::initialize() object main_module = python::import("__main__"); if (! main_module) - throw_(std::logic_error, "Python failed to initialize"); + throw_(std::logic_error, + "Python failed to initialize (couldn't find __main__)"); main_nspace = extract<dict>(main_module.attr("__dict__")); if (! main_nspace) - throw_(std::logic_error, "Python failed to initialize"); + throw_(std::logic_error, + "Python failed to initialize (couldn't find __dict__)"); python::detail::init_module("ledger", &initialize_for_python); is_initialized = true; + + // Hack ledger.__path__ so it points to a real location + python::object module_sys = import("sys"); + python::object sys_dict = module_sys.attr("__dict__"); + + python::list paths(sys_dict["path"]); + + bool path_initialized = false; + int n = python::extract<int>(paths.attr("__len__")()); + for (int i = 0; i < n; i++) { + python::extract<std::string> str(paths[i]); + path pathname(str); + DEBUG("python.interp", "sys.path = " << pathname); + + if (exists(pathname / "ledger" / "__init__.py")) { + if (python::object module_ledger = import("ledger")) { + DEBUG("python.interp", + "Setting ledger.__path__ = " << (pathname / "ledger")); + + python::object ledger_dict = module_ledger.attr("__dict__"); + python::list temp_list; + temp_list.append((pathname / "ledger").string()); + + ledger_dict["__path__"] = temp_list; + } else { + throw_(std::logic_error, + "Python failed to initialize (couldn't find ledger)"); + } + path_initialized = true; + break; + } + } + if (! path_initialized) + std::cerr + << "Warning: Ledger failed to find 'ledger/__init__.py' on the PYTHONPATH" + << std::endl; } catch (const error_already_set&) { PyErr_Print(); @@ -130,17 +170,13 @@ object python_interpreter_t::import(const string& str) initialize(); try { - TRACE_START(python_import, 1, "Imported Python module: " << str); - object mod = python::import(str.c_str()); if (! mod) throw_(std::logic_error, "Failed to import Python module " << str); - // Import all top-level xacts directly into the main namespace + // Import all top-level entries directly into the main namespace main_nspace.update(mod.attr("__dict__")); - TRACE_FINISH(python_import, 1); - return mod; } catch (const error_already_set&) { @@ -209,6 +245,17 @@ object python_interpreter_t::eval(const string& str, py_eval_mode_t mode) return object(); } +option_t<python_interpreter_t> * +python_interpreter_t::lookup_option(const char * p) +{ + switch (*p) { + case 'i': + OPT(import_); + break; + } + return NULL; +} + expr_t::ptr_op_t python_interpreter_t::lookup(const string& name) { // Give our superclass first dibs on symbol definitions @@ -218,16 +265,9 @@ expr_t::ptr_op_t python_interpreter_t::lookup(const string& name) const char * p = name.c_str(); switch (*p) { case 'o': - if (std::strncmp(p, "opt_", 4) == 0) { - p = p + 4; - switch (*p) { - case 'i': - if (std::strcmp(p, "import_") == 0) - return MAKE_FUNCTOR(python_interpreter_t::option_import_); - else if (std::strcmp(p, "import") == 0) - return expr_t::ptr_op_t(); - break; - } + if (WANT_OPT()) { const char * q = p + OPT_PREFIX_LEN; + if (option_t<python_interpreter_t> * handler = lookup_option(q)) + return MAKE_OPT_HANDLER(python_interpreter_t, handler); } break; } @@ -245,12 +285,20 @@ expr_t::ptr_op_t python_interpreter_t::lookup(const string& name) value_t python_interpreter_t::functor_t::operator()(call_scope_t& args) { try { + std::signal(SIGINT, SIG_DFL); if (! PyCallable_Check(func.ptr())) { extract<value_t> val(func); + std::signal(SIGINT, sigint_handler); if (val.check()) return val(); +#if 1 + // jww (2009-02-24): Distinguish between "no return" and a value with an + // unconvertable type + return NULL_VALUE; +#else throw_(calc_error, "Could not evaluate Python variable '" << name << "'"); +#endif } else { if (args.size() > 0) { list arglist; @@ -272,6 +320,7 @@ value_t python_interpreter_t::functor_t::operator()(call_scope_t& args) throw_(calc_error, "Could not evaluate Python variable '" << name << "'"); } + std::signal(SIGINT, sigint_handler); return result; } else if (PyErr_Occurred()) { @@ -281,15 +330,22 @@ value_t python_interpreter_t::functor_t::operator()(call_scope_t& args) assert(false); } } else { + std::signal(SIGINT, sigint_handler); return call<value_t>(func.ptr()); } } } catch (const error_already_set&) { + std::signal(SIGINT, sigint_handler); PyErr_Print(); throw_(calc_error, "Failed call to Python function '" << name << "'"); } + catch (...) { + std::signal(SIGINT, sigint_handler); + } + std::signal(SIGINT, sigint_handler); + return NULL_VALUE; } diff --git a/src/pyinterp.h b/src/pyinterp.h index 4863cbb9..1b0f4059 100644 --- a/src/pyinterp.h +++ b/src/pyinterp.h @@ -32,7 +32,7 @@ #ifndef _PYINTERP_H #define _PYINTERP_H -#include "scope.h" +#include "interactive.h" #include "session.h" #if defined(HAVE_BOOST_PYTHON) @@ -100,29 +100,36 @@ public: virtual value_t operator()(call_scope_t& args); }; + option_t<python_interpreter_t> * lookup_option(const char * p); + virtual expr_t::ptr_op_t lookup(const string& name); - value_t option_import_(call_scope_t& args) { - path file(args[0].to_string()); + OPTION_(python_interpreter_t, import_, DO_(scope) { + interactive_t args(scope, "s"); + + path file(args.get<string>(0)); - python::object module_sys = import("sys"); - python::object sys_dict = module_sys.attr("__dict__"); + python::object module_sys = parent->import("sys"); + python::object sys_dict = module_sys.attr("__dict__"); - python::list paths(sys_dict["path"]); + python::list paths(sys_dict["path"]); #if BOOST_VERSION >= 103700 - paths.insert(0, file.parent_path().string()); + paths.insert(0, file.parent_path().string()); #else - paths.insert(0, file.branch_path().string()); + paths.insert(0, file.branch_path().string()); #endif - sys_dict["path"] = paths; + sys_dict["path"] = paths; #if BOOST_VERSION >= 103700 - import(file.stem()); + string name = file.filename(); + if (contains(name, ".py")) + parent->import(file.stem()); + else + parent->import(name); #else - import(file.string()); + parent->import(file.leaf()); #endif - return true; - } + }); }; extern shared_ptr<python_interpreter_t> python_session; diff --git a/src/report.cc b/src/report.cc index dfbbf65b..90a8399d 100644 --- a/src/report.cc +++ b/src/report.cc @@ -317,6 +317,15 @@ namespace { }; } +bool report_t::maybe_import(const string& module) +{ + if (lookup(string(OPT_PREFIX) + "import_")) { + expr_t(string(OPT_PREFIX) + "import_(\"" + module + "\")").calc(*this); + return true; + } + return false; +} + option_t<report_t> * report_t::lookup_option(const char * p) { switch (*p) { @@ -607,6 +616,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name) (reporter<post_t, post_handler_ptr, &report_t::commodities_report> (new format_posts(*this, report_format(HANDLER(pricesdb_format_))), *this)); + else if (is_eq(q, "python") && maybe_import("ledger.interp")) + return session.lookup(string(CMD_PREFIX) + "python"); break; case 'r': @@ -622,6 +633,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name) case 's': if (is_eq(q, "stats") || is_eq(q, "stat")) return WRAP_FUNCTOR(reporter<>(new gather_statistics(*this), *this)); + else if (is_eq(q, "server") && maybe_import("ledger.server")) + return session.lookup(string(CMD_PREFIX) + "server"); break; } } @@ -686,6 +699,10 @@ expr_t::ptr_op_t report_t::lookup(const string& name) if (is_eq(q, "format")) return WRAP_FUNCTOR(format_command); break; + case 'h': + if (is_eq(q, "hello") && maybe_import("ledger.hello")) + return session.lookup(string(PRECMD_PREFIX) + "hello"); + break; case 'p': if (is_eq(q, "parse")) return WRAP_FUNCTOR(parse_command); diff --git a/src/report.h b/src/report.h index 7585493f..a98286a9 100644 --- a/src/report.h +++ b/src/report.h @@ -171,6 +171,8 @@ public: HANDLED(lots) || HANDLED(lot_tags)); } + bool maybe_import(const string& module); + option_t<report_t> * lookup_option(const char * p); virtual void define(const string& name, expr_t::ptr_op_t def) { |