diff options
-rw-r--r-- | src/amount.cc | 4 | ||||
-rw-r--r-- | src/annotate.cc | 6 | ||||
-rw-r--r-- | src/commodity.cc | 12 | ||||
-rw-r--r-- | src/commodity.h | 16 | ||||
-rw-r--r-- | src/pool.cc | 2 | ||||
-rw-r--r-- | src/py_account.cc | 222 | ||||
-rw-r--r-- | src/py_amount.cc | 3 | ||||
-rw-r--r-- | src/py_balance.cc | 3 | ||||
-rw-r--r-- | src/py_commodity.cc | 272 | ||||
-rw-r--r-- | src/py_item.cc | 113 | ||||
-rw-r--r-- | src/py_journal.cc | 456 | ||||
-rw-r--r-- | src/py_post.cc | 141 | ||||
-rw-r--r-- | src/py_utils.cc | 44 | ||||
-rw-r--r-- | src/py_value.cc | 172 | ||||
-rw-r--r-- | src/py_xact.cc | 138 | ||||
-rw-r--r-- | src/pyinterp.cc | 2 | ||||
-rw-r--r-- | src/value.h | 3 | ||||
-rw-r--r-- | tools/Makefile.am | 1 |
18 files changed, 1122 insertions, 488 deletions
diff --git a/src/amount.cc b/src/amount.cc index 435cdea4..e9b971f8 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -770,7 +770,7 @@ commodity_t& amount_t::commodity() const bool amount_t::has_commodity() const { - return commodity_ && commodity_ != commodity_->parent().null_commodity; + return commodity_ && commodity_ != commodity_->pool().null_commodity; } void amount_t::annotate(const annotation_t& details) @@ -795,7 +795,7 @@ void amount_t::annotate(const annotation_t& details) << *this << std::endl << details); if (commodity_t * ann_comm = - this_base->parent().find_or_create(*this_base, details)) + this_base->pool().find_or_create(*this_base, details)) set_commodity(*ann_comm); #ifdef ASSERTS_ON else diff --git a/src/annotate.cc b/src/annotate.cc index 9c676086..45a4e7c8 100644 --- a/src/annotate.cc +++ b/src/annotate.cc @@ -185,12 +185,12 @@ annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep) (keep_date && details.date) || (keep_tag && details.tag)) { - new_comm = parent().find_or_create + new_comm = pool().find_or_create (referent(), annotation_t(keep_price ? details.price : none, keep_date ? details.date : none, keep_tag ? details.tag : none)); } else { - new_comm = parent().find_or_create(base_symbol()); + new_comm = pool().find_or_create(base_symbol()); } assert(new_comm); @@ -199,7 +199,7 @@ annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep) void annotated_commodity_t::write_annotations(std::ostream& out) const { - details.print(out, parent().keep_base); + details.print(out, pool().keep_base); } } // namespace ledger diff --git a/src/commodity.cc b/src/commodity.cc index d896572f..a0827e7a 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -375,7 +375,7 @@ commodity_t::check_for_updated_price(const optional<price_point_t>& point, const optional<datetime_t>& moment, const optional<commodity_t&>& in_terms_of) { - if (parent().get_quotes && ! has_flags(COMMODITY_NOMARKET)) { + if (pool().get_quotes && ! has_flags(COMMODITY_NOMARKET)) { bool exceeds_leeway = true; if (point) { @@ -389,8 +389,8 @@ commodity_t::check_for_updated_price(const optional<price_point_t>& point, DEBUG("commodity.download", "slip.now = " << seconds_diff); } - DEBUG("commodity.download", "leeway = " << parent().quote_leeway); - if (seconds_diff < parent().quote_leeway) + DEBUG("commodity.download", "leeway = " << pool().quote_leeway); + if (seconds_diff < pool().quote_leeway) exceeds_leeway = false; } @@ -398,7 +398,7 @@ commodity_t::check_for_updated_price(const optional<price_point_t>& point, DEBUG("commodity.download", "attempting to download a more current quote..."); if (optional<price_point_t> quote = - parent().get_commodity_quote(*this, in_terms_of)) { + pool().get_commodity_quote(*this, in_terms_of)) { if (! in_terms_of || (quote->price.has_commodity() && quote->price.commodity() == *in_terms_of)) @@ -411,7 +411,7 @@ commodity_t::check_for_updated_price(const optional<price_point_t>& point, commodity_t::operator bool() const { - return this != parent().null_commodity; + return this != pool().null_commodity; } bool commodity_t::symbol_needs_quotes(const string& symbol) @@ -568,7 +568,7 @@ void commodity_t::parse_symbol(char *& p, string& symbol) bool commodity_t::valid() const { - if (symbol().empty() && this != parent().null_commodity) { + if (symbol().empty() && this != pool().null_commodity) { DEBUG("ledger.validate", "commodity_t: symbol().empty() && this != null_commodity"); return false; diff --git a/src/commodity.h b/src/commodity.h index 25397131..f65df1b9 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -222,8 +222,6 @@ protected: #endif // HAVE_BOOST_SERIALIZATION }; - static bool symbol_needs_quotes(const string& symbol); - shared_ptr<base_t> base; commodity_pool_t * parent_; @@ -247,28 +245,31 @@ public: operator bool() const; - bool is_annotated() const { - return annotated; - } - virtual bool operator==(const commodity_t& comm) const { if (comm.annotated) return comm == *this; return base.get() == comm.base.get(); } + static bool symbol_needs_quotes(const string& symbol); + virtual commodity_t& referent() { return *this; } virtual const commodity_t& referent() const { return *this; } + + bool is_annotated() const { + return annotated; + } + virtual commodity_t& strip_annotations(const keep_details_t&) { return *this; } virtual void write_annotations(std::ostream&) const {} - commodity_pool_t& parent() const { + commodity_pool_t& pool() const { return *parent_; } @@ -329,7 +330,6 @@ public: optional<history_t&> history(const optional<commodity_t&>& commodity); -public: // These methods provide a transparent pass-through to the underlying // base->varied_history object. diff --git a/src/pool.cc b/src/pool.cc index 06a4706c..b08c8fad 100644 --- a/src/pool.cc +++ b/src/pool.cc @@ -118,7 +118,7 @@ string commodity_pool_t::make_qualified_name(const commodity_t& comm, std::ostringstream name; comm.print(name); - details.print(name, comm.parent().keep_base); + details.print(name, comm.pool().keep_base); DEBUG("amounts.commodities", "make_qualified_name for " << *comm.qualified_symbol << std::endl << details); diff --git a/src/py_account.cc b/src/py_account.cc new file mode 100644 index 00000000..7fa30d0a --- /dev/null +++ b/src/py_account.cc @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2003-2009, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <system.hh> + +#include "pyinterp.h" +#include "account.h" +#include "post.h" + +namespace ledger { + +using namespace boost::python; + +namespace { + + long accounts_len(account_t& account) + { + return account.accounts.size(); + } + + account_t& accounts_getitem(account_t& account, long i) + { + static long last_index = 0; + static account_t * last_account = NULL; + static accounts_map::iterator elem; + + long len = account.accounts.size(); + + if (labs(i) >= len) { + PyErr_SetString(PyExc_IndexError, _("Index out of range")); + throw_error_already_set(); + } + + if (&account == last_account && i == last_index + 1) { + last_index = i; + return *(*++elem).second; + } + + long x = i < 0 ? len + i : i; + elem = account.accounts.begin(); + while (--x >= 0) + elem++; + + last_account = &account; + last_index = i; + + return *(*elem).second; + } + + account_t * py_find_account_1(journal_t& journal, const string& name) + { + return journal.find_account(name); + } + + account_t * py_find_account_2(journal_t& journal, const string& name, + const bool auto_create) + { + return journal.find_account(name, auto_create); + } + + account_t::xdata_t& py_xdata(account_t& account) { + return account.xdata(); + } + +} // unnamed namespace + +void export_account() +{ + scope().attr("ACCOUNT_EXT_SORT_CALC") = ACCOUNT_EXT_SORT_CALC; + scope().attr("ACCOUNT_EXT_HAS_NON_VIRTUALS") = ACCOUNT_EXT_HAS_NON_VIRTUALS; + scope().attr("ACCOUNT_EXT_HAS_UNB_VIRTUALS") = ACCOUNT_EXT_HAS_UNB_VIRTUALS; + scope().attr("ACCOUNT_EXT_AUTO_VIRTUALIZE") = ACCOUNT_EXT_AUTO_VIRTUALIZE; + scope().attr("ACCOUNT_EXT_VISITED") = ACCOUNT_EXT_VISITED; + scope().attr("ACCOUNT_EXT_MATCHING") = ACCOUNT_EXT_MATCHING; + scope().attr("ACCOUNT_EXT_TO_DISPLAY") = ACCOUNT_EXT_TO_DISPLAY; + scope().attr("ACCOUNT_EXT_DISPLAYED") = ACCOUNT_EXT_DISPLAYED; + + class_< account_t::xdata_t::details_t > ("AccountXDataDetails") + .def_readonly("total", &account_t::xdata_t::details_t::total) + .def_readonly("calculated", &account_t::xdata_t::details_t::calculated) + .def_readonly("gathered", &account_t::xdata_t::details_t::gathered) + + .def_readonly("posts_count", &account_t::xdata_t::details_t::posts_count) + .def_readonly("posts_virtuals_count", + &account_t::xdata_t::details_t::posts_virtuals_count) + .def_readonly("posts_cleared_count", + &account_t::xdata_t::details_t::posts_cleared_count) + .def_readonly("posts_last_7_count", + &account_t::xdata_t::details_t::posts_last_7_count) + .def_readonly("posts_last_30_count", + &account_t::xdata_t::details_t::posts_last_30_count) + .def_readonly("posts_this_month_count", + &account_t::xdata_t::details_t::posts_this_month_count) + + .def_readonly("earliest_post", + &account_t::xdata_t::details_t::earliest_post) + .def_readonly("earliest_cleared_post", + &account_t::xdata_t::details_t::earliest_cleared_post) + .def_readonly("latest_post", + &account_t::xdata_t::details_t::latest_post) + .def_readonly("latest_cleared_post", + &account_t::xdata_t::details_t::latest_cleared_post) + + .def_readonly("filenames", &account_t::xdata_t::details_t::filenames) + .def_readonly("accounts_referenced", + &account_t::xdata_t::details_t::accounts_referenced) + .def_readonly("payees_referenced", + &account_t::xdata_t::details_t::payees_referenced) + + .def(self += self) + + .def("update", &account_t::xdata_t::details_t::update) + ; + + class_< account_t::xdata_t > ("AccountXData") +#if 1 + .def("flags", &supports_flags<uint_least16_t>::flags) + .def("has_flags", &supports_flags<uint_least16_t>::has_flags) + .def("set_flags", &supports_flags<uint_least16_t>::set_flags) + .def("clear_flags", &supports_flags<uint_least16_t>::clear_flags) + .def("add_flags", &supports_flags<uint_least16_t>::add_flags) + .def("drop_flags", &supports_flags<uint_least16_t>::drop_flags) +#endif + + .def_readonly("self_details", &account_t::xdata_t::self_details) + .def_readonly("family_details", &account_t::xdata_t::family_details) + .def_readonly("reported_posts", &account_t::xdata_t::reported_posts) + .def_readonly("sort_values", &account_t::xdata_t::sort_values) + ; + + scope().attr("ACCOUNT_NORMAL") = ACCOUNT_NORMAL; + scope().attr("ACCOUNT_KNOWN") = ACCOUNT_KNOWN; + scope().attr("ACCOUNT_TEMP") = ACCOUNT_TEMP; + + class_< account_t > ("Account") +#if 1 + .def("flags", &supports_flags<>::flags) + .def("has_flags", &supports_flags<>::has_flags) + .def("set_flags", &supports_flags<>::set_flags) + .def("clear_flags", &supports_flags<>::clear_flags) + .def("add_flags", &supports_flags<>::add_flags) + .def("drop_flags", &supports_flags<>::drop_flags) +#endif + + .add_property("parent", + make_getter(&account_t::parent, + return_value_policy<reference_existing_object>())) + + .def_readwrite("name", &account_t::name) + .def_readwrite("note", &account_t::note) + .def_readonly("depth", &account_t::depth) + .def_readonly("accounts", &account_t::accounts) + .def_readonly("posts", &account_t::posts) + + .def(self_ns::str(self)) + + .def("fullname", &account_t::fullname) + .def("partial_name", &account_t::partial_name) + + .def("add_account", &account_t::add_account) + .def("remove_account", &account_t::remove_account) + + .def("find_account", &account_t::find_account, + return_value_policy<reference_existing_object>()) + .def("find_account_re", &account_t::find_account, + return_value_policy<reference_existing_object>()) + + .def("add_post", &account_t::add_post) + .def("remove_post", &account_t::remove_post) + + .def("valid", &account_t::valid) + + .def("__len__", accounts_len) + .def("__getitem__", accounts_getitem, return_internal_reference<1>()) + + .def("has_xdata", &account_t::has_xdata) + .def("clear_xdata", &account_t::clear_xdata) + .def("xdata", py_xdata, + return_value_policy<reference_existing_object>()) + + .def("amount", &account_t::amount) + .def("total", &account_t::total) + + .def("self_details", &account_t::self_details, + return_value_policy<reference_existing_object>()) + .def("family_details", &account_t::family_details, + return_value_policy<reference_existing_object>()) + + .def("has_xflags", &account_t::has_xflags) + .def("children_with_flags", &account_t::children_with_flags) + ; +} + +} // namespace ledger diff --git a/src/py_amount.cc b/src/py_amount.cc index efae7514..c6b3284a 100644 --- a/src/py_amount.cc +++ b/src/py_amount.cc @@ -282,9 +282,6 @@ internal precision.")) .def("parse_conversion", &amount_t::parse_conversion) .staticmethod("parse_conversion") - .def("print_", py_print) - .def("dump", &amount_t::dump) - .def("valid", &amount_t::valid) ; diff --git a/src/py_balance.cc b/src/py_balance.cc index 2d940876..effc6937 100644 --- a/src/py_balance.cc +++ b/src/py_balance.cc @@ -211,9 +211,6 @@ void export_balance() .def("strip_annotations", &balance_t::strip_annotations) - .def("print_", py_print) - .def("dump", &balance_t::dump) - .def("valid", &balance_t::valid) ; diff --git a/src/py_commodity.cc b/src/py_commodity.cc index 4932df97..c0412a45 100644 --- a/src/py_commodity.cc +++ b/src/py_commodity.cc @@ -33,20 +33,149 @@ #include "pyinterp.h" #include "commodity.h" +#include "annotate.h" +#include "pool.h" namespace ledger { using namespace boost::python; -void py_add_price(commodity_t& commodity, - const datetime_t& date, - const amount_t& price) -{ - commodity.add_price(date, price); -} +namespace { + + commodity_t * py_create_1(commodity_pool_t& pool, + const string& symbol) + { + return pool.create(symbol); + } + commodity_t * py_create_2(commodity_pool_t& pool, + const string& symbol, + const annotation_t& details) + { + return pool.create(symbol, details); + } + + commodity_t * py_find_or_create_1(commodity_pool_t& pool, + const string& symbol) + { + return pool.find_or_create(symbol); + } + commodity_t * py_find_or_create_2(commodity_pool_t& pool, + const string& symbol, + const annotation_t& details) + { + return pool.find_or_create(symbol, details); + } + + commodity_t * py_find_1(commodity_pool_t& pool, + const string& name) + { + return pool.find(name); + } + + commodity_t * py_find_2(commodity_pool_t& pool, + const string& symbol, + const annotation_t& details) + { + return pool.find(symbol, details); + } + + // Exchange one commodity for another, while recording the factored price. + + void py_exchange_3(commodity_pool_t& pool, + commodity_t& commodity, + const amount_t& per_unit_cost, + const datetime_t& moment) + { + pool.exchange(commodity, per_unit_cost, moment); + } + + cost_breakdown_t py_exchange_5(commodity_pool_t& pool, + const amount_t& amount, + const amount_t& cost, + const bool is_per_unit, + const boost::optional<datetime_t>& moment, + const boost::optional<string>& tag) + { + return pool.exchange(amount, cost, is_per_unit, moment, tag); + } + + void py_add_price_2(commodity_t& commodity, + const datetime_t& date, const amount_t& price) { + commodity.add_price(date, price); + } + + void py_add_price_3(commodity_t& commodity, const datetime_t& date, + const amount_t& price, const bool reflexive) { + commodity.add_price(date, price, reflexive); + } + + bool py_keep_all_0(keep_details_t& details) { + return details.keep_all(); + } + bool py_keep_all_1(keep_details_t& details, const commodity_t& comm) { + return details.keep_all(comm); + } + + bool py_keep_any_0(keep_details_t& details) { + return details.keep_any(); + } + bool py_keep_any_1(keep_details_t& details, const commodity_t& comm) { + return details.keep_any(comm); + } + +} // unnamed namespace void export_commodity() { + class_< commodity_pool_t, boost::noncopyable > ("CommodityPool", no_init) + .add_property("null_commodity", + make_getter(&commodity_pool_t::null_commodity, + return_value_policy<reference_existing_object>()), + make_setter(&commodity_pool_t::null_commodity, + with_custodian_and_ward<1, 2>())) + .add_property("default_commodity", + make_getter(&commodity_pool_t::default_commodity, + return_value_policy<reference_existing_object>()), + make_setter(&commodity_pool_t::default_commodity, + with_custodian_and_ward<1, 2>())) + + .add_property("keep_base", + make_getter(&commodity_pool_t::keep_base), + make_setter(&commodity_pool_t::keep_base)) + .add_property("price_db", + make_getter(&commodity_pool_t::price_db), + make_setter(&commodity_pool_t::price_db)) + .add_property("quote_leeway", + make_getter(&commodity_pool_t::quote_leeway), + make_setter(&commodity_pool_t::quote_leeway)) + .add_property("get_quotes", + make_getter(&commodity_pool_t::get_quotes), + make_setter(&commodity_pool_t::get_quotes)) + .add_property("get_commodity_quote", + make_getter(&commodity_pool_t::get_commodity_quote), + make_setter(&commodity_pool_t::get_commodity_quote)) + + .def("make_qualified_name", &commodity_pool_t::make_qualified_name) + + .def("create", py_create_1, return_value_policy<reference_existing_object>()) + .def("create", py_create_2, return_value_policy<reference_existing_object>()) + + .def("find_or_create", py_find_or_create_1, + return_value_policy<reference_existing_object>()) + .def("find_or_create", py_find_or_create_2, + return_value_policy<reference_existing_object>()) + + .def("find", py_find_1, return_value_policy<reference_existing_object>()) + .def("find", py_find_2, return_value_policy<reference_existing_object>()) + + .def("exchange", py_exchange_3, with_custodian_and_ward<1, 2>()) + .def("exchange", py_exchange_5) + + .def("parse_price_directive", &commodity_pool_t::parse_price_directive) + .def("parse_price_expression", &commodity_pool_t::parse_price_expression, + return_value_policy<reference_existing_object>()) + ; + scope().attr("COMMODITY_STYLE_DEFAULTS") = COMMODITY_STYLE_DEFAULTS; scope().attr("COMMODITY_STYLE_SUFFIXED") = COMMODITY_STYLE_SUFFIXED; scope().attr("COMMODITY_STYLE_SEPARATED") = COMMODITY_STYLE_SEPARATED; @@ -55,29 +184,136 @@ void export_commodity() scope().attr("COMMODITY_NOMARKET") = COMMODITY_NOMARKET; scope().attr("COMMODITY_BUILTIN") = COMMODITY_BUILTIN; scope().attr("COMMODITY_WALKED") = COMMODITY_WALKED; + scope().attr("COMMODITY_KNOWN") = COMMODITY_KNOWN; + scope().attr("COMMODITY_PRIMARY") = COMMODITY_PRIMARY; + + class_< commodity_t, boost::noncopyable > ("Commodity", no_init) +#if 1 + .def("flags", &delegates_flags<uint_least16_t>::flags) + .def("has_flags", &delegates_flags<uint_least16_t>::has_flags) + .def("set_flags", &delegates_flags<uint_least16_t>::set_flags) + .def("clear_flags", &delegates_flags<uint_least16_t>::clear_flags) + .def("add_flags", &delegates_flags<uint_least16_t>::add_flags) + .def("drop_flags", &delegates_flags<uint_least16_t>::drop_flags) +#endif + + .add_static_property("european_by_default", + make_getter(&commodity_t::european_by_default), + make_setter(&commodity_t::european_by_default)) + + .def("__nonzero__", &commodity_t::operator bool) - class_< commodity_t, bases<>, - commodity_t, boost::noncopyable > ("Commodity", no_init) .def(self == self) - .def("drop_flags", &commodity_t::drop_flags) + .def("symbol_needs_quotes", &commodity_t::symbol_needs_quotes) + .staticmethod("symbol_needs_quotes") - .def("add_price", py_add_price) +#if 0 + .def("referent", &commodity_t::referent, + return_value_policy<reference_existing_object>()) +#endif + + .def("is_annotated", &commodity_t::is_annotated) + .def("strip_annotations", &commodity_t::strip_annotations, + return_value_policy<reference_existing_object>()) + .def("write_annotations", &commodity_t::write_annotations) + + .def("pool", &commodity_t::pool, + return_value_policy<reference_existing_object>()) + .def("base_symbol", &commodity_t::base_symbol) + .def("symbol", &commodity_t::symbol) + .def("mapping_key", &commodity_t::mapping_key) + + .def("name", &commodity_t::name) + .def("set_name", &commodity_t::set_name) + .def("note", &commodity_t::note) + .def("set_note", &commodity_t::set_note) .def("precision", &commodity_t::precision) - ; + .def("set_precision", &commodity_t::set_precision) + .def("smaller", &commodity_t::smaller) + .def("set_smaller", &commodity_t::set_smaller) + .def("larger", &commodity_t::larger) + .def("set_larger", &commodity_t::set_larger) -#if 0 - class_< annotation_t, bases<>, - commodity_t, boost::noncopyable > ("Annotation", no_init) + .def("add_price", py_add_price_2) + .def("add_price", py_add_price_3) + .def("remove_price", &commodity_t::remove_price, + with_custodian_and_ward<1, 3>()) + .def("find_price", &commodity_t::find_price) + .def("check_for_updated_price", &commodity_t::check_for_updated_price) + + .def("valid", &commodity_t::valid) ; - class_< keep_details_t, bases<>, - commodity_t, boost::noncopyable > ("KeepDetails", no_init) + + class_< annotation_t > ("Annotation", no_init) +#if 1 + .def("flags", &supports_flags<>::flags) + .def("has_flags", &supports_flags<>::has_flags) + .def("set_flags", &supports_flags<>::set_flags) + .def("clear_flags", &supports_flags<>::clear_flags) + .def("add_flags", &supports_flags<>::add_flags) + .def("drop_flags", &supports_flags<>::drop_flags) +#endif + + .add_property("price", + make_getter(&annotation_t::price), + make_setter(&annotation_t::price)) + .add_property("date", + make_getter(&annotation_t::date), + make_setter(&annotation_t::date)) + .add_property("tag", + make_getter(&annotation_t::tag), + make_setter(&annotation_t::tag)) + + .def("__nonzero__", &annotation_t::operator bool) + + .def(self == self) + + .def("valid", &annotation_t::valid) ; - class_< annotated_commodity_t, bases<>, - commodity_t, boost::noncopyable > ("AnnotatedCommodity", no_init) + + class_< keep_details_t > ("KeepDetails") + .def(init<bool, bool, bool, bool>()) + + .add_property("keep_price", + make_getter(&keep_details_t::keep_price), + make_setter(&keep_details_t::keep_price)) + .add_property("keep_date", + make_getter(&keep_details_t::keep_date), + make_setter(&keep_details_t::keep_date)) + .add_property("keep_tag", + make_getter(&keep_details_t::keep_tag), + make_setter(&keep_details_t::keep_tag)) + .add_property("only_actuals", + make_getter(&keep_details_t::only_actuals), + make_setter(&keep_details_t::only_actuals)) + + .def("keep_all", py_keep_all_0) + .def("keep_all", py_keep_all_1) + .def("keep_any", py_keep_any_0) + .def("keep_any", py_keep_any_1) ; + + class_< annotated_commodity_t, bases<commodity_t>, + annotated_commodity_t, boost::noncopyable > + ("AnnotatedCommodity", no_init) + .add_property("details", + make_getter(&annotated_commodity_t::details), + make_setter(&annotated_commodity_t::details)) + + .def(self == self) + .def(self == other<commodity_t>()) + +#if 0 + .def("referent", &annotated_commodity_t::referent, + return_value_policy<reference_existing_object>()) #endif + + .def("strip_annotations", &annotated_commodity_t::strip_annotations, + return_value_policy<reference_existing_object>()) + .def("write_annotations", &annotated_commodity_t::write_annotations) + ; } } // namespace ledger diff --git a/src/py_item.cc b/src/py_item.cc index 0e1fe0f9..ac544c6a 100644 --- a/src/py_item.cc +++ b/src/py_item.cc @@ -32,11 +32,40 @@ #include <system.hh> #include "pyinterp.h" +#include "scope.h" +#include "mask.h" +#include "item.h" namespace ledger { using namespace boost::python; +namespace { + + bool py_has_tag_1s(item_t& item, const string& tag) { + return item.has_tag(tag); + } + bool py_has_tag_1m(item_t& item, const mask_t& tag_mask) { + return item.has_tag(tag_mask); + } + bool py_has_tag_2m(item_t& item, const mask_t& tag_mask, + const boost::optional<mask_t>& value_mask) { + return item.has_tag(tag_mask, value_mask); + } + + boost::optional<string> py_get_tag_1s(item_t& item, const string& tag) { + return item.get_tag(tag); + } + boost::optional<string> py_get_tag_1m(item_t& item, const mask_t& tag_mask) { + return item.get_tag(tag_mask); + } + boost::optional<string> py_get_tag_2m(item_t& item, const mask_t& tag_mask, + const boost::optional<mask_t>& value_mask) { + return item.get_tag(tag_mask, value_mask); + } + +} // unnamed namespace + #define EXC_TRANSLATOR(type) \ void exc_translate_ ## type(const type& err) { \ PyErr_SetString(PyExc_ArithmeticError, err.what()); \ @@ -46,19 +75,89 @@ using namespace boost::python; void export_item() { -#if 0 - class_< item_t > ("Item") + class_< position_t > ("Position") + .add_property("pathname", + make_getter(&position_t::pathname), + make_setter(&position_t::pathname)) + .add_property("beg_pos", + make_getter(&position_t::beg_pos), + make_setter(&position_t::beg_pos)) + .add_property("beg_line", + make_getter(&position_t::beg_line), + make_setter(&position_t::beg_line)) + .add_property("end_pos", + make_getter(&position_t::end_pos), + make_setter(&position_t::end_pos)) + .add_property("end_line", + make_getter(&position_t::end_line), + make_setter(&position_t::end_line)) ; + + scope().attr("ITEM_NORMAL") = ITEM_NORMAL; + scope().attr("ITEM_GENERATED") = ITEM_GENERATED; + scope().attr("ITEM_TEMP") = ITEM_TEMP; + + enum_< item_t::state_t > ("State") + .value("Uncleared", item_t::UNCLEARED) + .value("Cleared", item_t::CLEARED) + .value("Pending", item_t::PENDING) + ; + +#if 0 + class_< item_t, bases<scope_t> > ("JournalItem", init<uint_least8_t>()) +#else + class_< item_t > ("JournalItem", init<uint_least8_t>()) #endif +#if 1 + .def("flags", &supports_flags<>::flags) + .def("has_flags", &supports_flags<>::has_flags) + .def("set_flags", &supports_flags<>::set_flags) + .def("clear_flags", &supports_flags<>::clear_flags) + .def("add_flags", &supports_flags<>::add_flags) + .def("drop_flags", &supports_flags<>::drop_flags) +#endif + + .add_property("note", + make_getter(&item_t::note), + make_setter(&item_t::note)) + .add_property("pos", + make_getter(&item_t::pos), + make_setter(&item_t::pos)) + .add_property("metadata", + make_getter(&item_t::metadata), + make_setter(&item_t::metadata)) + + .def("copy_details", &item_t::copy_details) - //register_optional_to_python<amount_t>(); + .def(self == self) + .def(self != self) - //implicitly_convertible<string, amount_t>(); + .def("has_tag", py_has_tag_1s) + .def("has_tag", py_has_tag_1m) + .def("has_tag", py_has_tag_2m) + .def("get_tag", py_get_tag_1s) + .def("get_tag", py_get_tag_1m) + .def("get_tag", py_get_tag_2m) -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); + .def("set_tag", &item_t::set_tag) - //EXC_TRANSLATE(item_error); + .def("parse_tags", &item_t::parse_tags) + .def("append_note", &item_t::append_note) + + .add_static_property("use_effective_date", + make_getter(&item_t::use_effective_date), + make_setter(&item_t::use_effective_date)) + + .def("date", &item_t::date) + .def("effective_date", &item_t::effective_date) + + .def("set_state", &item_t::set_state) + .def("state", &item_t::state) + + .def("lookup", &item_t::lookup) + + .def("valid", &item_t::valid) + ; } } // namespace ledger diff --git a/src/py_journal.cc b/src/py_journal.cc index fb693ffc..873645d3 100644 --- a/src/py_journal.cc +++ b/src/py_journal.cc @@ -32,334 +32,176 @@ #include <system.hh> #include "pyinterp.h" +#include "pyutils.h" +#include "hooks.h" +#include "journal.h" +#include "xact.h" namespace ledger { using namespace boost::python; -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ - } - -//EXC_TRANSLATOR(journal_error) - -void export_journal() -{ -#if 0 - class_< journal_t > ("Journal") - ; -#endif - - //register_optional_to_python<amount_t>(); - - //implicitly_convertible<string, amount_t>(); - -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); - - //EXC_TRANSLATE(journal_error); -} - -} // namespace ledger +namespace { -#if 0 -xact_t& post_xact(const post_t& post) -{ - return *post.xact; -} - -unsigned int posts_len(xact_base_t& xact) -{ - return xact.posts.size(); -} - -post_t& posts_getitem(xact_base_t& xact, int i) -{ - static int last_index = 0; - static xact_base_t * last_xact = NULL; - static posts_list::iterator elem; - - std::size_t len = xact.posts.size(); + account_t& py_account_master(journal_t& journal) { + return *journal.master; + } - if (abs(i) >= len) { - PyErr_SetString(PyExc_IndexError, _("Index out of range")); - throw_error_already_set(); + commodity_pool_t& py_commodity_pool(journal_t& journal) { + return *journal.commodity_pool; } - if (&xact == last_xact && i == last_index + 1) { - last_index = i; - return **++elem; + long xacts_len(journal_t& journal) + { + return journal.xacts.size(); } - int x = i < 0 ? len + i : i; - elem = xact.posts.begin(); - while (--x >= 0) - elem++; + xact_t& xacts_getitem(journal_t& journal, long i) + { + static long last_index = 0; + static journal_t * last_journal = NULL; + static xacts_list::iterator elem; - last_xact = &xact; - last_index = i; + long len = journal.xacts.size(); - return **elem; -} + if (labs(i) >= len) { + PyErr_SetString(PyExc_IndexError, _("Index out of range")); + throw_error_already_set(); + } -unsigned int xacts_len(journal_t& journal) -{ - return journal.xacts.size(); -} + if (&journal == last_journal && i == last_index + 1) { + last_index = i; + return **++elem; + } -xact_t& xacts_getitem(journal_t& journal, int i) -{ - static int last_index = 0; - static journal_t * last_journal = NULL; - static xacts_list::iterator elem; + long x = i < 0 ? len + i : i; + elem = journal.xacts.begin(); + while (--x >= 0) + elem++; - std::size_t len = journal.xacts.size(); + last_journal = &journal; + last_index = i; - if (abs(i) >= len) { - PyErr_SetString(PyExc_IndexError, _("Index out of range")); - throw_error_already_set(); + return **elem; } - if (&journal == last_journal && i == last_index + 1) { - last_index = i; - return **++elem; + long accounts_len(account_t& account) + { + return account.accounts.size(); } - int x = i < 0 ? len + i : i; - elem = journal.xacts.begin(); - while (--x >= 0) - elem++; + account_t& accounts_getitem(account_t& account, long i) + { + static long last_index = 0; + static account_t * last_account = NULL; + static accounts_map::iterator elem; - last_journal = &journal; - last_index = i; + long len = account.accounts.size(); - return **elem; -} + if (labs(i) >= len) { + PyErr_SetString(PyExc_IndexError, _("Index out of range")); + throw_error_already_set(); + } -unsigned int accounts_len(account_t& account) -{ - return account.accounts.size(); -} + if (&account == last_account && i == last_index + 1) { + last_index = i; + return *(*++elem).second; + } -account_t& accounts_getitem(account_t& account, int i) -{ - static int last_index = 0; - static account_t * last_account = NULL; - static accounts_map::iterator elem; + long x = i < 0 ? len + i : i; + elem = account.accounts.begin(); + while (--x >= 0) + elem++; - std::size_t len = account.accounts.size(); + last_account = &account; + last_index = i; - if (abs(i) >= len) { - PyErr_SetString(PyExc_IndexError, _("Index out of range")); - throw_error_already_set(); + return *(*elem).second; } - if (&account == last_account && i == last_index + 1) { - last_index = i; - return *(*++elem).second; + account_t * py_find_account_1(journal_t& journal, const string& name) + { + return journal.find_account(name); } - int x = i < 0 ? len + i : i; - elem = account.accounts.begin(); - while (--x >= 0) - elem++; - - last_account = &account; - last_index = i; - - return *(*elem).second; -} - -account_t * py_find_account_1(journal_t& journal, const string& name) -{ - return journal.find_account(name); -} - -account_t * py_find_account_2(journal_t& journal, const string& name, - const bool auto_create) -{ - return journal.find_account(name, auto_create); -} - -bool py_add_xact(journal_t& journal, xact_t * xact) { - return journal.add_xact(new xact_t(*xact)); -} - -void py_add_post(xact_base_t& xact, post_t * post) { - return xact.add_post(new post_t(*post)); -} - -struct xact_base_wrap : public xact_base_t -{ - PyObject * self; - xact_base_wrap(PyObject * self_) : self(self_) {} - - virtual bool valid() const { - return call_method<bool>(self, "valid"); - } -}; - -struct py_xact_finalizer_t : public xact_finalizer_t { - object pyobj; - py_xact_finalizer_t() {} - py_xact_finalizer_t(object obj) : pyobj(obj) {} - py_xact_finalizer_t(const py_xact_finalizer_t& other) - : pyobj(other.pyobj) {} - virtual bool operator()(xact_t& xact, bool post) { - return call<bool>(pyobj.ptr(), xact, post); + account_t * py_find_account_2(journal_t& journal, const string& name, + const bool auto_create) + { + return journal.find_account(name, auto_create); } -}; -std::list<py_xact_finalizer_t> py_finalizers; - -void py_add_xact_finalizer(journal_t& journal, object x) -{ - py_finalizers.push_back(py_xact_finalizer_t(x)); - journal.add_xact_finalizer(&py_finalizers.back()); -} - -void py_remove_xact_finalizer(journal_t& journal, object x) -{ - for (std::list<py_xact_finalizer_t>::iterator i = py_finalizers.begin(); - i != py_finalizers.end(); - i++) - if ((*i).pyobj == x) { - journal.remove_xact_finalizer(&(*i)); - py_finalizers.erase(i); - return; + struct py_xact_finalizer_t : public xact_finalizer_t { + object pyobj; + py_xact_finalizer_t() {} + py_xact_finalizer_t(object obj) : pyobj(obj) {} + py_xact_finalizer_t(const py_xact_finalizer_t& other) + : pyobj(other.pyobj) {} + virtual bool operator()(xact_t& xact, bool post) { + return call<bool>(pyobj.ptr(), xact, post); } -} + }; -void py_run_xact_finalizers(journal_t& journal, xact_t& xact, bool post) -{ - run_hooks(journal.xact_finalize_hooks, xact, post); -} + std::list<py_xact_finalizer_t> py_finalizers; -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_RuntimeError, err.what()); \ + void py_add_xact_finalizer(journal_t& journal, object x) + { + py_finalizers.push_back(py_xact_finalizer_t(x)); + journal.add_xact_finalizer(&py_finalizers.back()); } -EXC_TRANSLATOR(balance_error) -EXC_TRANSLATOR(interval_expr_error) -EXC_TRANSLATOR(format_error) -EXC_TRANSLATOR(parse_error) + void py_remove_xact_finalizer(journal_t& journal, object x) + { + for (std::list<py_xact_finalizer_t>::iterator i = py_finalizers.begin(); + i != py_finalizers.end(); + i++) + if ((*i).pyobj == x) { + journal.remove_xact_finalizer(&(*i)); + py_finalizers.erase(i); + return; + } + } -value_t py_post_amount(post_t * post) { - return value_t(post->amount); -} + void py_run_xact_finalizers(journal_t& journal, xact_t& xact, bool post) + { + journal.xact_finalize_hooks.run_hooks(xact, post); + } -post_t::state_t py_xact_state(xact_t * xact) { - post_t::state_t state; - if (xact->get_state(&state)) - return state; - else - return post_t::UNCLEARED; -} +} // unnamed namespace void export_journal() { - scope().attr("POST_NORMAL") = POST_NORMAL; - scope().attr("POST_VIRTUAL") = POST_VIRTUAL; - scope().attr("POST_BALANCE") = POST_BALANCE; - scope().attr("POST_AUTO") = POST_AUTO; - scope().attr("POST_BULK_ALLOC") = POST_BULK_ALLOC; - scope().attr("POST_CALCULATED") = POST_CALCULATED; - - enum_< post_t::state_t > ("State") - .value("Uncleared", post_t::UNCLEARED) - .value("Cleared", post_t::CLEARED) - .value("Pending", post_t::PENDING) + class_< journal_t::fileinfo_t > ("FileInfo") + .add_property("filename", + make_getter(&journal_t::fileinfo_t::filename), + make_setter(&journal_t::fileinfo_t::filename)) + .add_property("size", + make_getter(&journal_t::fileinfo_t::size), + make_setter(&journal_t::fileinfo_t::size)) + .add_property("modtime", + make_getter(&journal_t::fileinfo_t::modtime), + make_setter(&journal_t::fileinfo_t::modtime)) + .add_property("from_stream", + make_getter(&journal_t::fileinfo_t::from_stream), + make_setter(&journal_t::fileinfo_t::from_stream)) ; - class_< post_t > ("Post") - .def(init<optional<account_t *> >()) - .def(init<account_t *, amount_t, optional<unsigned int, const string&> >()) - - .def(self == self) - .def(self != self) - - .add_property("xact", - make_getter(&post_t::xact, - return_value_policy<reference_existing_object>())) - .add_property("account", - make_getter(&post_t::account, - return_value_policy<reference_existing_object>())) - - .add_property("amount", &py_post_amount) - .def_readonly("amount_expr", &post_t::amount_expr) - .add_property("cost", - make_getter(&post_t::cost, - return_internal_reference<1>())) - .def_readonly("cost_expr", &post_t::cost_expr) - - .def_readwrite("state", &post_t::state) - .def_readwrite("flags", &post_t::flags) - .def_readwrite("note", &post_t::note) - - .def_readonly("beg_pos", &post_t::beg_pos) - .def_readonly("beg_line", &post_t::beg_line) - .def_readonly("end_pos", &post_t::end_pos) - .def_readonly("end_line", &post_t::end_line) - - .def("actual_date", &post_t::actual_date) - .def("effective_date", &post_t::effective_date) - .def("date", &post_t::date) - - .def("use_effective_date", &post_t::use_effective_date) - - .def("valid", &post_t::valid) - ; - - class_< account_t > - ("Account", init<optional<account_t *, string, string> >() - [with_custodian_and_ward<1, 2>()]) - .def(self == self) - .def(self != self) - - .def(self_ns::str(self)) - - .def("__len__", accounts_len) - .def("__getitem__", accounts_getitem, return_internal_reference<1>()) - - .add_property("journal", - make_getter(&account_t::journal, - return_value_policy<reference_existing_object>())) - .add_property("parent", - make_getter(&account_t::parent, - return_value_policy<reference_existing_object>())) - .def_readwrite("name", &account_t::name) - .def_readwrite("note", &account_t::note) - .def_readonly("depth", &account_t::depth) - .def_readonly("ident", &account_t::ident) - - .def("fullname", &account_t::fullname) - - .def("add_account", &account_t::add_account) - .def("remove_account", &account_t::remove_account) - - .def("find_account", &account_t::find_account, - return_value_policy<reference_existing_object>()) - - .def("valid", &account_t::valid) - ; - - class_< journal_t > ("Journal") - .def(self == self) - .def(self != self) - - .def("__len__", xacts_len) - .def("__getitem__", xacts_getitem, return_internal_reference<1>()) - + class_< journal_t, boost::noncopyable > ("Journal") .add_property("master", make_getter(&journal_t::master, return_internal_reference<1>())) - .add_property("basket", make_getter(&journal_t::basket, - return_internal_reference<1>())) - - .def_readonly("sources", &journal_t::sources) - - .def_readwrite("price_db", &journal_t::price_db) + .add_property("basket", + make_getter(&journal_t::basket, + return_internal_reference<1>()), + make_setter(&journal_t::basket)) + .add_property("sources", make_getter(&journal_t::sources)) + .add_property("was_loaded", make_getter(&journal_t::was_loaded)) + .add_property("commodity_pool", + make_getter(&journal_t::commodity_pool, + return_internal_reference<1>())) +#if 0 + .add_property("xact_finalize_hooks", + make_getter(&journal_t::xact_finalize_hooks), + make_setter(&journal_t::xact_finalize_hooks)) +#endif .def("add_account", &journal_t::add_account) .def("remove_account", &journal_t::remove_account) @@ -369,58 +211,18 @@ void export_journal() .def("find_account_re", &journal_t::find_account_re, return_internal_reference<1>()) - .def("add_xact", py_add_xact) + .def("add_xact", &journal_t::add_xact) .def("remove_xact", &journal_t::remove_xact) .def("add_xact_finalizer", py_add_xact_finalizer) .def("remove_xact_finalizer", py_remove_xact_finalizer) .def("run_xact_finalizers", py_run_xact_finalizers) - .def("valid", &journal_t::valid) - ; - - class_< xact_base_t, xact_base_wrap, boost::noncopyable > ("XactBase") - .def("__len__", posts_len) - .def("__getitem__", posts_getitem, - return_internal_reference<1>()) - - .def_readonly("journal", &xact_base_t::journal) - - .def_readonly("src_idx", &xact_base_t::src_idx) - .def_readonly("beg_pos", &xact_base_t::beg_pos) - .def_readonly("beg_line", &xact_base_t::beg_line) - .def_readonly("end_pos", &xact_base_t::end_pos) - .def_readonly("end_line", &xact_base_t::end_line) - - .def("add_post", py_add_post) - .def("remove_post", &xact_base_t::remove_post) - - .def(self == self) - .def(self != self) - - .def("finalize", &xact_base_t::finalize) - .def("valid", &xact_base_t::valid) - ; - - class_< xact_t, bases<xact_base_t> > ("Xact") - .add_property("date", &xact_t::date) - .add_property("effective_date", &xact_t::effective_date) - .add_property("actual_date", &xact_t::actual_date) - - .def_readwrite("code", &xact_t::code) - .def_readwrite("payee", &xact_t::payee) - - .add_property("state", &py_xact_state) + .def("__len__", xacts_len) + .def("__getitem__", xacts_getitem, return_internal_reference<1>()) - .def("valid", &xact_t::valid) + .def("valid", &journal_t::valid) ; - -#define EXC_TRANSLATE(type) \ - register_error_translator<type>(&exc_translate_ ## type); - - EXC_TRANSLATE(balance_error); - EXC_TRANSLATE(interval_expr_error); - EXC_TRANSLATE(format_error); - EXC_TRANSLATE(parse_error); } -#endif + +} // namespace ledger diff --git a/src/py_post.cc b/src/py_post.cc index b1d62464..b4849c3d 100644 --- a/src/py_post.cc +++ b/src/py_post.cc @@ -32,33 +32,150 @@ #include <system.hh> #include "pyinterp.h" +#include "post.h" +#include "xact.h" namespace ledger { using namespace boost::python; -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ +namespace { + + bool py_has_tag_1s(post_t& post, const string& tag) { + return post.has_tag(tag); + } + bool py_has_tag_1m(post_t& post, const mask_t& tag_mask) { + return post.has_tag(tag_mask); + } + bool py_has_tag_2m(post_t& post, const mask_t& tag_mask, + const boost::optional<mask_t>& value_mask) { + return post.has_tag(tag_mask, value_mask); + } + + boost::optional<string> py_get_tag_1s(post_t& post, const string& tag) { + return post.get_tag(tag); + } + boost::optional<string> py_get_tag_1m(post_t& post, const mask_t& tag_mask) { + return post.get_tag(tag_mask); + } + boost::optional<string> py_get_tag_2m(post_t& post, const mask_t& tag_mask, + const boost::optional<mask_t>& value_mask) { + return post.get_tag(tag_mask, value_mask); + } + + post_t::xdata_t& py_xdata(post_t& post) { + return post.xdata(); } -//EXC_TRANSLATOR(post_error) + account_t * py_reported_account(post_t& post) { + return post.reported_account(); + } + +} // unnamed namespace void export_post() { -#if 0 - class_< post_t > ("Post") - ; + scope().attr("POST_EXT_RECEIVED") = POST_EXT_RECEIVED; + scope().attr("POST_EXT_HANDLED") = POST_EXT_HANDLED; + scope().attr("POST_EXT_DISPLAYED") = POST_EXT_DISPLAYED; + scope().attr("POST_EXT_DIRECT_AMT") = POST_EXT_DIRECT_AMT; + scope().attr("POST_EXT_SORT_CALC") = POST_EXT_SORT_CALC; + scope().attr("POST_EXT_COMPOUND") = POST_EXT_COMPOUND; + scope().attr("POST_EXT_VISITED") = POST_EXT_VISITED; + scope().attr("POST_EXT_MATCHES") = POST_EXT_MATCHES; + scope().attr("POST_EXT_CONSIDERED") = POST_EXT_CONSIDERED; + + class_< post_t::xdata_t > ("PostingXData") +#if 1 + .def("flags", &supports_flags<uint_least16_t>::flags) + .def("has_flags", &supports_flags<uint_least16_t>::has_flags) + .def("set_flags", &supports_flags<uint_least16_t>::set_flags) + .def("clear_flags", &supports_flags<uint_least16_t>::clear_flags) + .def("add_flags", &supports_flags<uint_least16_t>::add_flags) + .def("drop_flags", &supports_flags<uint_least16_t>::drop_flags) #endif - //register_optional_to_python<amount_t>(); + .add_property("visited_value", + make_getter(&post_t::xdata_t::visited_value), + make_setter(&post_t::xdata_t::visited_value)) + .add_property("compound_value", + make_getter(&post_t::xdata_t::compound_value), + make_setter(&post_t::xdata_t::compound_value)) + .add_property("total", + make_getter(&post_t::xdata_t::total), + make_setter(&post_t::xdata_t::total)) + .add_property("count", + make_getter(&post_t::xdata_t::count), + make_setter(&post_t::xdata_t::count)) + .add_property("date", + make_getter(&post_t::xdata_t::date), + make_setter(&post_t::xdata_t::date)) + .add_property("datetime", + make_getter(&post_t::xdata_t::datetime), + make_setter(&post_t::xdata_t::datetime)) + .add_property("account", + make_getter(&post_t::xdata_t::account), + make_setter(&post_t::xdata_t::account)) + .add_property("sort_values", + make_getter(&post_t::xdata_t::sort_values), + make_setter(&post_t::xdata_t::sort_values)) + ; + + scope().attr("POST_VIRTUAL") = POST_VIRTUAL; + scope().attr("POST_MUST_BALANCE") = POST_MUST_BALANCE; + scope().attr("POST_CALCULATED") = POST_CALCULATED; + scope().attr("POST_COST_CALCULATED") = POST_COST_CALCULATED; + + class_< post_t, bases<item_t> > ("Posting") + //.def(init<account_t *>()) + + .add_property("xact", + make_getter(&post_t::xact, + return_value_policy<reference_existing_object>()), + make_setter(&post_t::xact, + with_custodian_and_ward<1, 2>())) + .add_property("account", + make_getter(&post_t::account, + return_value_policy<reference_existing_object>()), + make_setter(&post_t::account, + with_custodian_and_ward<1, 2>())) + .add_property("amount", + make_getter(&post_t::amount), + make_setter(&post_t::amount)) + .add_property("cost", + make_getter(&post_t::cost), + make_setter(&post_t::cost)) + .add_property("assigned_amount", + make_getter(&post_t::assigned_amount), + make_setter(&post_t::assigned_amount)) + + .def("has_tag", py_has_tag_1s) + .def("has_tag", py_has_tag_1m) + .def("has_tag", py_has_tag_2m) + .def("get_tag", py_get_tag_1s) + .def("get_tag", py_get_tag_1m) + .def("get_tag", py_get_tag_2m) - //implicitly_convertible<string, amount_t>(); + .def("date", &post_t::date) + .def("effective_date", &post_t::effective_date) -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); + .def("must_balance", &post_t::must_balance) - //EXC_TRANSLATE(post_error); + .def("lookup", &post_t::lookup) + + .def("valid", &post_t::valid) + + .def("has_xdata", &post_t::has_xdata) + .def("clear_xdata", &post_t::clear_xdata) + .def("xdata", py_xdata, + return_value_policy<reference_existing_object>()) + + .def("add_to_value", &post_t::add_to_value) + .def("set_reported_account", &post_t::set_reported_account) + + .def("reported_account", py_reported_account, + return_value_policy<reference_existing_object>()) + ; } } // namespace ledger diff --git a/src/py_utils.cc b/src/py_utils.cc index cf98c5fe..3e788442 100644 --- a/src/py_utils.cc +++ b/src/py_utils.cc @@ -164,6 +164,50 @@ typedef register_python_conversion<std::ostream, ostream_to_python, ostream_from void export_utils() { + class_< supports_flags<uint_least8_t> > ("SupportFlags8") + .def(init<supports_flags<uint_least8_t> >()) + .def(init<uint_least8_t>()) + + .def("flags", &supports_flags<uint_least8_t>::flags) + .def("has_flags", &supports_flags<uint_least8_t>::has_flags) + .def("set_flags", &supports_flags<uint_least8_t>::set_flags) + .def("clear_flags", &supports_flags<uint_least8_t>::clear_flags) + .def("add_flags", &supports_flags<uint_least8_t>::add_flags) + .def("drop_flags", &supports_flags<uint_least8_t>::drop_flags) + ; + + class_< supports_flags<uint_least16_t> > ("SupportFlags16") + .def(init<supports_flags<uint_least16_t> >()) + .def(init<uint_least16_t>()) + + .def("flags", &supports_flags<uint_least16_t>::flags) + .def("has_flags", &supports_flags<uint_least16_t>::has_flags) + .def("set_flags", &supports_flags<uint_least16_t>::set_flags) + .def("clear_flags", &supports_flags<uint_least16_t>::clear_flags) + .def("add_flags", &supports_flags<uint_least16_t>::add_flags) + .def("drop_flags", &supports_flags<uint_least16_t>::drop_flags) + ; + +#if 0 + class_< basic_flags_t<uint_least8_t>, + bases<supports_flags<uint_least8_t> > > ("BasicFlags8") + .def(init<uint_least8_t>()) + + .def("plus_flags", &basic_flags_t<uint_least8_t>::plus_flags) + .def("minus_flags", &basic_flags_t<uint_least8_t>::minus_flags) + ; +#endif + + class_< delegates_flags<uint_least16_t>, + boost::noncopyable > ("DelegatesFlags16", no_init) + .def("flags", &delegates_flags<uint_least16_t>::flags) + .def("has_flags", &delegates_flags<uint_least16_t>::has_flags) + .def("set_flags", &delegates_flags<uint_least16_t>::set_flags) + .def("clear_flags", &delegates_flags<uint_least16_t>::clear_flags) + .def("add_flags", &delegates_flags<uint_least16_t>::add_flags) + .def("drop_flags", &delegates_flags<uint_least16_t>::drop_flags) + ; + bool_python_conversion(); string_python_conversion(); istream_python_conversion(); diff --git a/src/py_value.cc b/src/py_value.cc index f6c71920..34ee2d82 100644 --- a/src/py_value.cc +++ b/src/py_value.cc @@ -41,8 +41,12 @@ namespace ledger { using namespace boost::python; BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(value_overloads, value, 0, 2) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(exchange_commodities_overloads, + exchange_commodities, 1, 2) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_string_overloads, set_string, 0, 2) namespace { + expr_t py_value_getattr(const value_t& value, const string& name) { if (value.is_scope()) { @@ -69,28 +73,47 @@ namespace { return amount.set_string(str); } +} // unnamed namespace + #define EXC_TRANSLATOR(type) \ void exc_translate_ ## type(const type& err) { \ PyErr_SetString(PyExc_ArithmeticError, err.what()); \ } - EXC_TRANSLATOR(value_error) -} +EXC_TRANSLATOR(value_error) void export_value() { + enum_< value_t::type_t >("ValueType") + .value("VOID", value_t::VOID) + .value("BOOLEAN", value_t::BOOLEAN) + .value("DATETIME", value_t::DATETIME) + .value("DATE", value_t::DATE) + .value("INTEGER", value_t::INTEGER) + .value("AMOUNT", value_t::AMOUNT) + .value("BALANCE", value_t::BALANCE) + .value("STRING", value_t::STRING) + .value("SEQUENCE", value_t::SEQUENCE) + .value("SCOPE", value_t::SCOPE) + ; + class_< value_t > ("Value") .def("initialize", &value_t::initialize) .staticmethod("initialize") .def("shutdown", &value_t::shutdown) .staticmethod("shutdown") - .def(init<double>()) + .def(init<bool>()) + .def(init<datetime_t>()) + .def(init<date_t>()) .def(init<long>()) + .def(init<double>()) + .def(init<amount_t>()) + .def(init<balance_t>()) + .def(init<mask_t>()) .def(init<std::string>()) - .def(init<date_t>()) - .def(init<datetime_t>()) - + // jww (2009-11-02): Need to support conversion of sequences + //.def(init<value_t::sequence_t>()) .def(init<value_t>()) .def("is_equal_to", &value_t::is_equal_to) @@ -100,80 +123,88 @@ void export_value() .def(self == self) .def(self == long()) .def(long() == self) - .def(self == double()) - .def(double() == self) + .def(self == other<amount_t>()) + .def(other<amount_t>() == self) + .def(self == other<balance_t>()) + .def(other<balance_t>() == self) .def(self != self) .def(self != long()) .def(long() != self) - .def(self != double()) - .def(double() != self) + .def(self != other<amount_t>()) + .def(other<amount_t>() != self) + .def(self != other<balance_t>()) + .def(other<balance_t>() != self) .def(! self) .def(self < self) .def(self < long()) .def(long() < self) - .def(self < double()) - .def(double() < self) + .def(self < other<amount_t>()) + .def(other<amount_t>() < self) .def(self <= self) .def(self <= long()) .def(long() <= self) - .def(self <= double()) - .def(double() <= self) + .def(self <= other<amount_t>()) + .def(other<amount_t>() <= self) .def(self > self) .def(self > long()) .def(long() > self) - .def(self > double()) - .def(double() > self) + .def(self > other<amount_t>()) + .def(other<amount_t>() > self) .def(self >= self) .def(self >= long()) .def(long() >= self) - .def(self >= double()) - .def(double() >= self) + .def(self >= other<amount_t>()) + .def(other<amount_t>() >= self) .def(self += self) .def(self += long()) - .def(self += double()) + .def(self += other<amount_t>()) + .def(self += other<balance_t>()) - .def(self + self) - .def(self + long()) - .def(long() + self) - .def(self + double()) - .def(double() + self) + .def(self + self) + .def(self + long()) + .def(long() + self) + .def(self + other<amount_t>()) + .def(other<amount_t>() + self) + .def(self + other<balance_t>()) .def(self -= self) .def(self -= long()) - .def(self -= double()) + .def(self -= other<amount_t>()) + .def(self -= other<balance_t>()) - .def(self - self) - .def(self - long()) - .def(long() - self) - .def(self - double()) - .def(double() - self) + .def(self - self) + .def(self - long()) + .def(long() - self) + .def(self - other<amount_t>()) + .def(other<amount_t>() - self) + .def(self - other<balance_t>()) .def(self *= self) .def(self *= long()) - .def(self *= double()) + .def(self *= other<amount_t>()) - .def(self * self) - .def(self * long()) - .def(long() * self) - .def(self * double()) - .def(double() * self) + .def(self * self) + .def(self * long()) + .def(long() * self) + .def(self * other<amount_t>()) + .def(other<amount_t>() * self) .def(self /= self) .def(self /= long()) - .def(self /= double()) + .def(self /= other<amount_t>()) - .def(self / self) - .def(self / long()) - .def(long() / self) - .def(self / double()) - .def(double() / self) + .def(self / self) + .def(self / long()) + .def(long() / self) + .def(self / other<amount_t>()) + .def(other<amount_t>() / self) .def("negated", &value_t::negated) .def("in_place_negate", &value_t::in_place_negate) @@ -184,15 +215,20 @@ void export_value() .def("__abs__", &value_t::abs) .def("rounded", &value_t::rounded) + .def("in_place_round", &value_t::in_place_round) + .def("truncated", &value_t::truncated) + .def("in_place_truncate", &value_t::in_place_truncate) .def("unrounded", &value_t::unrounded) - + .def("in_place_unround", &value_t::in_place_unround) .def("reduced", &value_t::reduced) .def("in_place_reduce", &value_t::in_place_reduce) - .def("unreduced", &value_t::unreduced) .def("in_place_unreduce", &value_t::in_place_unreduce) .def("value", &value_t::value, value_overloads()) + .def("price", &value_t::price) + .def("exchange_commodities", &value_t::exchange_commodities, + exchange_commodities_overloads()) .def("__nonzero__", &value_t::is_nonzero) .def("is_nonzero", &value_t::is_nonzero) @@ -206,9 +242,6 @@ void export_value() .def("is_boolean", &value_t::is_boolean) .def("set_boolean", &value_t::set_boolean) - .def("is_boolean", &value_t::is_boolean) - .def("set_boolean", &value_t::set_boolean) - .def("is_datetime", &value_t::is_datetime) .def("set_datetime", &value_t::set_datetime) @@ -219,11 +252,17 @@ void export_value() .def("set_long", &value_t::set_long) .def("is_amount", &value_t::is_amount) + .def("is_amount", &value_t::is_amount) + + .def("is_balance", &value_t::is_balance) .def("is_balance", &value_t::is_balance) .def("is_string", &value_t::is_string) .def("set_string", py_set_string) + .def("is_mask", &value_t::is_mask) + .def("is_mask", &value_t::is_mask) + .def("is_sequence", &value_t::is_sequence) .def("set_sequence", &value_t::set_sequence) @@ -232,7 +271,10 @@ void export_value() .def("__int__", &value_t::to_long) .def("to_datetime", &value_t::to_datetime) .def("to_date", &value_t::to_date) + .def("to_amount", &value_t::to_amount) + .def("to_balance", &value_t::to_balance) .def("to_string", &value_t::to_string) + .def("to_mask", &value_t::to_mask) .def("to_sequence", &value_t::to_sequence) .def("__str__", py_dump_relaxed) @@ -240,59 +282,39 @@ void export_value() .def("casted", &value_t::casted) .def("in_place_cast", &value_t::in_place_cast) - .def("simplified", &value_t::simplified) .def("in_place_simplify", &value_t::in_place_simplify) - // jww (2009-02-07): Allow annotating, and retrieving annotations + .def("annotate", &value_t::annotate) + .def("is_annotated", &value_t::is_annotated) +#if 0 + .def("annotation", &value_t::annotation) +#endif .def("strip_annotations", &value_t::strip_annotations) - // jww (2009-01-28): Allow for transparent exchanging with sequence - // protocol objects in Python too; and conversion to a list. #if 0 - // jww (2009-02-07): Methods to implement: - // Allow accepting and returning tuples as sequences - // count_commodities - // has_commodity(COMM) - // decompose .def("__getitem__", &value_t::operator[]) #endif + .def("__getattr__", py_value_getattr) .def("push_back", &value_t::push_back) .def("pop_back", &value_t::pop_back) .def("size", &value_t::size) .def("label", &value_t::label) - .def("dump", &value_t::dump) - .def("print", &value_t::print) - .def("valid", &value_t::valid) - - .def("__getattr__", py_value_getattr) - ; - - enum_< value_t::type_t >("ValueType") - .value("VOID", value_t::VOID) - .value("BOOLEAN", value_t::BOOLEAN) - .value("DATETIME", value_t::DATETIME) - .value("DATE", value_t::DATE) - .value("INTEGER", value_t::INTEGER) - .value("AMOUNT", value_t::AMOUNT) - .value("BALANCE", value_t::BALANCE) - .value("STRING", value_t::STRING) - .value("SEQUENCE", value_t::SEQUENCE) - .value("SCOPE", value_t::SCOPE) ; scope().attr("NULL_VALUE") = NULL_VALUE; scope().attr("string_value") = &string_value; + scope().attr("mask_value") = &mask_value; scope().attr("value_context") = &value_context; register_optional_to_python<value_t>(); - implicitly_convertible<double, value_t>(); implicitly_convertible<long, value_t>(); implicitly_convertible<string, value_t>(); + // jww (2009-11-02): ask mask objects here implicitly_convertible<date_t, value_t>(); implicitly_convertible<datetime_t, value_t>(); diff --git a/src/py_xact.cc b/src/py_xact.cc index b152e272..d98d226c 100644 --- a/src/py_xact.cc +++ b/src/py_xact.cc @@ -32,45 +32,141 @@ #include <system.hh> #include "pyinterp.h" +#include "pyutils.h" +#include "xact.h" +#include "post.h" namespace ledger { using namespace boost::python; -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ +namespace { + + long posts_len(xact_base_t& xact) + { + return xact.posts.size(); } -//EXC_TRANSLATOR(xact_error) + post_t& posts_getitem(xact_base_t& xact, long i) + { + static long last_index = 0; + static xact_base_t * last_xact = NULL; + static posts_list::iterator elem; + + long len = xact.posts.size(); + + if (labs(i) >= len) { + PyErr_SetString(PyExc_IndexError, _("Index out of range")); + throw_error_already_set(); + } + + if (&xact == last_xact && i == last_index + 1) { + last_index = i; + return **++elem; + } + + long x = i < 0 ? len + i : i; + elem = xact.posts.begin(); + while (--x >= 0) + elem++; + + last_xact = &xact; + last_index = i; + + return **elem; + } + +} // unnamed namespace + +using namespace boost::python; void export_xact() { -#if 0 - class_< xact_base_t > ("XactBase") - ; - class_< xact_t > ("Xact") - ; - struct_< xact_finalizer_t > ("XactFinalizer") - ; - class_< auto_xact_t > ("AutoXact") + class_< xact_base_t, bases<item_t> > ("TransactionBase") + .add_property("journal", + make_getter(&xact_base_t::journal, + return_value_policy<reference_existing_object>()), + make_setter(&xact_base_t::journal, + with_custodian_and_ward<1, 2>())) + .add_property("posts", + make_getter(&xact_base_t::posts), + make_setter(&xact_base_t::posts)) + + .def("__len__", posts_len) + .def("__getitem__", posts_getitem, + return_value_policy<reference_existing_object>()) + + .def("add_post", &xact_base_t::add_post, with_custodian_and_ward<1, 2>()) + .def("remove_post", &xact_base_t::add_post) + + .def("finalize", &xact_base_t::finalize) + .def("valid", &xact_base_t::valid) ; - struct_< auto_xact_finalizer_t > ("AutoXactFinalizer") + + class_< xact_t, bases<xact_base_t> > ("Transaction") + .add_property("code", + make_getter(&xact_t::code), + make_setter(&xact_t::code)) + .add_property("payee", + make_getter(&xact_t::payee), + make_setter(&xact_t::payee)) + + .def("add_post", &xact_t::add_post, with_custodian_and_ward<1, 2>()) + + .def("magnitude", &xact_t::magnitude) + .def("idstring", &xact_t::idstring) + .def("id", &xact_t::id) + + .def("lookup", &xact_t::lookup) + + .def("valid", &xact_t::valid) ; - class_< period_xact_t > ("PeriodXact") + + class_< xact_finalizer_t, boost::noncopyable > + ("TransactionFinalizer", no_init) + .def("__call__", &xact_finalizer_t::operator()) ; - class_< func_finalizer_t > ("FuncFinalizer") + + class_< auto_xact_t, bases<xact_base_t> > ("AutomatedTransaction") + .def(init<item_predicate>()) + + .add_property("predicate", + make_getter(&auto_xact_t::predicate), + make_setter(&auto_xact_t::predicate)) + + .def("extend_xact", &auto_xact_t::extend_xact) ; -#endif - //register_optional_to_python<amount_t>(); + class_< auto_xact_finalizer_t, bases<xact_finalizer_t> > + ("AutomatedTransactionFinalizer") + .add_property("journal", + make_getter(&auto_xact_finalizer_t::journal, + return_value_policy<reference_existing_object>()), + make_setter(&auto_xact_finalizer_t::journal, + with_custodian_and_ward<1, 2>())) + .def("__call__", &auto_xact_finalizer_t::operator()) + ; - //implicitly_convertible<string, amount_t>(); + class_< period_xact_t, bases<xact_base_t> > ("PeriodicTransaction") + .def(init<string>()) + + .add_property("period", + make_getter(&period_xact_t::period), + make_setter(&period_xact_t::period)) + .add_property("period_string", + make_getter(&period_xact_t::period_string), + make_setter(&period_xact_t::period_string)) + ; -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); + class_< func_finalizer_t, bases<xact_finalizer_t> > + ("FunctionalFinalizer", init<func_finalizer_t::func_t>()) + .add_property("func", + make_getter(&func_finalizer_t::func), + make_setter(&func_finalizer_t::func)) + .def("__call__", &func_finalizer_t::operator()) + ; - //EXC_TRANSLATE(xact_error); + scope().attr("extend_xact_base") = &extend_xact_base; } } // namespace ledger diff --git a/src/pyinterp.cc b/src/pyinterp.cc index 9ad9a906..f565f2c0 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -41,6 +41,7 @@ shared_ptr<python_interpreter_t> python_session; char * argv0; +void export_account(); void export_amount(); void export_balance(); void export_chain(); @@ -63,6 +64,7 @@ void export_xact(); void initialize_for_python() { + export_account(); export_amount(); export_balance(); export_chain(); diff --git a/src/value.h b/src/value.h index 3c5ce286..2ce90fa2 100644 --- a/src/value.h +++ b/src/value.h @@ -87,8 +87,7 @@ public: * The sequence_t member type abstracts the type used to represent a * resizable "array" of value_t objects. */ - typedef std::vector<value_t> sequence_t; - + typedef std::vector<value_t> sequence_t; typedef sequence_t::iterator iterator; typedef sequence_t::const_iterator const_iterator; typedef sequence_t::difference_type difference_type; diff --git a/tools/Makefile.am b/tools/Makefile.am index 4dd4a871..11f79050 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -205,6 +205,7 @@ lib_LTLIBRARIES += libledger_python.la libledger_python_la_SOURCES = \ src/pyutils.h \ src/pyfstream.h \ + src/py_account.cc \ src/py_amount.cc \ src/py_balance.cc \ src/py_chain.cc \ |