diff options
author | John Wiegley <johnw@newartisans.com> | 2009-02-24 16:08:49 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-02-24 16:08:49 -0400 |
commit | 1799ed3a2adf1af7ed08b3b3ded3594a4c0e184e (patch) | |
tree | ba0ad178f2ceefa0fad5975f6247e3f20de41344 /src | |
parent | 5ad9bc3951fcbecb5fcf7c1127e8f91e547fd37b (diff) | |
download | fork-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.cc | 340 | ||||
-rw-r--r-- | src/py_balance.cc | 270 | ||||
-rw-r--r-- | src/py_chain.cc | 62 | ||||
-rw-r--r-- | src/py_commodity.cc | 82 | ||||
-rw-r--r-- | src/py_expr.cc | 68 | ||||
-rw-r--r-- | src/py_flags.cc | 68 | ||||
-rw-r--r-- | src/py_format.cc | 64 | ||||
-rw-r--r-- | src/py_global.cc | 64 | ||||
-rw-r--r-- | src/py_item.cc | 64 | ||||
-rw-r--r-- | src/py_journal.cc | 437 | ||||
-rw-r--r-- | src/py_post.cc | 64 | ||||
-rw-r--r-- | src/py_report.cc | 64 | ||||
-rw-r--r-- | src/py_scope.cc | 78 | ||||
-rw-r--r-- | src/py_session.cc | 64 | ||||
-rw-r--r-- | src/py_timelog.cc | 66 | ||||
-rw-r--r-- | src/py_times.cc | 146 | ||||
-rw-r--r-- | src/py_utils.cc | 170 | ||||
-rw-r--r-- | src/py_value.cc | 304 | ||||
-rw-r--r-- | src/py_xact.cc | 76 | ||||
-rw-r--r-- | src/pyfstream.h | 203 | ||||
-rw-r--r-- | src/pyinterp.cc | 296 | ||||
-rw-r--r-- | src/pyinterp.h | 134 | ||||
-rw-r--r-- | src/pyledger.cc | 50 | ||||
-rw-r--r-- | src/pyledger.h | 38 | ||||
-rw-r--r-- | src/pyutils.h | 113 |
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 |