summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJared Crapo <jared@kotfu.net>2017-12-11 19:15:15 -0700
committerJared Crapo <jared@kotfu.net>2017-12-11 19:15:15 -0700
commit67e669e3345fb637e4f4779691a7a8ec4b1763f6 (patch)
tree7632e68cc845e1089111e9f10b105bce8c6d5a46
parent4f57dc14a7ffc2cbd741622da7d05d42ba7f7789 (diff)
parent63b0c6b3a92cab837a71bbad78e777c522823c93 (diff)
downloadcmd2-git-67e669e3345fb637e4f4779691a7a8ec4b1763f6.tar.gz
Merge branch 'master' of https://github.com/python-cmd2/cmd2 into argparse
-rw-r--r--.appveyor.yml2
-rw-r--r--CHANGELOG.md11
-rwxr-xr-xREADME.md107
-rwxr-xr-xcmd2.py19
-rw-r--r--docs/conf.py2
-rw-r--r--docs/index.rst6
-rw-r--r--docs/install.rst4
-rw-r--r--docs/integrating.rst12
-rw-r--r--docs/pycon2010/akkad.pngbin57996 -> 0 bytes
-rw-r--r--docs/pycon2010/apple.jpgbin72215 -> 0 bytes
-rw-r--r--docs/pycon2010/hook.jpgbin52555 -> 0 bytes
-rw-r--r--docs/pycon2010/pirate.py10
-rw-r--r--docs/pycon2010/pirate2.py24
-rw-r--r--docs/pycon2010/pirate3.py30
-rw-r--r--docs/pycon2010/pirate4.py36
-rw-r--r--docs/pycon2010/pirate5.py45
-rw-r--r--docs/pycon2010/pirate6.py50
-rw-r--r--docs/pycon2010/pirate7.py59
-rw-r--r--docs/pycon2010/pirate8.py71
-rw-r--r--docs/pycon2010/pycon2010.rst382
-rw-r--r--docs/pycon2010/sargon.jpgbin17452 -> 0 bytes
-rw-r--r--docs/pycon2010/schematic.pngbin8966 -> 0 bytes
-rw-r--r--docs/pycon2010/script.txt5
-rw-r--r--docs/pycon2010/strategy.pngbin29460 -> 0 bytes
-rw-r--r--docs/pycon2010/transcript.txt12
-rw-r--r--docs/pycon2010/urwid.pngbin40788 -> 0 bytes
-rw-r--r--docs/pycon2010/web-2-0-logos.gifbin55776 -> 0 bytes
-rw-r--r--docs/settingchanges.rst23
-rwxr-xr-xexamples/arg_print.py9
-rwxr-xr-xexamples/argparse_example.py16
-rwxr-xr-xexamples/example.py4
-rw-r--r--examples/exampleSession.txt88
-rwxr-xr-xsetup.py6
-rw-r--r--tests/test_cmd2.py2
-rw-r--r--tox.ini28
35 files changed, 158 insertions, 905 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index c397472f..fad8437a 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -4,4 +4,4 @@ install:
build: off
test_script:
- - python -m tox -e py27,py35,py36-win
+ - python -m tox -e py27-win,py35-win,py36-win
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd4011ac..7c40babb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,17 @@
-## 0.7.8 (TBD, 2017)
+## 0.7.9 (TBD)
+
+* Bug Fixes
+ * Fixed a couple broken examples
+* Enhancements
+ * Improved documentation for modifying shortcuts (command aliases)
+ * Made ``pyreadline`` a dependency on Windows to ensure tab-completion works
+
+## 0.7.8 (November 8, 2017)
* Bug Fixes
* Fixed ``poutput()`` so it can print an integer zero and other **falsy** things
* Fixed a bug which was causing autodoc to fail for building docs on Readthedocs
+ * Fixed bug due to ``pyperclip`` dependency radically changing its project structure in latest version
* Enhancements
* Improved documentation for user-settable environment parameters
* Improved documentation for overriding the default supported comment styles
diff --git a/README.md b/README.md
index 30523e50..c3625a80 100755
--- a/README.md
+++ b/README.md
@@ -48,7 +48,8 @@ pip install -U cmd2
cmd2 works with Python 2.7 and Python 3.3+ on Windows, macOS, and Linux. It is pure Python code with
the only 3rd-party dependencies being on [six](https://pypi.python.org/pypi/six),
-[pyparsing](http://pyparsing.wikispaces.com), and [pyperclip](https://github.com/asweigart/pyperclip).
+[pyparsing](http://pyparsing.wikispaces.com), and [pyperclip](https://github.com/asweigart/pyperclip)
+(on Windows, [pyreadline](https://pypi.python.org/pypi/pyreadline) is an additional dependency).
For information on other installation options, see
[Installation Instructions](https://cmd2.readthedocs.io/en/latest/install.html) in the cmd2
@@ -112,12 +113,11 @@ Instructions for implementing each feature follow.
Tutorials
---------
-A couple tutorials on using cmd2 exist:
+A few tutorials on using cmd2 exist:
-* A detailed PyCon 2010 talk by [Catherine Devlin](https://github.com/catherinedevlin), the original author
- * http://pyvideo.org/pycon-us-2010/pycon-2010--easy-command-line-applications-with-c.html
-* A nice brief step-by-step tutorial
- * https://kushaldas.in/posts/developing-command-line-interpreters-using-python-cmd2.html
+* Florida PyCon 2017 talk: [slides](https://docs.google.com/presentation/d/1LRmpfBt3V-pYQfgQHdczf16F3hcXmhK83tl77R6IJtE)
+* PyCon 2010 talk by Catherine Devlin, the original author: [video](http://pyvideo.org/pycon-us-2010/pycon-2010--easy-command-line-applications-with-c.html)
+* A nice brief step-by-step tutorial: [blog](https://kushaldas.in/posts/developing-command-line-interpreters-using-python-cmd2.html)
Example Application
@@ -173,91 +173,38 @@ if __name__ == '__main__':
The following is a sample session running example.py.
Thanks to Cmd2's built-in transcript testing capability, it also serves as a test
-suite for example.py when saved as *exampleSession.txt*.
+suite for example.py when saved as *transcript_regex.txt*.
Running
```bash
-python example.py -t exampleSession.txt
+python example.py -t transcript_regex.txt
```
will run all the commands in the transcript against `example.py`, verifying that the output produced
matches the transcript.
-example/exampleSession.txt:
+example/transcript_regex.txt:
```text
-(Cmd) help
-
-Documented commands (type help <topic>):
-========================================
-_relative_load edit history orate pyscript run say shell show
-cmdenvironment help load py quit save set shortcuts speak
-
-(Cmd) help say
-Repeats what you tell me to.
-Usage: speak [options] arg
-
-Options:
- -h, --help show this help message and exit
- -p, --piglatin atinLay
- -s, --shout N00B EMULATION MODE
- -r REPEAT, --repeat=REPEAT
- output [n] times
-
-(Cmd) say goodnight, Gracie
-goodnight, Gracie
-(Cmd) say -ps --repeat=5 goodnight, Gracie
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-(Cmd) set maxrepeats 5
-maxrepeats - was: 3
-now: 5
-(Cmd) say -ps --repeat=5 goodnight, Gracie
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-(Cmd) hi
--------------------------[1]
-help
--------------------------[2]
-help say
--------------------------[3]
-say goodnight, Gracie
--------------------------[4]
-say -ps --repeat=5 goodnight, Gracie
--------------------------[5]
-set maxrepeats 5
--------------------------[6]
-say -ps --repeat=5 goodnight, Gracie
-(Cmd) run 4
-say -ps --repeat=5 goodnight, Gracie
-
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-(Cmd) orate Four score and
-> seven releases ago
-> our BDFL
-> blah blah blah
-Four score and
-seven releases ago
-our BDFL
-blah blah blah
-(Cmd) & look, a shortcut!
-look, a shortcut!
-(Cmd) show color
+# Run this transcript with "python example.py -t transcript_regex.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
+(Cmd) set
+abbrev: True
+autorun_on_edit: False
colors: /(True|False)/
-(Cmd) set prompt "---> "
-prompt - was: (Cmd)
-now: --->
----> say goodbye
-goodbye
+continuation_prompt: >/ /
+debug: False
+echo: False
+editor: /.*?/
+feedback_to_output: False
+locals_in_py: True
+maxrepeats: 3
+prompt: (Cmd)/ /
+quiet: False
+timing: False
```
-Note how a regular expression `/(True|False)/` is used near the end for output of the **show color** command since
+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, `/`.
diff --git a/cmd2.py b/cmd2.py
index 64388de9..9b0bc66a 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -46,6 +46,13 @@ from optparse import make_option
import pyparsing
import pyperclip
+# Newer versions of pyperclip are released as a single file, but older versions had a more complicated structure
+try:
+ from pyperclip.exceptions import PyperclipException
+except ImportError:
+ # noinspection PyUnresolvedReferences
+ from pyperclip import PyperclipException
+
# On some systems, pyperclip will import gtk for its clipboard functionality.
# The following code is a workaround for gtk interfering with printing from a background
# thread while the CLI thread is blocking in raw_input() in Python 2 on Linux.
@@ -98,7 +105,7 @@ if six.PY3:
else:
BROKEN_PIPE_ERROR = IOError
-__version__ = '0.7.8a'
+__version__ = '0.7.9a'
# Pyparsing enablePackrat() can greatly speed up parsing, but problems have been seen in Python 3 in the past
pyparsing.ParserElement.enablePackrat()
@@ -339,13 +346,17 @@ def options(option_list, arg_desc="arg"):
# Can we access the clipboard? Should always be true on Windows and Mac, but only sometimes on Linux
# noinspection PyUnresolvedReferences
try:
- if sys.platform.startswith('linux'):
+ # Get the version of the pyperclip module as a float
+ pyperclip_ver = float('.'.join(pyperclip.__version__.split('.')[:2]))
+
+ # The extraneous output bug in pyperclip on Linux using xclip was fixed in more recent versions of pyperclip
+ if sys.platform.startswith('linux') and pyperclip_ver < 1.6:
# Avoid extraneous output to stderr from xclip when clipboard is empty at cost of overwriting clipboard contents
pyperclip.copy('')
else:
# Try getting the contents of the clipboard
_ = pyperclip.paste()
-except pyperclip.exceptions.PyperclipException:
+except PyperclipException:
can_clip = False
else:
can_clip = True
@@ -597,7 +608,7 @@ class Cmd(cmd.Cmd):
Also handles BrokenPipeError exceptions for when a commands's output has been piped to another process and
that process terminates before the cmd2 command is finished executing.
- :param msg: str - message to print to current stdout - anyting convertible to a str with '{}'.format() is OK
+ :param msg: str - message to print to current stdout - anything convertible to a str with '{}'.format() is OK
:param end: str - string appended after the end of the message if not already present, default a newline
"""
if msg is not None and msg != '':
diff --git a/docs/conf.py b/docs/conf.py
index f79d5b3c..1212a6e2 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -62,7 +62,7 @@ author = 'Catherine Devlin and Todd Leonhardt'
# The short X.Y version.
version = '0.7'
# The full version, including alpha/beta/rc tags.
-release = '0.7.7'
+release = '0.7.8'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/index.rst b/docs/index.rst
index ae7ea300..8e8817b2 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -46,10 +46,8 @@ Resources
* cmd_
* `cmd2 project page`_
* `project bug tracker`_
-* `PyCon 2010 presentation <https://github.com/python-cmd2/cmd2/blob/master/docs/pycon2010/pycon2010.rst>`_,
- *Easy Command-Line Applications with cmd and cmd2*:
- :doc:`slides <pycon2010/pycon2010>`,
- `video <http://pyvideo.org/pycon-us-2010/pycon-2010--easy-command-line-applications-with-c.html>`_
+* Florida PyCon 2017: `slides <https://docs.google.com/presentation/d/1LRmpfBt3V-pYQfgQHdczf16F3hcXmhK83tl77R6IJtE>`_
+* PyOhio 2011: `video <https://archive.org/details/pyvideo_541___pyohio-2011-interactive-command-line-interpreters-with-cmd-and-cmd2>`_
These docs will refer to ``App`` as your ``cmd2.Cmd``
subclass, and ``app`` as an instance of ``App``. Of
diff --git a/docs/install.rst b/docs/install.rst
index 1edba409..9e330c3c 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -107,6 +107,10 @@ the following Python packages are installed:
* pyparsing
* pyperclip
+On Windows, there is an additional dependency:
+
+ * pyreadline
+
Upgrading cmd2
--------------
diff --git a/docs/integrating.rst b/docs/integrating.rst
index 32ab37e0..bcb9301c 100644
--- a/docs/integrating.rst
+++ b/docs/integrating.rst
@@ -46,10 +46,14 @@ code like the following::
# Do this within whatever event loop mechanism you wish to run a single command
cmd_line_text = "help history"
- app.onecmd_plus_hooks(cmd_line_text)
+ app.runcmds_plus_hooks([cmd_line_text])
app.postloop()
+The **runcmds_plus_hooks()** method is a convenience method to run multiple commands via **onecmd_plus_hooks()**. It
+properly deals with ``load`` commands which under the hood put commands in a FIFO queue as it reads them in from a
+script file.
+
The **onecmd_plus_hooks()** method will do the following to execute a single ``cmd2`` command in a normal fashion:
#. Parse the command line text
@@ -70,4 +74,10 @@ several disadvantages, including:
* Does not support transcript testing
* Does not allow commands at invocation via command-line arguments
+Here is a little more info on ``runcmds_plus_hooks``:
+
+.. automethod:: cmd2.Cmd.runcmds_plus_hooks
+
+
+
diff --git a/docs/pycon2010/akkad.png b/docs/pycon2010/akkad.png
deleted file mode 100644
index 57799e97..00000000
--- a/docs/pycon2010/akkad.png
+++ /dev/null
Binary files differ
diff --git a/docs/pycon2010/apple.jpg b/docs/pycon2010/apple.jpg
deleted file mode 100644
index 2148af3b..00000000
--- a/docs/pycon2010/apple.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/pycon2010/hook.jpg b/docs/pycon2010/hook.jpg
deleted file mode 100644
index 819370d0..00000000
--- a/docs/pycon2010/hook.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/pycon2010/pirate.py b/docs/pycon2010/pirate.py
deleted file mode 100644
index bd8b5170..00000000
--- a/docs/pycon2010/pirate.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# 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
deleted file mode 100644
index 343f94ff..00000000
--- a/docs/pycon2010/pirate2.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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
deleted file mode 100644
index 46f26501..00000000
--- a/docs/pycon2010/pirate3.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# coding=utf-8
-from cmd import Cmd
-
-
-# using hook
-
-class Pirate(Cmd):
- gold = 3
- initial_gold = gold
-
- 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
deleted file mode 100644
index ae1e1f4b..00000000
--- a/docs/pycon2010/pirate4.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# coding=utf-8
-from cmd import Cmd
-
-
-# using arguments
-
-class Pirate(Cmd):
- gold = 3
- initial_gold = gold
-
- def do_loot(self, arg):
- 'Seize booty from a passing ship.'
- self.gold += 1
-
- def do_drink(self, arg):
- '''Drown your sorrrows in rrrum.
-
- drink [n] - drink [n] barrel[s] o' rum.'''
- try:
- self.gold -= int(arg)
- except:
- 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
deleted file mode 100644
index 68da88a5..00000000
--- a/docs/pycon2010/pirate5.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# coding=utf-8
-from cmd import Cmd
-
-
-# quitting
-
-class Pirate(Cmd):
- gold = 3
- initial_gold = gold
-
- def do_loot(self, arg):
- 'Seize booty from a passing ship.'
- self.gold += 1
-
- def do_drink(self, arg):
- '''Drown your sorrrows in rrrum.
-
- drink [n] - drink [n] barrel[s] o' rum.'''
- try:
- self.gold -= int(arg)
- except:
- 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))
- if self.gold < 0:
- 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
deleted file mode 100644
index bd5f5fe2..00000000
--- a/docs/pycon2010/pirate6.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# coding=utf-8
-from cmd2 import Cmd
-
-
-# prompts and defaults
-
-class Pirate(Cmd):
- gold = 3
- initial_gold = gold
- 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.
-
- drink [n] - drink [n] barrel[s] o' rum.'''
- try:
- self.gold -= int(arg)
- except:
- 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))
- if self.gold < 0:
- 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
deleted file mode 100644
index 799f73ed..00000000
--- a/docs/pycon2010/pirate7.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# coding=utf-8
-from cmd2 import Cmd
-
-
-# prompts and defaults
-
-class Pirate(Cmd):
- gold = 3
- initial_gold = gold
- 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.
-
- drink [n] - drink [n] barrel[s] o' rum.'''
- try:
- self.gold -= int(arg)
- except:
- 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))
- if self.gold < 0:
- 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
deleted file mode 100644
index 58b56208..00000000
--- a/docs/pycon2010/pirate8.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# coding=utf-8
-from cmd2 import Cmd, options, make_option
-
-
-# prompts and defaults
-
-class Pirate(Cmd):
- gold = 3
- initial_gold = gold
- 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.
-
- drink [n] - drink [n] barrel[s] o' rum.'''
- try:
- self.gold -= int(arg)
- except:
- 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))
- if self.gold < 0:
- 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',
- action="store_true",
- help="Intersperse commas")])
- def do_yo(self, arg, opts):
- chant = ['yo'] + ['ho'] * opts.ho
- separator = ', ' if opts.commas else ' '
- chant = separator.join(chant)
- print('{0} and a bottle of {1}'
- .format(chant, arg))
-
-
-pirate = Pirate()
-pirate.cmdloop()
diff --git a/docs/pycon2010/pycon2010.rst b/docs/pycon2010/pycon2010.rst
deleted file mode 100644
index 6c3af676..00000000
--- a/docs/pycon2010/pycon2010.rst
+++ /dev/null
@@ -1,382 +0,0 @@
-================================================
-Easy command-line interpreters with cmd and cmd2
-================================================
-
-:author: Catherine Devlin
-:date: 2010-02-20
-:slides: http://pypi.python.org/pypi/cmd2
-
-Web 2.0
-=======
-
-.. image:: web-2-0-logos.gif
- :height: 350px
-
-But first...
-============
-
-.. image:: sargon.jpg
- :height: 250px
-
-.. image:: akkad.png
- :height: 250px
-
-Sargon the Great
- Founder of Akkadian Empire
-
-.. twenty-third century BC
-
-In between
-==========
-
-.. image:: apple.jpg
- :height: 250px
-
-Command-Line Interface
- Unlike the Akkadian Empire,
- the CLI will never die.
-
-Defining CLI
-============
-
-Also known as
-
-- "Line-oriented command interpreter"
-- "Command-line interface"
-- "Shell"
-
-1. Accepts free text input at prompt
-2. Outputs lines of text
-3. (repeat)
-
-Examples
-========
-
-.. class:: big
-
- * Bash, Korn, zsh
- * Python shell
- * screen
- * Zork
- * SQL clients: psql, SQL*\Plus, mysql...
- * ed
-
-.. ``ed`` proves that CLI is sometimes the wrong answer.
-
-!= Command Line Utilities
-=========================
-
-.. class:: big
-
- (``ls``, ``grep``, ``ping``, etc.)
-
- 1. Accept arguments at invocation
- 2. execute
- 3. terminate
-
- Use ``sys.argv``, ``optparse``
-
-!="Text User Interface"
-=======================
-
-* Use entire (session) screen
-* I/O is *not* line-by-line
-* See ``curses``, ``urwid``
-
-.. image:: urwid.png
- :height: 250px
-
-
-Decide your priorities
-======================
-
-.. image:: strategy.png
- :height: 350px
-
-A ``cmd`` app: pirate.py
-========================
-
-::
-
- from cmd import Cmd
-
- class Pirate(Cmd):
- pass
-
- pirate = Pirate()
- pirate.cmdloop()
-
-.. Nothing here... but history and help
-
-.. ctrl-r for bash-style history
-
-Fundamental prrrinciple
-=======================
-
-.. class:: huge
-
- ``(Cmd) foo a b c``
-
- becomes
-
- ``self.do_foo('a b c')``
-
-``do_``-methods: pirate2.py
-===========================
-
-::
-
- class Pirate(Cmd):
- gold = 3
- def do_loot(self, arg):
- 'Seize booty frrrom 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))
-
-.. do_methods; more help
-
-Hooks
-=====
-
-.. image:: hook.jpg
- :height: 250px
-
-::
-
- self.preloop()
- self.postloop()
- self.precmd(line)
- self.postcmd(stop, line)
-
-Hooks: pirate3.py
-=================
-
-::
-
- 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))
-
-Arguments: pirate4.py
-=====================
-
-::
-
- def do_drink(self, arg):
- '''Drown your sorrrows in rrrum.
-
- drink [n] - drink [n] barrel[s] o' rum.'''
- try:
- self.gold -= int(arg)
- except:
- if arg:
- print('''What's "{0}"? I'll take rrrum.'''
- .format(arg))
- self.gold -= 1
-
-quitting: pirate5.py
-====================
-
-::
-
- def postcmd(self, stop, line):
- if self.gold != self.initial_gold:
- print('Now we gots {0} doubloons'
- .format(self.gold))
- if self.gold < 0:
- print("Off to debtorrr's prison.")
- stop = True
- return stop
- def do_quit(self, arg):
- print("Quiterrr!")
- return True
-
-prompts, defaults: pirate6.py
-=============================
-
-::
-
- prompt = 'arrr> '
- def default(self, line):
- print('What mean ye by "{0}"?'
- .format(line))
-
-Other CLI packages
-==================
-
-.. class:: big
-
- * CmdLoop
- * cly
- * CMdO
- * pycopia
- * cmdlin
- * cmd2
-
-Demo
-====
-
-.. class:: huge
-
- Convert ``cmd`` app to ``cmd2``
-
-cmd2
-====
-
-.. image:: schematic.png
- :height: 350px
-
-As you wish, Guido
-==================
-
-.. class:: huge
-
- Python 3 compatible
-
-(um, mostly)
-
-Absolutely free
-===============
-
-Script files
-
-Commands at invocation
-
-Output redirection
-
-Python
-
-Transcript testing
-
-But wait, there's more
-======================
-
- * Abbreviated commands
- * Shell commands
- * Quitting
- * Timing
- * Echo
- * Debug
-
-Minor changes: pirate7.py
-=========================
-
-::
-
- 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))
-
-Now how much would you pay?
-===========================
-
-options / flags
-
-Quiet (suppress feedback)
-
-BASH-style ``select``
-
-Parsing: terminators, suffixes
-
-Options: pirate8.py
-===================
-
-::
-
- @options([make_option('--ho', type='int', default=2,
- help="How often to chant 'ho'"),
- make_option('-c', '--commas',
- action="store_true",
- help="Intersperse commas")])
- def do_yo(self, arg, opts):
- chant = ['yo'] + ['ho'] * opts.ho
- separator = ', ' if opts.commas else ' '
- chant = separator.join(chant)
- print('{0} and a bottle of {1}'
- .format(chant, arg))
-
-Serious example: sqlpython
-==========================
-
-.. class:: big
-
- ``cmd``-based app by Luca Canali @ CERN
-
- Replacement for Oracle SQL\*Plus
-
- Now ``cmd2``-based; postgreSQL; MySQL
-
-File reporter
-=============
-
-.. class:: huge
-
- Gather info: Python
-
- Store: postgresql
-
- Report: html
-
-fileutil.py
-===========
-
-::
-
- import glob
- import os.path
-
- for fullfilename in glob.glob('/home/cat/proj/cmd2/*.py'):
- (dirpath, fname) = os.path.split(fullfilename)
- stats = os.stat(fullfilename)
- binds['path'] = dirpath
- binds['name'] = fname
- binds['bytes'] = stats.st_size
- cmd("""INSERT INTO cat.files (path, name, bytes)
- VALUES (%(path)s, %(name)s, %(bytes)s)""")
- quit()
-
-sqlpython features
-==================
-
-.. class:: big
-
- * from ``cmd2``: scripts, redirection,
- py, etc.
- * multiple connections
- * UNIX: ls, cat, grep
- * Special output
-
-
-Thank you
-=========
-
-.. class:: big
-
- http://pypi.python.org/pypi/cmd2
-
- http://catherinedevlin.blogspot.com
-
- http://catherinedevlin.pythoneers.com
-
-
diff --git a/docs/pycon2010/sargon.jpg b/docs/pycon2010/sargon.jpg
deleted file mode 100644
index 5960f1e0..00000000
--- a/docs/pycon2010/sargon.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/pycon2010/schematic.png b/docs/pycon2010/schematic.png
deleted file mode 100644
index d4b39092..00000000
--- a/docs/pycon2010/schematic.png
+++ /dev/null
Binary files differ
diff --git a/docs/pycon2010/script.txt b/docs/pycon2010/script.txt
deleted file mode 100644
index c638b1a7..00000000
--- a/docs/pycon2010/script.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-loot
-loot
-drink /* arrr */ 2 # matey
-drink chardonnay
-
diff --git a/docs/pycon2010/strategy.png b/docs/pycon2010/strategy.png
deleted file mode 100644
index 7d6afdcd..00000000
--- a/docs/pycon2010/strategy.png
+++ /dev/null
Binary files differ
diff --git a/docs/pycon2010/transcript.txt b/docs/pycon2010/transcript.txt
deleted file mode 100644
index d00e44fc..00000000
--- a/docs/pycon2010/transcript.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-arrr> loot
-Now we gots 4 doubloons
-arrr> loot
-Now we gots 5 doubloons
-arrr> drink 3
-Now we gots 2 doubloons
-arrr> drink chardonnay
-What's "chardonnay"? I'll take rrrum.
-Now we gots 1 doubloons
-arrr> quit
-Quiterrr!
-
diff --git a/docs/pycon2010/urwid.png b/docs/pycon2010/urwid.png
deleted file mode 100644
index c2b5a9bf..00000000
--- a/docs/pycon2010/urwid.png
+++ /dev/null
Binary files differ
diff --git a/docs/pycon2010/web-2-0-logos.gif b/docs/pycon2010/web-2-0-logos.gif
deleted file mode 100644
index 9d48e37d..00000000
--- a/docs/pycon2010/web-2-0-logos.gif
+++ /dev/null
Binary files differ
diff --git a/docs/settingchanges.rst b/docs/settingchanges.rst
index 326db3f5..0a24651b 100644
--- a/docs/settingchanges.rst
+++ b/docs/settingchanges.rst
@@ -19,11 +19,11 @@ Whether or not you set ``case_insensitive``, *please do not* define
command method names with any uppercase letters. ``cmd2`` expects all command methods
to be lowercase.
-Shortcuts
-=========
+Shortcuts (command aliases)
+===========================
-Special-character shortcuts for common commands can make life more convenient for your
-users. Shortcuts are used without a space separating them from their arguments,
+Command aliases for long command names such as special-character shortcuts for common commands can make life more
+convenient for your users. Shortcuts are used without a space separating them from their arguments,
like ``!ls``. By default, the following shortcuts are defined:
``?``
@@ -42,7 +42,20 @@ To define more shortcuts, update the dict ``App.shortcuts`` with the
{'shortcut': 'command_name'} (omit ``do_``)::
class App(Cmd2):
- Cmd2.shortcuts.update({'*': 'sneeze', '~': 'squirm'})
+ def __init__(self):
+ # Make sure you update the shortcuts attribute before calling the super class __init__
+ self.shortcuts.update({'*': 'sneeze', '~': 'squirm'})
+
+ # Make sure to call this super class __init__ after updating shortcuts
+ cmd2.Cmd.__init__(self)
+
+.. warning::
+
+ Command aliases needed to be created by updating the ``shortcuts`` dictionary attribute prior to calling the
+ ``cmd2.Cmd`` super class ``__init__()`` method. Moreover, that super class init method needs to be called after
+ updating the ``shortcuts`` attribute This warning applies in general to many other attributes which are not
+ settable at runtime such as ``commentGrammars``, ``multilineCommands``, etc.
+
Default to shell
================
diff --git a/examples/arg_print.py b/examples/arg_print.py
index 20fa7c02..849cf386 100755
--- a/examples/arg_print.py
+++ b/examples/arg_print.py
@@ -6,6 +6,8 @@
This is intended to serve as a live demonstration so that developers can experiment with and understand how command
and argument parsing is intended to work.
+
+It also serves as an example of how to create command aliases (shortcuts).
"""
import pyparsing
import cmd2
@@ -19,8 +21,13 @@ class ArgumentAndOptionPrinter(cmd2.Cmd):
# Uncomment this line to disable Python-style comments but still allow C-style comments
# self.commentGrammars = pyparsing.Or([pyparsing.cStyleComment])
- # Make sure to call this super class __init__ after setting commentGrammars and not before
+ # Create command aliases which are shorter
+ self.shortcuts.update({'ap': 'aprint', 'op': 'oprint'})
+
+ # Make sure to call this super class __init__ *after* setting commentGrammars and/or updating shortcuts
cmd2.Cmd.__init__(self)
+ # NOTE: It is critical that the super class __init__ method be called AFTER updating certain parameters which
+ # are not settable at runtime. This includes the commentGrammars, shortcuts, multilineCommands, etc.
def do_aprint(self, arg):
"""Print the argument string this basic command is called with."""
diff --git a/examples/argparse_example.py b/examples/argparse_example.py
index 8c25b0ef..805bab77 100755
--- a/examples/argparse_example.py
+++ b/examples/argparse_example.py
@@ -1,7 +1,8 @@
#!/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.
-It doubles as an example of how you can still do transcript testing even if allow_cli_args is false.
+It parses command line arguments looking for known arguments, but then still passes any unknown arguments onto cmd2
+to treat them as arguments at invocation.
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.
@@ -10,6 +11,7 @@ Running `python argparse_example.py -t exampleSession.txt` will run all the comm
argparse_example.py, verifying that the output produced matches the transcript.
"""
import argparse
+import sys
from cmd2 import Cmd, make_option, options, with_argument_parser
@@ -28,7 +30,7 @@ class CmdLineApp(Cmd):
Cmd.__init__(self, 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
+ # self.allow_cli_args = False
# Example of args set from the command-line (but they aren't being used here)
self._ip = ip_addr
@@ -92,8 +94,7 @@ if __name__ == '__main__':
parser.add_argument('-i', '--ip', type=str, help='IPv4 address')
# Add an argument which enables transcript testing
- parser.add_argument('-t', '--test', type=str, help='Test against transcript in FILE (wildcards OK)')
- args = parser.parse_args()
+ args, unknown_args = parser.parse_known_args()
port = None
if args.port:
@@ -103,12 +104,11 @@ if __name__ == '__main__':
if args.ip:
ip_addr = args.ip
- transcripts = None
- if args.test:
- transcripts = [args.test]
+ # 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(transcript_files=transcripts)
+ c = CmdLineApp()
# And run your cmd2 application
c.cmdloop()
diff --git a/examples/example.py b/examples/example.py
index e4158f13..889e62c0 100755
--- a/examples/example.py
+++ b/examples/example.py
@@ -4,9 +4,9 @@
A sample application for cmd2.
Thanks to cmd2's built-in transcript testing capability, it also serves as a
-test suite for example.py when used with the exampleSession.txt transcript.
+test suite for example.py when used with the transcript_regex.txt transcript.
-Running `python example.py -t exampleSession.txt` will run all the commands in
+Running `python example.py -t transcript_regex.txt` will run all the commands in
the transcript against example.py, verifying that the output produced matches
the transcript.
"""
diff --git a/examples/exampleSession.txt b/examples/exampleSession.txt
index de7eea96..ef6df857 100644
--- a/examples/exampleSession.txt
+++ b/examples/exampleSession.txt
@@ -1,72 +1,18 @@
-# Run this transcript with "python example.py -t exampleSession.txt"
-(Cmd) help
-
-Documented commands (type help <topic>):
-========================================
-_relative_load edit history orate pyscript run say shell show
-cmdenvironment help load py quit save set shortcuts speak
-
-(Cmd) help say
-Repeats what you tell me to.
-Usage: speak [options] arg
-
-Options:
- -h, --help show this help message and exit
- -p, --piglatin atinLay
- -s, --shout N00B EMULATION MODE
- -r REPEAT, --repeat=REPEAT
- output [n] times
-
-(Cmd) say goodnight, Gracie
-goodnight, Gracie
-(Cmd) say -ps --repeat=5 goodnight, Gracie
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-(Cmd) set maxrepeats 5
-maxrepeats - was: 3
-now: 5
-(Cmd) say -ps --repeat=5 goodnight, Gracie
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-(Cmd) hi
--------------------------[1]
-help
--------------------------[2]
-help say
--------------------------[3]
-say goodnight, Gracie
--------------------------[4]
-say -ps --repeat=5 goodnight, Gracie
--------------------------[5]
-set maxrepeats 5
--------------------------[6]
-say -ps --repeat=5 goodnight, Gracie
-(Cmd) run 4
-say -ps --repeat=5 goodnight, Gracie
-
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-OODNIGHT, GRACIEGAY
-(Cmd) orate Four score and
-> seven releases ago
-> our BDFL
-> blah blah blah
-Four score and
-seven releases ago
-our BDFL
-blah blah blah
-(Cmd) & look, a shortcut!
-look, a shortcut!
-(Cmd) show color
+# Run this transcript with "python argparse_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
+(Cmd) set
+abbrev: False
+autorun_on_edit: False
colors: /(True|False)/
-(Cmd) set prompt "---> "
-prompt - was: (Cmd)
-now: --->
----> say goodbye
-goodbye
+continuation_prompt: >/ /
+debug: False
+echo: False
+editor: /.*?/
+feedback_to_output: False
+locals_in_py: True
+maxrepeats: 3
+prompt: (Cmd)/ /
+quiet: False
+timing: False
diff --git a/setup.py b/setup.py
index b4b76098..efe715be 100755
--- a/setup.py
+++ b/setup.py
@@ -3,9 +3,10 @@
"""
Setuptools setup file, used to install or test 'cmd2'
"""
+import sys
from setuptools import setup
-VERSION = '0.7.8a'
+VERSION = '0.7.9a'
DESCRIPTION = "cmd2 - a tool for building interactive command line applications in Python"
LONG_DESCRIPTION = """cmd2 is a tool for building interactive command line applications in Python. Its goal is to make
it quick and easy for developers to build feature-rich and user-friendly interactive command line applications. It
@@ -61,6 +62,9 @@ Topic :: Software Development :: Libraries :: Python Modules
""".splitlines())))
INSTALL_REQUIRES = ['pyparsing >= 2.0.1', 'pyperclip', 'six']
+if sys.platform.startswith('win'):
+ INSTALL_REQUIRES += ['pyreadline']
+
# unittest.mock was added in Python 3.3. mock is a backport of unittest.mock to all versions of Python
TESTS_REQUIRE = ['mock', 'pytest']
DOCS_REQUIRE = ['sphinx', 'sphinx_rtd_theme', 'pyparsing', 'pyperclip', 'six']
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index c395acc3..c877e60f 100644
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -24,7 +24,7 @@ from conftest import run_cmd, normalize, BASE_HELP, HELP_HISTORY, SHORTCUTS_TXT,
def test_ver():
- assert cmd2.__version__ == '0.7.8a'
+ assert cmd2.__version__ == '0.7.9a'
def test_empty_statement(base_app):
diff --git a/tox.ini b/tox.ini
index b3ecd19f..cefc7f7b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -24,6 +24,22 @@ commands =
py.test {posargs: -n 2} --cov=cmd2 --cov-report=term-missing
codecov
+[testenv:py27-win]
+deps =
+ codecov
+ mock
+ pyparsing
+ pyperclip
+ pyreadline
+ pytest
+ pytest-cov
+ pytest-xdist
+ six
+ subprocess32
+commands =
+ py.test {posargs: -n 2} --cov=cmd2 --cov-report=term-missing
+ codecov
+
[testenv:py33]
deps =
mock
@@ -54,6 +70,17 @@ deps =
six
commands = py.test -v -n2
+[testenv:py35-win]
+deps =
+ mock
+ pyparsing
+ pyperclip
+ pyreadline
+ pytest
+ pytest-xdist
+ six
+commands = py.test -v -n2
+
[testenv:py36]
deps =
codecov
@@ -73,6 +100,7 @@ deps =
mock
pyparsing
pyperclip
+ pyreadline
pytest
pytest-xdist
six