summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-02-24 16:08:49 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-02-24 16:08:49 -0400
commit1799ed3a2adf1af7ed08b3b3ded3594a4c0e184e (patch)
treeba0ad178f2ceefa0fad5975f6247e3f20de41344 /src
parent5ad9bc3951fcbecb5fcf7c1127e8f91e547fd37b (diff)
downloadfork-ledger-1799ed3a2adf1af7ed08b3b3ded3594a4c0e184e.tar.gz
fork-ledger-1799ed3a2adf1af7ed08b3b3ded3594a4c0e184e.tar.bz2
fork-ledger-1799ed3a2adf1af7ed08b3b3ded3594a4c0e184e.zip
Moved python/*.cc files into src/
This is because soon, I intend to have real Python source files in python/.
Diffstat (limited to 'src')
-rw-r--r--src/py_amount.cc340
-rw-r--r--src/py_balance.cc270
-rw-r--r--src/py_chain.cc62
-rw-r--r--src/py_commodity.cc82
-rw-r--r--src/py_expr.cc68
-rw-r--r--src/py_flags.cc68
-rw-r--r--src/py_format.cc64
-rw-r--r--src/py_global.cc64
-rw-r--r--src/py_item.cc64
-rw-r--r--src/py_journal.cc437
-rw-r--r--src/py_post.cc64
-rw-r--r--src/py_report.cc64
-rw-r--r--src/py_scope.cc78
-rw-r--r--src/py_session.cc64
-rw-r--r--src/py_timelog.cc66
-rw-r--r--src/py_times.cc146
-rw-r--r--src/py_utils.cc170
-rw-r--r--src/py_value.cc304
-rw-r--r--src/py_xact.cc76
-rw-r--r--src/pyfstream.h203
-rw-r--r--src/pyinterp.cc296
-rw-r--r--src/pyinterp.h134
-rw-r--r--src/pyledger.cc50
-rw-r--r--src/pyledger.h38
-rw-r--r--src/pyutils.h113
25 files changed, 3385 insertions, 0 deletions
diff --git a/src/py_amount.cc b/src/py_amount.cc
new file mode 100644
index 00000000..980e049b
--- /dev/null
+++ b/src/py_amount.cc
@@ -0,0 +1,340 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "amount.h"
+
+#include <boost/python/exception_translator.hpp>
+#include <boost/python/implicit.hpp>
+#include <boost/python/args.hpp>
+
+namespace ledger {
+
+using namespace boost::python;
+
+boost::optional<amount_t> py_value_0(const amount_t& amount) {
+ return amount.value();
+}
+boost::optional<amount_t> py_value_1(const amount_t& amount,
+ const bool primary_only) {
+ return amount.value(primary_only);
+}
+boost::optional<amount_t> py_value_2(const amount_t& amount,
+ const bool primary_only,
+ const boost::optional<datetime_t>& moment) {
+ return amount.value(primary_only, moment);
+}
+boost::optional<amount_t> py_value_3(const amount_t& amount,
+ const bool primary_only,
+ const boost::optional<datetime_t>& moment,
+ const boost::optional<commodity_t&>& in_terms_of) {
+ return amount.value(primary_only, moment, in_terms_of);
+}
+
+void py_parse_2(amount_t& amount, object in, unsigned char flags) {
+ if (PyFile_Check(in.ptr())) {
+ pyifstream instr(reinterpret_cast<PyFileObject *>(in.ptr()));
+ amount.parse(instr, flags);
+ } else {
+ PyErr_SetString(PyExc_IOError,
+ "Argument to amount.parse(file) is not a file object");
+ }
+}
+void py_parse_1(amount_t& amount, object in) {
+ py_parse_2(amount, in, 0);
+}
+
+void py_parse_str_1(amount_t& amount, const string& str) {
+ amount.parse(str);
+}
+void py_parse_str_2(amount_t& amount, const string& str, unsigned char flags) {
+ amount.parse(str, flags);
+}
+
+void py_print(amount_t& amount, object out)
+{
+ if (PyFile_Check(out.ptr())) {
+ pyofstream outstr(reinterpret_cast<PyFileObject *>(out.ptr()));
+ amount.print(outstr);
+ } else {
+ PyErr_SetString(PyExc_IOError,
+ "Argument to amount.print_(file) is not a file object");
+ }
+}
+
+void py_amount_initialize() {
+ amount_t::initialize();
+}
+
+#define EXC_TRANSLATOR(type) \
+ void exc_translate_ ## type(const type& err) { \
+ PyErr_SetString(PyExc_ArithmeticError, err.what()); \
+ }
+
+EXC_TRANSLATOR(amount_error)
+
+void export_amount()
+{
+ class_< amount_t > ("Amount")
+ .def("initialize", py_amount_initialize) // only for the PyUnitTests
+ .staticmethod("initialize")
+ .def("shutdown", &amount_t::shutdown)
+ .staticmethod("shutdown")
+
+ .add_static_property("current_pool",
+ make_getter(&amount_t::current_pool,
+ return_value_policy<reference_existing_object>()))
+
+ .add_static_property("stream_fullstrings",
+ make_getter(&amount_t::stream_fullstrings),
+ make_setter(&amount_t::stream_fullstrings))
+
+#if 0
+ .def(init<double>())
+#endif
+ .def(init<long>())
+ .def(init<std::string>())
+
+ .def("exact", &amount_t::exact, args("value"),
+ "Construct an amount object whose display precision is always equal to its\n\
+internal precision.")
+ .staticmethod("exact")
+
+ .def(init<amount_t>())
+
+ .def("compare", &amount_t::compare)
+
+ .def(self == self)
+ .def(self == long())
+ .def(long() == self)
+#if 0
+ .def(self == double())
+ .def(double() == self)
+#endif
+
+ .def(self != self)
+ .def(self != long())
+ .def(long() != self)
+#if 0
+ .def(self != double())
+ .def(double() != self)
+#endif
+
+ .def(! self)
+
+ .def(self < self)
+ .def(self < long())
+ .def(long() < self)
+#if 0
+ .def(self < double())
+ .def(double() < self)
+#endif
+
+ .def(self <= self)
+ .def(self <= long())
+ .def(long() <= self)
+#if 0
+ .def(self <= double())
+ .def(double() <= self)
+#endif
+
+ .def(self > self)
+ .def(self > long())
+ .def(long() > self)
+#if 0
+ .def(self > double())
+ .def(double() > self)
+#endif
+
+ .def(self >= self)
+ .def(self >= long())
+ .def(long() >= self)
+#if 0
+ .def(self >= double())
+ .def(double() >= self)
+#endif
+
+ .def(self += self)
+ .def(self += long())
+#if 0
+ .def(self += double())
+#endif
+
+ .def(self + self)
+ .def(self + long())
+ .def(long() + self)
+#if 0
+ .def(self + double())
+ .def(double() + self)
+#endif
+
+ .def(self -= self)
+ .def(self -= long())
+#if 0
+ .def(self -= double())
+#endif
+
+ .def(self - self)
+ .def(self - long())
+ .def(long() - self)
+#if 0
+ .def(self - double())
+ .def(double() - self)
+#endif
+
+ .def(self *= self)
+ .def(self *= long())
+#if 0
+ .def(self *= double())
+#endif
+
+ .def(self * self)
+ .def(self * long())
+ .def(long() * self)
+#if 0
+ .def(self * double())
+ .def(double() * self)
+#endif
+
+ .def(self /= self)
+ .def(self /= long())
+#if 0
+ .def(self /= double())
+#endif
+
+ .def(self / self)
+ .def(self / long())
+ .def(long() / self)
+#if 0
+ .def(self / double())
+ .def(double() / self)
+#endif
+
+ .def("precision", &amount_t::precision)
+
+ .def("negated", &amount_t::negated)
+ .def("in_place_negate", &amount_t::in_place_negate,
+ return_value_policy<reference_existing_object>())
+ .def(- self)
+
+ .def("abs", &amount_t::abs)
+ .def("__abs__", &amount_t::abs)
+
+ .def("rounded", &amount_t::rounded)
+ .def("unrounded", &amount_t::unrounded)
+
+ .def("reduced", &amount_t::reduced)
+ .def("in_place_reduce", &amount_t::in_place_reduce,
+ return_value_policy<reference_existing_object>())
+
+ .def("unreduced", &amount_t::unreduced)
+ .def("in_place_unreduce", &amount_t::in_place_unreduce,
+ return_value_policy<reference_existing_object>())
+
+ .def("value", py_value_0)
+ .def("value", py_value_1)
+ .def("value", py_value_2)
+ .def("value", py_value_3)
+
+ .def("sign", &amount_t::sign)
+ .def("__nonzero__", &amount_t::is_nonzero)
+ .def("is_nonzero", &amount_t::is_nonzero)
+ .def("is_zero", &amount_t::is_zero)
+ .def("is_realzero", &amount_t::is_realzero)
+ .def("is_null", &amount_t::is_null)
+
+ .def("to_double", &amount_t::to_double)
+ .def("__float__", &amount_t::to_double)
+ .def("to_long", &amount_t::to_long)
+ .def("__int__", &amount_t::to_long)
+ .def("to_string", &amount_t::to_string)
+ .def("__str__", &amount_t::to_string)
+ .def("to_fullstring", &amount_t::to_fullstring)
+ .def("__repr__", &amount_t::to_fullstring)
+
+ .def("fits_in_long", &amount_t::fits_in_long)
+
+ .def("quantity_string", &amount_t::quantity_string)
+
+ .def("commodity", &amount_t::commodity,
+ return_value_policy<reference_existing_object>())
+ .def("set_commodity", &amount_t::set_commodity,
+ with_custodian_and_ward<1, 2>())
+
+ .def("has_commodity", &amount_t::has_commodity)
+ .def("clear_commodity", &amount_t::clear_commodity)
+ .def("number", &amount_t::number)
+
+ .def("annotate", &amount_t::annotate)
+ .def("is_annotated", &amount_t::is_annotated)
+#if 0
+ .def("annotation", &amount_t::annotation)
+#endif
+ .def("strip_annotations", &amount_t::strip_annotations)
+
+ .def("parse", py_parse_1)
+ .def("parse", py_parse_2)
+ .def("parse", py_parse_str_1)
+ .def("parse", py_parse_str_2)
+
+ .def("parse_conversion", &amount_t::parse_conversion)
+ .staticmethod("parse_conversion")
+
+ .def("print_", py_print)
+
+ .def("dump", &amount_t::dump)
+
+ .def("valid", &amount_t::valid)
+ ;
+
+ enum_< amount_t::parse_flags_enum_t >("AmountParse")
+ .value("DEFAULT", amount_t::PARSE_DEFAULT)
+ .value("NO_MIGRATE", amount_t::PARSE_NO_MIGRATE)
+ .value("NO_REDUCE", amount_t::PARSE_NO_REDUCE)
+ .value("SOFT_FAIL", amount_t::PARSE_SOFT_FAIL)
+ ;
+
+ register_optional_to_python<amount_t>();
+
+#if 0
+ implicitly_convertible<double, amount_t>();
+#endif
+ implicitly_convertible<long, amount_t>();
+ implicitly_convertible<string, amount_t>();
+
+#define EXC_TRANSLATE(type) \
+ register_exception_translator<type>(&exc_translate_ ## type);
+
+ EXC_TRANSLATE(amount_error);
+}
+
+} // namespace ledger
diff --git a/src/py_balance.cc b/src/py_balance.cc
new file mode 100644
index 00000000..4215519c
--- /dev/null
+++ b/src/py_balance.cc
@@ -0,0 +1,270 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "balance.h"
+
+#include <boost/python/exception_translator.hpp>
+#include <boost/python/implicit.hpp>
+#include <boost/python/args.hpp>
+
+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(balance_error)
+
+void export_balance()
+{
+#if 0
+ class_< balance_t > ("Balance")
+ ;
+#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(balance_error);
+}
+
+} // namespace ledger
+
+#if 0
+unsigned int balance_len(balance_t& bal)
+{
+ return bal.amounts.size();
+}
+
+amount_t balance_getitem(balance_t& bal, int i)
+{
+ std::size_t len = bal.amounts.size();
+
+ if (abs(i) >= len) {
+ PyErr_SetString(PyExc_IndexError, "Index out of range");
+ throw_error_already_set();
+ }
+
+ int x = i < 0 ? len + i : i;
+ balance_t::amounts_map::iterator elem = bal.amounts.begin();
+ while (--x >= 0)
+ elem++;
+
+ return (*elem).second;
+}
+
+unsigned int balance_pair_len(balance_pair_t& bal_pair)
+{
+ return balance_len(bal_pair.quantity);
+}
+
+amount_t balance_pair_getitem(balance_pair_t& bal_pair, int i)
+{
+ return balance_getitem(bal_pair.quantity, i);
+}
+
+void export_balance()
+{
+ class_< balance_t > ("Balance")
+ .def(init<balance_t>())
+ .def(init<amount_t>())
+ .def(init<long>())
+ .def(init<unsigned long>())
+ .def(init<double>())
+
+ .def(self += self)
+ .def(self += other<amount_t>())
+ .def(self += long())
+ .def(self + self)
+ .def(self + other<amount_t>())
+ .def(self + long())
+ .def(self -= self)
+ .def(self -= other<amount_t>())
+ .def(self -= long())
+ .def(self - self)
+ .def(self - other<amount_t>())
+ .def(self - long())
+ .def(self *= self)
+ .def(self *= other<amount_t>())
+ .def(self *= long())
+ .def(self * self)
+ .def(self * other<amount_t>())
+ .def(self * long())
+ .def(self /= self)
+ .def(self /= other<amount_t>())
+ .def(self /= long())
+ .def(self / self)
+ .def(self / other<amount_t>())
+ .def(self / long())
+ .def(- self)
+
+ .def(self < self)
+ .def(self < other<amount_t>())
+ .def(self < long())
+ .def(self <= self)
+ .def(self <= other<amount_t>())
+ .def(self <= long())
+ .def(self > self)
+ .def(self > other<amount_t>())
+ .def(self > long())
+ .def(self >= self)
+ .def(self >= other<amount_t>())
+ .def(self >= long())
+ .def(self == self)
+ .def(self == other<amount_t>())
+ .def(self == long())
+ .def(self != self)
+ .def(self != other<amount_t>())
+ .def(self != long())
+ .def(! self)
+
+ .def(self_ns::str(self))
+
+ .def("__abs__", &balance_t::abs)
+ .def("__len__", balance_len)
+ .def("__getitem__", balance_getitem)
+
+ .def("valid", &balance_t::valid)
+
+ .def("realzero", &balance_t::realzero)
+ .def("amount", &balance_t::amount)
+ .def("value", &balance_t::value)
+ .def("price", &balance_t::price)
+ .def("date", &balance_t::date)
+ .def("strip_annotations", &balance_t::strip_annotations)
+ .def("write", &balance_t::write)
+ .def("round", &balance_t::round)
+ .def("negate", &balance_t::negate)
+ .def("negated", &balance_t::negated)
+ ;
+
+ class_< balance_pair_t > ("BalancePair")
+ .def(init<balance_pair_t>())
+ .def(init<balance_t>())
+ .def(init<amount_t>())
+ .def(init<long>())
+ .def(init<unsigned long>())
+ .def(init<double>())
+
+ .def(self += self)
+ .def(self += other<balance_t>())
+ .def(self += other<amount_t>())
+ .def(self += long())
+ .def(self + self)
+ .def(self + other<balance_t>())
+ .def(self + other<amount_t>())
+ .def(self + long())
+ .def(self -= self)
+ .def(self -= other<balance_t>())
+ .def(self -= other<amount_t>())
+ .def(self -= long())
+ .def(self - self)
+ .def(self - other<balance_t>())
+ .def(self - other<amount_t>())
+ .def(self - long())
+ .def(self *= self)
+ .def(self *= other<balance_t>())
+ .def(self *= other<amount_t>())
+ .def(self *= long())
+ .def(self * self)
+ .def(self * other<balance_t>())
+ .def(self * other<amount_t>())
+ .def(self * long())
+ .def(self /= self)
+ .def(self /= other<balance_t>())
+ .def(self /= other<amount_t>())
+ .def(self /= long())
+ .def(self / self)
+ .def(self / other<balance_t>())
+ .def(self / other<amount_t>())
+ .def(self / long())
+ .def(- self)
+
+ .def(self < self)
+ .def(self < other<balance_t>())
+ .def(self < other<amount_t>())
+ .def(self < long())
+ .def(self <= self)
+ .def(self <= other<balance_t>())
+ .def(self <= other<amount_t>())
+ .def(self <= long())
+ .def(self > self)
+ .def(self > other<balance_t>())
+ .def(self > other<amount_t>())
+ .def(self > long())
+ .def(self >= self)
+ .def(self >= other<balance_t>())
+ .def(self >= other<amount_t>())
+ .def(self >= long())
+ .def(self == self)
+ .def(self == other<balance_t>())
+ .def(self == other<amount_t>())
+ .def(self == long())
+ .def(self != self)
+ .def(self != other<balance_t>())
+ .def(self != other<amount_t>())
+ .def(self != long())
+ .def(! self)
+
+ .def(self_ns::str(self))
+
+ .def("__abs__", &balance_pair_t::abs)
+ .def("__len__", balance_pair_len)
+ .def("__getitem__", balance_pair_getitem)
+
+ .def("valid", &balance_pair_t::valid)
+
+ .def("realzero", &balance_pair_t::realzero)
+ .def("amount", &balance_pair_t::amount)
+ .def("value", &balance_pair_t::value)
+ .def("price", &balance_pair_t::price)
+ .def("date", &balance_pair_t::date)
+ .def("strip_annotations", &balance_pair_t::strip_annotations)
+ .def("write", &balance_pair_t::write)
+ .def("round", &balance_pair_t::round)
+ .def("negate", &balance_pair_t::negate)
+ .def("negated", &balance_pair_t::negated)
+
+ .add_property("cost",
+ make_getter(&balance_pair_t::cost,
+ return_value_policy<reference_existing_object>()))
+ ;
+}
+#endif
diff --git a/src/py_chain.cc b/src/py_chain.cc
new file mode 100644
index 00000000..279d4375
--- /dev/null
+++ b/src/py_chain.cc
@@ -0,0 +1,62 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "chain.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(chain_error)
+
+void export_chain()
+{
+#if 0
+ struct_< item_handler_t > ("ItemHandler")
+ ;
+#endif
+
+ //register_optional_to_python<amount_t>();
+
+#define EXC_TRANSLATE(type) \
+ register_exception_translator<type>(&exc_translate_ ## type);
+
+ //EXC_TRANSLATE(chain_error);
+}
+
+} // namespace ledger
diff --git a/src/py_commodity.cc b/src/py_commodity.cc
new file mode 100644
index 00000000..7b101ec1
--- /dev/null
+++ b/src/py_commodity.cc
@@ -0,0 +1,82 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "amount.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);
+}
+
+void export_commodity()
+{
+ 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;
+
+ class_< commodity_t, bases<>,
+ commodity_t, boost::noncopyable > ("Commodity", no_init)
+ .def(self == self)
+
+ .def("drop_flags", &commodity_t::drop_flags)
+
+ .def("add_price", py_add_price)
+
+ .def("precision", &commodity_t::precision)
+ ;
+
+#if 0
+ class_< annotation_t, bases<>,
+ commodity_t, boost::noncopyable > ("Annotation", no_init)
+ ;
+ class_< keep_details_t, bases<>,
+ commodity_t, boost::noncopyable > ("KeepDetails", no_init)
+ ;
+ class_< annotated_commodity_t, bases<>,
+ commodity_t, boost::noncopyable > ("AnnotatedCommodity", no_init)
+ ;
+#endif
+}
+
+} // namespace ledger
diff --git a/src/py_expr.cc b/src/py_expr.cc
new file mode 100644
index 00000000..047fd2bc
--- /dev/null
+++ b/src/py_expr.cc
@@ -0,0 +1,68 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "expr.h"
+
+namespace ledger {
+
+using namespace boost::python;
+
+namespace {
+ value_t py_expr_call(expr_t& expr)
+ {
+ return expr.calc();
+ }
+}
+
+void export_expr()
+{
+ class_< expr_t > ("Expr")
+ .def(init<string>())
+
+ .def("__nonzero__", &expr_t::operator bool)
+ .def("text", &expr_t::text)
+ .def("set_text", &expr_t::set_text)
+
+ //.def("parse", &expr_t::parse)
+
+ .def("__call__", py_expr_call)
+ .def("compile", &expr_t::compile)
+ //.def("calc", &expr_t::calc)
+
+ .def("is_constant", &expr_t::is_constant)
+
+ //.def("constant_value", &expr_t::constant_value)
+ ;
+}
+
+} // namespace ledger
diff --git a/src/py_flags.cc b/src/py_flags.cc
new file mode 100644
index 00000000..440c81c6
--- /dev/null
+++ b/src/py_flags.cc
@@ -0,0 +1,68 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "flags.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(flags_error)
+
+void export_flags()
+{
+#if 0
+ class_< supports_flags > ("SupportsFlags")
+ ;
+ class_< basic_flags_t > ("BasicFlags")
+ ;
+ class_< delegates_flags > ("DelegatesFlags")
+ ;
+#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(flags_error);
+}
+
+} // namespace ledger
diff --git a/src/py_format.cc b/src/py_format.cc
new file mode 100644
index 00000000..2880cf3e
--- /dev/null
+++ b/src/py_format.cc
@@ -0,0 +1,64 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "format.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(format_error)
+
+void export_format()
+{
+#if 0
+ class_< format_t > ("Format")
+ ;
+#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(format_error);
+}
+
+} // namespace ledger
diff --git a/src/py_global.cc b/src/py_global.cc
new file mode 100644
index 00000000..c064f9d8
--- /dev/null
+++ b/src/py_global.cc
@@ -0,0 +1,64 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "global.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(global_error)
+
+void export_global()
+{
+#if 0
+ class_< global_scope_t > ("GlobalScope")
+ ;
+#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(global_error);
+}
+
+} // namespace ledger
diff --git a/src/py_item.cc b/src/py_item.cc
new file mode 100644
index 00000000..f0e3f440
--- /dev/null
+++ b/src/py_item.cc
@@ -0,0 +1,64 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "item.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(item_error)
+
+void export_item()
+{
+#if 0
+ class_< item_t > ("Item")
+ ;
+#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(item_error);
+}
+
+} // namespace ledger
diff --git a/src/py_journal.cc b/src/py_journal.cc
new file mode 100644
index 00000000..b0328844
--- /dev/null
+++ b/src/py_journal.cc
@@ -0,0 +1,437 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "journal.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
+
+#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();
+
+ if (abs(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;
+ }
+
+ int x = i < 0 ? len + i : i;
+ elem = xact.posts.begin();
+ while (--x >= 0)
+ elem++;
+
+ last_xact = &xact;
+ last_index = i;
+
+ return **elem;
+}
+
+unsigned int xacts_len(journal_t& journal)
+{
+ return journal.xacts.size();
+}
+
+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;
+
+ std::size_t len = journal.xacts.size();
+
+ if (abs(i) >= len) {
+ PyErr_SetString(PyExc_IndexError, "Index out of range");
+ throw_error_already_set();
+ }
+
+ if (&journal == last_journal && i == last_index + 1) {
+ last_index = i;
+ return **++elem;
+ }
+
+ int x = i < 0 ? len + i : i;
+ elem = journal.xacts.begin();
+ while (--x >= 0)
+ elem++;
+
+ last_journal = &journal;
+ last_index = i;
+
+ return **elem;
+}
+
+unsigned int accounts_len(account_t& account)
+{
+ return account.accounts.size();
+}
+
+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;
+
+ std::size_t len = account.accounts.size();
+
+ if (abs(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;
+ }
+
+ int x = i < 0 ? len + i : i;
+ elem = account.accounts.begin();
+ while (--x >= 0)
+ elem++;
+
+ last_account = &account;
+ last_index = i;
+
+ return *(*elem).second;
+}
+
+PyObject * py_account_get_data(account_t& account)
+{
+ return (PyObject *) account.data;
+}
+
+void py_account_set_data(account_t& account, PyObject * obj)
+{
+ account.data = obj;
+}
+
+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);
+ }
+};
+
+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;
+ }
+}
+
+void py_run_xact_finalizers(journal_t& journal, xact_t& xact, bool post)
+{
+ run_hooks(journal.xact_finalize_hooks, xact, post);
+}
+
+#define EXC_TRANSLATOR(type) \
+ void exc_translate_ ## type(const type& err) { \
+ PyErr_SetString(PyExc_RuntimeError, err.what()); \
+ }
+
+EXC_TRANSLATOR(balance_error)
+EXC_TRANSLATOR(interval_expr_error)
+EXC_TRANSLATOR(format_error)
+EXC_TRANSLATOR(parse_error)
+
+value_t py_post_amount(post_t * post) {
+ return value_t(post->amount);
+}
+
+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;
+}
+
+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_< 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)
+ .add_property("data", py_account_get_data, py_account_set_data)
+ .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>())
+
+ .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)
+
+ .def("add_account", &journal_t::add_account)
+ .def("remove_account", &journal_t::remove_account)
+
+ .def("find_account", py_find_account_1, return_internal_reference<1>())
+ .def("find_account", py_find_account_2, return_internal_reference<1>())
+ .def("find_account_re", &journal_t::find_account_re,
+ return_internal_reference<1>())
+
+ .def("add_xact", py_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("valid", &xact_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
diff --git a/src/py_post.cc b/src/py_post.cc
new file mode 100644
index 00000000..a60b79f9
--- /dev/null
+++ b/src/py_post.cc
@@ -0,0 +1,64 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.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()); \
+ }
+
+//EXC_TRANSLATOR(post_error)
+
+void export_post()
+{
+#if 0
+ class_< post_t > ("Post")
+ ;
+#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(post_error);
+}
+
+} // namespace ledger
diff --git a/src/py_report.cc b/src/py_report.cc
new file mode 100644
index 00000000..1a42b1d7
--- /dev/null
+++ b/src/py_report.cc
@@ -0,0 +1,64 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "report.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(report_error)
+
+void export_report()
+{
+#if 0
+ class_< report_t > ("Report")
+ ;
+#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(report_error);
+}
+
+} // namespace ledger
diff --git a/src/py_scope.cc b/src/py_scope.cc
new file mode 100644
index 00000000..55f779d2
--- /dev/null
+++ b/src/py_scope.cc
@@ -0,0 +1,78 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "scope.h"
+
+namespace ledger {
+
+using namespace boost::python;
+
+namespace {
+ void py_scope_define(scope_t& scope, const string& name, expr_t& def)
+ {
+ return scope.define(name, def.get_op());
+ }
+
+ expr_t py_scope_lookup(scope_t& scope, const string& name)
+ {
+ return scope.lookup(name);
+ }
+
+ expr_t py_scope_getattr(scope_t& scope, const string& name)
+ {
+ return scope.lookup(name);
+ }
+
+ struct scope_wrapper : public scope_t
+ {
+ PyObject * self;
+
+ scope_wrapper(PyObject * self_) : self(self_) {}
+
+ virtual expr_t::ptr_op_t lookup(const string&) {
+ return NULL;
+ }
+ };
+}
+
+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)
+ ;
+}
+
+} // namespace ledger
diff --git a/src/py_session.cc b/src/py_session.cc
new file mode 100644
index 00000000..108dcc3c
--- /dev/null
+++ b/src/py_session.cc
@@ -0,0 +1,64 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "session.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(session_error)
+
+void export_session()
+{
+#if 0
+ class_< session_t > ("Session")
+ ;
+#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(session_error);
+}
+
+} // namespace ledger
diff --git a/src/py_timelog.cc b/src/py_timelog.cc
new file mode 100644
index 00000000..03416ec2
--- /dev/null
+++ b/src/py_timelog.cc
@@ -0,0 +1,66 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "timelog.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(timelog_error)
+
+void export_timelog()
+{
+#if 0
+ class_< time_xact_t > ("TimeXact")
+ ;
+ class_< time_log_t > ("TimeLog")
+ ;
+#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(timelog_error);
+}
+
+} // namespace ledger
diff --git a/src/py_times.cc b/src/py_times.cc
new file mode 100644
index 00000000..f209929a
--- /dev/null
+++ b/src/py_times.cc
@@ -0,0 +1,146 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+
+// jww (2007-05-04): Convert time duration objects to PyDelta
+
+namespace ledger {
+
+using namespace boost::python;
+
+typedef boost::gregorian::date date;
+
+#define MY_PyDateTime_IMPORT \
+ PyDateTimeAPI = (PyDateTime_CAPI*) \
+ PyCObject_Import(const_cast<char *>("datetime"), \
+ const_cast<char *>("datetime_CAPI"))
+
+struct date_to_python
+{
+ static PyObject* convert(const date& dte)
+ {
+ MY_PyDateTime_IMPORT;
+ return PyDate_FromDate(dte.year(), dte.month(), dte.day());
+ }
+};
+
+struct date_from_python
+{
+ static void* convertible(PyObject* obj_ptr)
+ {
+ MY_PyDateTime_IMPORT;
+ if (PyDate_Check(obj_ptr)) return obj_ptr;
+ return 0;
+ }
+
+ static void construct(PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
+ {
+ MY_PyDateTime_IMPORT;
+ int y = PyDateTime_GET_YEAR(obj_ptr);
+ int m = PyDateTime_GET_MONTH(obj_ptr);
+ int d = PyDateTime_GET_DAY(obj_ptr);
+ date* dte = new date(y,m,d);
+ data->convertible = (void*)dte;
+ }
+};
+
+typedef register_python_conversion<date, date_to_python, date_from_python>
+ date_python_conversion;
+
+
+struct datetime_to_python
+{
+ static PyObject* convert(const datetime_t& moment)
+ {
+ MY_PyDateTime_IMPORT;
+ date dte = moment.date();
+ datetime_t::time_duration_type tod = moment.time_of_day();
+ return PyDateTime_FromDateAndTime(dte.year(), dte.month(), dte.day(),
+ tod.hours(), tod.minutes(), tod.seconds(),
+ tod.total_microseconds() % 1000000);
+ }
+};
+
+struct datetime_from_python
+{
+ static void* convertible(PyObject* obj_ptr)
+ {
+ MY_PyDateTime_IMPORT;
+ if(PyDateTime_Check(obj_ptr)) return obj_ptr;
+ return 0;
+ }
+
+ static void construct(PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
+ {
+ MY_PyDateTime_IMPORT;
+ int y = PyDateTime_GET_YEAR(obj_ptr);
+ int m = PyDateTime_GET_MONTH(obj_ptr);
+ int d = PyDateTime_GET_DAY(obj_ptr);
+ int h = PyDateTime_DATE_GET_HOUR(obj_ptr);
+ int min = PyDateTime_DATE_GET_MINUTE(obj_ptr);
+ int s = PyDateTime_DATE_GET_SECOND(obj_ptr);
+ datetime_t* moment = new datetime_t(date(y,m,d),
+ datetime_t::time_duration_type(h, min, s));
+ data->convertible = (void*)moment;
+ }
+};
+
+typedef register_python_conversion<datetime_t, datetime_to_python, datetime_from_python>
+ datetime_python_conversion;
+
+datetime_t py_parse_datetime(const string& str) {
+ return parse_datetime(str);
+}
+
+date_t py_parse_date(const string& str) {
+ return parse_date(str);
+}
+
+void export_times()
+{
+ datetime_python_conversion();
+ date_python_conversion();
+
+ register_optional_to_python<datetime_t>();
+ register_optional_to_python<date_t>();
+
+ scope().attr("parse_datetime") = &py_parse_datetime;
+ scope().attr("parse_date") = &py_parse_date;
+
+#if 0
+ class_< interval_t > ("Interval")
+ ;
+#endif
+}
+
+} // namespace ledger
diff --git a/src/py_utils.cc b/src/py_utils.cc
new file mode 100644
index 00000000..ac1ed822
--- /dev/null
+++ b/src/py_utils.cc
@@ -0,0 +1,170 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+
+namespace ledger {
+
+using namespace boost::python;
+
+struct bool_to_python
+{
+ static PyObject * convert(const bool truth)
+ {
+ if (truth)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+ }
+};
+
+struct bool_from_python
+{
+ static void* convertible(PyObject* obj_ptr)
+ {
+ if (!PyBool_Check(obj_ptr)) return 0;
+ return obj_ptr;
+ }
+
+ static void construct(PyObject* obj_ptr,
+ converter::rvalue_from_python_stage1_data* data)
+ {
+ void* storage = ((converter::rvalue_from_python_storage<bool>*) data)->storage.bytes;
+ if (obj_ptr == Py_True)
+ new (storage) bool(true);
+ else
+ new (storage) bool(false);
+ data->convertible = storage;
+ }
+};
+
+typedef register_python_conversion<bool, bool_to_python, bool_from_python>
+ bool_python_conversion;
+
+
+struct string_to_python
+{
+ static PyObject* convert(const string& str)
+ {
+ return incref(object(*boost::polymorphic_downcast<const std::string *>(&str)).ptr());
+ }
+};
+
+struct string_from_python
+{
+ static void* convertible(PyObject* obj_ptr)
+ {
+ if (!PyString_Check(obj_ptr)) return 0;
+ return obj_ptr;
+ }
+
+ static void construct(PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
+ {
+ const char* value = PyString_AsString(obj_ptr);
+ if (value == 0) throw_error_already_set();
+ void* storage =
+ reinterpret_cast<converter::rvalue_from_python_storage<string> *>(data)->storage.bytes;
+ new (storage) string(value);
+ data->convertible = storage;
+ }
+};
+
+typedef register_python_conversion<string, string_to_python, string_from_python>
+ string_python_conversion;
+
+
+struct istream_to_python
+{
+ static PyObject* convert(const std::istream&)
+ {
+ return incref(boost::python::detail::none());
+ }
+};
+
+struct istream_from_python
+{
+ static void* convertible(PyObject* obj_ptr)
+ {
+ if (!PyFile_Check(obj_ptr)) return 0;
+ return obj_ptr;
+ }
+
+ static void construct(PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
+ {
+ void* storage =
+ reinterpret_cast<converter::rvalue_from_python_storage<pyifstream> *>(data)->storage.bytes;
+ new (storage) pyifstream(reinterpret_cast<PyFileObject *>(obj_ptr));
+ data->convertible = storage;
+ }
+};
+
+typedef register_python_conversion<std::istream, istream_to_python, istream_from_python>
+ istream_python_conversion;
+
+
+struct ostream_to_python
+{
+ static PyObject* convert(const std::ostream&)
+ {
+ return incref(boost::python::detail::none());
+ }
+};
+
+struct ostream_from_python
+{
+ static void* convertible(PyObject* obj_ptr)
+ {
+ if (!PyFile_Check(obj_ptr)) return 0;
+ return obj_ptr;
+ }
+
+ static void construct(PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
+ {
+ void* storage = reinterpret_cast<converter::rvalue_from_python_storage<pyofstream> *>(data)->storage.bytes;
+ new (storage) pyofstream(reinterpret_cast<PyFileObject *>(obj_ptr));
+ data->convertible = storage;
+ }
+};
+
+typedef register_python_conversion<std::ostream, ostream_to_python, ostream_from_python>
+ ostream_python_conversion;
+
+
+void export_utils()
+{
+ bool_python_conversion();
+ string_python_conversion();
+ istream_python_conversion();
+ ostream_python_conversion();
+}
+
+} // namespace ledger
diff --git a/src/py_value.cc b/src/py_value.cc
new file mode 100644
index 00000000..a4de7c04
--- /dev/null
+++ b/src/py_value.cc
@@ -0,0 +1,304 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.h"
+#include "value.h"
+
+namespace ledger {
+
+using namespace boost::python;
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(value_overloads, value, 0, 2)
+
+namespace {
+ expr_t py_value_getattr(const value_t& value, const string& name)
+ {
+ if (value.is_pointer()) {
+ if (scope_t * scope = value.as_pointer<scope_t>())
+ return expr_t(scope->lookup(name), scope);
+ }
+ throw_(value_error, "Cannot lookup attributes in " << value.label());
+ return expr_t();
+ }
+
+ string py_dump(const value_t& value) {
+ std::ostringstream buf;
+ value.dump(buf);
+ return buf.str();
+ }
+
+ string py_dump_relaxed(const value_t& value) {
+ std::ostringstream buf;
+ value.dump(buf, true);
+ return buf.str();
+ }
+
+ void py_set_string(value_t& amount, const string& str) {
+ return amount.set_string(str);
+ }
+
+#define EXC_TRANSLATOR(type) \
+ void exc_translate_ ## type(const type& err) { \
+ PyErr_SetString(PyExc_ArithmeticError, err.what()); \
+ }
+
+ EXC_TRANSLATOR(value_error)
+}
+
+void export_value()
+{
+ class_< value_t > ("Value")
+#if 0
+ .def("initialize", &value_t::initialize)
+ .staticmethod("initialize")
+ .def("shutdown", &value_t::shutdown)
+ .staticmethod("shutdown")
+#endif
+
+ .def(init<double>())
+ .def(init<long>())
+ .def(init<std::string>())
+ .def(init<date_t>())
+ .def(init<datetime_t>())
+
+ .def(init<value_t>())
+
+ .def("is_equal_to", &value_t::is_equal_to)
+ .def("is_less_than", &value_t::is_less_than)
+ .def("is_greater_than", &value_t::is_greater_than)
+
+ .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 != double())
+ .def(double() != self)
+
+ .def(! self)
+
+ .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 <= double())
+ .def(double() <= self)
+
+ .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 >= double())
+ .def(double() >= self)
+
+ .def(self += self)
+ .def(self += long())
+ .def(self += double())
+
+ .def(self + self)
+ .def(self + long())
+ .def(long() + self)
+ .def(self + double())
+ .def(double() + self)
+
+ .def(self -= self)
+ .def(self -= long())
+ .def(self -= double())
+
+ .def(self - self)
+ .def(self - long())
+ .def(long() - self)
+ .def(self - double())
+ .def(double() - self)
+
+ .def(self *= self)
+ .def(self *= long())
+ .def(self *= double())
+
+ .def(self * self)
+ .def(self * long())
+ .def(long() * self)
+ .def(self * double())
+ .def(double() * self)
+
+ .def(self /= self)
+ .def(self /= long())
+ .def(self /= double())
+
+ .def(self / self)
+ .def(self / long())
+ .def(long() / self)
+ .def(self / double())
+ .def(double() / self)
+
+ .def("negated", &value_t::negated)
+ .def("in_place_negate", &value_t::in_place_negate)
+ .def("in_place_not", &value_t::in_place_not)
+ .def(- self)
+
+ .def("abs", &value_t::abs)
+ .def("__abs__", &value_t::abs)
+
+ .def("rounded", &value_t::rounded)
+ .def("unrounded", &value_t::unrounded)
+
+ .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("__nonzero__", &value_t::is_nonzero)
+ .def("is_nonzero", &value_t::is_nonzero)
+ .def("is_realzero", &value_t::is_realzero)
+ .def("is_zero", &value_t::is_zero)
+ .def("is_null", &value_t::is_null)
+
+ .def("type", &value_t::type)
+ .def("is_type", &value_t::is_type)
+
+ .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)
+
+ .def("is_date", &value_t::is_date)
+ .def("set_date", &value_t::set_date)
+
+ .def("is_long", &value_t::is_long)
+ .def("set_long", &value_t::set_long)
+
+ .def("is_amount", &value_t::is_amount)
+ .def("is_balance", &value_t::is_balance)
+
+ .def("is_string", &value_t::is_string)
+ .def("set_string", py_set_string)
+
+ .def("is_sequence", &value_t::is_sequence)
+ .def("set_sequence", &value_t::set_sequence)
+
+ .def("to_boolean", &value_t::to_boolean)
+ .def("to_long", &value_t::to_long)
+ .def("__int__", &value_t::to_long)
+ .def("to_datetime", &value_t::to_datetime)
+ .def("to_date", &value_t::to_date)
+ .def("to_string", &value_t::to_string)
+ .def("to_sequence", &value_t::to_sequence)
+
+ .def("__str__", py_dump_relaxed)
+ .def("__repr__", py_dump)
+
+ .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("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("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("POINTER", value_t::POINTER)
+ ;
+
+ scope().attr("NULL_VALUE") = NULL_VALUE;
+ scope().attr("string_value") = &string_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>();
+ implicitly_convertible<date_t, value_t>();
+ implicitly_convertible<datetime_t, value_t>();
+
+#define EXC_TRANSLATE(type) \
+ register_exception_translator<type>(&exc_translate_ ## type);
+
+ EXC_TRANSLATE(value_error);
+}
+
+} // namespace ledger
diff --git a/src/py_xact.cc b/src/py_xact.cc
new file mode 100644
index 00000000..441d5741
--- /dev/null
+++ b/src/py_xact.cc
@@ -0,0 +1,76 @@
+/*
+ * 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 "pyinterp.h"
+#include "pyutils.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(xact_error)
+
+void export_xact()
+{
+#if 0
+ class_< xact_base_t > ("XactBase")
+ ;
+ class_< xact_t > ("Xact")
+ ;
+ struct_< xact_finalizer_t > ("XactFinalizer")
+ ;
+ class_< auto_xact_t > ("AutoXact")
+ ;
+ struct_< auto_xact_finalizer_t > ("AutoXactFinalizer")
+ ;
+ class_< period_xact_t > ("PeriodXact")
+ ;
+ class_< func_finalizer_t > ("FuncFinalizer")
+ ;
+#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(xact_error);
+}
+
+} // namespace ledger
diff --git a/src/pyfstream.h b/src/pyfstream.h
new file mode 100644
index 00000000..2b21b45e
--- /dev/null
+++ b/src/pyfstream.h
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+#ifndef _PYFSTREAM_H
+#define _PYFSTREAM_H
+
+// pyofstream
+// - a stream that writes on a Python file object
+
+class pyoutbuf : public boost::noncopyable, public std::streambuf
+{
+ pyoutbuf();
+
+protected:
+ PyFileObject * fo; // Python file object
+
+public:
+ // constructor
+ pyoutbuf(PyFileObject * _fo) : fo(_fo) {
+ TRACE_CTOR(pyoutbuf, "PyFileObject *");
+ }
+ ~pyoutbuf() throw() {
+ TRACE_DTOR(pyoutbuf);
+ }
+
+protected:
+ // write one character
+ virtual int_type overflow (int_type c) {
+ if (c != EOF) {
+ char z[2];
+ z[0] = c;
+ z[1] = '\0';
+ if (PyFile_WriteString(z, reinterpret_cast<PyObject *>(fo)) < 0) {
+ return EOF;
+ }
+ }
+ return c;
+ }
+
+ // write multiple characters
+ virtual std::streamsize xsputn (const char* s, std::streamsize num) {
+ char * buf = new char[num + 1];
+ std::strncpy(buf, s, num);
+ buf[num] = '\0';
+ if (PyFile_WriteString(buf, reinterpret_cast<PyObject *>(fo)) < 0)
+ num = 0;
+ boost::checked_array_delete(buf);
+ return num;
+ }
+};
+
+class pyofstream : public boost::noncopyable, public std::ostream
+{
+ pyofstream();
+
+protected:
+ pyoutbuf buf;
+
+public:
+ pyofstream (PyFileObject * fo) : std::ostream(0), buf(fo) {
+ TRACE_CTOR(pyofstream, "PyFileObject *");
+ rdbuf(&buf);
+ }
+ ~pyofstream() throw() {
+ TRACE_DTOR(pyofstream);
+ }
+};
+
+// pyifstream
+// - a stream that reads on a file descriptor
+
+class pyinbuf : public boost::noncopyable, public std::streambuf
+{
+ pyinbuf();
+
+protected:
+ PyFileObject * fo; // Python file object
+
+protected:
+ /* data buffer:
+ * - at most, pbSize characters in putback area plus
+ * - at most, bufSize characters in ordinary read buffer
+ */
+ static const int pbSize = 4; // size of putback area
+ static const int bufSize = 1024; // size of the data buffer
+ char buffer[bufSize + pbSize]; // data buffer
+
+public:
+ /* constructor
+ * - initialize file descriptor
+ * - initialize empty data buffer
+ * - no putback area
+ * => force underflow()
+ */
+ pyinbuf (PyFileObject * _fo) : fo(_fo) {
+ TRACE_CTOR(pyinbuf, "PyFileObject *");
+
+ setg (buffer+pbSize, // beginning of putback area
+ buffer+pbSize, // read position
+ buffer+pbSize); // end position
+ }
+ ~pyinbuf() throw() {
+ TRACE_DTOR(pyinbuf);
+ }
+
+protected:
+ // insert new characters into the buffer
+ virtual int_type underflow () {
+#ifndef _MSC_VER
+ using std::memmove;
+#endif
+
+ // is read position before end of buffer?
+ if (gptr() < egptr()) {
+ return traits_type::to_int_type(*gptr());
+ }
+
+ /* process size of putback area
+ * - use number of characters read
+ * - but at most size of putback area
+ */
+ int numPutback;
+ numPutback = gptr() - eback();
+ if (numPutback > pbSize) {
+ numPutback = pbSize;
+ }
+
+ /* copy up to pbSize characters previously read into
+ * the putback area
+ */
+ memmove (buffer+(pbSize-numPutback), gptr()-numPutback,
+ numPutback);
+
+ // read at most bufSize new characters
+ int num;
+ PyObject *line = PyFile_GetLine(reinterpret_cast<PyObject *>(fo), bufSize);
+ if (! line || ! PyString_Check(line)) {
+ // ERROR or EOF
+ return EOF;
+ }
+
+ num = PyString_Size(line);
+ if (num == 0)
+ return EOF;
+
+ memmove (buffer+pbSize, PyString_AsString(line), num);
+
+ // reset buffer pointers
+ setg (buffer+(pbSize-numPutback), // beginning of putback area
+ buffer+pbSize, // read position
+ buffer+pbSize+num); // end of buffer
+
+ // return next character
+ return traits_type::to_int_type(*gptr());
+ }
+};
+
+class pyifstream : public boost::noncopyable, public std::istream
+{
+ pyifstream();
+
+protected:
+ pyinbuf buf;
+
+public:
+ pyifstream (PyFileObject * fo) : std::istream(0), buf(fo) {
+ TRACE_CTOR(pyifstream, "PyFileObject *");
+ rdbuf(&buf);
+ }
+ ~pyifstream() throw() {
+ TRACE_DTOR(pyifstream);
+ }
+};
+
+#endif // _PYFSTREAM_H
diff --git a/src/pyinterp.cc b/src/pyinterp.cc
new file mode 100644
index 00000000..9782f3a0
--- /dev/null
+++ b/src/pyinterp.cc
@@ -0,0 +1,296 @@
+/*
+ * 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 "pyinterp.h"
+
+namespace ledger {
+
+using namespace python;
+
+shared_ptr<python_interpreter_t> python_session;
+
+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_report();
+void export_scope();
+void export_session();
+void export_timelog();
+void export_times();
+void export_utils();
+void export_value();
+void export_post();
+
+void initialize_for_python()
+{
+ export_amount();
+ export_balance();
+ export_chain();
+ export_commodity();
+ export_xact();
+ export_expr();
+ export_flags();
+ export_format();
+ export_global();
+ export_item();
+ export_journal();
+ export_report();
+ export_scope();
+ export_session();
+ export_timelog();
+ export_times();
+ export_utils();
+ export_value();
+ export_post();
+}
+
+struct python_run
+{
+ object result;
+
+ 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())))) {}
+ operator object() {
+ return result;
+ }
+};
+
+void python_interpreter_t::initialize()
+{
+ TRACE_START(python_init, 1, "Initialized Python");
+
+ try {
+ DEBUG("python.interp", "Initializing Python");
+
+ Py_Initialize();
+ assert(Py_IsInitialized());
+
+ object main_module = python::import("__main__");
+ if (! main_module)
+ throw_(std::logic_error, "Python failed to initialize");
+
+ main_nspace = extract<dict>(main_module.attr("__dict__"));
+ if (! main_nspace)
+ throw_(std::logic_error, "Python failed to initialize");
+
+ python::detail::init_module("ledger", &initialize_for_python);
+
+ is_initialized = true;
+ }
+ catch (const error_already_set&) {
+ PyErr_Print();
+ throw_(std::logic_error, "Python failed to initialize");
+ }
+
+ TRACE_FINISH(python_init, 1);
+}
+
+object python_interpreter_t::import(const string& str)
+{
+ if (! is_initialized)
+ 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
+ main_nspace.update(mod.attr("__dict__"));
+
+ TRACE_FINISH(python_import, 1);
+
+ return mod;
+ }
+ catch (const error_already_set&) {
+ PyErr_Print();
+ }
+ return object();
+}
+
+object python_interpreter_t::eval(std::istream& in, py_eval_mode_t mode)
+{
+ bool first = true;
+ string buffer;
+ buffer.reserve(4096);
+
+ while (! in.eof()) {
+ char buf[256];
+ in.getline(buf, 255);
+ if (buf[0] == '!')
+ break;
+ if (first)
+ first = false;
+ else
+ buffer += "\n";
+ buffer += buf;
+ }
+
+ if (! is_initialized)
+ initialize();
+
+ try {
+ int input_mode;
+ switch (mode) {
+ case PY_EVAL_EXPR: input_mode = Py_eval_input; break;
+ case PY_EVAL_STMT: input_mode = Py_single_input; break;
+ case PY_EVAL_MULTI: input_mode = Py_file_input; break;
+ }
+
+ return python_run(this, buffer, input_mode);
+ }
+ catch (const error_already_set&) {
+ PyErr_Print();
+ throw_(std::logic_error, "Failed to evaluate Python code");
+ }
+ return object();
+}
+
+object python_interpreter_t::eval(const string& str, py_eval_mode_t mode)
+{
+ if (! is_initialized)
+ initialize();
+
+ try {
+ int input_mode;
+ switch (mode) {
+ case PY_EVAL_EXPR: input_mode = Py_eval_input; break;
+ case PY_EVAL_STMT: input_mode = Py_single_input; break;
+ case PY_EVAL_MULTI: input_mode = Py_file_input; break;
+ }
+
+ return python_run(this, str, input_mode);
+ }
+ catch (const error_already_set&) {
+ PyErr_Print();
+ throw_(std::logic_error, "Failed to evaluate Python code");
+ }
+ return object();
+}
+
+expr_t::ptr_op_t python_interpreter_t::lookup(const string& name)
+{
+ // Give our superclass first dibs on symbol definitions
+ if (expr_t::ptr_op_t op = session_t::lookup(name))
+ return op;
+
+ 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;
+ }
+ }
+ break;
+ }
+
+ 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(name, obj));
+ }
+
+ return NULL;
+}
+
+value_t python_interpreter_t::functor_t::operator()(call_scope_t& args)
+{
+ try {
+ if (! PyCallable_Check(func.ptr())) {
+ extract<value_t> val(func);
+ if (val.check())
+ return val();
+ throw_(calc_error,
+ "Could not evaluate Python variable '" << name << "'");
+ } else {
+ if (args.size() > 0) {
+ list arglist;
+ if (args.value().is_sequence())
+ foreach (const value_t& value, args.value().as_sequence())
+ arglist.append(value);
+ else
+ arglist.append(args.value());
+
+ if (PyObject * val =
+ PyObject_CallObject(func.ptr(), python::tuple(arglist).ptr())) {
+ extract<value_t> xval(val);
+ value_t result;
+ if (xval.check()) {
+ result = xval();
+ Py_DECREF(val);
+ } else {
+ Py_DECREF(val);
+ throw_(calc_error,
+ "Could not evaluate Python variable '" << name << "'");
+ }
+ return result;
+ }
+ else if (PyErr_Occurred()) {
+ PyErr_Print();
+ throw_(calc_error, "Failed call to Python function '" << name << "'");
+ } else {
+ assert(false);
+ }
+ } else {
+ return call<value_t>(func.ptr());
+ }
+ }
+ }
+ catch (const error_already_set&) {
+ PyErr_Print();
+ throw_(calc_error,
+ "Failed call to Python function '" << name << "'");
+ }
+ return NULL_VALUE;
+}
+
+} // namespace ledger
diff --git a/src/pyinterp.h b/src/pyinterp.h
new file mode 100644
index 00000000..4863cbb9
--- /dev/null
+++ b/src/pyinterp.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#ifndef _PYINTERP_H
+#define _PYINTERP_H
+
+#include "scope.h"
+#include "session.h"
+
+#if defined(HAVE_BOOST_PYTHON)
+
+namespace ledger {
+
+class python_interpreter_t : public session_t
+{
+public:
+ python::dict main_nspace;
+ bool is_initialized;
+
+ python_interpreter_t()
+ : session_t(), main_nspace(), is_initialized(false) {
+ TRACE_CTOR(python_interpreter_t, "");
+ }
+
+ virtual ~python_interpreter_t() {
+ TRACE_DTOR(python_interpreter_t);
+
+ if (is_initialized)
+ Py_Finalize();
+ }
+
+ void initialize();
+
+ python::object import(const string& name);
+
+ enum py_eval_mode_t {
+ PY_EVAL_EXPR,
+ PY_EVAL_STMT,
+ 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);
+ }
+
+ class functor_t {
+ functor_t();
+
+ protected:
+ python::object func;
+
+ public:
+ string name;
+
+ functor_t(const string& _name, python::object _func)
+ : func(_func), name(_name) {
+ TRACE_CTOR(functor_t, "const string&, python::object");
+ }
+ functor_t(const functor_t& other)
+ : func(other.func), name(other.name) {
+ TRACE_CTOR(functor_t, "copy");
+ }
+ virtual ~functor_t() throw() {
+ TRACE_DTOR(functor_t);
+ }
+ virtual value_t operator()(call_scope_t& args);
+ };
+
+ virtual expr_t::ptr_op_t lookup(const string& name);
+
+ value_t option_import_(call_scope_t& args) {
+ path file(args[0].to_string());
+
+ python::object module_sys = import("sys");
+ python::object sys_dict = module_sys.attr("__dict__");
+
+ python::list paths(sys_dict["path"]);
+#if BOOST_VERSION >= 103700
+ paths.insert(0, file.parent_path().string());
+#else
+ paths.insert(0, file.branch_path().string());
+#endif
+ sys_dict["path"] = paths;
+
+#if BOOST_VERSION >= 103700
+ import(file.stem());
+#else
+ import(file.string());
+#endif
+ return true;
+ }
+};
+
+extern shared_ptr<python_interpreter_t> python_session;
+
+} // namespace ledger
+
+#endif // HAVE_BOOST_PYTHON
+
+#endif // _PYINTERP_H
diff --git a/src/pyledger.cc b/src/pyledger.cc
new file mode 100644
index 00000000..963efe11
--- /dev/null
+++ b/src/pyledger.cc
@@ -0,0 +1,50 @@
+/*
+ * 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 <pyledger.h>
+
+using namespace boost::python;
+
+namespace ledger {
+ extern void initialize_for_python();
+}
+
+BOOST_PYTHON_MODULE(ledger)
+{
+ using namespace ledger;
+
+ if (! python_session.get())
+ python_session.reset(new python_interpreter_t);
+
+ set_session_context(python_session.get());
+
+ initialize_for_python();
+}
diff --git a/src/pyledger.h b/src/pyledger.h
new file mode 100644
index 00000000..ee27767a
--- /dev/null
+++ b/src/pyledger.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef _PYLEDGER_H
+#define _PYLEDGER_H
+
+#include <ledger.h>
+#include <pyinterp.h>
+
+#endif // _PYLEDGER_H
diff --git a/src/pyutils.h b/src/pyutils.h
new file mode 100644
index 00000000..c0e5a38a
--- /dev/null
+++ b/src/pyutils.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef _PY_UTILS_H
+#define _PY_UTILS_H
+
+#include "pyfstream.h"
+
+template <typename T, typename TfromPy>
+struct object_from_python
+{
+ object_from_python() {
+ boost::python::converter::registry::push_back
+ (&TfromPy::convertible, &TfromPy::construct,
+ boost::python::type_id<T>());
+ }
+};
+
+template <typename T, typename TtoPy, typename TfromPy>
+struct register_python_conversion
+{
+ register_python_conversion() {
+ boost::python::to_python_converter<T, TtoPy>();
+ object_from_python<T, TfromPy>();
+ }
+};
+
+template <typename T>
+struct register_optional_to_python : public boost::noncopyable
+{
+ struct optional_to_python
+ {
+ static PyObject * convert(const boost::optional<T>& value)
+ {
+ return boost::python::incref
+ (value ? boost::python::to_python_value<T>()(*value) :
+ boost::python::detail::none());
+ }
+ };
+
+ struct optional_from_python
+ {
+ static void * convertible(PyObject * source)
+ {
+ using namespace boost::python::converter;
+
+ if (source == Py_None)
+ return source;
+
+ const registration& converters(registered<T>::converters);
+
+ if (implicit_rvalue_convertible_from_python(source, converters)) {
+ rvalue_from_python_stage1_data data =
+ rvalue_from_python_stage1(source, converters);
+ return rvalue_from_python_stage2(source, data, converters);
+ }
+ return NULL;
+ }
+
+ static void construct(PyObject * source,
+ boost::python::converter::rvalue_from_python_stage1_data * data)
+ {
+ using namespace boost::python::converter;
+
+ void * const storage =
+ reinterpret_cast<rvalue_from_python_storage<T> *>(data)->storage.bytes;
+
+ if (data->convertible == source) // == None
+ new (storage) boost::optional<T>(); // A Boost uninitialized value
+ else
+ new (storage) boost::optional<T>(*reinterpret_cast<T *>(data->convertible));
+
+ data->convertible = storage;
+ }
+ };
+
+ explicit register_optional_to_python() {
+ register_python_conversion<boost::optional<T>,
+ optional_to_python, optional_from_python>();
+ }
+};
+
+//boost::python::register_ptr_to_python< boost::shared_ptr<Base> >();
+
+#endif // _PY_UTILS_H