Created
May 15, 2020 17:53
-
-
Save gvx/0bda90ef7e73e1578441b8250c5cdd3a to your computer and use it in GitHub Desktop.
simple argparse wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from inspect import signature, Signature, Parameter | |
from argparse import ArgumentParser | |
POSITIONAL = (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD) | |
def parse_args(parser, argv=None): | |
return parser.parse_args(argv).__dict__ | |
class Command: | |
def __init__(self, f, parser): | |
self.f = f | |
self.parser = parser | |
self.sig = signature(f).parameters.values() | |
self.varargs = None | |
for param in self.sig: | |
kwargs = {} | |
if param.kind is Parameter.KEYWORD_ONLY: | |
name = f'--{param.name.replace("_", "-")}' | |
kwargs['dest'] = param.name | |
else: | |
name = param.name | |
kwargs['metavar'] = name.replace("_", "-").upper() | |
if param.kind is Parameter.VAR_POSITIONAL: | |
kwargs['nargs'] = '*' | |
self.varargs = name | |
elif param.default is not Parameter.empty: | |
kwargs['nargs'] = '?' | |
if param.default is not Parameter.empty: | |
kwargs['default'] = param.default | |
if param.annotation is bool: | |
kwargs['action'] = 'store_false' | |
self.parser.add_argument(f'--no-{param.name.replace("_", "-")}', **kwargs) | |
kwargs['action'] = 'store_true' | |
elif param.annotation is not Parameter.empty: | |
kwargs['type'] = param.annotation | |
self.parser.add_argument(name, **kwargs) | |
def extract_args(self, arg_dict): | |
args = [arg_dict[param.name] for param in self.sig if param.kind in POSITIONAL] | |
if self.varargs: | |
args += arg_dict[self.varargs] | |
kwargs = {param.name: arg_dict[param.name] for param in self.sig if param.kind is Parameter.KEYWORD_ONLY} | |
return args, kwargs | |
def extract_and_call(self, args): | |
args, kwargs = self.extract_args(args) | |
return self.f(*args, **kwargs) | |
def __call__(self, argv=None): | |
return self.extract_and_call(parse_args(self.parser, argv)) | |
def run_subcommands(fs, help=None): | |
parser = ArgumentParser(description=help) | |
subparsers = parser.add_subparsers() | |
for f in fs: | |
sub = subparsers.add_parser(f.__name__, help=f.__doc__) | |
sub.set_defaults(_command_=Command(f, sub)) | |
args = parse_args(parser) | |
return args.pop('_command_').extract_and_call(args) | |
def run(f): | |
return Command(f, ArgumentParser(description=f.__doc__))() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from coco import run | |
from pathlib import Path | |
def main(req_arg, optional_arg: int=6, *args: Path, option: bool=False): | |
'''my command help''' | |
print(req_arg, optional_arg, option, args) | |
if __name__ == '__main__': | |
run(main) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from coco import run_subcommands | |
def add(name: str): | |
print('adding', name) | |
def search(*, house: bool=True, work: bool=False): | |
print('searching', house and 'house' or '', work and 'work' or '') | |
if __name__ == '__main__': | |
run_subcommands([add, search],'some commands') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment