first commit
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Translate an options data structure into command line args
|
||||
"""
|
||||
|
||||
# Import python libs
|
||||
import sys
|
||||
import inspect
|
||||
import argparse
|
||||
import dict_tools.update
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
|
||||
def __init__(hub):
|
||||
hub.config.args.DEFAULT = object()
|
||||
|
||||
|
||||
def _keys(opts):
|
||||
"""
|
||||
Return the keys in the right order
|
||||
"""
|
||||
return sorted(opts, key=lambda k: (opts[k].get("display_priority", sys.maxsize), k))
|
||||
|
||||
|
||||
def gather(
|
||||
hub, raw: Dict[str, Any], cli: str, parse_cli: bool
|
||||
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
||||
"""
|
||||
Return the cli arguments as they are parsed
|
||||
"""
|
||||
if not parse_cli:
|
||||
return {}, {}
|
||||
raw_cli = hub.config.args.get_cli(raw, cli)
|
||||
hub.config.args.init_parser()
|
||||
hub.config.args.subparsers(raw, cli)
|
||||
hub.config.args.setup(raw_cli)
|
||||
cli_args = hub.config.args.parse()
|
||||
cli_args = hub.config.args.render(cli_args, raw_cli)
|
||||
cli_args = hub.config.args.clean_defaults(cli_args)
|
||||
return cli_args, raw_cli
|
||||
|
||||
|
||||
def clean_defaults(hub, cli_args: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
If anyone did not pass in an argument then the key will match the
|
||||
bad default and needs to be removed
|
||||
"""
|
||||
ret = {}
|
||||
for key, val in cli_args.items():
|
||||
if val is not hub.config.args.DEFAULT:
|
||||
ret[key] = val
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def init_parser(hub):
|
||||
if "parser" not in hub.config.ARGS:
|
||||
# Instantiate the parser
|
||||
hub.config.ARGS["parser"] = argparse.ArgumentParser()
|
||||
|
||||
|
||||
def get_cli(hub, raw: Dict[str, Any], cli: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Gather the arguments that need to be parsed by the CLI
|
||||
"""
|
||||
ret = {}
|
||||
main = raw.get(cli, {}).get("CLI_CONFIG")
|
||||
main_raw = raw.get(cli, {}).get("CONFIG")
|
||||
|
||||
for key, data in main.items():
|
||||
ret[key] = {}
|
||||
dict_tools.update.update(ret[key], data)
|
||||
if key in main_raw:
|
||||
dict_tools.update.update(ret[key], main_raw[key])
|
||||
if "source" in data:
|
||||
src = raw.get(data["source"], {}).get("CONFIG", {}).get(key)
|
||||
if src is not None:
|
||||
dict_tools.update.update(ret[key], src)
|
||||
if "default" in ret[key]:
|
||||
ret[key]["default"] = hub.config.args.DEFAULT
|
||||
ret.update(hub.config.version.CONFIG)
|
||||
return ret
|
||||
|
||||
|
||||
def subparsers(hub, raw: Dict[str, Any], cli: str) -> bool:
|
||||
"""
|
||||
Look over the data and extract and set up the subparsers for subcommands
|
||||
"""
|
||||
subs = raw.get(cli, {}).get("SUBCOMMANDS")
|
||||
if not subs:
|
||||
return True
|
||||
hub.config.ARGS["sub"] = hub.config.ARGS["parser"].add_subparsers(
|
||||
dest="_subparser_"
|
||||
)
|
||||
hub.config.ARGS["subs"] = {}
|
||||
for arg in _keys(subs):
|
||||
if arg in ("_argparser_",):
|
||||
continue
|
||||
comps = subs[arg]
|
||||
kwargs = {}
|
||||
if "help" in comps:
|
||||
kwargs["help"] = comps["help"]
|
||||
if "desc" in comps:
|
||||
kwargs["description"] = comps["desc"]
|
||||
hub.config.ARGS["subs"][arg] = hub.config.ARGS["sub"].add_parser(arg, **kwargs)
|
||||
return True
|
||||
|
||||
|
||||
def setup(hub, raw_cli: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Take in a pre-defined dict and translate it to args
|
||||
|
||||
opts dict:
|
||||
<arg>:
|
||||
[group]: foo
|
||||
[default]: bar
|
||||
[action]: store_true
|
||||
[options]: # arg will be turned into --arg
|
||||
- '-A'
|
||||
- '--cheese'
|
||||
[choices]:
|
||||
- foo
|
||||
- bar
|
||||
- baz
|
||||
[nargs]: +
|
||||
[type]: int
|
||||
[dest]: cheese
|
||||
help: Some great help message
|
||||
"""
|
||||
# TODO: This should be broken up
|
||||
defaults = {}
|
||||
groups = {}
|
||||
ex_groups = {}
|
||||
for arg in _keys(raw_cli):
|
||||
if arg in ("_argparser_",):
|
||||
continue
|
||||
comps = raw_cli[arg]
|
||||
positional = comps.pop("positional", False)
|
||||
if positional:
|
||||
args = [arg]
|
||||
else:
|
||||
|
||||
args = [f"--{arg.replace('_', '-')}"]
|
||||
for o_str in comps.get("options", ()):
|
||||
if len(o_str) == 1:
|
||||
o_str = f"-{o_str}"
|
||||
elif not o_str.startswith("-"):
|
||||
o_str = f"--{o_str}"
|
||||
if o_str not in args:
|
||||
args.append(o_str)
|
||||
kwargs = {}
|
||||
kwargs["action"] = action = comps.get("action", None)
|
||||
|
||||
if action is None:
|
||||
# Non existing option defaults to a StoreAction in argparse
|
||||
action = hub.config.ARGS["parser"]._registry_get("action", action)
|
||||
|
||||
if isinstance(action, str):
|
||||
signature = inspect.signature(
|
||||
hub.config.ARGS["parser"]._registry_get("action", action).__init__
|
||||
)
|
||||
else:
|
||||
signature = inspect.signature(action.__init__)
|
||||
|
||||
for param in signature.parameters:
|
||||
if param == "self" or param not in comps:
|
||||
continue
|
||||
if param == "dest":
|
||||
kwargs["dest"] = comps.get("dest", arg)
|
||||
continue
|
||||
if param == "help":
|
||||
kwargs["help"] = comps.get("help", "THIS NEEDS SOME DOCUMENTATION!!")
|
||||
continue
|
||||
if param == "default":
|
||||
defaults[comps.get("dest", arg)] = comps[param]
|
||||
kwargs[param] = comps[param]
|
||||
|
||||
if "group" in comps:
|
||||
group = comps["group"]
|
||||
if group not in groups:
|
||||
groups[group] = hub.config.ARGS["parser"].add_argument_group(group)
|
||||
groups[group].add_argument(*args, **kwargs)
|
||||
continue
|
||||
if "ex_group" in comps:
|
||||
group = comps["ex_group"]
|
||||
if group not in ex_groups:
|
||||
ex_groups[group] = hub.config.ARGS[
|
||||
"parser"
|
||||
].add_mutually_exclusive_group()
|
||||
ex_groups[group].add_argument(*args, **kwargs)
|
||||
continue
|
||||
if "subcommands" in comps:
|
||||
subs = comps["subcommands"]
|
||||
if not isinstance(subs, list):
|
||||
subs = [subs]
|
||||
for sub in subs:
|
||||
if sub == "_global_":
|
||||
if "subs" not in hub.config.ARGS:
|
||||
continue
|
||||
hub.config.ARGS["parser"].add_argument(*args, **kwargs)
|
||||
for named, sparse in hub.config.ARGS["subs"].items():
|
||||
sparse.add_argument(*args, **kwargs)
|
||||
continue
|
||||
sparse = hub.config.ARGS.get("subs", {}).get(sub)
|
||||
if not sparse:
|
||||
# Maybe raise exception here? Malformed config?
|
||||
continue
|
||||
sparse.add_argument(*args, **kwargs)
|
||||
continue
|
||||
hub.config.ARGS["parser"].add_argument(*args, **kwargs)
|
||||
return defaults
|
||||
|
||||
|
||||
def parse(
|
||||
hub,
|
||||
args: List[str] = None,
|
||||
namespace: argparse.Namespace = None,
|
||||
only_parse_known_arguments: bool = False,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Parse the command line options
|
||||
"""
|
||||
if only_parse_known_arguments:
|
||||
opts, unknown_args = hub.config.ARGS["parser"].parse_known_args(args, namespace)
|
||||
opts_dict = opts.__dict__
|
||||
opts_dict["_unknown_args_"] = unknown_args
|
||||
else:
|
||||
opts = hub.config.ARGS["parser"].parse_args(args, namespace)
|
||||
opts_dict = opts.__dict__
|
||||
hub.SUBPARSER = opts_dict.get("_subparser_", None)
|
||||
return opts_dict
|
||||
|
||||
|
||||
def render(hub, cli_args: Dict[str, Any], raw_cli: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
For options specified as such, take the string passed into the cli and
|
||||
render it using the specified render flag
|
||||
"""
|
||||
for key, val in raw_cli.items():
|
||||
if key not in cli_args:
|
||||
continue
|
||||
if "render" not in val:
|
||||
continue
|
||||
if val["default"] != cli_args[key]:
|
||||
# The value was changed, render it
|
||||
cli_args[key] = hub.config.render.init.process(val["render"], cli_args[key])
|
||||
return cli_args
|
||||
Reference in New Issue
Block a user