#!/usr/bin/env python3 # coding: utf-8 from abc import abstractmethod, ABCMeta from argparse import Action, ArgumentParser from yaml import load class SetDefaultFromFile(Action, metaclass=ABCMeta): """ Populates arguments with file contents. This abstract class is to be inherited per type of file read. """ def __call__(self, parser, namespace, values, option_string=None): config = self._get_config_from_file(values) for key, value in config.items(): setattr(namespace, key, value) @abstractmethod def _get_config_from_file(self, filename): raise NotImplementedError class SetDefaultFromYAMLFile(SetDefaultFromFile): """ Populates arguments with a YAML file contents. """ def _get_config_from_file(self, filename): with open(filename) as f: config = load(f) return config _TEST_FILE = 'test.yaml' _NAME = 'spam' _FILE_VALUE = 'eggs' with open(_TEST_FILE, mode='w') as f: f.write('{}: {}'.format(_NAME, _FILE_VALUE)) _PARSER = ArgumentParser() _PARSER.add_argument('--config', action=SetDefaultFromYAMLFile) _PARSER.add_argument('--{}'.format(_NAME)) def test_file_content_populates_args(): args = _PARSER.parse_args('--config {}'.format(_TEST_FILE).split()) assert getattr(args, _NAME) == _FILE_VALUE def test_file_content_is_erased_if_arg_given_after(): expected = '42' args = _PARSER.parse_args('--config {} --spam {}'.format(_TEST_FILE, expected).split()) assert getattr(args, _NAME) == expected def test_arg_is_erases_if_file_is_given_after(): value = 12 args = _PARSER.parse_args('--spam {} --config {}'.format(value, _TEST_FILE).split()) assert getattr(args, _NAME) == _FILE_VALUE