#! /usr/bin/env python3 import sys import argparse import jinja2 import pydantic import yaml def to_yaml(value): value_str = yaml.safe_dump(value, default_style='"', default_flow_style=True) return value_str[:-1] if value_str and value_str[-1] == '\n' else value_str class ConfigBase(pydantic.BaseModel): pass class ConfigRoot(ConfigBase): answer: str = pydantic.Field() class Options(pydantic.BaseModel): config_path: str = pydantic.Field(alias='config') def main(argv): default_options = Options(**{ 'config': './config.yml' }) parser = argparse.ArgumentParser(description='Some awesome project') parser.add_argument('-c', '--config', type=str, default=default_options.config_path, help='Path to config file') args = parser.parse_args(argv[1:]) options = Options(**vars(args)) with open(options.config_path, 'r') as f: config_template = f.read() jinja_env = jinja2.Environment( loader=jinja2.PrefixLoader({ 'config': jinja2.DictLoader({ 'config.yml': config_template }), 'config.d': jinja2.FileSystemLoader('{}.d'.format(options.config_path)) }), extensions=["jinja2.ext.do"] ) jinja_env.filters['yaml'] = to_yaml template = jinja_env.get_template('config/config.yml') config_yml = template.render(options=options) config_dict = yaml.safe_load(config_yml) config = ConfigRoot(**config_dict) print(options.config_path) print(config.answer) return 0 if __name__ == '__main__': sys.exit(main(sys.argv))