Source code for xonsh.cli_utils
"""
small functions to create argparser CLI from functions.
"""
import argparse as ap
import os
import typing as tp
[docs]def _get_func_doc(doc: str) -> str:
lines = doc.splitlines()
if "Parameters" in lines:
idx = lines.index("Parameters")
lines = lines[:idx]
return os.linesep.join(lines)
[docs]def _from_index_of(container: tp.Sequence[str], key: str):
if key in container:
idx = container.index(key)
if idx + 1 < len(container):
return container[idx + 1 :]
return []
[docs]def _get_param_doc(doc: str, param: str) -> str:
lines = tuple(doc.splitlines())
if "Parameters" not in lines:
return ""
par_doc = []
for lin in _from_index_of(lines, param):
if lin and not lin.startswith(" "):
break
par_doc.append(lin)
return os.linesep.join(par_doc).strip()
[docs]def get_doc(func: tp.Callable, parameter: str = None):
"""Parse the function docstring and return its help content
Parameters
----------
func
a callable object that holds docstring
parameter
name of the function parameter to parse doc for
Returns
-------
str
doc of the parameter/function
"""
import inspect
doc = inspect.getdoc(func) or ""
if parameter:
return _get_param_doc(doc, parameter)
else:
return _get_func_doc(doc)
_FUNC_NAME = "_func_"
[docs]def make_parser(
func: tp.Callable,
subparser: ap._SubParsersAction = None,
params: tp.Dict[str, tp.Dict[str, tp.Any]] = None,
**kwargs
) -> "ap.ArgumentParser":
"""A bare-bones argparse builder from functions"""
doc = get_doc(func)
kwargs.setdefault("formatter_class", ap.RawTextHelpFormatter)
if subparser is None:
kwargs.setdefault("description", doc)
parser = ap.ArgumentParser(**kwargs)
parser.set_defaults(
**{_FUNC_NAME: lambda stdout: parser.print_help(file=stdout)}
)
return parser
else:
parser = subparser.add_parser(
kwargs.pop("prog", func.__name__),
help=doc,
**kwargs,
)
parser.set_defaults(**{_FUNC_NAME: func})
if params:
for par, args in params.items():
args.setdefault("help", get_doc(func, par))
parser.add_argument(par, **args)
return parser
[docs]def dispatch(**ns):
"""call the sub-command selected by user"""
import inspect
func = ns[_FUNC_NAME]
sign = inspect.signature(func)
kwargs = {}
for name, param in sign.parameters.items():
kwargs[name] = ns[name]
return func(**kwargs)