summaryrefslogtreecommitdiff
path: root/examples/modular_subcommands.py
diff options
context:
space:
mode:
authorEric Lin <anselor@gmail.com>2020-07-27 11:43:16 -0400
committeranselor <anselor@gmail.com>2020-08-04 13:38:08 -0400
commit3a6db395cb28b5b13dde38284dc22791583012fa (patch)
treea901fe8323d47cb061d9c2d4961565603f27b773 /examples/modular_subcommands.py
parent06cee9126839c465a356f8b44a5f008853eb8cad (diff)
downloadcmd2-git-3a6db395cb28b5b13dde38284dc22791583012fa.tar.gz
Adds support for injectable subcommands as part of CommandSet
load/unload. Updated examples and documentation to include discussion of injectable sub-commands.
Diffstat (limited to 'examples/modular_subcommands.py')
-rw-r--r--examples/modular_subcommands.py110
1 files changed, 110 insertions, 0 deletions
diff --git a/examples/modular_subcommands.py b/examples/modular_subcommands.py
new file mode 100644
index 00000000..e4d2fe45
--- /dev/null
+++ b/examples/modular_subcommands.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python3
+# coding=utf-8
+"""A simple example demonstracting modular sub-command loading through CommandSets
+
+In this example, there are loadable CommandSets defined. Each CommandSet has 1 sub-command defined that will be
+attached to the 'cut' command.
+
+The cut command is implemented with the `do_cut` function that has been tagged as an argparse command.
+
+The `load` and `unload` command will load and unload the CommandSets. The available top level commands as well as
+sub-commands to the `cut` command will change depending on which CommandSets are loaded.
+"""
+import argparse
+import cmd2
+from cmd2 import CommandSet, with_argparser, with_category, with_default_category
+
+
+@with_default_category('Fruits')
+class LoadableFruits(CommandSet):
+ def __init__(self):
+ super().__init__()
+
+ def do_apple(self, cmd: cmd2.Cmd, _: cmd2.Statement):
+ cmd.poutput('Apple')
+
+ banana_parser = cmd2.Cmd2ArgumentParser(add_help=False)
+ banana_parser.add_argument('direction', choices=['discs', 'lengthwise'])
+
+ @cmd2.as_subcommand_to('cut', 'banana', banana_parser)
+ def cut_banana(self, cmd: cmd2.Cmd, ns: argparse.Namespace):
+ """Cut banana"""
+ cmd.poutput('cutting banana: ' + ns.direction)
+
+
+@with_default_category('Vegetables')
+class LoadableVegetables(CommandSet):
+ def __init__(self):
+ super().__init__()
+
+ def do_arugula(self, cmd: cmd2.Cmd, _: cmd2.Statement):
+ cmd.poutput('Arugula')
+
+ bokchoy_parser = cmd2.Cmd2ArgumentParser(add_help=False)
+ bokchoy_parser.add_argument('style', choices=['quartered', 'diced'])
+
+ @cmd2.as_subcommand_to('cut', 'bokchoy', bokchoy_parser)
+ def cut_bokchoy(self, cmd: cmd2.Cmd, _: cmd2.Statement):
+ cmd.poutput('Bok Choy')
+
+
+class ExampleApp(cmd2.Cmd):
+ """
+ CommandSets are automatically loaded. Nothing needs to be done.
+ """
+
+ def __init__(self, *args, **kwargs):
+ # gotta have this or neither the plugin or cmd2 will initialize
+ super().__init__(*args, auto_load_commands=False, **kwargs)
+
+ self._fruits = LoadableFruits()
+ self._vegetables = LoadableVegetables()
+
+ load_parser = cmd2.Cmd2ArgumentParser('load')
+ load_parser.add_argument('cmds', choices=['fruits', 'vegetables'])
+
+ @with_argparser(load_parser)
+ @with_category('Command Loading')
+ def do_load(self, ns: argparse.Namespace):
+ if ns.cmds == 'fruits':
+ try:
+ self.install_command_set(self._fruits)
+ self.poutput('Fruits loaded')
+ except ValueError:
+ self.poutput('Fruits already loaded')
+
+ if ns.cmds == 'vegetables':
+ try:
+ self.install_command_set(self._vegetables)
+ self.poutput('Vegetables loaded')
+ except ValueError:
+ self.poutput('Vegetables already loaded')
+
+ @with_argparser(load_parser)
+ def do_unload(self, ns: argparse.Namespace):
+ if ns.cmds == 'fruits':
+ self.uninstall_command_set(self._fruits)
+ self.poutput('Fruits unloaded')
+
+ if ns.cmds == 'vegetables':
+ self.uninstall_command_set(self._vegetables)
+ self.poutput('Vegetables unloaded')
+
+ cut_parser = cmd2.Cmd2ArgumentParser('cut')
+ cut_subparsers = cut_parser.add_subparsers(title='item', help='item to cut', unloadable=True)
+
+ @with_argparser(cut_parser)
+ def do_cut(self, ns: argparse.Namespace):
+ func = getattr(ns, 'handler', None)
+ if func is not None:
+ # Call whatever subcommand function was selected
+ func(ns)
+ else:
+ # No subcommand was provided, so call help
+ self.poutput('This command does nothing without sub-parsers registered')
+ self.do_help('cut')
+
+
+if __name__ == '__main__':
+ app = ExampleApp()
+ app.cmdloop()