From 85727f9bd9b36d4936d4d19514b7cdfe4fffca43 Mon Sep 17 00:00:00 2001 From: Elena ``of Valhalla'' Grandi Date: Tue, 22 Feb 2022 17:45:23 +0100 Subject: Subcommands --- hazwaz/__init__.py | 2 +- hazwaz/command.py | 34 +++++++++++++++++++++------- tests/test_command.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 87 insertions(+), 11 deletions(-) diff --git a/hazwaz/__init__.py b/hazwaz/__init__.py index f5f0a6d..4986238 100644 --- a/hazwaz/__init__.py +++ b/hazwaz/__init__.py @@ -1 +1 @@ -from .command import MainCommand # noqa: F401 +from .command import MainCommand, Command # noqa: F401 diff --git a/hazwaz/command.py b/hazwaz/command.py index c99e012..a8866ab 100644 --- a/hazwaz/command.py +++ b/hazwaz/command.py @@ -10,6 +10,7 @@ def _get_first_docstring_line(obj): except (AttributeError, IndexError): return None + def _get_remaining_docstring_lines(obj): try: return "\n".join(obj.__doc__.split('\n')[2:]).strip() @@ -30,15 +31,15 @@ class MainCommand: self.add_arguments(self.parser) self.parser.set_defaults(func=self._main) self.subparsers = self.parser.add_subparsers() - for name, sub in self.commands: + for sub in self.commands: sub_help = _get_first_docstring_line(sub) + sub_epilog = _get_remaining_docstring_lines(sub) sub_parser = self.subparsers.add_parser( - name, - help=sub_help, - description=sub.__doc__, + sub.name, + description=sub_help, + epilog=sub_epilog, ) - for arg in sub.arguments: - sub_parser.add_argument(*arg[0], **arg[1]) + sub.add_arguments(sub_parser) sub_parser.set_defaults(func=sub._main) def _main(self, args): @@ -60,9 +61,26 @@ class MainCommand: def main(self): self.args = self.parser.parse_args() - if self.args.verbose: - logger.setLevel(logging.VERBOSE) if self.args.debug: logger.setLevel(logging.DEBUG) + elif self.args.verbose: + logger.setLevel(logging.INFO) + else: + logger.setLevel(logging.WARNING) self.args.func(self.args) + + +class Command: + name = None + + def __init__(self): + if self.name is None: + self.name = self.__class__.__name__.lower() + + def _main(self, args): + self.args = args + self.main() + + def add_arguments(self, parser): + pass diff --git a/tests/test_command.py b/tests/test_command.py index eed6e1f..d0b6437 100644 --- a/tests/test_command.py +++ b/tests/test_command.py @@ -6,19 +6,41 @@ import unittest import hazwaz +class MySubCommand(hazwaz.Command): + """ + A subcommand. + + This does very little. + """ + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + "--bar", + action="store_true", + help="barfoo things" + ) + + def main(self): + print("Hello World") + + class MyCommand(hazwaz.MainCommand): """ A command that does things. This is a command, but honestly it doesn't really do anything. """ - commands = () + commands = ( + MySubCommand(), + ) def add_arguments(self, parser): super().add_arguments(parser) parser.add_argument( "--foo", - help="foobar things" + action="store_true", + help="foobar things", ) @@ -68,12 +90,48 @@ class testCommand(unittest.TestCase): self.assertIn("--verbose", cmd_help) self.assertIn("--foo", cmd_help) + def test_subparser(self): + cmd = MyCommand() + sub_parser = cmd.subparsers.choices["mysubcommand"] + self.assertEqual(sub_parser.description, "A subcommand.") + self.assertEqual( + sub_parser.epilog, + "This does very little.", + ) + def test_run(self): cmd = MyCommand() cmd_help = cmd.parser.format_help() stream = self._run_with_argv(cmd, ["mycommand"]) self.assertEqual(stream["stdout"].getvalue(), cmd_help) + def test_run_with_option(self): + cmd = MyCommand() + cmd_help = cmd.parser.format_help() + stream = self._run_with_argv(cmd, [ + "mycommand", + "--verbose", + ]) + self.assertEqual(stream["stdout"].getvalue(), cmd_help) + stream = self._run_with_argv(cmd, [ + "mycommand", + "--debug", + ]) + self.assertEqual(stream["stdout"].getvalue(), cmd_help) + + def test_run_subcommand(self): + cmd = MyCommand() + stream = self._run_with_argv(cmd, ["mycommand", "mysubcommand"]) + self.assertEqual(stream["stdout"].getvalue(), "Hello World\n") + + def test_run_subcommand_with_option(self): + cmd = MyCommand() + stream = self._run_with_argv(cmd, [ + "mycommand", + "mysubcommand", + "--bar", + ]) + self.assertEqual(stream["stdout"].getvalue(), "Hello World\n") if __name__ == '__main__': -- cgit v1.2.3