diff options
-rw-r--r-- | .gitignore | 20 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | Makefile.in | 35 | ||||
-rw-r--r-- | gdtoa/.gitignore | 8 | ||||
-rw-r--r-- | src/commodity.h | 4 | ||||
-rw-r--r-- | src/py_amount.cc | 71 | ||||
-rw-r--r-- | src/py_commodity.cc | 75 | ||||
-rw-r--r-- | src/py_utils.cc | 61 | ||||
-rw-r--r-- | src/pyledger.cc | 2 | ||||
-rw-r--r-- | tests/python/numerics/t_amount.py | 505 |
10 files changed, 562 insertions, 221 deletions
@@ -1,4 +1,22 @@ -/acconf.h.in~ +*.Plo +*.Po +*.a +*.elc +*.la +*.lai +*.lo +*.o +.gdb_history +Makefile +UnitTests +acconf.h +acconf.h.in~ autom4te.cache +config.log +config.status +elc-stamp +libtool pending +stamp-h1 utils +ledger diff --git a/Makefile.am b/Makefile.am index 0f28d0cb..99e86a74 100644 --- a/Makefile.am +++ b/Makefile.am @@ -99,6 +99,7 @@ libpyledger_la_LDFLAGS = -release $(PACKAGE_VERSION) libpyledger_la_SOURCES = \ src/py_utils.cc \ src/py_times.cc \ + src/py_commodity.cc \ src/py_amount.cc @@ -179,6 +180,7 @@ ledger_so_SOURCES = \ src/pyledger.cc \ src/py_utils.cc \ src/py_times.cc \ + src/py_commodity.cc \ src/py_amount.cc ledger_so_DEPENDENCIES = libledger.la gdtoa/libgdtoa.la libpyledger.la diff --git a/Makefile.in b/Makefile.in index 9c246b8f..6f349752 100644 --- a/Makefile.in +++ b/Makefile.in @@ -118,7 +118,8 @@ libledger_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(CXXFLAGS) $(libledger_la_LDFLAGS) $(LDFLAGS) -o $@ libpyledger_la_LIBADD = am_libpyledger_la_OBJECTS = libpyledger_la-py_utils.lo \ - libpyledger_la-py_times.lo libpyledger_la-py_amount.lo + libpyledger_la-py_times.lo libpyledger_la-py_commodity.lo \ + libpyledger_la-py_amount.lo libpyledger_la_OBJECTS = $(am_libpyledger_la_OBJECTS) libpyledger_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ @@ -148,9 +149,10 @@ ledger_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ $(ledger_LDFLAGS) $(LDFLAGS) -o $@ am__ledger_so_SOURCES_DIST = src/pyledger.cc src/py_utils.cc \ - src/py_times.cc src/py_amount.cc + src/py_times.cc src/py_commodity.cc src/py_amount.cc @HAVE_BOOST_PYTHON_TRUE@am_ledger_so_OBJECTS = pyledger.$(OBJEXT) \ @HAVE_BOOST_PYTHON_TRUE@ py_utils.$(OBJEXT) py_times.$(OBJEXT) \ +@HAVE_BOOST_PYTHON_TRUE@ py_commodity.$(OBJEXT) \ @HAVE_BOOST_PYTHON_TRUE@ py_amount.$(OBJEXT) ledger_so_OBJECTS = $(am_ledger_so_OBJECTS) ledger_so_LDADD = $(LDADD) @@ -351,7 +353,7 @@ CLEANFILES = $(am__append_12) $(am__append_14) ESC_srcdir = `echo "$(srcdir)" | sed 's/\//\\\\\//g'` ESC_builddir = `echo "$(top_builddir)" | sed 's/\//\\\\\//g'` ESC_distdir = `echo "$(distdir)" | sed 's/\//\\\\\//g'` -EXTRA_DIST = docs tests ledger.pdf ledger.info +EXTRA_DIST = docs tests lib_LTLIBRARIES = libledger.la $(am__append_1) AM_YFLAGS = -d AM_LFLAGS = -o $(LEX_OUTPUT_ROOT).c @@ -378,6 +380,7 @@ libpyledger_la_LDFLAGS = -release $(PACKAGE_VERSION) libpyledger_la_SOURCES = \ src/py_utils.cc \ src/py_times.cc \ + src/py_commodity.cc \ src/py_amount.cc pkginclude_HEADERS = \ @@ -390,6 +393,7 @@ pkginclude_HEADERS = \ src/csv.h \ src/derive.h \ src/emacs.h \ + src/fdstream.hpp \ src/flags.h \ src/format.h \ src/gnucash.h \ @@ -410,6 +414,7 @@ pkginclude_HEADERS = \ src/report.h \ src/scoped_execute.h \ src/session.h \ + src/system.hh \ src/textual.h \ src/times.h \ src/transform.h \ @@ -434,6 +439,7 @@ dist_lisp_LISP = lisp/ledger.el lisp/timeclock.el @HAVE_BOOST_PYTHON_TRUE@ src/pyledger.cc \ @HAVE_BOOST_PYTHON_TRUE@ src/py_utils.cc \ @HAVE_BOOST_PYTHON_TRUE@ src/py_times.cc \ +@HAVE_BOOST_PYTHON_TRUE@ src/py_commodity.cc \ @HAVE_BOOST_PYTHON_TRUE@ src/py_amount.cc @HAVE_BOOST_PYTHON_TRUE@ledger_so_DEPENDENCIES = libledger.la gdtoa/libgdtoa.la libpyledger.la @@ -639,9 +645,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-xmlparse.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libledger_la-xpath.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyledger_la-py_amount.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyledger_la-py_commodity.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyledger_la-py_times.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyledger_la-py_utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/py_amount.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/py_commodity.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/py_times.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/py_utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pyledger.Po@am__quote@ @@ -870,6 +878,13 @@ libpyledger_la-py_times.lo: src/py_times.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyledger_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyledger_la-py_times.lo `test -f 'src/py_times.cc' || echo '$(srcdir)/'`src/py_times.cc +libpyledger_la-py_commodity.lo: src/py_commodity.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyledger_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyledger_la-py_commodity.lo -MD -MP -MF $(DEPDIR)/libpyledger_la-py_commodity.Tpo -c -o libpyledger_la-py_commodity.lo `test -f 'src/py_commodity.cc' || echo '$(srcdir)/'`src/py_commodity.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libpyledger_la-py_commodity.Tpo $(DEPDIR)/libpyledger_la-py_commodity.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/py_commodity.cc' object='libpyledger_la-py_commodity.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyledger_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpyledger_la-py_commodity.lo `test -f 'src/py_commodity.cc' || echo '$(srcdir)/'`src/py_commodity.cc + libpyledger_la-py_amount.lo: src/py_amount.cc @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyledger_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpyledger_la-py_amount.lo -MD -MP -MF $(DEPDIR)/libpyledger_la-py_amount.Tpo -c -o libpyledger_la-py_amount.lo `test -f 'src/py_amount.cc' || echo '$(srcdir)/'`src/py_amount.cc @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libpyledger_la-py_amount.Tpo $(DEPDIR)/libpyledger_la-py_amount.Plo @@ -1031,6 +1046,20 @@ py_times.obj: src/py_times.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o py_times.obj `if test -f 'src/py_times.cc'; then $(CYGPATH_W) 'src/py_times.cc'; else $(CYGPATH_W) '$(srcdir)/src/py_times.cc'; fi` +py_commodity.o: src/py_commodity.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT py_commodity.o -MD -MP -MF $(DEPDIR)/py_commodity.Tpo -c -o py_commodity.o `test -f 'src/py_commodity.cc' || echo '$(srcdir)/'`src/py_commodity.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/py_commodity.Tpo $(DEPDIR)/py_commodity.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/py_commodity.cc' object='py_commodity.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o py_commodity.o `test -f 'src/py_commodity.cc' || echo '$(srcdir)/'`src/py_commodity.cc + +py_commodity.obj: src/py_commodity.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT py_commodity.obj -MD -MP -MF $(DEPDIR)/py_commodity.Tpo -c -o py_commodity.obj `if test -f 'src/py_commodity.cc'; then $(CYGPATH_W) 'src/py_commodity.cc'; else $(CYGPATH_W) '$(srcdir)/src/py_commodity.cc'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/py_commodity.Tpo $(DEPDIR)/py_commodity.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/py_commodity.cc' object='py_commodity.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o py_commodity.obj `if test -f 'src/py_commodity.cc'; then $(CYGPATH_W) 'src/py_commodity.cc'; else $(CYGPATH_W) '$(srcdir)/src/py_commodity.cc'; fi` + py_amount.o: src/py_amount.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT py_amount.o -MD -MP -MF $(DEPDIR)/py_amount.Tpo -c -o py_amount.o `test -f 'src/py_amount.cc' || echo '$(srcdir)/'`src/py_amount.cc @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/py_amount.Tpo $(DEPDIR)/py_amount.Po diff --git a/gdtoa/.gitignore b/gdtoa/.gitignore new file mode 100644 index 00000000..787fbe1c --- /dev/null +++ b/gdtoa/.gitignore @@ -0,0 +1,8 @@ +Makefile +acconf.h +arith.h +config.log +config.status +gd_qnan.h +libtool +stamp-h1 diff --git a/src/commodity.h b/src/commodity.h index 6551d3b5..a5a13aeb 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -49,7 +49,7 @@ class annotated_commodity_t; class commodity_t : public delegates_flags<>, - equality_comparable1<commodity_t, noncopyable> + public equality_comparable1<commodity_t, noncopyable> { friend class commodity_pool_t; @@ -255,7 +255,7 @@ inline std::ostream& operator<<(std::ostream& out, const annotation_t& details) class annotated_commodity_t : public commodity_t, - equality_comparable<annotated_commodity_t, + public equality_comparable<annotated_commodity_t, equality_comparable2<annotated_commodity_t, commodity_t, noncopyable> > { diff --git a/src/py_amount.cc b/src/py_amount.cc index 7fc667e7..88e2c993 100644 --- a/src/py_amount.cc +++ b/src/py_amount.cc @@ -40,6 +40,13 @@ namespace ledger { using namespace boost::python; +amount_t py_round_0(const amount_t& amount) { + return amount.round(); +} +amount_t py_round_1(const amount_t& amount, amount_t::precision_t prec) { + return amount.round(prec); +} + double py_to_double_0(amount_t& amount) { return amount.to_double(); } @@ -54,26 +61,46 @@ long py_to_long_1(amount_t& amount, bool no_check) { return amount.to_long(no_check); } -void py_parse_1(amount_t& amount, const string& str) { - amount.parse(str); +boost::optional<amount_t> py_value_0(const amount_t& amount) { + return amount.value(); } -void py_parse_2(amount_t& amount, const string& str, unsigned char flags) { - amount.parse(str, flags); +boost::optional<amount_t> py_value_1(const amount_t& amount, + const boost::optional<moment_t>& moment) { + return amount.value(moment); } -amount_t py_round_0(const amount_t& amount) { - return amount.round(); +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"); + } } -amount_t py_round_1(const amount_t& amount, amount_t::precision_t prec) { - return amount.round(prec); +void py_parse_1(amount_t& amount, object in) { + py_parse_2(amount, in, 0); } -boost::optional<amount_t> py_value_0(const amount_t& amount) { - return amount.value(); +void py_parse_str_1(amount_t& amount, const string& str) { + amount.parse(str); } -boost::optional<amount_t> py_value_1(const amount_t& amount, - const boost::optional<moment_t>& moment) { - return amount.value(moment); +void py_parse_str_2(amount_t& amount, const string& str, unsigned char flags) { + amount.parse(str, flags); +} + +void py_read_1(amount_t& amount, object in) { + if (PyFile_Check(in.ptr())) { + pyifstream instr(reinterpret_cast<PyFileObject *>(in.ptr())); + amount.read(instr); + } else { + PyErr_SetString(PyExc_IOError, + "Argument to amount.parse(file) is not a file object"); + } +} +void py_read_2(amount_t& amount, const std::string& str) { + const char * p = str.c_str(); + amount.read(p); } #define EXC_TRANSLATOR(type) \ @@ -112,7 +139,9 @@ void export_amount() .def(init<long>()) .def(init<std::string>()) - .def("exact", &amount_t::exact) + .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>()) @@ -197,7 +226,7 @@ void export_amount() .def(self / double()) .def(double() / self) - .def("precision", &amount_t::precision) + .add_property("precision", &amount_t::precision) .def("negate", &amount_t::negate) .def("in_place_negate", &amount_t::in_place_negate, @@ -243,7 +272,7 @@ void export_amount() .def("fits_in_double", &amount_t::fits_in_double) .def("fits_in_long", &amount_t::fits_in_long) - .def("quantity_string", &amount_t::quantity_string) + .add_property("quantity_string", &amount_t::quantity_string) .add_property("commodity", make_function(&amount_t::commodity, @@ -253,19 +282,25 @@ void export_amount() .def("has_commodity", &amount_t::has_commodity) .def("clear_commodity", &amount_t::clear_commodity) - .def("number", &amount_t::number) + .add_property("number", &amount_t::number) .def("annotate_commodity", &amount_t::annotate_commodity) .def("commodity_annotated", &amount_t::commodity_annotated) - .def("annotation_details", &amount_t::annotation_details) + .add_property("annotation_details", &amount_t::annotation_details) .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("read", py_read_1) + .def("read", py_read_2) + .def("write", &amount_t::write) + .def("valid", &amount_t::valid) ; diff --git a/src/py_commodity.cc b/src/py_commodity.cc index dc065567..f857a448 100644 --- a/src/py_commodity.cc +++ b/src/py_commodity.cc @@ -30,47 +30,18 @@ */ #include "pyinterp.h" +#include "pyutils.h" #include "amount.h" #include <boost/python/exception_translator.hpp> +#include <boost/python/implicit.hpp> namespace ledger { using namespace boost::python; -struct commodity_updater_wrap : public commodity_base_t::updater_t -{ - PyObject * self; - commodity_updater_wrap(PyObject * self_) : self(self_) {} - - virtual void operator()(commodity_base_t& commodity, - const moment_t& moment, - const moment_t& date, - const moment_t& last, - amount_t& price) { - call_method<void>(self, "__call__", commodity, moment, date, last, price); - } -}; - -commodity_t * py_find_commodity(const string& symbol) -{ - return commodity_t::find(symbol); -} - -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ - } - -EXC_TRANSLATOR(commodity_error) - void export_commodity() { - class_< commodity_base_t::updater_t, commodity_updater_wrap, - boost::noncopyable > - ("updater") - ; - scope().attr("COMMODITY_STYLE_DEFAULTS") = COMMODITY_STYLE_DEFAULTS; scope().attr("COMMODITY_STYLE_SUFFIXED") = COMMODITY_STYLE_SUFFIXED; scope().attr("COMMODITY_STYLE_SEPARATED") = COMMODITY_STYLE_SEPARATED; @@ -79,46 +50,14 @@ void export_commodity() scope().attr("COMMODITY_STYLE_NOMARKET") = COMMODITY_STYLE_NOMARKET; scope().attr("COMMODITY_STYLE_BUILTIN") = COMMODITY_STYLE_BUILTIN; - class_< commodity_t > ("commodity") - .add_property("symbol", &commodity_t::symbol) - - .add_property("name", &commodity_t::name, &commodity_t::set_name) - .add_property("note", &commodity_t::note, &commodity_t::set_note) - .add_property("precision", &commodity_t::precision, - &commodity_t::set_precision) - .add_property("flags", &commodity_t::flags, &commodity_t::set_flags) - .add_property("add_flags", &commodity_t::add_flags) - .add_property("drop_flags", &commodity_t::drop_flags) - //.add_property("updater", &commodity_t::updater) - - .add_property("smaller", - make_getter(&commodity_t::smaller, - return_value_policy<reference_existing_object>()), - make_setter(&commodity_t::smaller, - return_value_policy<reference_existing_object>())) - .add_property("larger", - make_getter(&commodity_t::larger, - return_value_policy<reference_existing_object>()), - make_setter(&commodity_t::larger, - return_value_policy<reference_existing_object>())) + class_< commodity_t, bases<>, + commodity_t, boost::noncopyable > ("commodity", no_init) + .def(self == self) - .def(self_ns::str(self)) + .def("drop_flags", &commodity_t::drop_flags) - .def("find", py_find_commodity, - return_value_policy<reference_existing_object>()) - .staticmethod("find") - - .def("add_price", &commodity_t::add_price) - .def("remove_price", &commodity_t::remove_price) - .def("value", &commodity_t::value) - - .def("valid", &commodity_t::valid) + .add_property("precision", &commodity_t::precision) ; - -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); - - EXC_TRANSLATE(commodity_error); } } // namespace ledger diff --git a/src/py_utils.cc b/src/py_utils.cc index ea439297..09fb9740 100644 --- a/src/py_utils.cc +++ b/src/py_utils.cc @@ -31,6 +31,7 @@ #include "pyinterp.h" #include "pyutils.h" +#include "pyfstream.h" #include <boost/python/module.hpp> #include <boost/python/def.hpp> @@ -74,6 +75,7 @@ struct bool_from_python typedef register_python_conversion<bool, bool_to_python, bool_from_python> bool_python_conversion; + struct string_to_python { static PyObject* convert(const string& str) @@ -103,10 +105,69 @@ struct string_from_python typedef register_python_conversion<string, string_to_python, string_from_python> string_python_conversion; + +struct istream_to_python +{ + static PyObject* convert(const std::istream& str) + { + 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 = ((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& str) + { + 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 = ((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/pyledger.cc b/src/pyledger.cc index f4adae53..4c2cd96e 100644 --- a/src/pyledger.cc +++ b/src/pyledger.cc @@ -38,6 +38,7 @@ namespace ledger { void export_utils(); void export_times(); void export_amount(); +void export_commodity(); #if 0 void export_balance(); void export_value(); @@ -55,6 +56,7 @@ void initialize_for_python() export_utils(); export_times(); export_amount(); + export_commodity(); #if 0 export_balance(); export_value(); diff --git a/tests/python/numerics/t_amount.py b/tests/python/numerics/t_amount.py index 856e13ee..f7eeee8f 100644 --- a/tests/python/numerics/t_amount.py +++ b/tests/python/numerics/t_amount.py @@ -1,27 +1,36 @@ # -*- coding: utf-8 -*- -import sys - import unittest import exceptions import operator -from ledger import amount +from ledger import * +from StringIO import * internalAmount = amount.exact -class AmountTestCase(unittest.TestCase): +class t_amountTestCase(unittest.TestCase): + testSession = None + + def assertValid(self, amt): + self.assertTrue(amt.valid()) + def setUp(self): + #self.testSession = session() + #set_session_context(self.testSession) + # Cause the display precision for dollars to be initialized to 2. x1 = amount("$1.00") self.assertTrue(x1) - amount.full_strings = True # makes error reports from UnitTests accurate - + + #amount.stream_fullstrings = True # make reports from UnitTests accurate + def tearDown(self): - amount.full_strings = False + pass + #amount.stream_fullstrings = False - def assertValid(self, amt): - self.assertTrue(amt.valid()) + #set_session_context() + #self.testSession = None def testParser(self): x0 = amount() @@ -32,29 +41,64 @@ class AmountTestCase(unittest.TestCase): x5 = amount(x4) x6 = amount(x4) x7 = amount(x4) - x8 = amount("$123.456") + x8 = amount("$123.45") x9 = amount(x8) x10 = amount(x8) x11 = amount(x8) x12 = amount("$100") - - self.assertEqual(3, x12.commodity().precision()) - + + self.assertEqual(2, x12.commodity.precision) + + #buf = "$100..." + #input = StringIO(buf) + #x13 = amount() + #x13.parse(input) + #self.assertEqual(x12, x13) + + x14 = amount() + self.assertRaises(exceptions.ArithmeticError, lambda: x14.parse("DM")) + + x15 = amount("$1.000.000,00") + + x16 = amount("$2000") + self.assertEqual("$2.000,00", x16.to_string()) + x16.parse("$2000,00") + self.assertEqual("$2.000,00", x16.to_string()) + + # Since European-ness is an additive quality, we must switch back + # to American-ness manually + x15.commodity.drop_flags(COMMODITY_STYLE_EUROPEAN) + + x17 = amount("$1,000,000.00") + + x18 = amount("$2000") + self.assertEqual("$2,000.00", x18.to_string()) + x18.parse("$2,000") + self.assertEqual("$2,000.00", x18.to_string()) + + self.assertEqual(x15, x17) + + x19 = amount("EUR 1000") + x20 = amount("EUR 1000") + + self.assertEqual("EUR 1000", x19.to_string()) + self.assertEqual("EUR 1000", x20.to_string()) + x1.parse("$100.0000", AMOUNT_PARSE_NO_MIGRATE) - self.assertEqual(3, x12.commodity().precision()) - self.assertEqual(x1.commodity(), x12.commodity()) + self.assertEqual(2, x12.commodity.precision) + self.assertEqual(x1.commodity, x12.commodity) self.assertEqual(x1, x12) - + x0.parse("$100.0000") - self.assertEqual(4, x12.commodity().precision()) - self.assertEqual(x0.commodity(), x12.commodity()) + self.assertEqual(4, x12.commodity.precision) + self.assertEqual(x0.commodity, x12.commodity) self.assertEqual(x0, x12) - + x2.parse("$100.00", AMOUNT_PARSE_NO_REDUCE) self.assertEqual(x2, x12) x3.parse("$100.00", AMOUNT_PARSE_NO_MIGRATE | AMOUNT_PARSE_NO_REDUCE) self.assertEqual(x3, x12) - + x4.parse("$100.00") self.assertEqual(x4, x12) x5.parse("$100.00", AMOUNT_PARSE_NO_MIGRATE) @@ -63,7 +107,7 @@ class AmountTestCase(unittest.TestCase): self.assertEqual(x6, x12) x7.parse("$100.00", AMOUNT_PARSE_NO_MIGRATE | AMOUNT_PARSE_NO_REDUCE) self.assertEqual(x7, x12) - + x8.parse("$100.00") self.assertEqual(x8, x12) x9.parse("$100.00", AMOUNT_PARSE_NO_MIGRATE) @@ -72,7 +116,7 @@ class AmountTestCase(unittest.TestCase): self.assertEqual(x10, x12) x11.parse("$100.00", AMOUNT_PARSE_NO_MIGRATE | AMOUNT_PARSE_NO_REDUCE) self.assertEqual(x11, x12) - + self.assertValid(x0) self.assertValid(x1) self.assertValid(x2) @@ -93,16 +137,21 @@ class AmountTestCase(unittest.TestCase): x3 = amount(123.456) x5 = amount("123456") x6 = amount("123.456") + x7 = amount("123456") + x8 = amount("123.456") x9 = amount(x3) x10 = amount(x6) + x11 = amount(x8) - self.assertRaises(exceptions.ArithmeticError, operator.eq, amount(0), x0) - self.assertRaises(exceptions.ArithmeticError, operator.eq, amount(), x0) - self.assertRaises(exceptions.ArithmeticError, operator.eq, amount("0"), x0) - self.assertRaises(exceptions.ArithmeticError, operator.eq, amount("0.0"), x0) + self.assertRaises(exceptions.ArithmeticError, lambda: amount(0) == x0) + self.assertRaises(exceptions.ArithmeticError, lambda: amount() == x0) + self.assertRaises(exceptions.ArithmeticError, lambda: amount("0") == x0) + self.assertRaises(exceptions.ArithmeticError, lambda: amount("0.0") == x0) self.assertEqual(x2, x1) self.assertEqual(x5, x1) + self.assertEqual(x7, x1) self.assertEqual(x6, x3) + self.assertEqual(x8, x3) self.assertEqual(x10, x3) self.assertEqual(x10, x9) @@ -112,19 +161,22 @@ class AmountTestCase(unittest.TestCase): self.assertValid(x3) self.assertValid(x5) self.assertValid(x6) + self.assertValid(x7) + self.assertValid(x8) self.assertValid(x9) self.assertValid(x10) + self.assertValid(x11) def testCommodityConstructors(self): - x1 = amount("$123.45") - x2 = amount("-$123.45") - x3 = amount("$-123.45") - x4 = amount("DM 123.45") - x5 = amount("-DM 123.45") - x6 = amount("DM -123.45") - x7 = amount("123.45 euro") - x8 = amount("-123.45 euro") - x9 = amount("123.45€") + x1 = amount("$123.45") + x2 = amount("-$123.45") + x3 = amount("$-123.45") + x4 = amount("DM 123.45") + x5 = amount("-DM 123.45") + x6 = amount("DM -123.45") + x7 = amount("123.45 euro") + x8 = amount("-123.45 euro") + x9 = amount("123.45€") x10 = amount("-123.45€") self.assertEqual(amount("$123.45"), x1) @@ -161,18 +213,22 @@ class AmountTestCase(unittest.TestCase): self.assertValid(x10) def testAssignment(self): - x0 = amount() - x1 = amount(123456) - x2 = amount(123456L) - x3 = amount(123.456) - x5 = amount("123456") - x6 = amount("123.456") - x9 = x3 + x0 = amount() + x1 = amount(123456) + x2 = amount(123456L) + x3 = amount(123.456) + x5 = amount("123456") + x6 = amount("123.456") + x7 = "123456" + x8 = "123.456" + x9 = amount(x3) x10 = amount(x6) self.assertEqual(x2, x1) self.assertEqual(x5, x1) + self.assertEqual(x7, x1) self.assertEqual(x6, x3) + self.assertEqual(x8, x3) self.assertEqual(x10, x3) self.assertEqual(x10, x9) @@ -181,12 +237,16 @@ class AmountTestCase(unittest.TestCase): x3 = amount(123.456) x5 = amount("123456") x6 = amount("123.456") + x7 = amount("123456") + x8 = amount("123.456") x9 = x3 x10 = amount(x6) self.assertEqual(x2, x1) self.assertEqual(x5, x1) + self.assertEqual(x7, x1) self.assertEqual(x6, x3) + self.assertEqual(x8, x3) self.assertEqual(x10, x3) self.assertEqual(x10, x9) @@ -201,6 +261,8 @@ class AmountTestCase(unittest.TestCase): self.assertValid(x3) self.assertValid(x5) self.assertValid(x6) + self.assertValid(x7) + self.assertValid(x8) self.assertValid(x9) self.assertValid(x10) @@ -255,18 +317,28 @@ class AmountTestCase(unittest.TestCase): x3 = amount(333333) x4 = amount(123456.0) x5 = amount("123456.0") + x6 = amount(123456.0) self.assertTrue(x1 == 123456) self.assertTrue(x1 != x2) self.assertTrue(x1 == (x2 - x3)) self.assertTrue(x1 == x4) self.assertTrue(x4 == x5) + self.assertTrue(x4 == x6) + + self.assertTrue(x1 == 123456) + self.assertTrue(123456 == x1) + self.assertTrue(x1 == 123456L) + self.assertTrue(123456L == x1) + self.assertTrue(x1 == 123456.0) + self.assertTrue(123456.0 == x1) self.assertValid(x1) self.assertValid(x2) self.assertValid(x3) self.assertValid(x4) self.assertValid(x5) + self.assertValid(x6) def testCommodityEquality(self): x0 = amount() @@ -282,10 +354,12 @@ class AmountTestCase(unittest.TestCase): x10 = amount("-123.45€") self.assertTrue(x0.is_null()) - self.assertRaises(exceptions.ArithmeticError, amount.is_zero, x0) - self.assertRaises(exceptions.ArithmeticError, amount.is_realzero, x0) - self.assertRaises(exceptions.ArithmeticError, amount.sign, x0) - self.assertRaises(exceptions.ArithmeticError, amount.compare, x0, 0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.is_zero()) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.is_realzero()) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.sign() == 0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.compare(x1) < 0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.compare(x2) > 0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.compare(x0) == 0) self.assertTrue(x1 != x2) self.assertTrue(x1 != x4) @@ -318,12 +392,12 @@ class AmountTestCase(unittest.TestCase): x5 = amount("-123.45") x6 = amount("123.45") - self.assertRaises(exceptions.ArithmeticError, operator.gt, x0, x1) - self.assertRaises(exceptions.ArithmeticError, operator.lt, x0, x2) - self.assertRaises(exceptions.ArithmeticError, operator.gt, x0, x3) - self.assertRaises(exceptions.ArithmeticError, operator.lt, x0, x4) - self.assertRaises(exceptions.ArithmeticError, operator.gt, x0, x5) - self.assertRaises(exceptions.ArithmeticError, operator.lt, x0, x6) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 > x1) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 < x2) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 > x3) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 < x4) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 > x5) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 < x6) self.assertTrue(x1 > x3) self.assertTrue(x3 <= x5) @@ -332,10 +406,10 @@ class AmountTestCase(unittest.TestCase): self.assertTrue(x3 < x4) self.assertTrue(x1 < 100) - self.assertTrue(x1 < 100L) - self.assertTrue(x1 < 100.0) self.assertTrue(100 > x1) + self.assertTrue(x1 < 100L) self.assertTrue(100L > x1) + self.assertTrue(x1 < 100.0) self.assertTrue(100.0 > x1) self.assertValid(x0) @@ -353,6 +427,7 @@ class AmountTestCase(unittest.TestCase): x4 = amount(internalAmount("$123.4544")) x5 = amount("$-123.45") x6 = amount("$123.45") + x7 = amount("DM 123.45") self.assertTrue(x1 > x3) self.assertTrue(x3 <= x5) @@ -361,6 +436,8 @@ class AmountTestCase(unittest.TestCase): self.assertFalse(x3 == x5) self.assertTrue(x3 < x1) self.assertTrue(x3 < x4) + self.assertFalse(x6 == x7) + self.assertRaises(exceptions.ArithmeticError, lambda: x6 < x7) self.assertValid(x1) self.assertValid(x2) @@ -370,6 +447,7 @@ class AmountTestCase(unittest.TestCase): self.assertValid(x6) def testIntegerAddition(self): + x0 = amount() x1 = amount(123) y1 = amount(456) @@ -386,6 +464,7 @@ class AmountTestCase(unittest.TestCase): self.assertEqual(amount("246913578246913578246913578"), x4 + x4) + self.assertValid(x0) self.assertValid(x1) self.assertValid(y1) self.assertValid(x4) @@ -430,13 +509,15 @@ class AmountTestCase(unittest.TestCase): self.assertEqual("$246.90", (x1 + x1).to_string()) self.assertEqual("$246.91", (x1 + x2).to_string()) - self.assertRaises(exceptions.ArithmeticError, operator.add, x1, x0) - self.assertRaises(exceptions.ArithmeticError, operator.add, x1, x3) - self.assertRaises(exceptions.ArithmeticError, operator.add, x1, x4) - self.assertRaises(exceptions.ArithmeticError, operator.add, x1, x5) - self.assertRaises(exceptions.ArithmeticError, operator.add, x1, x6) - self.assertRaises(exceptions.ArithmeticError, operator.add, x1, 123.45) - self.assertRaises(exceptions.ArithmeticError, operator.add, x1, 123) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 + x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 + x1) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 + x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 + x3) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 + x4) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 + x5) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 + x6) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 + 123.45) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 + 123) self.assertEqual(amount("DM 246.90"), x3 + x3) self.assertEqual(amount("246.90 euro"), x4 + x4) @@ -536,13 +617,15 @@ class AmountTestCase(unittest.TestCase): self.assertEqual("$0.00", (x1 - x1).to_string()) self.assertEqual("$-0.01", (x1 - x2).to_string()) - self.assertRaises(exceptions.ArithmeticError, operator.sub, x1, x0) - self.assertRaises(exceptions.ArithmeticError, operator.sub, x1, x3) - self.assertRaises(exceptions.ArithmeticError, operator.sub, x1, x4) - self.assertRaises(exceptions.ArithmeticError, operator.sub, x1, x5) - self.assertRaises(exceptions.ArithmeticError, operator.sub, x1, x6) - self.assertRaises(exceptions.ArithmeticError, operator.sub, x1, 123.45) - self.assertRaises(exceptions.ArithmeticError, operator.sub, x1, 123) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 - x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 - x1) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 - x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 - x3) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 - x4) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 - x5) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 - x6) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 - 123.45) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 - 123) self.assertEqual(amount("DM 0.00"), x3 - x3) self.assertEqual(amount("DM 23.45"), x3 - amount("DM 100.00")) @@ -619,7 +702,7 @@ class AmountTestCase(unittest.TestCase): x4 = amount("123456789123456789123456789") self.assertEqual(amount("15241578780673678546105778281054720515622620750190521"), - x4 * x4) + x4 * x4) self.assertValid(x1) self.assertValid(y1) @@ -654,13 +737,14 @@ class AmountTestCase(unittest.TestCase): x2 = amount("123456789123456789.123456789123456789") self.assertEqual(amount("15241578780673678546105778311537878.046486820281054720515622620750190521"), - x2 * x2) + x2 * x2) self.assertValid(x1) self.assertValid(y1) self.assertValid(x2) def testCommodityMultiplication(self): + x0 = amount() x1 = amount("$123.12") y1 = amount("$456.45") x2 = amount(internalAmount("$123.456789")) @@ -686,9 +770,12 @@ class AmountTestCase(unittest.TestCase): self.assertEqual("$15200.00", (x1 * x2).to_string()) self.assertEqual("$15199.99986168", (x2 * x1).to_string()) - self.assertRaises(exceptions.ArithmeticError, operator.mul, x1, x3) - self.assertRaises(exceptions.ArithmeticError, operator.mul, x1, x4) - self.assertRaises(exceptions.ArithmeticError, operator.mul, x1, x5) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 * x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 * x1) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 * x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 * x3) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 * x4) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 * x5) x1 *= amount("123.12") self.assertEqual(internalAmount("$15158.5344"), x1) @@ -712,14 +799,11 @@ class AmountTestCase(unittest.TestCase): self.assertValid(x5) self.assertValid(x7) - def divideByZero(self, amt): - return amt / 0 - def testIntegerDivision(self): x1 = amount(123) y1 = amount(456) - self.assertRaises(exceptions.ArithmeticError, self.divideByZero, x1) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 / 0) self.assertEqual(amount(0), amount(0) / x1) self.assertEqual(amount(0), 0 / x1) self.assertEqual(x1, x1 / 1) @@ -754,7 +838,7 @@ class AmountTestCase(unittest.TestCase): x1 = amount(123.123) y1 = amount(456.456) - self.assertRaises(exceptions.ArithmeticError, self.divideByZero, x1) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 / 0) self.assertEqual(amount("0.008121959"), amount(1.0) / x1) self.assertEqual(amount("0.008121959"), 1.0 / x1) self.assertEqual(x1, x1 / 1.0) @@ -780,8 +864,7 @@ class AmountTestCase(unittest.TestCase): y4 = amount("56.789") self.assertEqual(amount(1.0), x4 / x4) - self.assertEqual(amount("21739560323910.7554497273748437197344556164046"), - x4 / y4) + self.assertEqual(amount("21739560323910.7554497273748437197344556164046"), x4 / y4) self.assertValid(x1) self.assertValid(y1) @@ -789,6 +872,7 @@ class AmountTestCase(unittest.TestCase): self.assertValid(y4) def testCommodityDivision(self): + x0 = amount() x1 = amount("$123.12") y1 = amount("$456.45") x2 = amount(internalAmount("$123.456789")) @@ -796,7 +880,7 @@ class AmountTestCase(unittest.TestCase): x4 = amount("123.45 euro") x5 = amount("123.45€") - self.assertRaises(exceptions.ArithmeticError, operator.div, x1, 0) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 / 0) self.assertEqual(amount("$0.00"), 0 / x1) self.assertEqual(x1, x1 / 1) self.assertEqual(internalAmount("$0.00812216"), 1 / x1) @@ -814,9 +898,12 @@ class AmountTestCase(unittest.TestCase): self.assertEqual("$1.00", (x1 / x2).to_string()) self.assertEqual("$1.00273545321637426901", (x2 / x1).to_string()) - self.assertRaises(exceptions.ArithmeticError, operator.div, x1, x3) - self.assertRaises(exceptions.ArithmeticError, operator.div, x1, x4) - self.assertRaises(exceptions.ArithmeticError, operator.div, x1, x5) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 / x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 / x1) + self.assertRaises(exceptions.ArithmeticError, lambda: x0 / x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 / x3) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 / x4) + self.assertRaises(exceptions.ArithmeticError, lambda: x1 / x5) x1 /= amount("123.12") self.assertEqual(internalAmount("$1.00"), x1) @@ -846,14 +933,20 @@ class AmountTestCase(unittest.TestCase): self.assertValid(x7) def testNegation(self): + x0 = amount() x1 = amount(-123456) x3 = amount(-123.456) x5 = amount("-123456") x6 = amount("-123.456") + x7 = amount("-123456") + x8 = amount("-123.456") x9 = amount(- x3) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.negate()) self.assertEqual(x5, x1) + self.assertEqual(x7, x1) self.assertEqual(x6, x3) + self.assertEqual(x8, x3) self.assertEqual(- x6, x9) self.assertEqual(x3.negate(), x9) @@ -865,6 +958,8 @@ class AmountTestCase(unittest.TestCase): self.assertValid(x3) self.assertValid(x5) self.assertValid(x6) + self.assertValid(x7) + self.assertValid(x8) self.assertValid(x9) self.assertValid(x10) @@ -926,9 +1021,9 @@ class AmountTestCase(unittest.TestCase): x1 = amount(-1234) x2 = amount(1234) - self.assertRaises(exceptions.ArithmeticError, amount.abs, x0) - self.assertEqual(amount(1234), abs(x1)) - self.assertEqual(amount(1234), abs(x2)) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.abs()) + self.assertEqual(amount(1234), x1.abs()) + self.assertEqual(amount(1234), x2.abs()) self.assertValid(x0) self.assertValid(x1) @@ -938,22 +1033,52 @@ class AmountTestCase(unittest.TestCase): x1 = amount("$-1234.56") x2 = amount("$1234.56") - self.assertEqual(amount("$1234.56"), abs(x1)) - self.assertEqual(amount("$1234.56"), abs(x2)) + self.assertEqual(amount("$1234.56"), x1.abs()) + self.assertEqual(amount("$1234.56"), x2.abs()) self.assertValid(x1) self.assertValid(x2) def testFractionalRound(self): + x0 = amount() x1 = amount("1234.567890") - self.assertEqual(amount("1234.56789"), x1.round(6)) - self.assertEqual(amount("1234.56789"), x1.round(5)) - self.assertEqual(amount("1234.5679"), x1.round(4)) - self.assertEqual(amount("1234.568"), x1.round(3)) - self.assertEqual(amount("1234.57"), x1.round(2)) - self.assertEqual(amount("1234.6"), x1.round(1)) - self.assertEqual(amount("1235"), x1.round(0)) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.precision) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.round()) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.round(2)) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.unround()) + self.assertEqual(6, x1.precision) + + x1b = amount(x1.unround()) + + self.assertEqual(x1b.precision, x1b.unround().precision) + + y7 = amount(x1.round(7)) + y6 = amount(x1.round(6)) + y5 = amount(x1.round(5)) + y4 = amount(x1.round(4)) + y3 = amount(x1.round(3)) + y2 = amount(x1.round(2)) + y1 = amount(x1.round(1)) + y0 = amount(x1.round(0)) + + self.assertEqual(6, y7.precision) + self.assertEqual(6, y6.precision) + self.assertEqual(5, y5.precision) + self.assertEqual(4, y4.precision) + self.assertEqual(3, y3.precision) + self.assertEqual(2, y2.precision) + self.assertEqual(1, y1.precision) + self.assertEqual(0, y0.precision) + + self.assertEqual(amount("1234.56789"), y7) + self.assertEqual(amount("1234.56789"), y6) + self.assertEqual(amount("1234.56789"), y5) + self.assertEqual(amount("1234.5679"), y4) + self.assertEqual(amount("1234.568"), y3) + self.assertEqual(amount("1234.57"), y2) + self.assertEqual(amount("1234.6"), y1) + self.assertEqual(amount("1235"), y0) x2 = amount("9876.543210") @@ -988,7 +1113,7 @@ class AmountTestCase(unittest.TestCase): x5 = amount("0.0000000000000000000000000000000000001") self.assertEqual(amount("0.0000000000000000000000000000000000001"), - x5.round(37)) + x5.round(37)) self.assertEqual(amount(0), x5.round(36)) self.assertValid(x1) @@ -1074,22 +1199,26 @@ class AmountTestCase(unittest.TestCase): self.assertEqual("$1.13", x1.to_string()) def testReduction(self): - x1 = amount("60s") - x2 = amount("600s") - x3 = amount("6000s") - x4 = amount("360000s") - x5 = amount("10m") # 600s - x6 = amount("100m") # 6000s - x7 = amount("1000m") # 60000s - x8 = amount("10000m") # 600000s - x9 = amount("10h") # 36000s - x10 = amount("100h") # 360000s - x11 = amount("1000h") # 3600000s - x12 = amount("10000h") # 36000000s - + x0 = amount() + x1 = amount("60s") + x2 = amount("600s") + x3 = amount("6000s") + x4 = amount("360000s") + x5 = amount("10m") + x6 = amount("100m") + x7 = amount("1000m") + x8 = amount("10000m") + x9 = amount("10h") + x10 = amount("100h") + x11 = amount("1000h") + x12 = amount("10000h") + + self.assertRaises(exceptions.ArithmeticError, lambda: x0.reduce()) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.unreduce()) self.assertEqual(x2, x5) self.assertEqual(x3, x6) self.assertEqual(x4, x10) + self.assertEqual("100.0h", x4.unreduce().to_string()) def testSign(self): x0 = amount() @@ -1098,7 +1227,7 @@ class AmountTestCase(unittest.TestCase): x3 = amount("1") x4 = amount("-1") - self.assertRaises(exceptions.ArithmeticError, amount.sign, x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.sign()) self.assertTrue(x1.sign() > 0) self.assertTrue(x2.sign() < 0) self.assertTrue(x3.sign() > 0) @@ -1131,7 +1260,8 @@ class AmountTestCase(unittest.TestCase): x1 = amount("1234") x2 = amount("1234.56") - self.assertRaises(exceptions.ArithmeticError, operator.truth, x0) + self.assertRaises(exceptions.ArithmeticError, lambda: 1 if x0 else 0) + self.assertTrue(x1) self.assertTrue(x2) @@ -1144,14 +1274,14 @@ class AmountTestCase(unittest.TestCase): x2 = amount("$1234.56") if x1: - self.assertTrue(True) + self.assertTrue(True) else: - self.assertTrue(False) + self.assertTrue(False) if x2: - self.assertTrue(True) + self.assertTrue(True) else: - self.assertTrue(False) + self.assertTrue(False) self.assertValid(x1) self.assertValid(x2) @@ -1161,8 +1291,8 @@ class AmountTestCase(unittest.TestCase): x1 = amount("0.000000000000000000001") self.assertTrue(x1) - self.assertRaises(exceptions.ArithmeticError, amount.is_zero, x0) - self.assertRaises(exceptions.ArithmeticError, amount.is_realzero, x0) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.is_zero()) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.is_realzero()) self.assertFalse(x1.is_zero()) self.assertFalse(x1.is_realzero()) @@ -1179,45 +1309,162 @@ class AmountTestCase(unittest.TestCase): self.assertValid(x1) def testIntegerConversion(self): + x0 = amount() x1 = amount(123456) + x2 = amount("12345682348723487324") - self.assertEqual(123456, int(x1)) - self.assertEqual(123456.0, float(x1)) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.to_long()) + self.assertRaises(exceptions.ArithmeticError, lambda: x0.to_double()) + self.assertFalse(x2.fits_in_long()) + self.assertEqual(123456, x1.to_long()) + self.assertEqual(123456.0, x1.to_double()) self.assertEqual("123456", x1.to_string()) - self.assertEqual("123456", x1.quantity_string()) + self.assertEqual("123456", x1.quantity_string) self.assertValid(x1) def testFractionalConversion(self): x1 = amount(1234.56) + x2 = amount("1234.5683787634678348734") - self.assertRaises(exceptions.ArithmeticError, amount.to_long, x1) + self.assertRaises(exceptions.ArithmeticError, lambda: x1.to_long()) # loses precision + self.assertRaises(exceptions.ArithmeticError, lambda: x2.to_double()) # loses precision + self.assertFalse(x2.fits_in_double()) self.assertEqual(1234, x1.to_long(True)) - self.assertEqual(1234.56, float(x1)) + self.assertEqual(1234.56, x1.to_double()) self.assertEqual("1234.56", x1.to_string()) - self.assertEqual("1234.56", x1.quantity_string()) + self.assertEqual("1234.56", x1.quantity_string) self.assertValid(x1) def testCommodityConversion(self): x1 = amount("$1234.56") - self.assertRaises(exceptions.ArithmeticError, amount.to_long, x1) + self.assertRaises(exceptions.ArithmeticError, lambda: x1.to_long()) # loses precision self.assertEqual(1234, x1.to_long(True)) - self.assertEqual(1234.56, float(x1)) + self.assertEqual(1234.56, x1.to_double()) self.assertEqual("$1234.56", x1.to_string()) - self.assertEqual("1234.56", x1.quantity_string()) + self.assertEqual("1234.56", x1.quantity_string) self.assertValid(x1) def testPrinting(self): pass + #x0 = amount() + #x1 = amount("982340823.380238098235098235098235098") + # + #bufstr = StringIO() + #self.assertRaises(exceptions.ArithmeticError, lambda: bufstr.write(x0)) + # + #bufstr = StringIO() + #bufstr.write(x1) + # + #self.assertEqual("982340823.380238098235098235098235098", + # bufstr.getvalue()) + # + #self.assertValid(x0) + #self.assertValid(x1) def testCommodityPrinting(self): pass - + #x1 = amount(internalAmount("$982340823.386238098235098235098235098")) + #x2 = amount("$982340823.38") + # + #bufstr = StringIO() + #bufstr.write(x1) + # + #self.assertEqual("$982340823.386238098235098235098235098", + # bufstr.getvalue()) + # + #bufstr = StringIO() + #bufstr.write((x1 * x2).to_string()) + # + #self.assertEqual("$964993493285024293.18099172508158508135413499124", + # bufstr.getvalue()) + # + #bufstr = StringIO() + #bufstr.write((x2 * x1).to_string()) + # + #self.assertEqual("$964993493285024293.18", bufstr.getvalue()) + # + #self.assertValid(x1) + #self.assertValid(x2) + + def testSerialization(self): + pass + #x0 = amount() + #x1 = amount("$8,192.34") + #x2 = amount("8192.34") + #x3 = amount("8192.34") + #x4 = amount("-8192.34") + #x5 = amount(x4) + # + ## Force x3's pointer to actually be set to null_commodity + ##x3.set_commodity(*x3.current_pool.null_commodity) + # + #buf = "" + #storage = StringIO() + #self.assertRaises(exceptions.ArithmeticError, lambda: x0.write(storage)) + #x1.write(storage) + #x2.write(storage) + #x3.write(storage) + #x4.write(storage) + #x5.write(storage) + #buf = storage.getvalue() + # + #x1b = amount() + #x2b = amount() + #x3b = amount() + #x4b = amount() + #x5b = amount() + # + #storage = StringIO(buf) + #x1b.read(storage) + #x2b.read(storage) + #x3b.read(storage) + #x4b.read(storage) + #x5b.read(storage) + # + #self.assertEqual(x1, x1b) + #self.assertEqual(x2, x2b) + #self.assertEqual(x3, x3b) + #self.assertEqual(x4, x4b) + # + #ptr = buf.c_str() + # + #x1c = amount() + #x2c = amount() + #x3c = amount() + #x4c = amount() + #x5c = amount() + # + #x1c.read(ptr) + #x2c.read(ptr) + #x3c.read(ptr) + #x4c.read(ptr) + #x5c.read(ptr) + # + #self.assertEqual(x1, x1b) + #self.assertEqual(x2, x2b) + #self.assertEqual(x3, x3b) + #self.assertEqual(x4, x4b) + # + #self.assertValid(x1) + #self.assertValid(x2) + #self.assertValid(x3) + #self.assertValid(x4) + #self.assertValid(x1b) + #self.assertValid(x2b) + #self.assertValid(x3b) + #self.assertValid(x4b) + #self.assertValid(x1c) + #self.assertValid(x2c) + #self.assertValid(x3c) + #self.assertValid(x4c) + + def suite(): - return unittest.TestLoader().loadTestsFromTestCase(AmountTestCase) + return unittest.TestLoader().loadTestsFromTestCase(t_amountTestCase) if __name__ == '__main__': unittest.main() |