Configuration: Parse more conversion arguments for historical subcommand.
This commit is contained in:
parent
667c214e91
commit
08073f752b
2 changed files with 80 additions and 2 deletions
|
@ -1,6 +1,7 @@
|
||||||
import argparse
|
import argparse
|
||||||
import configparser
|
import configparser
|
||||||
import datetime
|
import datetime
|
||||||
|
import decimal
|
||||||
import os.path
|
import os.path
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ base=USD
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def currency_code(s):
|
def currency_code(s):
|
||||||
if not (len(s) == 3) and s.isalpha():
|
if not ((len(s) == 3) and s.isalpha()):
|
||||||
raise ValueError("bad currency code: {!r}".format(s))
|
raise ValueError("bad currency code: {!r}".format(s))
|
||||||
return s.upper()
|
return s.upper()
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ def date_from(fmt_s):
|
||||||
|
|
||||||
class Configuration:
|
class Configuration:
|
||||||
DEFAULT_CONFIG_PATH = pathlib.Path(HOME_PATH, '.config', 'oxrlib.ini')
|
DEFAULT_CONFIG_PATH = pathlib.Path(HOME_PATH, '.config', 'oxrlib.ini')
|
||||||
|
PREPOSITIONS = frozenset(['in', 'to', 'into'])
|
||||||
|
|
||||||
def __init__(self, arglist):
|
def __init__(self, arglist):
|
||||||
argparser = self._build_argparser()
|
argparser = self._build_argparser()
|
||||||
|
@ -56,15 +58,24 @@ class Configuration:
|
||||||
subparsers = prog_parser.add_subparsers()
|
subparsers = prog_parser.add_subparsers()
|
||||||
|
|
||||||
hist_parser = subparsers.add_parser('historical', aliases=['hist'])
|
hist_parser = subparsers.add_parser('historical', aliases=['hist'])
|
||||||
hist_parser.set_defaults(command='historical')
|
hist_parser.set_defaults(
|
||||||
|
command='historical',
|
||||||
|
amount=None,
|
||||||
|
from_currency=None,
|
||||||
|
)
|
||||||
hist_parser.add_argument(
|
hist_parser.add_argument(
|
||||||
'--base',
|
'--base',
|
||||||
|
type=currency_code,
|
||||||
help="Base currency (default USD)",
|
help="Base currency (default USD)",
|
||||||
)
|
)
|
||||||
hist_parser.add_argument(
|
hist_parser.add_argument(
|
||||||
'date',
|
'date',
|
||||||
type=date_from('%Y-%m-%d'), metavar='YYYY-MM-DD',
|
type=date_from('%Y-%m-%d'), metavar='YYYY-MM-DD',
|
||||||
)
|
)
|
||||||
|
hist_parser.add_argument(
|
||||||
|
'remainder',
|
||||||
|
nargs=argparse.REMAINDER,
|
||||||
|
)
|
||||||
|
|
||||||
return prog_parser
|
return prog_parser
|
||||||
|
|
||||||
|
@ -73,9 +84,42 @@ class Configuration:
|
||||||
conffile.read_string(CONFFILE_SEED)
|
conffile.read_string(CONFFILE_SEED)
|
||||||
return conffile
|
return conffile
|
||||||
|
|
||||||
|
def _convert_or_error(self, argtype, s_value, argname=None, typename=None):
|
||||||
|
try:
|
||||||
|
return argtype(s_value)
|
||||||
|
except (decimal.InvalidOperation, TypeError, ValueError):
|
||||||
|
errmsg = []
|
||||||
|
if argname:
|
||||||
|
errmsg.append("argument {}".format(argname))
|
||||||
|
if typename is None:
|
||||||
|
typename = argtype.__name__.replace('_', ' ')
|
||||||
|
errmsg.append("invalid {} value".format(typename))
|
||||||
|
errmsg.append(repr(s_value))
|
||||||
|
self.error(': '.join(errmsg))
|
||||||
|
|
||||||
def _post_hook_historical(self):
|
def _post_hook_historical(self):
|
||||||
if self.args.base is None:
|
if self.args.base is None:
|
||||||
self.args.base = self.conffile.get('Historical', 'base')
|
self.args.base = self.conffile.get('Historical', 'base')
|
||||||
|
self.args.to_currency = self.args.base
|
||||||
|
remain_len = len(self.args.remainder)
|
||||||
|
if (remain_len > 3) and (self.args.remainder[2].lower() in self.PREPOSITIONS):
|
||||||
|
del self.args.remainder[2]
|
||||||
|
remain_len -= 1
|
||||||
|
if remain_len == 0:
|
||||||
|
pass
|
||||||
|
elif remain_len == 1:
|
||||||
|
self.args.from_currency = self._convert_or_error(
|
||||||
|
currency_code, self.args.remainder[0])
|
||||||
|
elif remain_len < 4:
|
||||||
|
self.args.amount = self._convert_or_error(
|
||||||
|
decimal.Decimal, self.args.remainder[0])
|
||||||
|
self.args.from_currency = self._convert_or_error(
|
||||||
|
currency_code, self.args.remainder[1])
|
||||||
|
if remain_len == 3:
|
||||||
|
self.args.to_currency = self._convert_or_error(
|
||||||
|
currency_code, self.args.remainder[2])
|
||||||
|
else:
|
||||||
|
self.error("too many arguments")
|
||||||
|
|
||||||
def _build_cache_loader(self):
|
def _build_cache_loader(self):
|
||||||
kwargs = dict(self.conffile.items('Cache'))
|
kwargs = dict(self.conffile.items('Cache'))
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import decimal
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -42,3 +43,36 @@ def test_historical_default_base(ini_filename, expected_currency, use_switch, an
|
||||||
arglist.append(any_date.isoformat())
|
arglist.append(any_date.isoformat())
|
||||||
config = config_from(ini_filename, arglist)
|
config = config_from(ini_filename, arglist)
|
||||||
assert config.args.base == expected_currency
|
assert config.args.base == expected_currency
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('amount,from_curr,preposition,to_curr', [
|
||||||
|
(None, 'JPY', None, None),
|
||||||
|
(decimal.Decimal('1000'), 'chf', None, None),
|
||||||
|
(decimal.Decimal('999'), 'Eur', None, 'Chf'),
|
||||||
|
(decimal.Decimal('12.34'), 'gbp', 'IN', 'eur'),
|
||||||
|
])
|
||||||
|
def test_historical_argparsing_success(amount, from_curr, preposition, to_curr, any_date):
|
||||||
|
arglist = ['historical', any_date.isoformat()]
|
||||||
|
arglist.extend(str(s) for s in [amount, from_curr, preposition, to_curr]
|
||||||
|
if s is not None)
|
||||||
|
config = config_from(os.devnull, arglist)
|
||||||
|
assert config.args.amount == amount
|
||||||
|
assert config.args.from_currency == from_curr.upper()
|
||||||
|
if to_curr is not None:
|
||||||
|
assert config.args.to_currency == to_curr.upper()
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('arglist', [
|
||||||
|
['100'],
|
||||||
|
['120', 'dollars'],
|
||||||
|
['to', '42', 'usd'],
|
||||||
|
['99', 'usd', 'minus', 'jpy'],
|
||||||
|
['usdjpy'],
|
||||||
|
['44', 'eur', 'in', 'chf', 'pronto'],
|
||||||
|
])
|
||||||
|
def test_historical_argparsing_failure(arglist, any_date):
|
||||||
|
arglist = ['historical', any_date.isoformat()] + arglist
|
||||||
|
try:
|
||||||
|
config = config_from(os.devnull, arglist)
|
||||||
|
except SystemExit:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
assert not vars(config.args), "bad arglist succeeded"
|
||||||
|
|
Loading…
Reference in a new issue