summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcmd2.py266
-rw-r--r--docs/conf.py73
-rw-r--r--docs/pycon2010/pirate.py2
-rw-r--r--docs/pycon2010/pirate2.py5
-rw-r--r--docs/pycon2010/pirate3.py7
-rw-r--r--docs/pycon2010/pirate4.py7
-rw-r--r--docs/pycon2010/pirate5.py8
-rw-r--r--docs/pycon2010/pirate6.py9
-rw-r--r--docs/pycon2010/pirate7.py11
-rw-r--r--docs/pycon2010/pirate8.py12
-rwxr-xr-xexample/example.py7
-rw-r--r--tests/test_transcript.py4
12 files changed, 280 insertions, 131 deletions
diff --git a/cmd2.py b/cmd2.py
index c16cba9b..606eed8c 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -63,6 +63,7 @@ from six.moves.urllib.request import urlopen
# Due to one occurence of isinstance(<foo>, file) checking to see if something is of file type
try:
import io
+
file = io.TextIOWrapper
except ImportError:
pass # Python2
@@ -87,6 +88,7 @@ NameError: global name 'exc' is not defined
Bug report filed: https://sourceforge.net/tracker/?func=detail&atid=617311&aid=3381439&group_id=97203
"""
+
class OptionParser(optparse.OptionParser):
def exit(self, status=0, msg=None):
self.values._exit = True
@@ -140,9 +142,10 @@ def _which(editor):
except OSError:
return None
+
optparse.Values.get = _attr_get_
-options_defined = [] # used to distinguish --options from SQL-style --comments
+options_defined = [] # used to distinguish --options from SQL-style --comments
def options(option_list, arg_desc="arg"):
@@ -165,18 +168,20 @@ def options(option_list, arg_desc="arg"):
option_list = [option_list]
for opt in option_list:
options_defined.append(pyparsing.Literal(opt.get_opt_string()))
+
def option_setup(func):
optionParser = OptionParser()
for opt in option_list:
optionParser.add_option(opt)
optionParser.set_usage("%s [options] %s" % (func.__name__[3:], arg_desc))
optionParser._func = func
+
def new_func(instance, arg):
try:
opts, newArgList = optionParser.parse_args(arg.split())
# Must find the remaining args in the original argument list, but
# mustn't include the command itself
- #if hasattr(arg, 'parsed') and newArgList[0] == arg.parsed.command:
+ # if hasattr(arg, 'parsed') and newArgList[0] == arg.parsed.command:
# newArgList = newArgList[1:]
newArgs = remaining_args(arg, newArgList)
if isinstance(arg, ParsedString):
@@ -194,6 +199,7 @@ def options(option_list, arg_desc="arg"):
new_func.__doc__ = '%s\n%s' % (func.__doc__, optionParser.format_help())
return new_func
+
return option_setup
@@ -209,9 +215,11 @@ Download from http://sourceforge.net/projects/pywin32/"""
errmsg = """Redirecting to or from paste buffer requires xclip
to be installed on operating system.
On Debian/Ubuntu, 'sudo apt-get install xclip' will install it."""
+
def __init__(self):
Exception.__init__(self, self.errmsg)
+
pastebufferr = """Redirecting to or from paste buffer requires %s
to be installed on operating system.
%s"""
@@ -219,14 +227,18 @@ to be installed on operating system.
if sys.platform == "win32":
try:
import win32clipboard
+
+
def get_paste_buffer():
win32clipboard.OpenClipboard(0)
try:
result = win32clipboard.GetClipboardData()
except TypeError:
- result = '' #non-text
+ result = '' # non-text
win32clipboard.CloseClipboard()
return result
+
+
def write_to_paste_buffer(txt):
win32clipboard.OpenClipboard(0)
win32clipboard.EmptyClipboard()
@@ -235,30 +247,41 @@ if sys.platform == "win32":
except ImportError:
def get_paste_buffer(*args):
raise OSError(pastebufferr % ('pywin32', 'Download from http://sourceforge.net/projects/pywin32/'))
+
+
write_to_paste_buffer = get_paste_buffer
elif sys.platform == 'darwin':
can_clip = False
try:
# test for pbcopy - AFAIK, should always be installed on MacOS
- subprocess.check_call('pbcopy -help', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
+ subprocess.check_call('pbcopy -help', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
+ stderr=subprocess.PIPE)
can_clip = True
except (subprocess.CalledProcessError, OSError, IOError):
pass
if can_clip:
def get_paste_buffer():
- pbcopyproc = subprocess.Popen('pbcopy -help', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
+ pbcopyproc = subprocess.Popen('pbcopy -help', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
+ stderr=subprocess.PIPE)
return pbcopyproc.stdout.read()
+
+
def write_to_paste_buffer(txt):
- pbcopyproc = subprocess.Popen('pbcopy', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
+ pbcopyproc = subprocess.Popen('pbcopy', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
+ stderr=subprocess.PIPE)
pbcopyproc.communicate(txt.encode())
else:
def get_paste_buffer(*args):
- raise OSError(pastebufferr % ('pbcopy', 'On MacOS X - error should not occur - part of the default installation'))
+ raise OSError(
+ pastebufferr % ('pbcopy', 'On MacOS X - error should not occur - part of the default installation'))
+
+
write_to_paste_buffer = get_paste_buffer
else:
can_clip = False
try:
- subprocess.check_call('xclip -o -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
+ subprocess.check_call('xclip -o -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
+ stderr=subprocess.PIPE)
can_clip = True
except AttributeError: # check_call not defined, Python < 2.5
try:
@@ -266,17 +289,21 @@ else:
xclipproc = subprocess.Popen('xclip -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
xclipproc.stdin.write(teststring)
xclipproc.stdin.close()
- xclipproc = subprocess.Popen('xclip -o -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
+ xclipproc = subprocess.Popen('xclip -o -sel clip', shell=True, stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE)
if xclipproc.stdout.read() == teststring:
can_clip = True
- except Exception: # hate a bare Exception call, but exception classes vary too much b/t stdlib versions
+ except Exception: # hate a bare Exception call, but exception classes vary too much b/t stdlib versions
pass
except Exception:
- pass # something went wrong with xclip and we cannot use it
+ pass # something went wrong with xclip and we cannot use it
if can_clip:
def get_paste_buffer():
- xclipproc = subprocess.Popen('xclip -o -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
+ xclipproc = subprocess.Popen('xclip -o -sel clip', shell=True, stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE)
return xclipproc.stdout.read()
+
+
def write_to_paste_buffer(txt):
xclipproc = subprocess.Popen('xclip -sel clip', shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
xclipproc.stdin.write(txt.encode())
@@ -288,6 +315,8 @@ else:
else:
def get_paste_buffer(*args):
raise OSError(pastebufferr % ('xclip', 'On Debian/Ubuntu, install with "sudo apt-get install xclip"'))
+
+
write_to_paste_buffer = get_paste_buffer
pyparsing.ParserElement.setDefaultWhitespaceChars(' \t')
@@ -308,6 +337,7 @@ class ParsedString(str):
new.parsed.statement['args'] = newargs
return new
+
class StubbornDict(dict):
'''Dictionary that tolerates many input formats.
Create it with stubbornDict(arg) factory function.
@@ -322,8 +352,10 @@ class StubbornDict(dict):
>>> sorted(d.items())
[('girl', 'Frauelein, Maedchen'), ('large', 'gross'), ('plaid', ''), ('plain', ''), ('shoe', 'schuh'), ('small', 'klein')]
'''
+
def update(self, arg):
dict.update(self, StubbornDict.to_dict(arg))
+
append = update
def __iadd__(self, arg):
@@ -406,28 +438,29 @@ def ljust(x, width, fillchar=' '):
x = (x + [fillchar] * width)[:width]
return x
+
class Cmd(cmd.Cmd):
echo = False
- case_insensitive = True # Commands recognized regardless of case
+ case_insensitive = True # Commands recognized regardless of case
continuation_prompt = '> '
- timing = False # Prints elapsed time for each command
+ timing = False # Prints elapsed time for each command
# make sure your terminators are not in legalChars!
legalChars = u'!#$%.:?@_' + pyparsing.alphanums + pyparsing.alphas8bit
shortcuts = {'?': 'help', '!': 'shell', '@': 'load', '@@': '_relative_load'}
excludeFromHistory = '''run r list l history hi ed edit li eof'''.split()
default_to_shell = False
noSpecialParse = 'set ed edit exit'.split()
- defaultExtension = 'txt' # For ``save``, ``load``, etc.
- default_file_name = 'command.txt' # For ``save``, ``load``, etc.
- abbrev = True # Abbreviated commands recognized
+ defaultExtension = 'txt' # For ``save``, ``load``, etc.
+ default_file_name = 'command.txt' # For ``save``, ``load``, etc.
+ abbrev = True # Abbreviated commands recognized
current_script_dir = None
reserved_words = []
- feedback_to_output = False # Do include nonessentials in >, | output
- quiet = False # Do not suppress nonessential output
+ feedback_to_output = False # Do include nonessentials in >, | output
+ quiet = False # Do not suppress nonessential output
debug = False
locals_in_py = True
kept_state = None
- redirector = '>' # for sending output to file
+ redirector = '>' # for sending output to file
settable = stubbornDict('''
prompt
colors Colorized output (*nix only)
@@ -463,6 +496,7 @@ class Cmd(cmd.Cmd):
self.poutput(msg)
else:
print(msg)
+
_STOP_AND_EXIT = True # distinguish end of script file from actual exit
_STOP_SCRIPT_NO_EXIT = -999
editor = os.environ.get('EDITOR')
@@ -474,14 +508,15 @@ class Cmd(cmd.Cmd):
if _which(editor):
break
- colorcodes = {'bold':{True:'\x1b[1m',False:'\x1b[22m'},
- 'cyan':{True:'\x1b[36m',False:'\x1b[39m'},
- 'blue':{True:'\x1b[34m',False:'\x1b[39m'},
- 'red':{True:'\x1b[31m',False:'\x1b[39m'},
- 'magenta':{True:'\x1b[35m',False:'\x1b[39m'},
- 'green':{True:'\x1b[32m',False:'\x1b[39m'},
- 'underline':{True:'\x1b[4m',False:'\x1b[24m'}}
+ colorcodes = {'bold': {True: '\x1b[1m', False: '\x1b[22m'},
+ 'cyan': {True: '\x1b[36m', False: '\x1b[39m'},
+ 'blue': {True: '\x1b[34m', False: '\x1b[39m'},
+ 'red': {True: '\x1b[31m', False: '\x1b[39m'},
+ 'magenta': {True: '\x1b[35m', False: '\x1b[39m'},
+ 'green': {True: '\x1b[32m', False: '\x1b[39m'},
+ 'underline': {True: '\x1b[4m', False: '\x1b[24m'}}
colors = (platform.system() != 'Windows')
+
def colorize(self, val, color):
'''Given a string (``val``), returns that string wrapped in UNIX-style
special characters that turn on (and then off) text color and style.
@@ -498,11 +533,11 @@ class Cmd(cmd.Cmd):
self.stdout.write("""
Commands are %(casesensitive)scase-sensitive.
Commands may be terminated with: %(terminators)s
- Settable parameters: %(settable)s\n""" % \
- { 'casesensitive': (self.case_insensitive and 'not ') or '',
- 'terminators': str(self.terminators),
- 'settable': ' '.join(self.settable)
- })
+ Settable parameters: %(settable)s\n""" %
+ {'casesensitive': (self.case_insensitive and 'not ') or '',
+ 'terminators': str(self.terminators),
+ 'settable': ' '.join(self.settable)
+ })
def do_help(self, arg):
if arg:
@@ -529,13 +564,12 @@ class Cmd(cmd.Cmd):
def do_shortcuts(self, args):
"""Lists single-key shortcuts available."""
result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in sorted(self.shortcuts))
- self.stdout.write("Single-key shortcuts for other commands:\n%s\n" % (result))
+ self.stdout.write("Single-key shortcuts for other commands:\n{}\n".format(result))
prefixParser = pyparsing.Empty()
commentGrammars = pyparsing.Or([pyparsing.pythonStyleComment, pyparsing.cStyleComment])
commentGrammars.addParseAction(lambda x: '')
- commentInProgress = pyparsing.Literal('/*') + pyparsing.SkipTo(
- pyparsing.stringEnd ^ '*/')
+ commentInProgress = pyparsing.Literal('/*') + pyparsing.SkipTo(pyparsing.stringEnd ^ '*/')
terminators = [';']
blankLinesAllowed = False
multilineCommands = []
@@ -716,21 +750,25 @@ class Cmd(cmd.Cmd):
- args: if "quoted strings /* seem to " start comments?
- command: what
'''
- #outputParser = (pyparsing.Literal('>>') | (pyparsing.WordStart() + '>') | pyparsing.Regex('[^=]>'))('output')
- outputParser = (pyparsing.Literal(self.redirector *2) |
- (pyparsing.WordStart() + self.redirector) |
+ # outputParser = (pyparsing.Literal('>>') | (pyparsing.WordStart() + '>') | pyparsing.Regex('[^=]>'))('output')
+ outputParser = (pyparsing.Literal(self.redirector * 2) |
+ (pyparsing.WordStart() + self.redirector) |
pyparsing.Regex('[^=]' + self.redirector))('output')
- terminatorParser = pyparsing.Or([(hasattr(t, 'parseString') and t) or pyparsing.Literal(t) for t in self.terminators])('terminator')
+ terminatorParser = pyparsing.Or(
+ [(hasattr(t, 'parseString') and t) or pyparsing.Literal(t) for t in self.terminators])('terminator')
stringEnd = pyparsing.stringEnd ^ '\nEOF'
- self.multilineCommand = pyparsing.Or([pyparsing.Keyword(c, caseless=self.case_insensitive) for c in self.multilineCommands])('multilineCommand')
+ self.multilineCommand = pyparsing.Or(
+ [pyparsing.Keyword(c, caseless=self.case_insensitive) for c in self.multilineCommands])('multilineCommand')
oneLineCommand = (~self.multilineCommand + pyparsing.Word(self.legalChars))('command')
pipe = pyparsing.Keyword('|', identChars='|')
self.commentGrammars.ignore(pyparsing.quotedString).setParseAction(lambda x: '')
doNotParse = self.commentGrammars | self.commentInProgress | pyparsing.quotedString
afterElements = \
pyparsing.Optional(pipe + pyparsing.SkipTo(outputParser ^ stringEnd, ignore=doNotParse)('pipeTo')) + \
- pyparsing.Optional(outputParser + pyparsing.SkipTo(stringEnd, ignore=doNotParse).setParseAction(lambda x: x[0].strip())('outputTo'))
+ pyparsing.Optional(
+ outputParser + pyparsing.SkipTo(stringEnd, ignore=doNotParse).setParseAction(lambda x: x[0].strip())(
+ 'outputTo'))
if self.case_insensitive:
self.multilineCommand.setParseAction(lambda x: x[0].lower())
oneLineCommand.setParseAction(lambda x: x[0].lower())
@@ -739,14 +777,21 @@ class Cmd(cmd.Cmd):
else:
self.blankLineTerminator = (pyparsing.lineEnd + pyparsing.lineEnd)('terminator')
self.blankLineTerminator.setResultsName('terminator')
- self.blankLineTerminationParser = ((self.multilineCommand ^ oneLineCommand) + pyparsing.SkipTo(self.blankLineTerminator, ignore=doNotParse).setParseAction(lambda x: x[0].strip())('args') + self.blankLineTerminator)('statement')
- self.multilineParser = (((self.multilineCommand ^ oneLineCommand) + pyparsing.SkipTo(terminatorParser, ignore=doNotParse).setParseAction(lambda x: x[0].strip())('args') + terminatorParser)('statement') +
- pyparsing.SkipTo(outputParser ^ pipe ^ stringEnd, ignore=doNotParse).setParseAction(lambda x: x[0].strip())('suffix') + afterElements)
+ self.blankLineTerminationParser = ((self.multilineCommand ^ oneLineCommand) +
+ pyparsing.SkipTo(self.blankLineTerminator, ignore=doNotParse).setParseAction(
+ lambda x: x[0].strip())('args') + self.blankLineTerminator)('statement')
+ self.multilineParser = (((self.multilineCommand ^ oneLineCommand) + pyparsing.SkipTo(terminatorParser,
+ ignore=doNotParse).setParseAction(
+ lambda x: x[0].strip())('args') + terminatorParser)('statement') +
+ pyparsing.SkipTo(outputParser ^ pipe ^ stringEnd, ignore=doNotParse).setParseAction(
+ lambda x: x[0].strip())('suffix') + afterElements)
self.multilineParser.ignore(self.commentInProgress)
- self.singleLineParser = ((oneLineCommand + pyparsing.SkipTo(terminatorParser ^ stringEnd ^ pipe ^ outputParser, ignore=doNotParse).setParseAction(lambda x:x[0].strip())('args'))('statement') +
+ self.singleLineParser = ((oneLineCommand + pyparsing.SkipTo(terminatorParser ^ stringEnd ^ pipe ^ outputParser,
+ ignore=doNotParse).setParseAction(
+ lambda x: x[0].strip())('args'))('statement') +
pyparsing.Optional(terminatorParser) + afterElements)
- #self.multilineParser = self.multilineParser.setResultsName('multilineParser')
- #self.singleLineParser = self.singleLineParser.setResultsName('singleLineParser')
+ # self.multilineParser = self.multilineParser.setResultsName('multilineParser')
+ # self.singleLineParser = self.singleLineParser.setResultsName('singleLineParser')
self.blankLineTerminationParser = self.blankLineTerminationParser.setResultsName('statement')
self.parser = self.prefixParser + (
stringEnd |
@@ -754,7 +799,7 @@ class Cmd(cmd.Cmd):
self.singleLineParser |
self.blankLineTerminationParser |
self.multilineCommand + pyparsing.SkipTo(stringEnd, ignore=doNotParse)
- )
+ )
self.parser.ignore(self.commentGrammars)
inputMark = pyparsing.Literal('<')
@@ -770,6 +815,7 @@ class Cmd(cmd.Cmd):
def preparse(self, raw, **kwargs):
return raw
+
def postparse(self, parseResult):
return parseResult
@@ -799,6 +845,7 @@ class Cmd(cmd.Cmd):
def postparsing_precmd(self, statement):
stop = 0
return stop, statement
+
def postparsing_postcmd(self, stop):
return stop
@@ -808,11 +855,12 @@ class Cmd(cmd.Cmd):
if target in dir(self):
result = target
else:
- if self.abbrev: # accept shortened versions of commands
+ if self.abbrev: # accept shortened versions of commands
funcs = [fname for fname in self.keywords if fname.startswith(arg)]
if len(funcs) == 1:
result = 'do_' + funcs[0]
return result
+
def onecmd_plus_hooks(self, line):
# The outermost level of try/finally nesting can be condensed once
# Python 2.4 support can be dropped.
@@ -842,11 +890,10 @@ class Cmd(cmd.Cmd):
self.perror(str(e), statement)
finally:
return self.postparsing_postcmd(stop)
+
def complete_statement(self, line):
"""Keep accepting lines of input until the command is complete."""
- if (not line) or (
- not pyparsing.Or(self.commentGrammars).
- setParseAction(lambda x: '').transformString(line)):
+ if not line or (not pyparsing.Or(self.commentGrammars).setParseAction(lambda x: '').transformString(line)):
raise EmptyStatement()
statement = self.parsed(line)
while statement.parsed.multilineCommand and (statement.parsed.terminator == ''):
@@ -861,7 +908,8 @@ class Cmd(cmd.Cmd):
if statement.parsed.pipeTo:
self.kept_state = Statekeeper(self, ('stdout',))
self.kept_sys = Statekeeper(sys, ('stdout',))
- self.redirect = subprocess.Popen(statement.parsed.pipeTo, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
+ self.redirect = subprocess.Popen(statement.parsed.pipeTo, shell=True, stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE)
sys.stdout = self.stdout = self.redirect.stdin
elif statement.parsed.output:
if (not statement.parsed.outputTo) and (not can_clip):
@@ -939,7 +987,7 @@ class Cmd(cmd.Cmd):
if not len(line):
line = 'EOF'
else:
- if line[-1] == '\n': # this was always true in Cmd
+ if line[-1] == '\n': # this was always true in Cmd
line = line[:-1]
return line
@@ -958,7 +1006,7 @@ class Cmd(cmd.Cmd):
import readline
self.old_completer = readline.get_completer()
readline.set_completer(self.complete)
- readline.parse_and_bind(self.completekey+": complete")
+ readline.parse_and_bind(self.completekey + ": complete")
except ImportError:
pass
stop = None
@@ -966,7 +1014,7 @@ class Cmd(cmd.Cmd):
if intro is not None:
self.intro = intro
if self.intro:
- self.stdout.write(str(self.intro)+"\n")
+ self.stdout.write(str(self.intro) + "\n")
while not stop:
if self.cmdqueue:
line = self.cmdqueue.pop(0)
@@ -986,11 +1034,13 @@ class Cmd(cmd.Cmd):
return stop
def do_EOF(self, arg):
- return self._STOP_SCRIPT_NO_EXIT # End of script; should not exit app
+ return self._STOP_SCRIPT_NO_EXIT # End of script; should not exit app
+
do_eof = do_EOF
def do_quit(self, arg):
return self._STOP_AND_EXIT
+
do_exit = do_quit
do_q = do_quit
@@ -1018,7 +1068,7 @@ class Cmd(cmd.Cmd):
except IndexError:
fulloptions.append((opt[0], opt[0]))
for (idx, (value, text)) in enumerate(fulloptions):
- self.poutput(' %2d. %s\n' % (idx+1, text))
+ self.poutput(' %2d. %s\n' % (idx + 1, text))
while True:
response = input(prompt)
try:
@@ -1026,11 +1076,10 @@ class Cmd(cmd.Cmd):
result = fulloptions[response - 1][0]
break
except ValueError:
- pass # loop and ask again
+ pass # loop and ask again
return result
- @options([make_option('-l', '--long', action="store_true",
- help="describe function of parameter")])
+ @options([make_option('-l', '--long', action="store_true", help="describe function of parameter")])
def do_show(self, arg, opts):
'''Shows value of a parameter.'''
param = arg.strip().lower()
@@ -1047,7 +1096,7 @@ class Cmd(cmd.Cmd):
else:
self.poutput(result[p])
else:
- raise NotImplementedError("Parameter '%s' not supported (type 'show' for list of parameters)." % param)
+ raise LookupError("Parameter '%s' not supported (type 'show' for list of parameters)." % param)
def do_set(self, arg):
'''
@@ -1106,8 +1155,10 @@ class Cmd(cmd.Cmd):
else:
def quit():
raise EmbeddedConsoleExit
+
def onecmd_plus_hooks(arg):
return self.onecmd_plus_hooks(arg + '\n')
+
def run(arg):
try:
file = open(arg)
@@ -1115,6 +1166,7 @@ class Cmd(cmd.Cmd):
file.close()
except IOError as e:
self.perror(e)
+
self.pystate['quit'] = quit
self.pystate['exit'] = quit
self.pystate['cmd'] = onecmd_plus_hooks
@@ -1122,18 +1174,18 @@ class Cmd(cmd.Cmd):
keepstate = None
try:
cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
- keepstate = Statekeeper(sys, ('stdin','stdout'))
+ keepstate = Statekeeper(sys, ('stdin', 'stdout'))
sys.stdout = self.stdout
sys.stdin = self.stdin
- interp.interact(banner= "Python %s on %s\n%s\n(%s)\n%s" %
- (sys.version, sys.platform, cprt, self.__class__.__name__, self.do_py.__doc__))
+ interp.interact(banner="Python %s on %s\n%s\n(%s)\n%s" %
+ (sys.version, sys.platform, cprt, self.__class__.__name__, self.do_py.__doc__))
except EmbeddedConsoleExit:
pass
if keepstate is not None:
keepstate.restore()
@options([make_option('-s', '--script', action="store_true", help="Script format; no separation lines"),
- ], arg_desc = '(limit on which commands to include)')
+ ], arg_desc='(limit on which commands to include)')
def do_history(self, arg, opts):
"""history [arg]: lists past commands issued
@@ -1151,6 +1203,7 @@ class Cmd(cmd.Cmd):
self.poutput(hi)
else:
self.stdout.write(hi.pr())
+
def last_matching(self, arg):
try:
if arg:
@@ -1159,6 +1212,7 @@ class Cmd(cmd.Cmd):
return self.history[-1]
except IndexError:
return None
+
def do_list(self, arg):
"""list [arg]: lists last command issued
@@ -1206,11 +1260,13 @@ class Cmd(cmd.Cmd):
os.system('%s %s' % (self.editor, filename))
self.do__load(filename)
+
do_edit = do_ed
- saveparser = (pyparsing.Optional(pyparsing.Word(pyparsing.nums)^'*')("idx") +
+ saveparser = (pyparsing.Optional(pyparsing.Word(pyparsing.nums) ^ '*')("idx") +
pyparsing.Optional(pyparsing.Word(legalChars + '/\\'))("fname") +
pyparsing.stringEnd)
+
def do_save(self, arg):
"""`save [N] [filename.ext]`
@@ -1228,16 +1284,16 @@ class Cmd(cmd.Cmd):
if args.idx == '*':
saveme = '\n\n'.join(self.history[:])
elif args.idx:
- saveme = self.history[int(args.idx)-1]
+ saveme = self.history[int(args.idx) - 1]
else:
saveme = self.history[-1]
try:
f = open(os.path.expanduser(fname), 'w')
f.write(saveme)
f.close()
- self.pfeedback('Saved to %s' % (fname))
+ self.pfeedback('Saved to {}'.format(fname))
except Exception as e:
- self.perror('Error saving %s' % (fname))
+ self.perror('Error saving {}'.format(fname))
raise
def read_file_or_url(self, fname):
@@ -1269,6 +1325,7 @@ class Cmd(cmd.Cmd):
self.do__load('%s %s' % (targetname, args))
urlre = re.compile('(https?://[-\\w\\./]+)')
+
def do_load(self, arg=None):
"""Runs script of command(s) from a file or URL."""
if arg is None:
@@ -1281,8 +1338,8 @@ class Cmd(cmd.Cmd):
except IOError as e:
self.perror('Problem accessing script from %s: \n%s' % (targetname, e))
return
- keepstate = Statekeeper(self, ('stdin','use_rawinput','prompt',
- 'continuation_prompt','current_script_dir'))
+ keepstate = Statekeeper(self, ('stdin', 'use_rawinput', 'prompt',
+ 'continuation_prompt', 'current_script_dir'))
self.stdin = target
self.use_rawinput = False
self.prompt = self.continuation_prompt = ''
@@ -1292,6 +1349,7 @@ class Cmd(cmd.Cmd):
keepstate.restore()
self.lastcmd = ''
return stop and (stop != self._STOP_SCRIPT_NO_EXIT)
+
do__load = do_load # avoid an unfortunate legacy use of do_load from sqlpython
def do_run(self, arg):
@@ -1307,6 +1365,7 @@ class Cmd(cmd.Cmd):
self.pfeedback(runme)
if runme:
stop = self.onecmd_plus_hooks(runme)
+
do_r = do_run
def fileimport(self, statement, source):
@@ -1322,8 +1381,9 @@ class Cmd(cmd.Cmd):
def runTranscriptTests(self, callargs):
class TestMyAppCase(Cmd2TestCase):
CmdApp = self.__class__
+
self.__class__.testfiles = callargs
- sys.argv = [sys.argv[0]] # the --test argument upsets unittest.main()
+ sys.argv = [sys.argv[0]] # the --test argument upsets unittest.main()
testcase = TestMyAppCase()
runner = unittest.TextTestRunner()
result = runner.run(testcase)
@@ -1337,8 +1397,8 @@ class Cmd(cmd.Cmd):
def cmdloop(self, intro=None):
parser = optparse.OptionParser()
parser.add_option('-t', '--test', dest='test',
- action="store_true",
- help='Test against transcript(s) in FILE (wildcards OK)')
+ action="store_true",
+ help='Test against transcript(s) in FILE (wildcards OK)')
(callopts, callargs) = parser.parse_args()
if callopts.test:
self.runTranscriptTests(callargs)
@@ -1346,15 +1406,19 @@ class Cmd(cmd.Cmd):
if not self.run_commands_at_invocation(callargs):
self._cmdloop()
+
class HistoryItem(str):
listformat = '-------------------------[%d]\n%s\n'
+
def __init__(self, instr):
str.__init__(self)
self.lowercase = self.lower()
self.idx = None
+
def pr(self):
return self.listformat % (self.idx, str(self))
+
class History(list):
'''A list of HistoryItems that knows how to respond to user requests.
>>> h = History([HistoryItem('first'), HistoryItem('second'), HistoryItem('third'), HistoryItem('fourth')])
@@ -1377,17 +1441,20 @@ class History(list):
>>> h.search('/IR/')
['first', 'third']
'''
+
def zero_based_index(self, onebased):
result = onebased
if result > 0:
result -= 1
return result
+
def to_index(self, raw):
if raw:
result = self.zero_based_index(int(raw))
else:
result = None
return result
+
def search(self, target):
target = target.strip()
if target[0] == target[-1] == '/' and len(target) > 1:
@@ -1396,7 +1463,9 @@ class History(list):
target = re.escape(target)
pattern = re.compile(target, re.IGNORECASE)
return [s for s in self if pattern.search(s)]
+
spanpattern = re.compile(r'^\s*(?P<start>\-?\d+)?\s*(?P<separator>:|(\.{2,}))?\s*(?P<end>\-?\d+)?\s*$')
+
def span(self, raw):
if raw.lower() in ('*', '-', 'all'):
raw = ':'
@@ -1419,10 +1488,12 @@ class History(list):
return result
rangePattern = re.compile(r'^\s*(?P<start>[\d]+)?\s*\-\s*(?P<end>[\d]+)?\s*$')
+
def append(self, new):
new = HistoryItem(new)
list.append(self, new)
new.idx = len(self)
+
def extend(self, new):
for n in new:
self.append(n)
@@ -1435,7 +1506,7 @@ class History(list):
if getme < 0:
return self[:(-1 * getme)]
else:
- return [self[getme-1]]
+ return [self[getme - 1]]
except IndexError:
return []
except ValueError:
@@ -1453,16 +1524,19 @@ class History(list):
if getme.startswith(r'/') and getme.endswith(r'/'):
finder = re.compile(getme[1:-1], re.DOTALL | re.MULTILINE | re.IGNORECASE)
+
def isin(hi):
return finder.search(hi)
else:
def isin(hi):
- return (getme.lower() in hi.lowercase)
+ return getme.lower() in hi.lowercase
return [itm for itm in self if isin(itm)]
+
class NotSettableError(Exception):
pass
+
def cast(current, new):
"""Tries to force a new value into the same type as the current."""
typ = type(current)
@@ -1475,9 +1549,9 @@ def cast(current, new):
new = new.lower()
except:
pass
- if (new=='on') or (new[0] in ('y','t')):
+ if (new == 'on') or (new[0] in ('y', 't')):
return True
- if (new=='off') or (new[0] in ('n','f')):
+ if (new == 'off') or (new[0] in ('n', 'f')):
return False
else:
try:
@@ -1487,42 +1561,52 @@ def cast(current, new):
print("Problem setting parameter (now %s) to %s; incorrect type?" % (current, new))
return current
+
class Statekeeper(object):
def __init__(self, obj, attribs):
self.obj = obj
self.attribs = attribs
if self.obj:
self.save()
+
def save(self):
for attrib in self.attribs:
setattr(self, attrib, getattr(self.obj, attrib))
+
def restore(self):
if self.obj:
for attrib in self.attribs:
setattr(self.obj, attrib, getattr(self, attrib))
+
class Borg(object):
'''All instances of any Borg subclass will share state.
from Python Cookbook, 2nd Ed., recipe 6.16'''
_shared_state = {}
+
def __new__(cls, *a, **k):
obj = object.__new__(cls, *a, **k)
obj.__dict__ = cls._shared_state
return obj
+
class OutputTrap(Borg):
'''Instantiate an OutputTrap to divert/capture ALL stdout output. For use in unit testing.
Call `tearDown()` to return to normal output.'''
+
def __init__(self):
self.contents = ''
self.old_stdout = sys.stdout
sys.stdout = self
+
def write(self, txt):
self.contents += txt
+
def read(self):
result = self.contents
self.contents = ''
return result
+
def tearDown(self):
sys.stdout = self.old_stdout
self.contents = ''
@@ -1533,6 +1617,7 @@ class Cmd2TestCase(unittest.TestCase):
that will execute the commands in a transcript file and expect the results shown.
See example.py'''
CmdApp = None
+
def fetchTranscripts(self):
self.transcripts = {}
for fileset in self.CmdApp.testfiles:
@@ -1542,22 +1627,26 @@ class Cmd2TestCase(unittest.TestCase):
tfile.close()
if not len(self.transcripts):
raise Exception("No test files found - nothing to test.")
+
def setUp(self):
if self.CmdApp:
self.outputTrap = OutputTrap()
self.cmdapp = self.CmdApp()
self.fetchTranscripts()
- def runTest(self): # was testall
+
+ def runTest(self): # was testall
if self.CmdApp:
its = sorted(self.transcripts.items())
for (fname, transcript) in its:
self._test_transcript(fname, transcript)
+
regexPattern = pyparsing.QuotedString(quoteChar=r'/', escChar='\\', multiline=True, unquoteResults=True)
regexPattern.ignore(pyparsing.cStyleComment)
notRegexPattern = pyparsing.Word(pyparsing.printables)
notRegexPattern.setParseAction(lambda t: re.escape(t[0]))
expectationParser = regexPattern | notRegexPattern
anyWhitespace = re.compile(r'\s', re.DOTALL | re.MULTILINE)
+
def _test_transcript(self, fname, transcript):
lineNum = 0
finished = False
@@ -1589,13 +1678,13 @@ class Cmd2TestCase(unittest.TestCase):
command = ''.join(command)
# Send the command into the application and capture the resulting output
stop = self.cmdapp.onecmd_plus_hooks(command)
- #TODO: should act on ``stop``
+ # TODO: should act on ``stop``
result = self.outputTrap.read()
# Read the expected result from transcript
if line.startswith(self.cmdapp.prompt):
- message = '\nFile %s, line %d\nCommand was:\n%r\nExpected: (nothing)\nGot:\n%r\n'%\
- (fname, lineNum, command, result)
- self.assert_(not(result.strip()), message)
+ message = '\nFile %s, line %d\nCommand was:\n%r\nExpected: (nothing)\nGot:\n%r\n' % \
+ (fname, lineNum, command, result)
+ self.assert_(not (result.strip()), message)
continue
expected = []
while not line.startswith(self.cmdapp.prompt):
@@ -1608,8 +1697,8 @@ class Cmd2TestCase(unittest.TestCase):
lineNum += 1
expected = ''.join(expected)
# Compare actual result to expected
- message = '\nFile %s, line %d\nCommand was:\n%s\nExpected:\n%s\nGot:\n%s\n'%\
- (fname, lineNum, command, expected, result)
+ message = '\nFile %s, line %d\nCommand was:\n%s\nExpected:\n%s\nGot:\n%s\n' % \
+ (fname, lineNum, command, expected, result)
expected = self.expectationParser.transformString(expected)
# checking whitespace is a pain - let's skip it
expected = self.anyWhitespace.sub('', expected)
@@ -1620,8 +1709,9 @@ class Cmd2TestCase(unittest.TestCase):
if self.CmdApp:
self.outputTrap.tearDown()
+
if __name__ == '__main__':
- doctest.testmod(optionflags = doctest.NORMALIZE_WHITESPACE)
+ doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)
'''
To make your application transcript-testable, replace
@@ -1645,5 +1735,3 @@ into a file, ``transcript.test``, and invoke the test like::
Wildcards can be used to test against multiple transcript files.
'''
-
-
diff --git a/docs/conf.py b/docs/conf.py
index 29fe144a..32d9243c 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -16,7 +16,7 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.append(os.path.abspath('.'))
+# sys.path.append(os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
@@ -31,7 +31,7 @@ templates_path = ['_templates']
source_suffix = '.rst'
# The encoding of source files.
-#source_encoding = 'utf-8'
+# source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
@@ -51,40 +51,40 @@ release = '0.6.9a'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
-#unused_docs = []
+# unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
+# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
@@ -96,26 +96,26 @@ html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-#html_theme_options = {}
+# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
-#html_title = None
+# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -124,74 +124,73 @@ html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
-#html_use_modindex = True
+# html_use_modindex = True
# If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = ''
+# html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'cmd2doc'
-
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
+# latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
+# latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
- ('index', 'cmd2.tex', u'cmd2 Documentation',
- u'Catherine Devlin', 'manual'),
+ ('index', 'cmd2.tex', u'cmd2 Documentation',
+ u'Catherine Devlin', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
+# latex_preamble = ''
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
# If false, no module index is generated.
-#latex_use_modindex = True
+# latex_use_modindex = True
# Example configuration for intersphinx: refer to the Python standard library.
diff --git a/docs/pycon2010/pirate.py b/docs/pycon2010/pirate.py
index 48afe629..bd8b5170 100644
--- a/docs/pycon2010/pirate.py
+++ b/docs/pycon2010/pirate.py
@@ -1,8 +1,10 @@
# coding=utf-8
from cmd import Cmd
+
class Pirate(Cmd):
pass
+
pirate = Pirate()
pirate.cmdloop()
diff --git a/docs/pycon2010/pirate2.py b/docs/pycon2010/pirate2.py
index c1852f03..343f94ff 100644
--- a/docs/pycon2010/pirate2.py
+++ b/docs/pycon2010/pirate2.py
@@ -1,19 +1,24 @@
# coding=utf-8
from cmd import Cmd
+
+
# using ``do_`` methods
class Pirate(Cmd):
gold = 3
+
def do_loot(self, arg):
'Seize booty from a passing ship.'
self.gold += 1
print('Now we gots {0} doubloons'
.format(self.gold))
+
def do_drink(self, arg):
'Drown your sorrrows in rrrum.'
self.gold -= 1
print('Now we gots {0} doubloons'
.format(self.gold))
+
pirate = Pirate()
pirate.cmdloop()
diff --git a/docs/pycon2010/pirate3.py b/docs/pycon2010/pirate3.py
index 61eb2d4e..ecc70f3f 100644
--- a/docs/pycon2010/pirate3.py
+++ b/docs/pycon2010/pirate3.py
@@ -1,22 +1,29 @@
# coding=utf-8
from cmd import Cmd
+
+
# using hook
class Pirate(Cmd):
gold = 3
+
def do_loot(self, arg):
'Seize booty from a passing ship.'
self.gold += 1
+
def do_drink(self, arg):
'Drown your sorrrows in rrrum.'
self.gold -= 1
+
def precmd(self, line):
self.initial_gold = self.gold
return line
+
def postcmd(self, stop, line):
if self.gold != self.initial_gold:
print('Now we gots {0} doubloons'
.format(self.gold))
+
pirate = Pirate()
pirate.cmdloop()
diff --git a/docs/pycon2010/pirate4.py b/docs/pycon2010/pirate4.py
index 29de7301..a4e4816d 100644
--- a/docs/pycon2010/pirate4.py
+++ b/docs/pycon2010/pirate4.py
@@ -1,12 +1,16 @@
# coding=utf-8
from cmd import Cmd
+
+
# using arguments
class Pirate(Cmd):
gold = 3
+
def do_loot(self, arg):
'Seize booty from a passing ship.'
self.gold += 1
+
def do_drink(self, arg):
'''Drown your sorrrows in rrrum.
@@ -17,12 +21,15 @@ class Pirate(Cmd):
if arg:
print('''What's "{0}"? I'll take rrrum.'''.format(arg))
self.gold -= 1
+
def precmd(self, line):
self.initial_gold = self.gold
return line
+
def postcmd(self, stop, line):
if self.gold != self.initial_gold:
print('Now we gots {0} doubloons'.format(self.gold))
+
pirate = Pirate()
pirate.cmdloop()
diff --git a/docs/pycon2010/pirate5.py b/docs/pycon2010/pirate5.py
index f6125f57..2167c7f4 100644
--- a/docs/pycon2010/pirate5.py
+++ b/docs/pycon2010/pirate5.py
@@ -1,12 +1,16 @@
# coding=utf-8
from cmd import Cmd
+
+
# quitting
class Pirate(Cmd):
gold = 3
+
def do_loot(self, arg):
'Seize booty from a passing ship.'
self.gold += 1
+
def do_drink(self, arg):
'''Drown your sorrrows in rrrum.
@@ -17,9 +21,11 @@ class Pirate(Cmd):
if arg:
print('''What's "{0}"? I'll take rrrum.'''.format(arg))
self.gold -= 1
+
def precmd(self, line):
self.initial_gold = self.gold
return line
+
def postcmd(self, stop, line):
if self.gold != self.initial_gold:
print('Now we gots {0} doubloons'
@@ -28,9 +34,11 @@ class Pirate(Cmd):
print("Off to debtorrr's prison.")
stop = True
return stop
+
def do_quit(self, arg):
print("Quiterrr!")
return True
+
pirate = Pirate()
pirate.cmdloop()
diff --git a/docs/pycon2010/pirate6.py b/docs/pycon2010/pirate6.py
index dbb18ce9..a90c2b52 100644
--- a/docs/pycon2010/pirate6.py
+++ b/docs/pycon2010/pirate6.py
@@ -1,16 +1,21 @@
# coding=utf-8
from cmd2 import Cmd
+
+
# prompts and defaults
class Pirate(Cmd):
gold = 3
prompt = 'arrr> '
+
def default(self, line):
print('What mean ye by "{0}"?'
.format(line))
+
def do_loot(self, arg):
'Seize booty from a passing ship.'
self.gold += 1
+
def do_drink(self, arg):
'''Drown your sorrrows in rrrum.
@@ -21,9 +26,11 @@ class Pirate(Cmd):
if arg:
print('''What's "{0}"? I'll take rrrum.'''.format(arg))
self.gold -= 1
+
def precmd(self, line):
self.initial_gold = self.gold
return line
+
def postcmd(self, stop, line):
if self.gold != self.initial_gold:
print('Now we gots {0} doubloons'
@@ -32,9 +39,11 @@ class Pirate(Cmd):
print("Off to debtorrr's prison.")
stop = True
return stop
+
def do_quit(self, arg):
print("Quiterrr!")
return True
+
pirate = Pirate()
pirate.cmdloop()
diff --git a/docs/pycon2010/pirate7.py b/docs/pycon2010/pirate7.py
index 32f4954d..a333070c 100644
--- a/docs/pycon2010/pirate7.py
+++ b/docs/pycon2010/pirate7.py
@@ -1,15 +1,20 @@
# coding=utf-8
from cmd2 import Cmd
+
+
# prompts and defaults
class Pirate(Cmd):
gold = 3
prompt = 'arrr> '
+
def default(self, line):
print('What mean ye by "{0}"?'.format(line))
+
def do_loot(self, arg):
'Seize booty from a passing ship.'
self.gold += 1
+
def do_drink(self, arg):
'''Drown your sorrrows in rrrum.
@@ -20,9 +25,11 @@ class Pirate(Cmd):
if arg:
print('''What's "{0}"? I'll take rrrum.'''.format(arg))
self.gold -= 1
+
def precmd(self, line):
self.initial_gold = self.gold
return line
+
def postcmd(self, stop, line):
if self.gold != self.initial_gold:
print('Now we gots {0} doubloons'
@@ -31,17 +38,21 @@ class Pirate(Cmd):
print("Off to debtorrr's prison.")
stop = True
return stop
+
def do_quit(self, arg):
print("Quiterrr!")
return True
+
default_to_shell = True
multilineCommands = ['sing']
terminators = Cmd.terminators + ['...']
songcolor = 'blue'
settable = Cmd.settable + 'songcolor Color to ``sing`` in (red/blue/green/cyan/magenta, bold, underline)'
Cmd.shortcuts.update({'~': 'sing'})
+
def do_sing(self, arg):
print(self.colorize(arg, self.songcolor))
+
pirate = Pirate()
pirate.cmdloop()
diff --git a/docs/pycon2010/pirate8.py b/docs/pycon2010/pirate8.py
index c80d41f4..55d6df5c 100644
--- a/docs/pycon2010/pirate8.py
+++ b/docs/pycon2010/pirate8.py
@@ -1,15 +1,20 @@
# coding=utf-8
from cmd2 import Cmd, options, make_option
+
+
# prompts and defaults
class Pirate(Cmd):
gold = 3
prompt = 'arrr> '
+
def default(self, line):
print('What mean ye by "{0}"?'.format(line))
+
def do_loot(self, arg):
'Seize booty from a passing ship.'
self.gold += 1
+
def do_drink(self, arg):
'''Drown your sorrrows in rrrum.
@@ -20,9 +25,11 @@ class Pirate(Cmd):
if arg:
print('''What's "{0}"? I'll take rrrum.'''.format(arg))
self.gold -= 1
+
def precmd(self, line):
self.initial_gold = self.gold
return line
+
def postcmd(self, stop, line):
if self.gold != self.initial_gold:
print('Now we gots {0} doubloons'
@@ -31,17 +38,21 @@ class Pirate(Cmd):
print("Off to debtorrr's prison.")
stop = True
return stop
+
def do_quit(self, arg):
print("Quiterrr!")
return True
+
default_to_shell = True
multilineCommands = ['sing']
terminators = Cmd.terminators + ['...']
songcolor = 'blue'
settable = Cmd.settable + 'songcolor Color to ``sing`` in (red/blue/green/cyan/magenta, bold, underline)'
Cmd.shortcuts.update({'~': 'sing'})
+
def do_sing(self, arg):
print(self.colorize(arg, self.songcolor))
+
@options([make_option('--ho', type='int', default=2,
help="How often to chant 'ho'"),
make_option('-c', '--commas',
@@ -54,5 +65,6 @@ class Pirate(Cmd):
print('{0} and a bottle of {1}'
.format(chant, arg))
+
pirate = Pirate()
pirate.cmdloop()
diff --git a/example/example.py b/example/example.py
index 081bdb6f..863084cd 100755
--- a/example/example.py
+++ b/example/example.py
@@ -15,7 +15,7 @@ class CmdLineApp(Cmd):
@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")
- ], arg_desc = '(text to say)')
+ ], arg_desc='(text to say)')
def do_speak(self, arg, opts=None):
"""Repeats what you tell me to."""
arg = ''.join(arg)
@@ -30,8 +30,9 @@ class CmdLineApp(Cmd):
# 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
+ do_say = do_speak # now "say" is a synonym for "speak"
+ do_orate = do_speak # another synonym, but this one takes multi-line input
+
c = CmdLineApp()
c.cmdloop()
diff --git a/tests/test_transcript.py b/tests/test_transcript.py
index ebd13a59..dfb37da7 100644
--- a/tests/test_transcript.py
+++ b/tests/test_transcript.py
@@ -38,7 +38,7 @@ class CmdLineApp(Cmd):
# 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_say = do_speak # now "say" is a synonym for "speak"
do_orate = do_speak # another synonym, but this one takes multi-line input
@@ -46,7 +46,7 @@ class CmdLineApp(Cmd):
def _cmdline_app():
c = CmdLineApp()
c.stdout = StdOut()
- #c.shortcuts.update({'&': 'speak', 'h': 'hello'})
+ # c.shortcuts.update({'&': 'speak', 'h': 'hello'})
c.settable.append('maxrepeats Max number of `--repeat`s allowed')
return c