summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkotfu <kotfu@kotfu.net>2018-09-09 20:05:08 -0600
committerkotfu <kotfu@kotfu.net>2018-09-09 20:05:08 -0600
commit63f0aa3256ef4422c2b3eab3d9ea0d44a15cc93e (patch)
tree8c3f93f3deb4a02ac990c23632d1e4ed6069c841
parente2adc8fe379aa40142d8fee1414a5b563084b704 (diff)
downloadcmd2-git-63f0aa3256ef4422c2b3eab3d9ea0d44a15cc93e.tar.gz
Added/updated documentation for `Statement`
-rw-r--r--cmd2/parsing.py88
-rw-r--r--docs/argument_processing.rst31
2 files changed, 103 insertions, 16 deletions
diff --git a/cmd2/parsing.py b/cmd2/parsing.py
index f6186624..61b6f745 100644
--- a/cmd2/parsing.py
+++ b/cmd2/parsing.py
@@ -28,6 +28,57 @@ class Statement(str):
The string portion of the class contains the arguments, but not the command, nor
the output redirection clauses.
+
+ Here's some suggestions and best practices for how to use the attributes of this
+ object:
+
+ command - the name of the command, shortcuts and aliases have already been
+ expanded
+
+ args - the arguments to the command, excluding output redirection and command
+ terminators. If the user used quotes in their input, they remain here,
+ and you will have to handle them on your own.
+
+ arg_list - the arguments to the command, excluding output redirection and
+ command terminators. Each argument is represented as an element
+ in the list. Quoted arguments remain quoted. If you want to
+ remove the quotes, use `cmd2.utils.strip_quotes()` or use
+ `argv[1:]`
+
+ command_and_args - join the args and the command together with a space. Output
+ redirection is excluded.
+
+ argv - this is a list of arguments in the style of `sys.argv`. The first element
+ of the list is the command. Subsequent elements of the list contain any
+ additional arguments, with quotes removed, just like bash would. This
+ is very useful if you are going to use `argparse.parse_args()`:
+ ```
+ def do_mycommand(stmt):
+ mycommand_argparser.parse_args(stmt.argv)
+ ...
+ ```
+
+ raw - if you want full access to exactly what the user typed at the input prompt
+ you can get it, but you'll have to parse it on your own, including:
+ - shortcuts and aliases
+ - quoted commands and arguments
+ - output redirection
+ - multi-line command terminator handling
+ if you use multiline commands, all the input will be passed to you in
+ this string, but there will be embedded newlines where
+ the user hit return to continue the command on the next line.
+
+ Tips:
+
+ 1. `argparse` is your friend for anything complex. `cmd2` has two decorators
+ (`with_argparser`, and `with_argparser_and_unknown_args`) which you can use
+ to make your command method receive a namespace of parsed arguments, whether
+ positional or denoted with switches.
+
+ 2. For commands with simple positional arguments, use `args` or `arg_list`
+
+ 3. If you don't want to have to worry about quoted arguments, use
+ argv[1:], which strips them all off for you.
"""
# the arguments, but not the command, nor the output redirection clauses.
args = attr.ib(default='', validator=attr.validators.instance_of(str), type=str)
@@ -62,10 +113,11 @@ class Statement(str):
def __new__(cls, value: object, *pos_args, **kw_args):
"""Create a new instance of Statement.
- We must override __new__ because we are subclassing `str` which is immutable and takes a different number of
- arguments as Statement.
+ We must override __new__ because we are subclassing `str` which is
+ immutable and takes a different number of arguments as Statement.
- NOTE: attrs takes care of initializing other members in the __init__ it generates.
+ NOTE: attrs takes care of initializing other members in the __init__ it
+ generates.
"""
stmt = super().__new__(cls, value)
return stmt
@@ -74,7 +126,8 @@ class Statement(str):
def command_and_args(self) -> str:
"""Combine command and args with a space separating them.
- Quoted arguments remain quoted.
+ Quoted arguments remain quoted. Output redirection and piping are
+ excluded, as are any multiline command terminators.
"""
if self.command and self.args:
rtn = '{} {}'.format(self.command, self.args)
@@ -87,8 +140,10 @@ class Statement(str):
@property
def argv(self) -> List[str]:
- """a list of arguments a la sys.argv. Quotes, if any, are removed
- from the elements of the list, and aliases and shortcuts are expanded
+ """a list of arguments a la sys.argv.
+
+ Quotes, if any, are removed from the elements of the list, and aliases
+ and shortcuts are expanded
"""
if self.command:
rtn = [utils.strip_quotes(self.command)]
@@ -103,7 +158,8 @@ class Statement(str):
class StatementParser:
"""Parse raw text into command components.
- Shortcuts is a list of tuples with each tuple containing the shortcut and the expansion.
+ Shortcuts is a list of tuples with each tuple containing the shortcut and
+ the expansion.
"""
def __init__(
self,
@@ -396,15 +452,16 @@ class StatementParser:
This method is used by tab completion code and therefore must not
generate an exception if there are unclosed quotes.
- The Statement object returned by this method can at most contain
- values in the following attributes:
+ The Statement object returned by this method can at most contain values
+ in the following attributes:
- args
- raw
- command
- multiline_command
- Different from parse(), this method does not remove redundant whitespace within args.
- However, it does ensure args has no leading or trailing whitespace.
+ Different from parse(), this method does not remove redundant whitespace
+ within args. However, it does ensure args has no leading or trailing
+ whitespace.
"""
# expand shortcuts and aliases
line = self._expand(rawinput)
@@ -503,10 +560,11 @@ class StatementParser:
return matched_string
def _split_on_punctuation(self, tokens: List[str]) -> List[str]:
- """
- # Further splits tokens from a command line using punctuation characters
- # as word breaks when they are in unquoted strings. Each run of punctuation
- # characters is treated as a single token.
+ """Further splits tokens from a command line using punctuation characters
+
+ Punctuation characters are treated as word breaks when they are in
+ unquoted strings. Each run of punctuation characters is treated as a
+ single token.
:param tokens: the tokens as parsed by shlex
:return: the punctuated tokens
diff --git a/docs/argument_processing.rst b/docs/argument_processing.rst
index 5aef3720..022ea4d6 100644
--- a/docs/argument_processing.rst
+++ b/docs/argument_processing.rst
@@ -296,7 +296,36 @@ Receiving an argument list
==========================
The default behavior of ``cmd2`` is to pass the user input directly to your
-``do_*`` methods as a string. If you don't want to use the full argument parser support outlined above, you can still have ``cmd2`` apply shell parsing rules to the user input and pass you a list of arguments instead of a string. Apply the ``@with_argument_list`` decorator to those methods that should receive an argument list instead of a string::
+``do_*`` methods as a string. The object passed to your method is actually a
+``Statement`` object, which has additional attributes that may be helpful,
+including ``arg_list`` and ``argv``::
+
+ class CmdLineApp(cmd2.Cmd):
+ """ Example cmd2 application. """
+
+ def do_say(self, statement):
+ # statement contains a string
+ self.poutput(statement)
+
+ def do_speak(self, statement):
+ # statement also has a list of arguments
+ # quoted arguments remain quoted
+ for arg in statement.arg_list:
+ self.poutput(arg)
+
+ def do_articulate(self, statement):
+ # statement.argv contains the command
+ # and the arguments, which have had quotes
+ # stripped
+ for arg in statement.argv:
+ self.poutput(arg)
+
+
+If you don't want to access the additional attributes on the string passed to
+you``do_*`` method you can still have ``cmd2`` apply shell parsing rules to the
+user input and pass you a list of arguments instead of a string. Apply the
+``@with_argument_list`` decorator to those methods that should receive an
+argument list instead of a string::
from cmd2 import with_argument_list