diff options
-rwxr-xr-x | README.md | 20 | ||||
-rwxr-xr-x | cmd2.py | 100 | ||||
-rwxr-xr-x | examples/example.py | 11 | ||||
-rw-r--r-- | tests/test_parsing.py | 21 | ||||
-rw-r--r-- | tests/test_transcript.py | 12 |
5 files changed, 45 insertions, 119 deletions
@@ -103,16 +103,22 @@ Example cmd2 application (**examples/example.py**): ```python '''A sample application for cmd2.''' -from cmd2 import Cmd, make_option, options +from cmd2 import Cmd, make_option, options, set_use_arg_list class CmdLineApp(Cmd): - multilineCommands = ['orate'] - Cmd.shortcuts.update({'&': 'speak'}) - maxrepeats = 3 - Cmd.settable.append('maxrepeats') + def __init__(self): + self.multilineCommands = ['orate'] + self.maxrepeats = 3 - # Setting this true makes it run a shell command if a cmd2/cmd command doesn't exist - # default_to_shell = True + # Add stuff to settable and shortcutgs 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"), @@ -27,7 +27,6 @@ Git repository on GitHub at https://github.com/python-cmd2/cmd2 """ import cmd import collections -import copy import datetime import glob import optparse @@ -474,71 +473,6 @@ class ParsedString(str): return new -class StubbornDict(dict): - """ Dictionary that tolerates many input formats. - - Create it with the stubbornDict(arg) factory function. - """ - # noinspection PyMethodOverriding - def update(self, arg): - """Adds dictionary arg's key-values pairs in to dict - - :param arg: an object convertible to a StubbornDict - """ - dict.update(self, StubbornDict.to_dict(arg)) - - append = update - - def __iadd__(self, arg): - self.update(arg) - return self - - def __add__(self, arg): - selfcopy = copy.copy(self) - selfcopy.update(stubborn_dict(arg)) - return selfcopy - - def __radd__(self, arg): - selfcopy = copy.copy(self) - selfcopy.update(stubborn_dict(arg)) - return selfcopy - - @classmethod - def to_dict(cls, arg): - """Generates dictionary from string or list of strings""" - if hasattr(arg, 'splitlines'): - arg = arg.splitlines() - if hasattr(arg, '__reversed__'): - result = {} - for a in arg: - a = a.strip() - if a: - key_val = a.split(None, 1) - key = key_val[0] - if len(key_val) > 1: - val = key_val[1] - else: - val = '' - result[key] = val - else: - result = arg - return result - - -def stubborn_dict(*arg, **kwarg): - """ Factory function which creates instances of the StubbornDict class. - - :param arg: an argument which could be used to construct a built-in dict dictionary - :param kwarg: a variable number of key/value pairs - :return: StubbornDict - a StubbornDict containing everything in both arg and kwarg - """ - result = {} - for a in arg: - result.update(StubbornDict.to_dict(a)) - result.update(kwarg) - return StubbornDict(result) - - def replace_with_file_contents(fname): """Action to perform when successfully matching parse element definition for inputFrom parser. @@ -619,21 +553,20 @@ class Cmd(cmd.Cmd): timing = False # Prints elapsed time for each command # To make an attribute settable with the "do_set" command, add it to this ... - settable = stubborn_dict(''' - abbrev Accept abbreviated commands - autorun_on_edit Automatically run files after editing - case_insensitive Upper- and lower-case both OK - colors Colorized output (*nix only) - continuation_prompt On 2nd+ line of input - debug Show full error stack on error - echo Echo command issued into output - editor Program used by ``edit`` - feedback_to_output Include nonessentials in `|`, `>` results - locals_in_py Allow access to your application in py via self - prompt The prompt issued to solicit input - quiet Don't print nonessential feedback - timing Report execution times - ''') + # This starts out as a dictionary but gets converted to an OrderedDict sorted alphabetically by key + settable = {'abbrev': 'Accept abbreviated commands', + 'autorun_on_edit': 'Automatically run files after editing', + 'case_insensitive': 'Upper- and lower-case both OK', + 'colors': 'Colorized output (*nix only)', + 'continuation_prompt': 'On 2nd+ line of input', + 'debug': 'Show full error stack on error', + 'echo': 'Echo command issued into output', + 'editor': 'Program used by ``edit``', + 'feedback_to_output': 'Include nonessentials in `|`, `>` results', + 'locals_in_py': 'Allow access to your application in py via self', + 'prompt': 'The prompt issued to solicit input', + 'quiet': "Don't print nonessential feedback", + 'timing': 'Report execution times'} def __init__(self, completekey='tab', stdin=None, stdout=None, use_ipython=False, transcript_files=None): """An easy but powerful framework for writing line-oriented command interpreters, extends Python's cmd package. @@ -710,6 +643,9 @@ class Cmd(cmd.Cmd): # noinspection PyUnresolvedReferences self.shortcuts = sorted(self.shortcuts.items(), reverse=True) + # Make sure settable parameters are sorted alphabetically by key + self.settable = collections.OrderedDict(sorted(self.settable.items(), key=lambda t: t[0])) + def poutput(self, msg): """Convenient shortcut for self.stdout.write(); adds newline if necessary.""" if msg: @@ -1271,7 +1207,7 @@ class Cmd(cmd.Cmd): if result: for p in sorted(result): if opts.long: - self.poutput('%s # %s' % (result[p].ljust(maxlen), self.settable[p])) + self.poutput('{} # {}'.format(result[p].ljust(maxlen), self.settable[p])) else: self.poutput(result[p]) else: diff --git a/examples/example.py b/examples/example.py index 68e08890..fd886a76 100755 --- a/examples/example.py +++ b/examples/example.py @@ -14,15 +14,18 @@ from cmd2 import Cmd, make_option, options, set_use_arg_list class CmdLineApp(Cmd): """ Example cmd2 application. """ - multilineCommands = ['orate'] - Cmd.shortcuts.update({'&': 'speak'}) - maxrepeats = 3 - Cmd.settable.append('maxrepeats') # Setting this true makes it run a shell command if a cmd2/cmd command doesn't exist # default_to_shell = True def __init__(self): + self.multilineCommands = ['orate'] + self.maxrepeats = 3 + + # Add stuff to settable and shortcutgs 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) diff --git a/tests/test_parsing.py b/tests/test_parsing.py index a3b601db..dda29911 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -43,27 +43,6 @@ def test_remaining_args(): assert cmd2.remaining_args('-f bar bar cow', ['bar', 'cow']) == 'bar cow' -def test_stubborn_dict_class(): - d = cmd2.StubbornDict(large='gross', small='klein') - assert sorted(d.items()) == [('large', 'gross'), ('small', 'klein')] - - d.append(['plain', ' plaid']) - assert sorted(d.items()) == [('large', 'gross'), ('plaid', ''), ('plain', ''), ('small', 'klein')] - - d += ' girl Frauelein, Maedchen\n\n shoe schuh' - assert sorted(d.items()) == [('girl', 'Frauelein, Maedchen'), ('large', 'gross'), ('plaid', ''), ('plain', ''), - ('shoe', 'schuh'), ('small', 'klein')] - -def test_stubborn_dict_factory(): - assert sorted(cmd2.stubborn_dict('cow a bovine\nhorse an equine').items()) == [('cow', 'a bovine'), - ('horse', 'an equine')] - assert sorted(cmd2.stubborn_dict(['badger', 'porcupine a poky creature']).items()) == [('badger', ''), - ('porcupine', - 'a poky creature')] - assert sorted(cmd2.stubborn_dict(turtle='has shell', frog='jumpy').items()) == [('frog', 'jumpy'), - ('turtle', 'has shell')] - - def test_history_span(hist): h = hist assert h.span('-2..') == ['third', 'fourth'] diff --git a/tests/test_transcript.py b/tests/test_transcript.py index 4b6f4c99..a31ebd17 100644 --- a/tests/test_transcript.py +++ b/tests/test_transcript.py @@ -20,14 +20,16 @@ from conftest import run_cmd, StdOut, normalize class CmdLineApp(Cmd): - multilineCommands = ['orate'] - maxrepeats = 3 - redirector = '->' - def __init__(self, *args, **kwargs): + self.multilineCommands = ['orate'] + self.maxrepeats = 3 + self.redirector = '->' + + # Add stuff to settable and/or shortcuts before calling base class initializer + self.settable['maxrepeats'] = 'Max number of `--repeat`s allowed' + # Need to use this older form of invoking super class constructor to support Python 2.x and Python 3.x Cmd.__init__(self, *args, **kwargs) - self.settable.append('maxrepeats Max number of `--repeat`s allowed') # Configure how arguments are parsed for @options commands set_posix_shlex(False) |