summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.rst8
-rwxr-xr-xREADME.rst3
-rwxr-xr-xcmd2.py22
-rw-r--r--docs/freefeatures.rst26
-rwxr-xr-xexamples/argparse_example.py88
5 files changed, 135 insertions, 12 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index fdfad54a..827d492e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,10 +1,14 @@
News
====
-0.7.1a
+0.7.1
------
-Placeholder
+*Release date: TBD
+
+* Fixed a bug where ``-`` wasn't being treated as a legal character
+* Added CONTRIBUTING.md and CODE_OF_CONDUCT.md files
+* Fixed a bug where the allow_cli_args attribute wasn't properly disabling parsing of args at invocation when False
0.7.0
-----
diff --git a/README.rst b/README.rst
index 9cba1ec5..6db4843b 100755
--- a/README.rst
+++ b/README.rst
@@ -69,8 +69,7 @@ Instructions for implementing each feature follow.
- Searchable command history
All commands will automatically be tracked in the session's history, unless the command is listed in Cmd's excludeFromHistory attribute.
- The history is accessed through the ``history``, ``list``, and ``run`` commands
- (and their abbreviations: `hi`, `li`, `l`, `r`).
+ The history is accessed through the ``history``, ``list``, and ``run`` commands.
If you wish to exclude some of your custom commands from the history, append their names
to the list at Cmd.ExcludeFromHistory.
diff --git a/cmd2.py b/cmd2.py
index ae39d568..74d44a8b 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -566,13 +566,14 @@ class Cmd(cmd.Cmd):
timing Report execution times
''')
- def __init__(self, completekey='tab', stdin=None, stdout=None, use_ipython=False):
+ 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.
:param completekey: str - (optional) readline name of a completion key, default to Tab
:param stdin: (optional) alternate input file object, if not specified, sys.stdin is used
:param stdout: (optional) alternate output file object, if not specified, sys.stdout is used
:param use_ipython: (optional) should the "ipy" command be included for an embedded IPython shell
+ :param transcript_files: str - (optional) allows running transcript tests when allow_cli_args is False
"""
# If use_ipython is False, make sure the do_ipy() method doesn't exit
if not use_ipython:
@@ -592,6 +593,7 @@ class Cmd(cmd.Cmd):
if fname.startswith('do_')]
self._init_parser()
self._temp_filename = None
+ self._transcript_files = transcript_files
def poutput(self, msg):
"""Convenient shortcut for self.stdout.write(); adds newline if necessary."""
@@ -1491,13 +1493,17 @@ Script should contain one command per line, just like command would be typed in
return self._STOP_AND_EXIT
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)')
- (callopts, callargs) = parser.parse_args()
- if callopts.test:
- self.runTranscriptTests(callargs)
+ if self.allow_cli_args:
+ parser = optparse.OptionParser()
+ parser.add_option('-t', '--test', dest='test',
+ action="store_true",
+ help='Test against transcript(s) in FILE (wildcards OK)')
+ (callopts, callargs) = parser.parse_args()
+ if callopts.test:
+ self._transcript_files = callargs
+
+ if self._transcript_files is not None:
+ self.runTranscriptTests(self._transcript_files)
else:
# Always run the preloop first
self.preloop()
diff --git a/docs/freefeatures.rst b/docs/freefeatures.rst
index 2c41c213..0f6a0e84 100644
--- a/docs/freefeatures.rst
+++ b/docs/freefeatures.rst
@@ -63,6 +63,18 @@ quotation marks if it is more than a one-word command.
Gracie
cat@eee:~/proj/cmd2/example$
+.. note::
+
+ if you wish to disable cmd2's consumption of command-line arguments, you can do so by setting the ``allow_cli_args``
+ attribute of your ``cmd2.Cmd`` class instance to ``False``. This would be useful, for example, if you wish to use
+ someting like Argparse_ to parse the overall command line arguments for your application::
+
+ from cmd2 import Cmd
+ class App(Cmd):
+ def __init__(self):
+ self.allow_cli_args = False
+
+.. _Argparse: https://docs.python.org/3/library/argparse.html
Output redirection
==================
@@ -242,3 +254,17 @@ Regular expressions can be embedded in the transcript inside paired ``/``
slashes. These regular expressions should not include any whitespace
expressions.
+.. note::
+
+ If you have set ``allow_cli_args`` to False in order to disable parsing of command line arguments at invocaiton,
+ then the use of ``-t`` or ``--test`` to run transcript testing is automatically disabled. In this case, you can
+ alternatively provide a value for the optional ``transcript_files`` when constructing the instance of your
+ ``cmd2.Cmd`` derived class in order to cause a transcript test to run::
+
+ from cmd2 import Cmd
+ class App(Cmd):
+ # customized attributes and methods here
+
+ if __name__ == '__main__':
+ app = App(transcript_files='exampleSession.txt')
+ app.cmdloop()
diff --git a/examples/argparse_example.py b/examples/argparse_example.py
new file mode 100755
index 00000000..8f833578
--- /dev/null
+++ b/examples/argparse_example.py
@@ -0,0 +1,88 @@
+#!/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.
+
+Thanks to cmd2's built-in transtript testing capability, it also serves as a test suite for argparse_example.py when
+used with the exampleSession.txt transcript.
+
+Running `python argparse_example.py -t exampleSession.txt` will run all the commands in the transcript against
+argparse_example.py, verifying that the output produced matches the transcript.
+"""
+import argparse
+
+from cmd2 import Cmd, make_option, options
+
+
+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, ip_addr=None, port=None, transcript_files=None):
+ # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell
+ 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
+
+ # Example of args set from the command-line (but they aren't being used here)
+ self._ip = ip_addr
+ self._port = port
+
+ @options([make_option('-p', '--piglatin', action="store_true", help="atinLay"),
+ make_option('-s', '--shout', action="store_true", help="N00B EMULATION MODE"),
+ make_option('-r', '--repeat', type="int", help="output [n] times")
+ ])
+ def do_speak(self, arg, opts=None):
+ """Repeats what you tell me to."""
+ arg = ''.join(arg)
+ if opts.piglatin:
+ arg = '%s%say' % (arg[1:], arg[0])
+ if opts.shout:
+ arg = arg.upper()
+ repetitions = opts.repeat or 1
+ for i in range(min(repetitions, self.maxrepeats)):
+ self.stdout.write(arg)
+ self.stdout.write('\n')
+ # self.stdout.write is better than "print", because Cmd can be
+ # initialized with a non-standard output destination
+
+ do_say = do_speak # now "say" is a synonym for "speak"
+ do_orate = do_speak # another synonym, but this one takes multi-line input
+
+
+if __name__ == '__main__':
+ # You can do your custom Argparse parsing here to meet your application's needs
+ parser = argparse.ArgumentParser(description='Process the arguments however you like.')
+
+ # Add a few arguments which aren't really used, but just to get the gist
+ parser.add_argument('-p', '--port', type=int, help='TCP port')
+ parser.add_argument('-i', '--ip', type=str, help='IPv4 address')
+
+ # Add an argument which enables transcript testing
+ parser.add_argument('-t', '--test', type=str, help='Test against transcript in FILE (wildcards OK)')
+ args = parser.parse_args()
+
+ port = None
+ if args.port:
+ port = args.port
+
+ ip_addr = None
+ if args.ip:
+ ip_addr = args.ip
+
+ transcript = None
+ if args.test:
+ transcripts = [args.test]
+
+ # Instantiate your cmd2 applicaiton
+ c = CmdLineApp(transcript_files=transcripts)
+
+ # And run your cmd2 application
+ c.cmdloop()