summaryrefslogtreecommitdiff
path: root/src/py_commodity.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/py_commodity.cc')
-rw-r--r--src/py_commodity.cc451
1 files changed, 451 insertions, 0 deletions
diff --git a/src/py_commodity.cc b/src/py_commodity.cc
new file mode 100644
index 00000000..984be5f0
--- /dev/null
+++ b/src/py_commodity.cc
@@ -0,0 +1,451 @@
+/*
+ * 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 "pyutils.h"
+#include "commodity.h"
+#include "annotate.h"
+#include "pool.h"
+
+namespace ledger {
+
+using namespace boost::python;
+
+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_2(commodity_pool_t& pool,
+ commodity_t& commodity,
+ const amount_t& per_unit_cost)
+ {
+ pool.exchange(commodity, per_unit_cost, CURRENT_TIME());
+ }
+ 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);
+ }
+
+ commodity_t * py_pool_getitem(commodity_pool_t& pool, const string& symbol)
+ {
+ commodity_pool_t::commodities_map::iterator i =
+ pool.commodities.find(symbol);
+ if (i == pool.commodities.end()) {
+ PyErr_SetString(PyExc_ValueError,
+ (string("Could not find commodity ") + symbol).c_str());
+ throw boost::python::error_already_set();
+ }
+ return (*i).second;
+ }
+
+ python::list py_pool_keys(commodity_pool_t& pool) {
+ python::list keys;
+ BOOST_REVERSE_FOREACH
+ (const commodity_pool_t::commodities_map::value_type& pair,
+ pool.commodities) {
+ keys.insert(0, pair.first);
+ }
+ return keys;
+ }
+
+ bool py_pool_contains(commodity_pool_t& pool, const string& symbol) {
+ return pool.commodities.find(symbol) != pool.commodities.end();
+ }
+
+ commodity_pool_t::commodities_map::iterator
+ py_pool_commodities_begin(commodity_pool_t& pool) {
+ return pool.commodities.begin();
+ }
+ commodity_pool_t::commodities_map::iterator
+ py_pool_commodities_end(commodity_pool_t& pool) {
+ return pool.commodities.end();
+ }
+
+ typedef transform_iterator
+ <function<string(commodity_pool_t::commodities_map::value_type&)>,
+ commodity_pool_t::commodities_map::iterator>
+ commodities_map_firsts_iterator;
+ commodities_map_firsts_iterator
+
+ py_pool_commodities_keys_begin(commodity_pool_t& pool) {
+ return make_transform_iterator
+ (pool.commodities.begin(),
+ bind(&commodity_pool_t::commodities_map::value_type::first, _1));
+ }
+ commodities_map_firsts_iterator
+ py_pool_commodities_keys_end(commodity_pool_t& pool) {
+ return make_transform_iterator
+ (pool.commodities.end(),
+ bind(&commodity_pool_t::commodities_map::value_type::first, _1));
+ }
+
+ typedef transform_iterator
+ <function<commodity_t *(commodity_pool_t::commodities_map::value_type&)>,
+ commodity_pool_t::commodities_map::iterator>
+ commodities_map_seconds_iterator;
+
+ commodities_map_seconds_iterator
+ py_pool_commodities_values_begin(commodity_pool_t& pool) {
+ return make_transform_iterator
+ (pool.commodities.begin(),
+ bind(&commodity_pool_t::commodities_map::value_type::second, _1));
+ }
+ commodities_map_seconds_iterator
+ py_pool_commodities_values_end(commodity_pool_t& pool) {
+ return make_transform_iterator
+ (pool.commodities.end(),
+ bind(&commodity_pool_t::commodities_map::value_type::second, _1));
+ }
+
+ 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);
+ }
+
+ commodity_t& py_commodity_referent(commodity_t& comm) {
+ return comm.referent();
+ }
+ commodity_t& py_annotated_commodity_referent(annotated_commodity_t& comm) {
+ return comm.referent();
+ }
+
+ commodity_t& py_strip_annotations_0(commodity_t& comm) {
+ return comm.strip_annotations(keep_details_t());
+ }
+ commodity_t& py_strip_annotations_1(commodity_t& comm,
+ const keep_details_t& keep) {
+ return comm.strip_annotations(keep);
+ }
+
+ commodity_t& py_strip_ann_annotations_0(annotated_commodity_t& comm) {
+ return comm.strip_annotations(keep_details_t());
+ }
+ commodity_t& py_strip_ann_annotations_1(annotated_commodity_t& comm,
+ const keep_details_t& keep) {
+ return comm.strip_annotations(keep);
+ }
+
+ boost::optional<amount_t> py_price(annotation_t& ann) {
+ return ann.price;
+ }
+ boost::optional<amount_t> py_set_price(annotation_t& ann,
+ const boost::optional<amount_t>& price) {
+ return ann.price = price;
+ }
+
+ PyObject * py_commodity_unicode(commodity_t& commodity) {
+ return str_to_py_unicode(commodity.symbol());
+ }
+
+} // unnamed namespace
+
+void export_commodity()
+{
+ class_< commodity_pool_t, shared_ptr<commodity_pool_t>,
+ boost::noncopyable > ("CommodityPool", no_init)
+ .add_property("null_commodity",
+ make_getter(&commodity_pool_t::null_commodity,
+ return_internal_reference<>()))
+ .add_property("default_commodity",
+ make_getter(&commodity_pool_t::default_commodity,
+ return_internal_reference<>()),
+ 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_2, with_custodian_and_ward<1, 2>())
+ .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>())
+
+ .def("__getitem__", py_pool_getitem,
+ return_value_policy<reference_existing_object>())
+ .def("keys", py_pool_keys)
+ .def("has_key", py_pool_contains)
+ .def("__contains__", py_pool_contains)
+ .def("__iter__", range<return_value_policy<reference_existing_object> >
+ (py_pool_commodities_begin, py_pool_commodities_end))
+ .def("iteritems", range<return_value_policy<reference_existing_object> >
+ (py_pool_commodities_begin, py_pool_commodities_end))
+ .def("iterkeys", range<>(py_pool_commodities_keys_begin,
+ py_pool_commodities_keys_end))
+ .def("itervalues", range<return_value_policy<reference_existing_object> >
+ (py_pool_commodities_values_begin, py_pool_commodities_values_end))
+ ;
+
+ map_value_type_converter<commodity_pool_t::commodities_map>();
+
+ scope().attr("commodities") = commodity_pool_t::current_pool;
+
+ scope().attr("COMMODITY_STYLE_DEFAULTS") = COMMODITY_STYLE_DEFAULTS;
+ scope().attr("COMMODITY_STYLE_SUFFIXED") = COMMODITY_STYLE_SUFFIXED;
+ scope().attr("COMMODITY_STYLE_SEPARATED") = COMMODITY_STYLE_SEPARATED;
+ scope().attr("COMMODITY_STYLE_EUROPEAN") = COMMODITY_STYLE_EUROPEAN;
+ scope().attr("COMMODITY_STYLE_THOUSANDS") = COMMODITY_STYLE_THOUSANDS;
+ 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
+ .add_property("flags",
+ &supports_flags<uint_least16_t>::flags,
+ &supports_flags<uint_least16_t>::set_flags)
+ .def("has_flags", &delegates_flags<uint_least16_t>::has_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("__str__", &commodity_t::symbol)
+ .def("__unicode__", py_commodity_unicode)
+ .def("__nonzero__", &commodity_t::operator bool)
+
+ .def(self == self)
+
+ .def("symbol_needs_quotes", &commodity_t::symbol_needs_quotes)
+ .staticmethod("symbol_needs_quotes")
+
+ .add_property("referent",
+ make_function(py_commodity_referent,
+ return_value_policy<reference_existing_object>()))
+
+ .def("has_annotation", &commodity_t::has_annotation)
+ .def("strip_annotations", py_strip_annotations_0,
+ return_value_policy<reference_existing_object>())
+ .def("strip_annotations", py_strip_annotations_1,
+ return_value_policy<reference_existing_object>())
+ .def("write_annotations", &commodity_t::write_annotations)
+
+ .def("pool", &commodity_t::pool,
+ return_value_policy<reference_existing_object>())
+
+ .add_property("base_symbol", &commodity_t::base_symbol)
+ .add_property("symbol", &commodity_t::symbol)
+ .add_property("mapping_key", &commodity_t::mapping_key)
+
+ .add_property("name", &commodity_t::name, &commodity_t::set_name)
+ .add_property("note", &commodity_t::note, &commodity_t::set_note)
+ .add_property("precision", &commodity_t::precision,
+ &commodity_t::set_precision)
+ .add_property("smaller", &commodity_t::smaller, &commodity_t::set_smaller)
+ .add_property("larger", &commodity_t::larger, &commodity_t::set_larger)
+
+ .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_< annotation_t > ("Annotation", no_init)
+#if 1
+ .add_property("flags", &supports_flags<>::flags,
+ &supports_flags<>::set_flags)
+ .def("has_flags", &supports_flags<>::has_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", py_price, py_set_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_< 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>())
+
+ .add_property("referent",
+ make_function(py_annotated_commodity_referent,
+ return_value_policy<reference_existing_object>()))
+
+ .def("strip_annotations", py_strip_ann_annotations_0,
+ return_value_policy<reference_existing_object>())
+ .def("strip_annotations", py_strip_ann_annotations_1,
+ return_value_policy<reference_existing_object>())
+ .def("write_annotations", &annotated_commodity_t::write_annotations)
+ ;
+}
+
+} // namespace ledger