summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--python/demo.py120
-rw-r--r--src/amount.cc54
-rw-r--r--src/amount.h6
-rw-r--r--src/annotate.cc4
-rw-r--r--src/balance.cc6
-rw-r--r--src/commodity.cc10
-rw-r--r--src/commodity.h2
-rw-r--r--src/journal.cc16
-rw-r--r--src/journal.h3
-rw-r--r--src/op.cc2
-rw-r--r--src/pool.cc5
-rw-r--r--src/pool.h5
-rw-r--r--src/py_amount.cc76
-rw-r--r--src/py_balance.cc10
-rw-r--r--src/py_commodity.cc199
-rw-r--r--src/py_journal.cc8
-rw-r--r--src/py_value.cc39
-rw-r--r--src/pyutils.h20
-rw-r--r--src/quotes.cc8
-rw-r--r--src/report.cc17
-rw-r--r--src/session.cc4
-rw-r--r--src/textual.cc6
-rw-r--r--src/value.cc7
-rw-r--r--src/value.h2
-rw-r--r--src/xact.cc13
-rwxr-xr-xtest/convert.py2
-rw-r--r--test/regress/25A099C9.test12
27 files changed, 449 insertions, 207 deletions
diff --git a/python/demo.py b/python/demo.py
new file mode 100644
index 00000000..788610d7
--- /dev/null
+++ b/python/demo.py
@@ -0,0 +1,120 @@
+import sys
+
+import ledger
+
+print "Welcome to the Ledger.Python demo!"
+
+def assertEqual(pat, candidate):
+ if pat != candidate:
+ print "FAILED: %s != %s" % (pat, candidate)
+ sys.exit(1)
+
+# COMMODITIES
+
+pool = ledger.commodity_pool
+
+usd = pool.find_or_create('$')
+eur = pool.find_or_create('EUR')
+xcd = pool.find_or_create('XCD')
+
+assertEqual('$', usd.symbol)
+assertEqual('$', pool['$'].symbol)
+
+assert not pool.find('CAD')
+assert not pool.has_key('CAD')
+assert not 'CAD' in pool
+
+# There are a few built-in commodities: null, %, h, m and s
+assertEqual([u'', u'$', u'%', u'EUR', u'XCD',
+ u'h', u'm', u's'], sorted(pool.keys()))
+
+for symbol in pool.iterkeys(): pass
+for commodity in pool.itervalues(): pass
+
+# jww (2009-11-19): Not working: missing conversion from std::pair
+#for symbol, commodity in pool.iteritems(): pass
+#for symbol, commodity in pool: pass
+
+# This creates a price exchange entry, trading EUR for $0.77 each at the
+# current time.
+pool.exchange(eur, ledger.Amount('$0.77'))
+
+# AMOUNTS & BALANCES
+
+# When two amounts are multipied or divided, the result carries the commodity
+# of the first term. So, 1 EUR / $0.77 == roughly 1.2987 EUR
+amt = ledger.Amount('$100.12')
+market = ((ledger.Amount('1 EUR') / ledger.Amount('$0.77')) * amt)
+
+# An amount's "precision" is a notional thing only. Since Ledger uses
+# rational numbers throughout, and only renders to decimal form for printing
+# to the user, the meaning of amt.precision should not be relied on as
+# meaningful. It only controls how much precision unrounded numbers (those
+# for which keep_precision is True, and thus that ignore display_precision)
+# are rendered into strings. This is the case, btw, for all uncommoditized
+# amounts.
+assert not amt.keep_precision
+assertEqual(2, amt.precision)
+assertEqual(2, amt.display_precision)
+
+assertEqual('$-100.12', str(amt.negated())) # negate the amount
+assertEqual('$0.01', str(amt.inverted())) # reverse NUM/DEM
+assertEqual('$100.12', str(amt.rounded())) # round it to display precision
+assertEqual('$100.12', str(amt.truncated())) # truncate to display precision
+assertEqual('$100.00', str(amt.floored())) # floor it to nearest integral
+assertEqual(market, amt.value(eur)) # find present market value
+assertEqual('$100.12', str(abs(amt))) # absolute value
+assertEqual('$100.12', str(amt)) # render to a string
+assertEqual('100.12', amt.quantity_string()) # render quantity to a string
+assertEqual('100.12', str(amt.number())) # strip away commodity
+assertEqual(1, amt.sign()) # -1, 0 or 1
+assert amt.is_nonzero() # True if display amount nonzero
+assert not amt.is_zero() # True if display amount is zero
+assert not amt.is_realzero() # True only if value is 0/0
+assert not amt.is_null() # True if uninitialized
+
+assertEqual(100.12, amt.to_double())
+assert amt.fits_in_long()
+assertEqual(100, amt.to_long())
+
+amt2 = ledger.Amount('$100.12 {140 EUR}')
+
+assert amt2.has_annotation()
+assertEqual(amt, amt2.strip_annotations(ledger.KeepDetails()))
+
+# jww (2009-11-19): Not working: missing conversion from optional<amount_t>
+#assertEqual(ledger.Amount('20 EUR'), amt.annotation.price)
+
+# VALUES
+
+val = ledger.Value('$100.00')
+
+assert val.is_amount()
+assertEqual('$', val.to_amount().commodity.symbol)
+
+# JOURNALS
+
+#journal.find_account('')
+#journal.find_or_create_account('')
+
+# ACCOUNTS
+
+#account.name
+#account.fullname()
+#account.amount
+#account.total
+
+# TRANSACTIONS
+
+#txn.payee
+
+# POSTINGS
+
+#post.account
+
+# REPORTING
+
+#journal.collect('-M food')
+#journal.collect_accounts('^assets ^liab ^equity')
+
+print 'Demo completed successfully.'
diff --git a/src/amount.cc b/src/amount.cc
index 82b93931..eddbca18 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -106,8 +106,6 @@ private:
#endif // HAVE_BOOST_SERIALIZATION
};
-shared_ptr<commodity_pool_t> amount_t::current_pool;
-
bool amount_t::is_initialized = false;
namespace {
@@ -203,7 +201,7 @@ namespace {
}
}
-void amount_t::initialize(shared_ptr<commodity_pool_t> pool)
+void amount_t::initialize()
{
if (! is_initialized) {
mpz_init(temp);
@@ -211,26 +209,35 @@ void amount_t::initialize(shared_ptr<commodity_pool_t> pool)
mpfr_init(tempf);
mpfr_init(tempfb);
+ commodity_pool_t::current_pool.reset(new commodity_pool_t);
+
+ // Add time commodity conversions, so that timelog's may be parsed
+ // in terms of seconds, but reported as minutes or hours.
+ if (commodity_t * commodity = commodity_pool_t::current_pool->create("s"))
+ commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
+ else
+ assert(false);
+
+ // Add a "percentile" commodity
+ if (commodity_t * commodity = commodity_pool_t::current_pool->create("%"))
+ commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
+ else
+ assert(false);
+
is_initialized = true;
}
- current_pool = pool;
-}
-
-void amount_t::initialize()
-{
- initialize(shared_ptr<commodity_pool_t>(new commodity_pool_t));
}
void amount_t::shutdown()
{
- current_pool.reset();
-
if (is_initialized) {
mpz_clear(temp);
mpq_clear(tempq);
mpfr_clear(tempf);
mpfr_clear(tempfb);
+ commodity_pool_t::current_pool.reset();
+
is_initialized = false;
}
}
@@ -670,7 +677,7 @@ amount_t::value(const bool primary_only,
if (in_terms_of && commodity() == *in_terms_of) {
return *this;
}
- else if (is_annotated() && annotation().price &&
+ else if (has_annotation() && annotation().price &&
annotation().has_flags(ANNOTATION_PRICE_FIXATED)) {
return (*annotation().price * number()).rounded();
}
@@ -696,7 +703,7 @@ amount_t::value(const bool primary_only,
amount_t amount_t::price() const
{
- if (is_annotated() && annotation().price) {
+ if (has_annotation() && annotation().price) {
amount_t temp(*annotation().price);
temp *= *this;
DEBUG("amount.price", "Returning price of " << *this << " = " << temp);
@@ -776,7 +783,8 @@ bool amount_t::fits_in_long() const
commodity_t& amount_t::commodity() const
{
- return has_commodity() ? *commodity_ : *current_pool->null_commodity;
+ return (has_commodity() ?
+ *commodity_ : *commodity_pool_t::current_pool->null_commodity);
}
bool amount_t::has_commodity() const
@@ -794,7 +802,7 @@ void amount_t::annotate(const annotation_t& details)
else if (! has_commodity())
return; // ignore attempt to annotate a "bare commodity
- if (commodity().is_annotated()) {
+ if (commodity().has_annotation()) {
this_ann = &as_annotated_commodity(commodity());
this_base = &this_ann->referent();
} else {
@@ -816,15 +824,15 @@ void amount_t::annotate(const annotation_t& details)
DEBUG("amounts.commodities", "Annotated amount is " << *this);
}
-bool amount_t::is_annotated() const
+bool amount_t::has_annotation() const
{
if (! quantity)
throw_(amount_error,
_("Cannot determine if an uninitialized amount's commodity is annotated"));
- assert(! has_commodity() || ! commodity().is_annotated() ||
+ assert(! has_commodity() || ! commodity().has_annotation() ||
as_annotated_commodity(commodity()).details);
- return has_commodity() && commodity().is_annotated();
+ return has_commodity() && commodity().has_annotation();
}
annotation_t& amount_t::annotation()
@@ -833,7 +841,7 @@ annotation_t& amount_t::annotation()
throw_(amount_error,
_("Cannot return commodity annotation details of an uninitialized amount"));
- if (! commodity().is_annotated())
+ if (! commodity().has_annotation())
throw_(amount_error,
_("Request for annotation details from an unannotated amount"));
@@ -963,15 +971,16 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
if (symbol.empty()) {
commodity_ = NULL;
} else {
- commodity_ = current_pool->find(symbol);
+ commodity_ = commodity_pool_t::current_pool->find(symbol);
if (! commodity_) {
- commodity_ = current_pool->create(symbol);
+ commodity_ = commodity_pool_t::current_pool->create(symbol);
newly_created = true;
}
assert(commodity_);
if (details)
- commodity_ = current_pool->find_or_create(*commodity_, details);
+ commodity_ =
+ commodity_pool_t::current_pool->find_or_create(*commodity_, details);
}
// Quickly scan through and verify the correctness of the amount's use of
@@ -1206,7 +1215,6 @@ void to_xml(std::ostream& out, const amount_t& amt, bool commodity_details)
template<class Archive>
void amount_t::serialize(Archive& ar, const unsigned int /* version */)
{
- ar & current_pool;
ar & is_initialized;
ar & quantity;
ar & commodity_;
diff --git a/src/amount.h b/src/amount.h
index c75370e3..a8c08905 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -97,12 +97,8 @@ class amount_t
ordered_field_operators<amount_t, long> > > >
{
public:
- /** Indicates which commodity pool should be used. */
- static shared_ptr<commodity_pool_t> current_pool;
-
/** Ready the amount subsystem for use.
@note Normally called by session_t::initialize(). */
- static void initialize(shared_ptr<commodity_pool_t> pool);
static void initialize();
/** Shutdown the amount subsystem and free all resources.
@note Normally called by session_t::shutdown(). */
@@ -577,7 +573,7 @@ public:
been stripped.
*/
void annotate(const annotation_t& details);
- bool is_annotated() const;
+ bool has_annotation() const;
annotation_t& annotation();
const annotation_t& annotation() const {
diff --git a/src/annotate.cc b/src/annotate.cc
index bd5a8ef8..146a7afd 100644
--- a/src/annotate.cc
+++ b/src/annotate.cc
@@ -135,13 +135,13 @@ void annotation_t::print(std::ostream& out, bool keep_base) const
bool keep_details_t::keep_all(const commodity_t& comm) const
{
- return (! comm.is_annotated() ||
+ return (! comm.has_annotation() ||
(keep_price && keep_date && keep_tag && ! only_actuals));
}
bool keep_details_t::keep_any(const commodity_t& comm) const
{
- return comm.is_annotated() && (keep_price || keep_date || keep_tag);
+ return comm.has_annotation() && (keep_price || keep_date || keep_tag);
}
bool annotated_commodity_t::operator==(const commodity_t& comm) const
diff --git a/src/balance.cc b/src/balance.cc
index 59eb4d92..4ff51ffc 100644
--- a/src/balance.cc
+++ b/src/balance.cc
@@ -43,21 +43,21 @@ balance_t::balance_t(const double val)
{
TRACE_CTOR(balance_t, "const double");
amounts.insert
- (amounts_map::value_type(amount_t::current_pool->null_commodity, val));
+ (amounts_map::value_type(commodity_pool_t::current_pool->null_commodity, val));
}
balance_t::balance_t(const unsigned long val)
{
TRACE_CTOR(balance_t, "const unsigned long");
amounts.insert
- (amounts_map::value_type(amount_t::current_pool->null_commodity, val));
+ (amounts_map::value_type(commodity_pool_t::current_pool->null_commodity, val));
}
balance_t::balance_t(const long val)
{
TRACE_CTOR(balance_t, "const long");
amounts.insert
- (amounts_map::value_type(amount_t::current_pool->null_commodity, val));
+ (amounts_map::value_type(commodity_pool_t::current_pool->null_commodity, val));
}
balance_t& balance_t::operator+=(const balance_t& bal)
diff --git a/src/commodity.cc b/src/commodity.cc
index b76c7896..79ed77fe 100644
--- a/src/commodity.cc
+++ b/src/commodity.cc
@@ -600,11 +600,11 @@ bool compare_amount_commodities::operator()(const amount_t * left,
if (cmp != 0)
return cmp < 0;
- if (! leftcomm.is_annotated()) {
- return rightcomm.is_annotated();
+ if (! leftcomm.has_annotation()) {
+ return rightcomm.has_annotation();
}
- else if (! rightcomm.is_annotated()) {
- return ! leftcomm.is_annotated();
+ else if (! rightcomm.has_annotation()) {
+ return ! leftcomm.has_annotation();
}
else {
annotated_commodity_t& aleftcomm(static_cast<annotated_commodity_t&>(leftcomm));
@@ -675,7 +675,7 @@ void to_xml(std::ostream& out, const commodity_t& comm,
}
if (commodity_details) {
- if (comm.is_annotated())
+ if (comm.has_annotation())
to_xml(out, as_annotated_commodity(comm).details);
if (comm.varied_history()) {
diff --git a/src/commodity.h b/src/commodity.h
index 42cc6d8f..d5f18844 100644
--- a/src/commodity.h
+++ b/src/commodity.h
@@ -251,7 +251,7 @@ public:
return *this;
}
- bool is_annotated() const {
+ bool has_annotation() const {
return annotated;
}
diff --git a/src/journal.cc b/src/journal.cc
index 2366ce30..6ebccd66 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -77,7 +77,6 @@ journal_t::~journal_t()
checked_delete(xact);
checked_delete(master);
- commodity_pool.reset();
}
void journal_t::initialize()
@@ -85,21 +84,6 @@ void journal_t::initialize()
master = new account_t;
bucket = NULL;
was_loaded = false;
-
- commodity_pool.reset(new commodity_pool_t);
-
- // Add time commodity conversions, so that timelog's may be parsed
- // in terms of seconds, but reported as minutes or hours.
- if (commodity_t * commodity = commodity_pool->create("s"))
- commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
- else
- assert(false);
-
- // Add a "percentile" commodity
- if (commodity_t * commodity = commodity_pool->create("%"))
- commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
- else
- assert(false);
}
void journal_t::add_account(account_t * acct)
diff --git a/src/journal.h b/src/journal.h
index f7124736..8d59e3b4 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -47,7 +47,6 @@
namespace ledger {
-class commodity_pool_t;
class xact_base_t;
class xact_t;
class auto_xact_t;
@@ -112,8 +111,6 @@ public:
std::list<fileinfo_t> sources;
bool was_loaded;
- shared_ptr<commodity_pool_t> commodity_pool;
-
journal_t();
journal_t(const path& pathname);
journal_t(const string& str);
diff --git a/src/op.cc b/src/op.cc
index 2815ac1a..f38fc86b 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -624,7 +624,7 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const
}
if (! symbol.empty()) {
- if (amount_t::current_pool->find(symbol))
+ if (commodity_pool_t::current_pool->find(symbol))
out << '@';
out << symbol;
}
diff --git a/src/pool.cc b/src/pool.cc
index b08c8fad..9e06613f 100644
--- a/src/pool.cc
+++ b/src/pool.cc
@@ -39,6 +39,8 @@
namespace ledger {
+shared_ptr<commodity_pool_t> commodity_pool_t::current_pool;
+
commodity_pool_t::commodity_pool_t()
: default_commodity(NULL), keep_base(false),
quote_leeway(86400), get_quotes(false),
@@ -318,8 +320,7 @@ optional<price_point_t> commodity_pool_t::parse_price_directive(char * line)
VERIFY(point.price.valid());
DEBUG("commodity.download", "Looking up symbol: " << symbol);
- if (commodity_t * commodity =
- amount_t::current_pool->find_or_create(symbol)) {
+ if (commodity_t * commodity = find_or_create(symbol)) {
DEBUG("commodity.download", "Adding price for " << symbol << ": "
<< point.when << " " << point.price);
commodity->add_price(point.when, point.price, true);
diff --git a/src/pool.h b/src/pool.h
index 7328df9d..c3d701b9 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -57,6 +57,7 @@ struct cost_breakdown_t
class commodity_pool_t : public noncopyable
{
+public:
/**
* The commodities collection in commodity_pool_t maintains pointers to all
* the commodities which have ever been created by the user, whether
@@ -65,7 +66,6 @@ class commodity_pool_t : public noncopyable
*/
typedef std::map<string, commodity_t *> commodities_map;
-public:
commodities_map commodities;
commodity_t * null_commodity;
commodity_t * default_commodity;
@@ -76,6 +76,8 @@ public:
long quote_leeway; // --leeway=
bool get_quotes; // --download
+ static shared_ptr<commodity_pool_t> current_pool;
+
function<optional<price_point_t>
(commodity_t& commodity, const optional<commodity_t&>& in_terms_of)>
get_commodity_quote;
@@ -136,6 +138,7 @@ private:
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
+ ar & current_pool;
ar & commodities;
ar & null_commodity;
ar & default_commodity;
diff --git a/src/py_amount.cc b/src/py_amount.cc
index b44f3716..2307c454 100644
--- a/src/py_amount.cc
+++ b/src/py_amount.cc
@@ -44,27 +44,14 @@ using namespace boost::python;
namespace {
- 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);
+ py_value_1(const amount_t& amount, commodity_t& in_terms_of) {
+ return amount.value(false, CURRENT_TIME(), in_terms_of);
}
-
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);
+ py_value_2(const amount_t& amount, commodity_t& in_terms_of,
+ datetime_t& moment) {
+ return amount.value(false, moment, in_terms_of);
}
void py_parse_2(amount_t& amount, object in, unsigned char flags) {
@@ -97,8 +84,15 @@ namespace {
}
}
- void py_amount_initialize() {
- amount_t::initialize();
+ annotation_t& py_amount_annotation(amount_t& amount) {
+ return amount.annotation();
+ }
+
+ amount_t py_strip_annotations_0(amount_t& amount) {
+ return amount.strip_annotations(keep_details_t());
+ }
+ amount_t py_strip_annotations_1(amount_t& amount, const keep_details_t& keep) {
+ return amount.strip_annotations(keep);
}
} // unnamed namespace
@@ -113,11 +107,7 @@ EXC_TRANSLATOR(amount_error)
void export_amount()
{
class_< amount_t > ("Amount")
- .add_static_property("current_pool",
- make_getter(&amount_t::current_pool,
- return_internal_reference<>()))
-
- .def("initialize", py_amount_initialize) // only for the PyUnitTests
+ .def("initialize", &amount_t::initialize) // only for the PyUnitTests
.staticmethod("initialize")
.def("shutdown", &amount_t::shutdown)
.staticmethod("shutdown")
@@ -196,11 +186,11 @@ internal precision."))
.def(self / long())
.def(long() / self)
- .def("precision", &amount_t::precision)
- .def("keep_precision", &amount_t::keep_precision)
- .def("set_keep_precision", &amount_t::set_keep_precision, args("keep"),
- _("Set whether an amount should always display at full precision."))
- .def("display_precision", &amount_t::display_precision)
+ .add_property("precision", &amount_t::precision)
+ .add_property("display_precision", &amount_t::display_precision)
+ .add_property("keep_precision",
+ &amount_t::keep_precision,
+ &amount_t::set_keep_precision)
.def("negated", &amount_t::negated)
.def("in_place_negate", &amount_t::in_place_negate,
@@ -236,10 +226,8 @@ internal precision."))
.def("in_place_unreduce", &amount_t::in_place_unreduce,
return_internal_reference<>())
- .def("value", py_value_0)
- .def("value", py_value_1, args("primary_only"))
- .def("value", py_value_2, args("primary_only", "moment"))
- .def("value", py_value_3, args("primary_only", "moment", "in_terms_of"))
+ .def("value", py_value_1, args("moment"))
+ .def("value", py_value_2, args("in_terms_of", "moment"))
.def("price", &amount_t::price)
@@ -262,21 +250,23 @@ internal precision."))
.def("__repr__", &amount_t::to_fullstring)
.def("quantity_string", &amount_t::quantity_string)
- .def("commodity", &amount_t::commodity,
- return_internal_reference<>())
+ .add_property("commodity",
+ make_function(&amount_t::commodity,
+ return_value_policy<reference_existing_object>()),
+ make_function(&amount_t::set_commodity,
+ with_custodian_and_ward<1, 2>()))
.def("has_commodity", &amount_t::has_commodity)
- .def("set_commodity", &amount_t::set_commodity,
- with_custodian_and_ward<1, 2>())
.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("has_annotation", &amount_t::has_annotation)
+ .add_property("annotation",
+ make_function(py_amount_annotation,
+ return_internal_reference<>()))
+ .def("strip_annotations", py_strip_annotations_0)
+ .def("strip_annotations", py_strip_annotations_1)
.def("parse", py_parse_1)
.def("parse", py_parse_2)
diff --git a/src/py_balance.cc b/src/py_balance.cc
index 23a2ff73..5aed2b43 100644
--- a/src/py_balance.cc
+++ b/src/py_balance.cc
@@ -108,6 +108,13 @@ namespace {
return (*elem).second;
}
+ balance_t py_strip_annotations_0(balance_t& balance) {
+ return balance.strip_annotations(keep_details_t());
+ }
+ balance_t py_strip_annotations_1(balance_t& balance, const keep_details_t& keep) {
+ return balance.strip_annotations(keep);
+ }
+
} // unnamed namespace
#define EXC_TRANSLATOR(type) \
@@ -215,7 +222,8 @@ void export_balance()
.def("number", &balance_t::number)
- .def("strip_annotations", &balance_t::strip_annotations)
+ .def("strip_annotations", py_strip_annotations_0)
+ .def("strip_annotations", py_strip_annotations_1)
.def("valid", &balance_t::valid)
;
diff --git a/src/py_commodity.cc b/src/py_commodity.cc
index 08af8f62..dfaf7f5b 100644
--- a/src/py_commodity.cc
+++ b/src/py_commodity.cc
@@ -32,6 +32,7 @@
#include <system.hh>
#include "pyinterp.h"
+#include "pyutils.h"
#include "commodity.h"
#include "annotate.h"
#include "pool.h"
@@ -81,6 +82,12 @@ namespace {
// Exchange one commodity for another, while recording the factored price.
+ void py_exchange_2(commodity_pool_t& pool,
+ commodity_t& commodity,
+ const amount_t& per_unit_cost)
+ {
+ pool.exchange(commodity, per_unit_cost, CURRENT_TIME());
+ }
void py_exchange_3(commodity_pool_t& pool,
commodity_t& commodity,
const amount_t& per_unit_cost,
@@ -99,6 +106,77 @@ namespace {
return pool.exchange(amount, cost, is_per_unit, moment, tag);
}
+ commodity_t * py_pool_getitem(commodity_pool_t& pool, const string& symbol)
+ {
+ commodity_pool_t::commodities_map::iterator i =
+ pool.commodities.find(symbol);
+ if (i == pool.commodities.end()) {
+ PyErr_SetString(PyExc_ValueError,
+ (string("Could not find commodity ") + symbol).c_str());
+ throw boost::python::error_already_set();
+ }
+ return (*i).second;
+ }
+
+ python::list py_pool_keys(commodity_pool_t& pool) {
+ python::list keys;
+ BOOST_REVERSE_FOREACH
+ (const commodity_pool_t::commodities_map::value_type& pair,
+ pool.commodities) {
+ keys.insert(0, pair.first);
+ }
+ return keys;
+ }
+
+ bool py_pool_contains(commodity_pool_t& pool, const string& symbol) {
+ return pool.commodities.find(symbol) != pool.commodities.end();
+ }
+
+ commodity_pool_t::commodities_map::iterator
+ py_pool_commodities_begin(commodity_pool_t& pool) {
+ return pool.commodities.begin();
+ }
+ commodity_pool_t::commodities_map::iterator
+ py_pool_commodities_end(commodity_pool_t& pool) {
+ return pool.commodities.end();
+ }
+
+ typedef transform_iterator
+ <function<string(commodity_pool_t::commodities_map::value_type&)>,
+ commodity_pool_t::commodities_map::iterator>
+ commodities_map_firsts_iterator;
+ commodities_map_firsts_iterator
+
+ py_pool_commodities_keys_begin(commodity_pool_t& pool) {
+ return make_transform_iterator
+ (pool.commodities.begin(),
+ bind(&commodity_pool_t::commodities_map::value_type::first, _1));
+ }
+ commodities_map_firsts_iterator
+ py_pool_commodities_keys_end(commodity_pool_t& pool) {
+ return make_transform_iterator
+ (pool.commodities.end(),
+ bind(&commodity_pool_t::commodities_map::value_type::first, _1));
+ }
+
+ typedef transform_iterator
+ <function<commodity_t *(commodity_pool_t::commodities_map::value_type&)>,
+ commodity_pool_t::commodities_map::iterator>
+ commodities_map_seconds_iterator;
+
+ commodities_map_seconds_iterator
+ py_pool_commodities_values_begin(commodity_pool_t& pool) {
+ return make_transform_iterator
+ (pool.commodities.begin(),
+ bind(&commodity_pool_t::commodities_map::value_type::second, _1));
+ }
+ commodities_map_seconds_iterator
+ py_pool_commodities_values_end(commodity_pool_t& pool) {
+ return make_transform_iterator
+ (pool.commodities.end(),
+ bind(&commodity_pool_t::commodities_map::value_type::second, _1));
+ }
+
void py_add_price_2(commodity_t& commodity,
const datetime_t& date, const amount_t& price) {
commodity.add_price(date, price);
@@ -123,16 +201,38 @@ namespace {
return details.keep_any(comm);
}
+ commodity_t& py_commodity_referent(commodity_t& comm) {
+ return comm.referent();
+ }
+ commodity_t& py_annotated_commodity_referent(annotated_commodity_t& comm) {
+ return comm.referent();
+ }
+
+ commodity_t& py_strip_annotations_0(commodity_t& comm) {
+ return comm.strip_annotations(keep_details_t());
+ }
+ commodity_t& py_strip_annotations_1(commodity_t& comm,
+ const keep_details_t& keep) {
+ return comm.strip_annotations(keep);
+ }
+
+ commodity_t& py_strip_ann_annotations_0(annotated_commodity_t& comm) {
+ return comm.strip_annotations(keep_details_t());
+ }
+ commodity_t& py_strip_ann_annotations_1(annotated_commodity_t& comm,
+ const keep_details_t& keep) {
+ return comm.strip_annotations(keep);
+ }
+
} // unnamed namespace
void export_commodity()
{
- class_< commodity_pool_t, boost::noncopyable > ("CommodityPool", no_init)
+ class_< commodity_pool_t, shared_ptr<commodity_pool_t>,
+ boost::noncopyable > ("CommodityPool", no_init)
.add_property("null_commodity",
make_getter(&commodity_pool_t::null_commodity,
- return_internal_reference<>()),
- make_setter(&commodity_pool_t::null_commodity,
- with_custodian_and_ward<1, 2>()))
+ return_internal_reference<>()))
.add_property("default_commodity",
make_getter(&commodity_pool_t::default_commodity,
return_internal_reference<>()),
@@ -157,25 +257,46 @@ void export_commodity()
.def("make_qualified_name", &commodity_pool_t::make_qualified_name)
- .def("create", py_create_1, return_internal_reference<>())
- .def("create", py_create_2, return_internal_reference<>())
+ .def("create", py_create_1,
+ return_value_policy<reference_existing_object>())
+ .def("create", py_create_2,
+ return_value_policy<reference_existing_object>())
.def("find_or_create", py_find_or_create_1,
- return_internal_reference<>())
+ return_value_policy<reference_existing_object>())
.def("find_or_create", py_find_or_create_2,
- return_internal_reference<>())
+ return_value_policy<reference_existing_object>())
- .def("find", py_find_1, return_internal_reference<>())
- .def("find", py_find_2, return_internal_reference<>())
+ .def("find", py_find_1, return_value_policy<reference_existing_object>())
+ .def("find", py_find_2, return_value_policy<reference_existing_object>())
+ .def("exchange", py_exchange_2, with_custodian_and_ward<1, 2>())
.def("exchange", py_exchange_3, with_custodian_and_ward<1, 2>())
.def("exchange", py_exchange_5)
.def("parse_price_directive", &commodity_pool_t::parse_price_directive)
.def("parse_price_expression", &commodity_pool_t::parse_price_expression,
- return_internal_reference<>())
+ return_value_policy<reference_existing_object>())
+
+ .def("__getitem__", py_pool_getitem,
+ return_value_policy<reference_existing_object>())
+ .def("keys", py_pool_keys)
+ .def("has_key", py_pool_contains)
+ .def("__contains__", py_pool_contains)
+ .def("__iter__", range<return_value_policy<reference_existing_object> >
+ (py_pool_commodities_begin, py_pool_commodities_end))
+ .def("iteritems", range<return_value_policy<reference_existing_object> >
+ (py_pool_commodities_begin, py_pool_commodities_end))
+ .def("iterkeys", range<>(py_pool_commodities_keys_begin,
+ py_pool_commodities_keys_end))
+ .def("itervalues", range<return_value_policy<reference_existing_object> >
+ (py_pool_commodities_values_begin, py_pool_commodities_values_end))
;
+ map_value_type_converter<commodity_pool_t::commodities_map>();
+
+ scope().attr("commodity_pool") = commodity_pool_t::current_pool;
+
scope().attr("COMMODITY_STYLE_DEFAULTS") = COMMODITY_STYLE_DEFAULTS;
scope().attr("COMMODITY_STYLE_SUFFIXED") = COMMODITY_STYLE_SUFFIXED;
scope().attr("COMMODITY_STYLE_SEPARATED") = COMMODITY_STYLE_SEPARATED;
@@ -209,33 +330,30 @@ void export_commodity()
.def("symbol_needs_quotes", &commodity_t::symbol_needs_quotes)
.staticmethod("symbol_needs_quotes")
-#if 0
- .def("referent", &commodity_t::referent,
- return_internal_reference<>())
-#endif
+ .add_property("referent",
+ make_function(py_commodity_referent,
+ return_value_policy<reference_existing_object>()))
- .def("is_annotated", &commodity_t::is_annotated)
- .def("strip_annotations", &commodity_t::strip_annotations,
- return_internal_reference<>())
+ .def("has_annotation", &commodity_t::has_annotation)
+ .def("strip_annotations", py_strip_annotations_0,
+ return_value_policy<reference_existing_object>())
+ .def("strip_annotations", py_strip_annotations_1,
+ return_value_policy<reference_existing_object>())
.def("write_annotations", &commodity_t::write_annotations)
.def("pool", &commodity_t::pool,
- return_internal_reference<>())
-
- .def("base_symbol", &commodity_t::base_symbol)
- .def("symbol", &commodity_t::symbol)
- .def("mapping_key", &commodity_t::mapping_key)
-
- .def("name", &commodity_t::name)
- .def("set_name", &commodity_t::set_name)
- .def("note", &commodity_t::note)
- .def("set_note", &commodity_t::set_note)
- .def("precision", &commodity_t::precision)
- .def("set_precision", &commodity_t::set_precision)
- .def("smaller", &commodity_t::smaller)
- .def("set_smaller", &commodity_t::set_smaller)
- .def("larger", &commodity_t::larger)
- .def("set_larger", &commodity_t::set_larger)
+ return_value_policy<reference_existing_object>())
+
+ .add_property("base_symbol", &commodity_t::base_symbol)
+ .add_property("symbol", &commodity_t::symbol)
+ .add_property("mapping_key", &commodity_t::mapping_key)
+
+ .add_property("name", &commodity_t::name, &commodity_t::set_name)
+ .add_property("note", &commodity_t::note, &commodity_t::set_note)
+ .add_property("precision", &commodity_t::precision,
+ &commodity_t::set_precision)
+ .add_property("smaller", &commodity_t::smaller, &commodity_t::set_smaller)
+ .add_property("larger", &commodity_t::larger, &commodity_t::set_larger)
.def("add_price", py_add_price_2)
.def("add_price", py_add_price_3)
@@ -306,13 +424,14 @@ void export_commodity()
.def(self == self)
.def(self == other<commodity_t>())
-#if 0
- .def("referent", &annotated_commodity_t::referent,
- return_internal_reference<>())
-#endif
+ .add_property("referent",
+ make_function(py_annotated_commodity_referent,
+ return_value_policy<reference_existing_object>()))
- .def("strip_annotations", &annotated_commodity_t::strip_annotations,
- return_internal_reference<>())
+ .def("strip_annotations", py_strip_ann_annotations_0,
+ return_value_policy<reference_existing_object>())
+ .def("strip_annotations", py_strip_ann_annotations_1,
+ return_value_policy<reference_existing_object>())
.def("write_annotations", &annotated_commodity_t::write_annotations)
;
}
diff --git a/src/py_journal.cc b/src/py_journal.cc
index 7e9f8a1b..5be9cbe1 100644
--- a/src/py_journal.cc
+++ b/src/py_journal.cc
@@ -52,10 +52,6 @@ namespace {
return *journal.master;
}
- commodity_pool_t& py_commodity_pool(journal_t& journal) {
- return *journal.commodity_pool;
- }
-
long xacts_len(journal_t& journal)
{
return journal.xacts.size();
@@ -276,10 +272,6 @@ void export_journal()
with_custodian_and_ward_postcall<1, 0> >()),
make_setter(&journal_t::bucket))
.add_property("was_loaded", make_getter(&journal_t::was_loaded))
- .add_property("commodity_pool",
- make_getter(&journal_t::commodity_pool,
- return_internal_reference<1,
- with_custodian_and_ward_postcall<1, 0> >()))
.def("add_account", &journal_t::add_account)
.def("remove_account", &journal_t::remove_account)
diff --git a/src/py_value.cc b/src/py_value.cc
index ee039519..98f3f079 100644
--- a/src/py_value.cc
+++ b/src/py_value.cc
@@ -47,7 +47,8 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_string_overloads, set_string, 0, 2)
namespace {
- PyObject * py_base_type(value_t& value) {
+ PyObject * py_base_type(value_t& value)
+ {
if (value.is_boolean()) {
return (PyObject *)&PyBool_Type;
}
@@ -63,16 +64,6 @@ namespace {
}
}
- expr_t py_value_getattr(const value_t& value, const string& name)
- {
- if (value.is_scope()) {
- if (scope_t * scope = value.as_scope())
- return expr_t(scope->lookup(symbol_t::FUNCTION, name), scope);
- }
- throw_(value_error, _("Cannot lookup attributes in %1") << value.label());
- return expr_t();
- }
-
string py_dump(const value_t& value) {
std::ostringstream buf;
value.dump(buf);
@@ -85,10 +76,20 @@ namespace {
return buf.str();
}
- void py_set_string(value_t& amount, const string& str) {
- return amount.set_string(str);
+ void py_set_string(value_t& value, const string& str) {
+ return value.set_string(str);
}
+ annotation_t& py_value_annotation(value_t& value) {
+ return value.annotation();
+ }
+
+ value_t py_strip_annotations_0(value_t& value) {
+ return value.strip_annotations(keep_details_t());
+ }
+ value_t py_strip_annotations_1(value_t& value, const keep_details_t& keep) {
+ return value.strip_annotations(keep);
+ }
} // unnamed namespace
#define EXC_TRANSLATOR(type) \
@@ -306,16 +307,16 @@ void export_value()
.def("number", &value_t::number)
.def("annotate", &value_t::annotate)
- .def("is_annotated", &value_t::is_annotated)
-#if 0
- .def("annotation", &value_t::annotation)
-#endif
- .def("strip_annotations", &value_t::strip_annotations)
+ .def("has_annotation", &value_t::has_annotation)
+ .add_property("annotation",
+ make_function(py_value_annotation,
+ return_internal_reference<>()))
+ .def("strip_annotations", py_strip_annotations_0)
+ .def("strip_annotations", py_strip_annotations_1)
#if 0
.def("__getitem__", &value_t::operator[])
#endif
- .def("__getattr__", py_value_getattr)
.def("push_back", &value_t::push_back)
.def("pop_back", &value_t::pop_back)
.def("size", &value_t::size)
diff --git a/src/pyutils.h b/src/pyutils.h
index a9e968e0..d8a46527 100644
--- a/src/pyutils.h
+++ b/src/pyutils.h
@@ -106,6 +106,26 @@ struct register_optional_to_python : public boost::noncopyable
}
};
+template <typename T1, typename T2>
+struct PairToTupleConverter
+{
+ static PyObject * convert(const std::pair<T1, T2>& pair) {
+ return boost::python::incref
+ (boost::python::make_tuple(pair.first, pair.second).ptr());
+ }
+};
+
+template <typename MapType>
+struct map_value_type_converter
+{
+ map_value_type_converter() {
+ boost::python::to_python_converter
+ <typename MapType::value_type,
+ PairToTupleConverter<const typename MapType::key_type,
+ typename MapType::mapped_type> >();
+ }
+};
+
namespace boost { namespace python {
// Use expr to create the PyObject corresponding to x
diff --git a/src/quotes.cc b/src/quotes.cc
index 7f41e4ff..ffe2142a 100644
--- a/src/quotes.cc
+++ b/src/quotes.cc
@@ -76,13 +76,13 @@ commodity_quote_from_script(commodity_t& commodity,
DEBUG("commodity.download", "downloaded quote: " << buf);
if (optional<price_point_t> point =
- amount_t::current_pool->parse_price_directive(buf)) {
- if (amount_t::current_pool->price_db) {
+ commodity_pool_t::current_pool->parse_price_directive(buf)) {
+ if (commodity_pool_t::current_pool->price_db) {
#if defined(__GNUG__) && __GNUG__ < 3
- ofstream database(*amount_t::current_pool->price_db,
+ ofstream database(*commodity_pool_t::current_pool->price_db,
ios::out | ios::app);
#else
- ofstream database(*amount_t::current_pool->price_db,
+ ofstream database(*commodity_pool_t::current_pool->price_db,
std::ios_base::out | std::ios_base::app);
#endif
database << "P "
diff --git a/src/report.cc b/src/report.cc
index 7da44f8c..4c157312 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -69,18 +69,17 @@ void report_t::normalize_options(const string& verb)
item_t::use_effective_date = (HANDLED(effective) &&
! HANDLED(actual_dates));
- session.journal->commodity_pool->keep_base = HANDLED(base);
- session.journal->commodity_pool->get_quotes = session.HANDLED(download);
+ commodity_pool_t::current_pool->keep_base = HANDLED(base);
+ commodity_pool_t::current_pool->get_quotes = session.HANDLED(download);
if (session.HANDLED(price_exp_))
- session.journal->commodity_pool->quote_leeway =
+ commodity_pool_t::current_pool->quote_leeway =
session.HANDLER(price_exp_).value.as_long();
if (session.HANDLED(price_db_))
- session.journal->commodity_pool->price_db =
- session.HANDLER(price_db_).str();
+ commodity_pool_t::current_pool->price_db = session.HANDLER(price_db_).str();
else
- session.journal->commodity_pool->price_db = none;
+ commodity_pool_t::current_pool->price_db = none;
if (HANDLED(date_format_))
set_date_format(HANDLER(date_format_).str().c_str());
@@ -522,7 +521,7 @@ value_t report_t::fn_price(call_scope_t& scope)
value_t report_t::fn_lot_date(call_scope_t& scope)
{
interactive_t args(scope, "v");
- if (args.value_at(0).is_annotated()) {
+ if (args.value_at(0).has_annotation()) {
const annotation_t& details(args.value_at(0).annotation());
if (details.date)
return *details.date;
@@ -533,7 +532,7 @@ value_t report_t::fn_lot_date(call_scope_t& scope)
value_t report_t::fn_lot_price(call_scope_t& scope)
{
interactive_t args(scope, "v");
- if (args.value_at(0).is_annotated()) {
+ if (args.value_at(0).has_annotation()) {
const annotation_t& details(args.value_at(0).annotation());
if (details.price)
return *details.price;
@@ -544,7 +543,7 @@ value_t report_t::fn_lot_price(call_scope_t& scope)
value_t report_t::fn_lot_tag(call_scope_t& scope)
{
interactive_t args(scope, "v");
- if (args.value_at(0).is_annotated()) {
+ if (args.value_at(0).has_annotation()) {
const annotation_t& details(args.value_at(0).annotation());
if (details.tag)
return string_value(*details.tag);
diff --git a/src/session.cc b/src/session.cc
index 0d6a6829..1882e554 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -45,7 +45,7 @@ void set_session_context(session_t * session)
{
if (session) {
times_initialize();
- amount_t::initialize(session->journal->commodity_pool);
+ amount_t::initialize();
amount_t::parse_conversion("1.0m", "60s");
amount_t::parse_conversion("1.0h", "60m");
@@ -179,7 +179,7 @@ void session_t::close_journal_files()
amount_t::shutdown();
journal.reset(new journal_t);
- amount_t::initialize(journal->commodity_pool);
+ amount_t::initialize();
}
option_t<session_t> * session_t::lookup_option(const char * p)
diff --git a/src/textual.cc b/src/textual.cc
index aec7dbda..071e111d 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -490,7 +490,7 @@ void instance_t::default_commodity_directive(char * line)
{
amount_t amt(skip_ws(line + 1));
VERIFY(amt.valid());
- amount_t::current_pool->default_commodity = &amt.commodity();
+ commodity_pool_t::current_pool->default_commodity = &amt.commodity();
amt.commodity().add_flags(COMMODITY_KNOWN);
}
@@ -511,7 +511,7 @@ void instance_t::price_conversion_directive(char * line)
void instance_t::price_xact_directive(char * line)
{
optional<price_point_t> point =
- amount_t::current_pool->parse_price_directive(skip_ws(line + 1));
+ commodity_pool_t::current_pool->parse_price_directive(skip_ws(line + 1));
if (! point)
throw parse_error(_("Pricing entry failed to parse"));
}
@@ -523,7 +523,7 @@ void instance_t::nomarket_directive(char * line)
commodity_t::parse_symbol(p, symbol);
if (commodity_t * commodity =
- amount_t::current_pool->find_or_create(symbol))
+ commodity_pool_t::current_pool->find_or_create(symbol))
commodity->add_flags(COMMODITY_NOMARKET | COMMODITY_KNOWN);
}
diff --git a/src/value.cc b/src/value.cc
index f4df3329..e2e748f4 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -1353,7 +1353,8 @@ value_t value_t::exchange_commodities(const std::string& commodities,
p;
p = std::strtok(NULL, ",")) {
if (commodity_t * commodity =
- amount_t::current_pool->parse_price_expression(p, add_prices, moment)) {
+ commodity_pool_t::current_pool->parse_price_expression(p, add_prices,
+ moment)) {
value_t result = value(false, moment, *commodity);
if (! result.is_null())
return result;
@@ -1523,10 +1524,10 @@ void value_t::annotate(const annotation_t& details)
throw_(value_error, _("Cannot annotate %1") << label());
}
-bool value_t::is_annotated() const
+bool value_t::has_annotation() const
{
if (is_amount())
- return as_amount().is_annotated();
+ return as_amount().has_annotation();
else
throw_(value_error,
_("Cannot determine whether %1 is annotated") << label());
diff --git a/src/value.h b/src/value.h
index 2a420cd3..ffbb89e8 100644
--- a/src/value.h
+++ b/src/value.h
@@ -774,7 +774,7 @@ public:
* Annotated commodity methods.
*/
void annotate(const annotation_t& details);
- bool is_annotated() const;
+ bool has_annotation() const;
annotation_t& annotation();
const annotation_t& annotation() const {
diff --git a/src/xact.cc b/src/xact.cc
index f2694976..623c5772 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -122,7 +122,7 @@ bool xact_base_t::finalize()
amount_t& p(post->cost ? *post->cost : post->amount);
if (! p.is_null()) {
DEBUG("xact.finalize", "post must balance = " << p.reduced());
- if (! post->cost && post->amount.is_annotated() &&
+ if (! post->cost && post->amount.has_annotation() &&
post->amount.annotation().price) {
// If the amount has no cost, but is annotated with a per-unit
// price, use the price times the amount as the cost
@@ -221,7 +221,7 @@ bool xact_base_t::finalize()
foreach (post_t * post, posts) {
if (! post->amount.is_null()) {
- if (post->amount.is_annotated())
+ if (post->amount.has_annotation())
top_post = post;
else if (! top_post)
top_post = post;
@@ -260,7 +260,7 @@ bool xact_base_t::finalize()
foreach (post_t * post, posts) {
if (post != top_post && post->must_balance() &&
! post->amount.is_null() &&
- post->amount.is_annotated() &&
+ post->amount.has_annotation() &&
post->amount.annotation().price) {
amount_t temp = *post->amount.annotation().price * post->amount;
if (total_cost.is_null()) {
@@ -309,10 +309,11 @@ bool xact_base_t::finalize()
_("A posting's cost must be of a different commodity than its amount"));
cost_breakdown_t breakdown =
- amount_t::current_pool->exchange(post->amount, *post->cost, false,
- datetime_t(date(), time_duration(0, 0, 0, 0)));
+ commodity_pool_t::current_pool->exchange
+ (post->amount, *post->cost, false,
+ datetime_t(date(), time_duration(0, 0, 0, 0)));
- if (post->amount.is_annotated() &&
+ if (post->amount.has_annotation() &&
breakdown.basis_cost.commodity() ==
breakdown.final_cost.commodity()) {
if (amount_t gain_loss = (breakdown.basis_cost -
diff --git a/test/convert.py b/test/convert.py
index 0c64fde4..05a62b7e 100755
--- a/test/convert.py
+++ b/test/convert.py
@@ -158,6 +158,8 @@ for line in fd.readlines():
line = re.sub('false', 'False', line)
line = re.sub('CURRENT_TIME\(\)', 'datetime.now()', line)
line = re.sub('CURRENT_DATE\(\)', 'date.today()', line)
+ line = re.sub('commodity\(\)', 'commodity', line)
+ line = re.sub('precision\(\)', 'precision', line)
line = re.sub('([0-9]+)[FL]', '\\1', line)
line = re.sub('([0-9]+)UL', '\\1L', line)
line = re.sub(';', '', line)
diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test
index 604939d8..dec51008 100644
--- a/test/regress/25A099C9.test
+++ b/test/regress/25A099C9.test
@@ -4,16 +4,16 @@
>>>2
While parsing file "$sourcepath/src/amount.h", line 67:
Error: No quantity specified for amount
-While parsing file "$sourcepath/src/amount.h", line 721:
+While parsing file "$sourcepath/src/amount.h", line 717:
Error: Invalid date/time: line amount_t amoun
-While parsing file "$sourcepath/src/amount.h", line 727:
+While parsing file "$sourcepath/src/amount.h", line 723:
Error: Invalid date/time: line string amount_
-While parsing file "$sourcepath/src/amount.h", line 733:
+While parsing file "$sourcepath/src/amount.h", line 729:
Error: Invalid date/time: line string amount_
-While parsing file "$sourcepath/src/amount.h", line 739:
+While parsing file "$sourcepath/src/amount.h", line 735:
Error: Invalid date/time: line string amount_
-While parsing file "$sourcepath/src/amount.h", line 745:
+While parsing file "$sourcepath/src/amount.h", line 741:
Error: Invalid date/time: line std::ostream&
-While parsing file "$sourcepath/src/amount.h", line 752:
+While parsing file "$sourcepath/src/amount.h", line 748:
Error: Invalid date/time: line std::istream&
=== 7