From 7cf4deac39a0de1895509f430a4ca3068bd86a68 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Tue, 31 Dec 2019 12:09:31 -0800 Subject: [PATCH] Add basic CLI infrastructure --- amanuensis/__main__.py | 65 ++++++++++++++++++++++++++++++++++++++++++ amanuensis/cli.py | 21 ++++++++++++++ amanuensis/configs.py | 19 ++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 amanuensis/__main__.py create mode 100644 amanuensis/cli.py create mode 100644 amanuensis/configs.py diff --git a/amanuensis/__main__.py b/amanuensis/__main__.py new file mode 100644 index 0000000..513830d --- /dev/null +++ b/amanuensis/__main__.py @@ -0,0 +1,65 @@ +# Standard library imports +import argparse + +# Application imports +import cli +import configs + + +def get_parser(valid_commands): + # Pull out the command functions' docstrings to describe them. + command_descs = "\n".join([ + "- {0}: {1}".format(name, func.__doc__) + for name, func in valid_commands.items()]) + + # Set up the top-level parser. + parser = argparse.ArgumentParser( + description="Available commands:\n{}\n".format(command_descs), + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("-n", + dest="lexicon", + help="The name of the lexicon to operate on") + parser.add_argument("-v", + action="store_true", + dest="verbose", + help="Enable debug logging") + parser.set_defaults(func=lambda a: parser.print_help()) + subp = parser.add_subparsers( + metavar="COMMAND", + help="The command to execute") + + # Set up command subparsers. + # command_ functions perform setup or execution depending on + # whether their argument is an ArgumentParser. + for name, func in valid_commands.items(): + # Create the subparser. + cmd = subp.add_parser(name) + # Delegate subparser setup. + func(cmd) + # Store function for later execution + cmd.set_defaults(func=func) + + return parser + +def no_command(): + print("nothing") + +def main(): + # Enumerate valid commands from the CLI module. + commands = { + name[8:] : func + for name, func in vars(cli).items() + if name.startswith("command_")} + + args = get_parser(commands).parse_args() + + # Configure logging. + if args.verbose: + configs.log_verbose() + + # Execute command. + args.func(args) + +if __name__ == "__main__": + import sys + sys.exit(main()) diff --git a/amanuensis/cli.py b/amanuensis/cli.py new file mode 100644 index 0000000..67c0465 --- /dev/null +++ b/amanuensis/cli.py @@ -0,0 +1,21 @@ +# Standard library imports +from argparse import ArgumentParser as AP + + +def add_argument(*args, **kwargs): + def argument_adder(command): + def augmented_command(cmd_args): + if type(cmd_args) is AP: + cmd_args.add_argument(*args, **kwargs) + else: + command(cmd_args) + augmented_command.__doc__ = command.__doc__ + return augmented_command + return argument_adder + +@add_argument("--foo", action="store_true") +def command_a(args): + """a docstring""" + print(args.foo) + + diff --git a/amanuensis/configs.py b/amanuensis/configs.py new file mode 100644 index 0000000..f864e2c --- /dev/null +++ b/amanuensis/configs.py @@ -0,0 +1,19 @@ +import logging + +logger = logging.getLogger("amanuensis") +handler = logging.StreamHandler() +logger.addHandler(handler) + +def log_normal(): + logger.setLevel(logging.INFO) + handler.setLevel(logging.INFO) + formatter = logging.Formatter('[{levelname}] {message}', style="{") + handler.setFormatter(formatter) + +def log_verbose(): + logger.setLevel(logging.DEBUG) + handler.setLevel(logging.DEBUG) + formatter = logging.Formatter('[{asctime}] [{levelname}:{filename}:{lineno}] {message}', style="{") + handler.setFormatter(formatter) + +log_normal()