From d0654e136ae19837d8659b064205115ce59f940f Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 6 Oct 2018 19:27:08 -0400 Subject: Added warning to documentation about how help_foo won't be called for command foo if it uses an argparse decorator Also: - Renamed argparse_example.py to decorator_example.py --- CHANGELOG.md | 1 + docs/argument_processing.rst | 12 +++- examples/argparse_example.py | 113 -------------------------------- examples/decorator_example.py | 112 +++++++++++++++++++++++++++++++ examples/transcripts/exampleSession.txt | 2 +- 5 files changed, 124 insertions(+), 116 deletions(-) delete mode 100755 examples/argparse_example.py create mode 100755 examples/decorator_example.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ef1f666..0042b86b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ * Never - output methods strip all ANSI escape sequences * Added ``macro`` command to create macros, which are similar to aliases, but can take arguments when called * All cmd2 command functions have been converted to use argparse. + * Renamed argparse_example.py to decorator_example.py to help clarify its intent * Deprecations * Deprecated the built-in ``cmd2`` support for colors including ``Cmd.colorize()`` and ``Cmd._colorcodes`` * Deletions (potentially breaking changes) diff --git a/docs/argument_processing.rst b/docs/argument_processing.rst index 9d13a7c8..8931c60b 100644 --- a/docs/argument_processing.rst +++ b/docs/argument_processing.rst @@ -15,11 +15,11 @@ Argument Processing These features are all provided by the ``@with_argparser`` decorator which is importable from ``cmd2``. -See the either the argprint_ or argparse_ example to learn more about how to use the various ``cmd2`` argument +See the either the argprint_ or decorator_ example to learn more about how to use the various ``cmd2`` argument processing decorators in your ``cmd2`` applications. .. _argprint: https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py -.. _argparse: https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_example.py +.. _decorator: https://github.com/python-cmd2/cmd2/blob/master/examples/decorator_example.py Using the argument parser decorator =================================== @@ -171,6 +171,14 @@ Which yields: This command can not generate tags with no content, like
+.. warning:: + + If a command **foo** is decorated with one of cmd2's argparse decorators, then **help_foo** will not + be invoked when ``help foo`` is called. The argparse_ module provides a rich API which can be used to + tweak every aspect of the displayed help and we encourage ``cmd2`` developers to utilize that. + +.. _argparse: https://docs.python.org/3/library/argparse.html + Grouping Commands ================= diff --git a/examples/argparse_example.py b/examples/argparse_example.py deleted file mode 100755 index 236e2af4..00000000 --- a/examples/argparse_example.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -"""A sample application for cmd2 showing how to use argparse to -process command line arguments for your application. - -Thanks to cmd2's built-in transcript testing capability, it also -serves as a test suite for argparse_example.py when used with the -exampleSession.txt transcript. - -Running `python argparse_example.py -t exampleSession.txt` will run -all the commands in the transcript against argparse_example.py, -verifying that the output produced matches the transcript. -""" -import argparse -import sys - -import cmd2 - - -class CmdLineApp(cmd2.Cmd): - """ Example cmd2 application. """ - def __init__(self, ip_addr=None, port=None, transcript_files=None): - self.multiline_commands = ['orate'] - self.shortcuts.update({'&': 'speak'}) - self.maxrepeats = 3 - - # Add stuff to settable and/or shortcuts before calling base class initializer - self.settable['maxrepeats'] = 'Max number of `--repeat`s allowed' - - # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell - super().__init__(use_ipython=False, transcript_files=transcript_files) - - # Disable cmd's usage of command-line arguments as commands to be run at invocation - # self.allow_cli_args = False - - # Example of args set from the command-line (but they aren't being used here) - self._ip = ip_addr - self._port = port - - # Setting this true makes it run a shell command if a cmd2/cmd command doesn't exist - # self.default_to_shell = True - - speak_parser = argparse.ArgumentParser() - speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') - speak_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') - speak_parser.add_argument('-r', '--repeat', type=int, help='output [n] times') - speak_parser.add_argument('words', nargs='+', help='words to say') - - @cmd2.with_argparser(speak_parser) - def do_speak(self, args): - """Repeats what you tell me to.""" - words = [] - for word in args.words: - if args.piglatin: - word = '%s%say' % (word[1:], word[0]) - if args.shout: - word = word.upper() - words.append(word) - repetitions = args.repeat or 1 - for i in range(min(repetitions, self.maxrepeats)): - self.poutput(' '.join(words)) - - do_say = do_speak # now "say" is a synonym for "speak" - do_orate = do_speak # another synonym, but this one takes multi-line input - - tag_parser = argparse.ArgumentParser() - tag_parser.add_argument('tag', help='tag') - tag_parser.add_argument('content', nargs='+', help='content to surround with tag') - - @cmd2.with_argparser(tag_parser) - def do_tag(self, args): - """create a html tag""" - self.poutput('<{0}>{1}'.format(args.tag, ' '.join(args.content))) - - - @cmd2.with_argument_list - def do_tagg(self, arglist): - """verion of creating an html tag using arglist instead of argparser""" - if len(arglist) >= 2: - tag = arglist[0] - content = arglist[1:] - self.poutput('<{0}>{1}'.format(tag, ' '.join(content))) - else: - self.perror("tagg requires at least 2 arguments") - - -if __name__ == '__main__': - # You can do your custom Argparse parsing here to meet your application's needs - parser = argparse.ArgumentParser(description='Process the arguments however you like.') - - # Add a few arguments which aren't really used, but just to get the gist - parser.add_argument('-p', '--port', type=int, help='TCP port') - parser.add_argument('-i', '--ip', type=str, help='IPv4 address') - - # Add an argument which enables transcript testing - args, unknown_args = parser.parse_known_args() - - port = None - if args.port: - port = args.port - - ip_addr = None - if args.ip: - ip_addr = args.ip - - # Perform surgery on sys.argv to remove the arguments which have already been processed by argparse - sys.argv = sys.argv[:1] + unknown_args - - # Instantiate your cmd2 application - c = CmdLineApp() - - # And run your cmd2 application - c.cmdloop() diff --git a/examples/decorator_example.py b/examples/decorator_example.py new file mode 100755 index 00000000..5b8b303b --- /dev/null +++ b/examples/decorator_example.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# coding=utf-8 +"""A sample application showing how to use cmd2's argparse decorators to +process command line arguments for your application. + +Thanks to cmd2's built-in transcript testing capability, it also +serves as a test suite when used with the exampleSession.txt transcript. + +Running `python decorator_example.py -t exampleSession.txt` will run +all the commands in the transcript against decorator_example.py, +verifying that the output produced matches the transcript. +""" +import argparse +import sys + +import cmd2 + + +class CmdLineApp(cmd2.Cmd): + """ Example cmd2 application. """ + def __init__(self, ip_addr=None, port=None, transcript_files=None): + self.multiline_commands = ['orate'] + self.shortcuts.update({'&': 'speak'}) + self.maxrepeats = 3 + + # Add stuff to settable and/or shortcuts before calling base class initializer + self.settable['maxrepeats'] = 'Max number of `--repeat`s allowed' + + # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell + super().__init__(use_ipython=False, transcript_files=transcript_files) + + # Disable cmd's usage of command-line arguments as commands to be run at invocation + # self.allow_cli_args = False + + # Example of args set from the command-line (but they aren't being used here) + self._ip = ip_addr + self._port = port + + # Setting this true makes it run a shell command if a cmd2/cmd command doesn't exist + # self.default_to_shell = True + + speak_parser = argparse.ArgumentParser() + speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') + speak_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') + speak_parser.add_argument('-r', '--repeat', type=int, help='output [n] times') + speak_parser.add_argument('words', nargs='+', help='words to say') + + @cmd2.with_argparser(speak_parser) + def do_speak(self, args): + """Repeats what you tell me to.""" + words = [] + for word in args.words: + if args.piglatin: + word = '%s%say' % (word[1:], word[0]) + if args.shout: + word = word.upper() + words.append(word) + repetitions = args.repeat or 1 + for i in range(min(repetitions, self.maxrepeats)): + self.poutput(' '.join(words)) + + do_say = do_speak # now "say" is a synonym for "speak" + do_orate = do_speak # another synonym, but this one takes multi-line input + + tag_parser = argparse.ArgumentParser() + tag_parser.add_argument('tag', help='tag') + tag_parser.add_argument('content', nargs='+', help='content to surround with tag') + + @cmd2.with_argparser(tag_parser) + def do_tag(self, args): + """create a html tag""" + self.poutput('<{0}>{1}'.format(args.tag, ' '.join(args.content))) + + + @cmd2.with_argument_list + def do_tagg(self, arglist): + """verion of creating an html tag using arglist instead of argparser""" + if len(arglist) >= 2: + tag = arglist[0] + content = arglist[1:] + self.poutput('<{0}>{1}'.format(tag, ' '.join(content))) + else: + self.perror("tagg requires at least 2 arguments") + + +if __name__ == '__main__': + # You can do your custom Argparse parsing here to meet your application's needs + parser = argparse.ArgumentParser(description='Process the arguments however you like.') + + # Add a few arguments which aren't really used, but just to get the gist + parser.add_argument('-p', '--port', type=int, help='TCP port') + parser.add_argument('-i', '--ip', type=str, help='IPv4 address') + + # Add an argument which enables transcript testing + args, unknown_args = parser.parse_known_args() + + port = None + if args.port: + port = args.port + + ip_addr = None + if args.ip: + ip_addr = args.ip + + # Perform surgery on sys.argv to remove the arguments which have already been processed by argparse + sys.argv = sys.argv[:1] + unknown_args + + # Instantiate your cmd2 application + c = CmdLineApp() + + # And run your cmd2 application + c.cmdloop() diff --git a/examples/transcripts/exampleSession.txt b/examples/transcripts/exampleSession.txt index 38fb0659..8fa7c9bb 100644 --- a/examples/transcripts/exampleSession.txt +++ b/examples/transcripts/exampleSession.txt @@ -1,4 +1,4 @@ -# Run this transcript with "python argparse_example.py -t exampleSession.txt" +# Run this transcript with "python decorator_example.py -t exampleSession.txt" # The regex for colors is because no color on Windows. # The regex for editor will match whatever program you use. # regexes on prompts just make the trailing space obvious -- cgit v1.2.1