@@ -52,60 +52,78 @@ class Formatter:
self.format_currency(from_amt, from_curr),
self.format_currency(to_amt, to_curr),
)
class LedgerFormatter(Formatter):
RATE_PREC = 5
def __init__(self, rate, signed_currencies=(), base_fmt='#,##0.###',
rate_precision=5, denomination=None):
super().__init__(rate, signed_currencies, base_fmt)
self.rate_prec = rate_precision
self.denomination = denomination
def normalize_rate(self, rate, prec=None):
# Return prec nonzero digits of precision, if available.
if prec is None:
prec = self.RATE_PREC
def normalize_rate(self, rate):
_, digits, exponent = rate.normalize().as_tuple()
prec -= min(0, exponent + len(digits))
# Return ``self.rate_prec`` nonzero digits of precision, if available.
prec = self.rate_prec - min(0, exponent + len(digits))
quant_to = '1.{}'.format('0' * prec)
try:
qrate = rate.quantize(decimal.Decimal(quant_to))
except decimal.InvalidOperation:
# The original rate doesn't have that much precision, so use it raw.
qrate = rate
return qrate.normalize()
def format_rate(self, rate, prec=None):
return str(self.normalize_rate(rate, prec))
def format_rate(self, rate):
return str(self.normalize_rate(rate))
def format_ledger_rate(self, rate, curr, prec=None):
nrate = self.normalize_rate(rate, prec)
def format_ledger_rate(self, rate, curr):
nrate = self.normalize_rate(rate)
rate_s = self.format_currency(nrate, curr, currency_digits=False)
return "{{={0}}} @ {0}".format(rate_s)
def format_rate_pair(self, from_curr, to_curr):
from_amt = 1
to_amt = self.rate.convert(from_amt, from_curr, to_curr)
return "{} {} {}".format(
from_amt, from_curr, self.format_ledger_rate(to_amt, to_curr))
def _denomination_for(self, currency, default):
if self.denomination is None:
return default
elif self.denomination == currency:
return None
else:
return self.denomination
def format_denominated_rate(self, amount, currency, default_denomination):
denomination = self._denomination_for(currency, default_denomination)
amt_s = self.format_currency(amount, currency)
if denomination is None:
return amt_s
rate = self.rate.convert(1, currency, denomination)
return "{} {}".format(amt_s, self.format_ledger_rate(rate, denomination))
def format_conversion(self, from_amt, from_curr, to_curr):
to_rate = self.rate.convert(1, from_curr, to_curr)
return "{} {}\n{}".format(
self.format_ledger_rate(to_rate, to_curr),
return "{}\n{}".format(
self.format_denominated_rate(from_amt, from_curr, to_curr),
self.format_denominated_rate(to_amt, to_curr, None),
def run(config, stdout, stderr):
loaders = config.get_loaders()
with loaders.historical(config.args.date, config.args.base) as rate_json:
rate = oxrrate.Rate.from_json_file(rate_json)
if loaders.should_cache():
config.cache.save_rate(rate)
if config.args.ledger:
formatter = LedgerFormatter(rate, config.args.signed_currencies)
formatter = LedgerFormatter(rate, config.args.signed_currencies,
denomination=config.args.denomination)
formatter = Formatter(rate)
if not config.args.from_currency:
for from_curr in sorted(rate.rates):
print(formatter.format_rate_pair_bidir(from_curr, config.args.to_currency),
file=stdout)