diff --git a/oxrlib/config.py b/oxrlib/config.py new file mode 100644 index 0000000000000000000000000000000000000000..d748861534c8e116a8ef1dc03ef6c4e65650a928 --- /dev/null +++ b/oxrlib/config.py @@ -0,0 +1,104 @@ +import argparse +import configparser +import datetime +import os.path +import pathlib + +from . import loaders + +HOME_PATH = pathlib.Path(os.path.expanduser('~')) +CONFFILE_SEED = """ +[Historical] +base=USD +""" + +def currency_code(s): + if not (len(s) == 3) and s.isalpha(): + raise ValueError("bad currency code: {!r}".format(s)) + return s.upper() + +def date_from(fmt_s): + def date_from_fmt(s): + return datetime.datetime.strptime(s, fmt_s).date + return date_from_fmt + +class Configuration: + DEFAULT_CONFIG_PATH = pathlib.Path(HOME_PATH, '.config', 'oxrlib.ini') + + def __init__(self, arglist): + argparser = self._build_argparser() + self.error = argparser.error + self.args = argparser.parse_args(arglist) + + if self.args.config_file is None: + self.args.config_file = [self.DEFAULT_CONFIG_PATH] + self.conffile = self._build_conffile() + conffile_paths = [path.as_posix() for path in self.args.config_file] + read_files = self.conffile.read(conffile_paths) + for expected_path, read_path in zip(conffile_paths, read_files): + if read_path != expected_path: + self.error("failed to read configuration file {!r}".format(expected_path)) + + try: + post_hook = getattr(self, '_post_hook_' + self.args.command) + except AttributeError: + pass + else: + post_hook() + + def _build_argparser(self): + prog_parser = argparse.ArgumentParser() + prog_parser.add_argument( + '--config-file', '-c', + action='append', type=pathlib.Path, + help="Path of a configuration file to read", + ) + subparsers = prog_parser.add_subparsers() + + hist_parser = subparsers.add_parser('historical', aliases=['hist']) + hist_parser.set_defaults(command='historical') + hist_parser.add_argument( + '--base', + help="Base currency (default USD)", + ) + hist_parser.add_argument( + 'date', + type=date_from('%Y-%m-%d'), metavar='YYYY-MM-DD', + ) + + return prog_parser + + def _build_conffile(self): + conffile = configparser.ConfigParser() + conffile.read_string(CONFFILE_SEED) + return conffile + + def _post_hook_historical(self): + if self.args.base is None: + self.args.base = self.conffile.get('Historical', 'base') + + def _build_cache_loader(self): + kwargs = dict(self.conffile.items('Cache')) + try: + kwargs['dir_path'] = kwargs.pop('directory') + except KeyError: + pass + return loaders.FileCache(**kwargs) + + def _build_oxrapi_loader(self): + kwargs = dict(self.conffile.items('OXR')) + return loaders.OXRAPIRequest(**kwargs) + + def get_loaders(self): + loader_chain = loaders.LoaderChain() + for build_func in [ + self._build_cache_loader, + self._build_oxrapi_loader, + ]: + try: + loader = build_func() + except (TypeError, ValueError, configparser.NoSectionError): + pass + else: + loader_chain.add_loader(loader) + return loader_chain