diff options
-rwxr-xr-x | README.md | 111 | ||||
-rwxr-xr-x | cmd2.py | 6 | ||||
-rwxr-xr-x | examples/argparse_example.py | 9 | ||||
-rwxr-xr-x | examples/example.py | 51 | ||||
-rw-r--r-- | tests/test_argparse.py | 16 |
5 files changed, 126 insertions, 67 deletions
@@ -29,7 +29,7 @@ Main Features - Multi-line, case-insensitive, and abbreviated commands - Special-character command shortcuts (beyond cmd's `@` and `!`) - Settable environment parameters -- Parsing commands with flags +- Parsing commands with arguments using `argparse` - Unicode character support (*Python 3 only*) - Good tab-completion of commands, file system paths, and shell commands - Python 2.7 and 3.4+ support @@ -97,17 +97,27 @@ Instructions for implementing each feature follow. To allow a user to change an environment parameter during program execution, append the parameter's name to `Cmd.settable`` -- Parsing commands with `optparse` options (flags) +- Parsing commands with `argparse` ```python - @options([make_option('-m', '--myoption', action="store_true", help="all about my option")]) - def do_myfunc(self, arg, opts): - if opts.myoption: - #TODO: Do something useful - pass + argparser = argparse.ArgumentParser() + argparser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') + argparser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') + argparser.add_argument('words', nargs='+', help='words to say') + @with_argument_parser(argparser) + def do_speak(self, cmdline, args=None): + """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) + self.stdout.write('{}\n'.format(' '.join(words))) ``` - See Python standard library's `optparse` documentation: https://docs.python.org/3/library/optparse.html + See https://cmd2.readthedocs.io/en/latest/argument_processing.html for more details Tutorials @@ -126,45 +136,80 @@ Example Application Example cmd2 application (**examples/example.py**): ```python -'''A sample application for cmd2.''' +#!/usr/bin/env python +# coding=utf-8 +""" +A sample application for cmd2. +""" + +import random +import argparse + +from cmd2 import Cmd, with_argument_parser -from cmd2 import Cmd, make_option, options, set_use_arg_list class CmdLineApp(Cmd): + """ Example cmd2 application. """ + + # Setting this true makes it run a shell command if a cmd2/cmd command doesn't exist + # default_to_shell = True + MUMBLES = ['like', '...', 'um', 'er', 'hmmm', 'ahh'] + MUMBLE_FIRST = ['so', 'like', 'well'] + MUMBLE_LAST = ['right?'] + def __init__(self): + self.abbrev = True self.multilineCommands = ['orate'] self.maxrepeats = 3 - # Add stuff to settable and shortcutgs before calling base class initializer + # Add stuff to settable and shortcuts before calling base class initializer self.settable['maxrepeats'] = 'max repetitions for speak command' self.shortcuts.update({'&': 'speak'}) # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell Cmd.__init__(self, use_ipython=False) - # For option commands, pass a single argument string instead of a list of argument strings to the do_* methods - set_use_arg_list(False) - - @options([make_option('-p', '--piglatin', action="store_true", help="atinLay"), - make_option('-s', '--shout', action="store_true", help="N00B EMULATION MODE"), - make_option('-r', '--repeat', type="int", help="output [n] times") - ]) - def do_speak(self, arg, opts=None): + argparser = argparse.ArgumentParser() + argparser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') + argparser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') + argparser.add_argument('-r', '--repeat', type=int, help='output [n] times') + argparser.add_argument('words', nargs='+', help='words to say') + @with_argument_parser(argparser) + def do_speak(self, cmdline, opts=None): """Repeats what you tell me to.""" - arg = ''.join(arg) - if opts.piglatin: - arg = '%s%say' % (arg[1:], arg[0]) - if opts.shout: - arg = arg.upper() - repetitions = opts.repeat or 1 + 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.stdout.write(arg) - self.stdout.write('\n') - # self.stdout.write is better than "print", because Cmd can be - # initialized with a non-standard output destination - - do_say = do_speak # now "say" is a synonym for "speak" - do_orate = do_speak # another synonym, but this one takes multi-line input + # .poutput handles newlines, and accommodates output redirection too + 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 + + argparser = argparse.ArgumentParser() + argparser.add_argument('-r', '--repeat', type=int, help='how many times to repeat') + argparser.add_argument('words', nargs='+', help='words to say') + @with_argument_parser(argparser) + def do_mumble(self, cmdline, args=None): + """Mumbles what you tell me to.""" + repetitions = args.repeat or 1 + for i in range(min(repetitions, self.maxrepeats)): + output = [] + if (random.random() < .33): + output.append(random.choice(self.MUMBLE_FIRST)) + for word in args.words: + if (random.random() < .40): + output.append(random.choice(self.MUMBLES)) + output.append(word) + if (random.random() < .25): + output.append(random.choice(self.MUMBLE_LAST)) + self.poutput(' '.join(output)) if __name__ == '__main__': c = CmdLineApp() @@ -207,4 +252,4 @@ timing: False Note how a regular expression `/(True|False)/` is used for output of the **show color** command since colored text is currently not available for cmd2 on Windows. Regular expressions can be used anywhere within a -transcript file simply by embedding them within two forward slashes, `/`. +transcript file simply by enclosing them within forward slashes, `/`. @@ -248,9 +248,9 @@ def with_argument_parser(argparser): argparse.ArgumentParser. """ def arg_decorator(func): - def cmd_wrapper(instance, arg): + def cmd_wrapper(instance, cmdline): # Use shlex to split the command line into a list of arguments based on shell rules - lexed_arglist = shlex.split(arg, posix=POSIX_SHLEX) + lexed_arglist = shlex.split(cmdline, posix=POSIX_SHLEX) # If not using POSIX shlex, make sure to strip off outer quotes for convenience if not POSIX_SHLEX and STRIP_QUOTES_FOR_NON_POSIX: temp_arglist = [] @@ -258,7 +258,7 @@ def with_argument_parser(argparser): temp_arglist.append(strip_quotes(arg)) lexed_arglist = temp_arglist opts = argparser.parse_args(lexed_arglist) - func(instance, arg, opts) + func(instance, cmdline, opts) # argparser defaults the program name to sys.argv[0] # we want it to be the name of our command diff --git a/examples/argparse_example.py b/examples/argparse_example.py index 4c5d6f59..d784ccf5 100755 --- a/examples/argparse_example.py +++ b/examples/argparse_example.py @@ -41,13 +41,13 @@ class CmdLineApp(Cmd): # self.default_to_shell = True - argparser = argparse.ArgumentParser(prog='speak') + argparser = argparse.ArgumentParser() argparser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') argparser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') argparser.add_argument('-r', '--repeat', type=int, help='output [n] times') argparser.add_argument('words', nargs='+', help='words to say') @with_argument_parser(argparser) - def do_speak(self, argv, args=None): + def do_speak(self, cmdline, args=None): """Repeats what you tell me to.""" words = [] for word in args.words: @@ -58,10 +58,7 @@ class CmdLineApp(Cmd): words.append(word) repetitions = args.repeat or 1 for i in range(min(repetitions, self.maxrepeats)): - self.stdout.write(' '.join(words)) - self.stdout.write('\n') - # self.stdout.write is better than "print", because Cmd can be - # initialized with a non-standard output destination + 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 diff --git a/examples/example.py b/examples/example.py index 889e62c0..d7d4e21c 100755 --- a/examples/example.py +++ b/examples/example.py @@ -12,8 +12,9 @@ the transcript. """ import random +import argparse -from cmd2 import Cmd, make_option, options, set_use_arg_list +from cmd2 import Cmd, with_argument_parser class CmdLineApp(Cmd): @@ -37,41 +38,41 @@ class CmdLineApp(Cmd): # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell Cmd.__init__(self, use_ipython=False) - # For option commands, pass a single argument string instead of a list of argument strings to the do_* methods - set_use_arg_list(False) - - opts = [make_option('-p', '--piglatin', action="store_true", help="atinLay"), - make_option('-s', '--shout', action="store_true", help="N00B EMULATION MODE"), - make_option('-r', '--repeat', type="int", help="output [n] times")] - - @options(opts, arg_desc='(text to say)') - def do_speak(self, arg, opts=None): + argparser = argparse.ArgumentParser() + argparser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') + argparser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') + argparser.add_argument('-r', '--repeat', type=int, help='output [n] times') + argparser.add_argument('words', nargs='+', help='words to say') + @with_argument_parser(argparser) + def do_speak(self, cmdline, opts=None): """Repeats what you tell me to.""" - arg = ''.join(arg) - if opts.piglatin: - arg = '%s%say' % (arg[1:], arg[0]) - if opts.shout: - arg = arg.upper() - repetitions = opts.repeat or 1 + 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(arg) - # recommend using the poutput function instead of - # self.stdout.write or "print", because Cmd allows the user - # to redirect output + # .poutput handles newlines, and accommodates output redirection too + 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 - @options([ make_option('-r', '--repeat', type="int", help="output [n] times") ]) - def do_mumble(self, arg, opts=None): + argparser = argparse.ArgumentParser() + argparser.add_argument('-r', '--repeat', type=int, help='how many times to repeat') + argparser.add_argument('words', nargs='+', help='words to say') + @with_argument_parser(argparser) + def do_mumble(self, cmdline, args=None): """Mumbles what you tell me to.""" - repetitions = opts.repeat or 1 - arg = arg.split() + repetitions = args.repeat or 1 for i in range(min(repetitions, self.maxrepeats)): output = [] if (random.random() < .33): output.append(random.choice(self.MUMBLE_FIRST)) - for word in arg: + for word in args.words: if (random.random() < .40): output.append(random.choice(self.MUMBLES)) output.append(word) diff --git a/tests/test_argparse.py b/tests/test_argparse.py index e9dbc1b3..52ce7de8 100644 --- a/tests/test_argparse.py +++ b/tests/test_argparse.py @@ -2,6 +2,7 @@ """ Cmd2 testing for argument parsing """ +import re import argparse import pytest @@ -43,6 +44,16 @@ class ArgparseApp(cmd2.Cmd): self.stdout.write('<{0}>{1}</{0}>'.format(args.tag[0], ' '.join(args.content))) self.stdout.write('\n') + argparser = argparse.ArgumentParser() + argparser.add_argument('args', nargs='*') + @cmd2.with_argument_parser(argparser) + def do_compare(self, cmdline, args=None): + cmdline_str = re.sub('\s+', ' ', cmdline) + args_str = re.sub('\s+', ' ', ' '.join(args.args)) + if cmdline_str == args_str: + self.stdout.write('True') + else: + self.stdout.write('False') @pytest.fixture def argparse_app(): @@ -88,4 +99,9 @@ def test_argparse_prog(argparse_app): out = run_cmd(argparse_app, 'help tag') progname = out[0].split(' ')[1] assert progname == 'tag' + +def test_argparse_cmdline(argparse_app): + out = run_cmd(argparse_app, 'compare this is a test') + assert out[0] == 'True' +
\ No newline at end of file |