Ok, it ain't pretty, but I have a hack to keep moving.
With some help from here regarding the programmatic building of the cli and good old sys.argv
:-)
import click
import yaml
import sys
cfg_path = sys.argv[1]
if cfg_path.endswith('.yaml'):
with open(cfg_path, 'r') as f:
cfg = yaml.load(f, Loader=yaml.SafeLoader)
sys.argv.remove(cfg_path)
else:
cfg = {}
def options_from_pipeline_def(cfg):
def decorator(f):
for k,v in cfg.items():
param_decls = [
f'--{k}',
]
attrs = dict(
required=False,
default=v,
type=type(v)
)
click.option(*param_decls, **attrs)(f)
return f
return decorator
@click.group()
def cli():
pass
@cli.command("run")
@options_from_pipeline_def(cfg)
def run(**kwargs):
print(f"kwargs: {kwargs}")
if __name__ == '__main__':
cli()
Examples
$ python build-cli.py --help
---
Usage: build-cli.py [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
run
########################################
$ python build-cli.py cfg.yaml run --help
---
Usage: build-cli.py run [OPTIONS]
Options:
--opt2 INTEGER
--opt1 TEXT
--help Show this message and exit.
########################################
$ python z-build-cli.py cfg.yaml run
---
kwargs: {'opt2': 42, 'opt1': 'Bailey is the cutest doggo ever!!!'}
########################################
$ python build-cli.py cfg.yaml run --opt1 "I cannot stress how cute Bailey is!" --opt2 314159
---
kwargs: {'opt1': 'I cannot stress how cute Bailey is!', 'opt2': 314159}