summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Leonhardt <todd.leonhardt@gmail.com>2019-11-08 19:17:53 -0500
committerGitHub <noreply@github.com>2019-11-08 19:17:53 -0500
commitd5916797620225391379ea40ae466bd7f496ff52 (patch)
tree6452dc4a3f1f45e31cfae16c8acccf3dd7746f14
parenta18eef6f6aa89280b5f9b92d4e681f22a438ff8b (diff)
parent36796c2c6be67085f3d9000086de7052f08f433c (diff)
downloadcmd2-git-d5916797620225391379ea40ae466bd7f496ff52.tar.gz
Merge pull request #799 from python-cmd2/doc_updates
Doc updates
-rwxr-xr-xREADME.md4
-rw-r--r--docs/features/argument_processing.rst24
-rw-r--r--docs/features/completion.rst47
-rw-r--r--docs/features/embedded_python_shells.rst2
-rw-r--r--docs/features/generating_output.rst34
-rw-r--r--docs/features/index.rst1
-rw-r--r--docs/features/initialization.rst52
-rw-r--r--docs/features/misc.rst49
-rw-r--r--docs/features/plugins.rst154
-rw-r--r--docs/features/redirection.rst80
-rw-r--r--docs/features/scripting.rst7
-rw-r--r--docs/features/settings.rst1
-rw-r--r--docs/features/shortcuts_aliases_macros.rst18
-rw-r--r--docs/features/startup_commands.rst64
-rw-r--r--docs/features/transcripts.rst4
-rw-r--r--docs/overview/installation.rst4
-rwxr-xr-xexamples/arg_decorators.py59
-rwxr-xr-xexamples/basic.py43
-rwxr-xr-xexamples/python_scripting.py2
19 files changed, 551 insertions, 98 deletions
diff --git a/README.md b/README.md
index a352dc8f..7b68965f 100755
--- a/README.md
+++ b/README.md
@@ -102,11 +102,11 @@ Instructions for implementing each feature follow.
- Searchable command history
- Readline history using `<Ctrl>+r`, arrow keys, and other [Readline Shortcut keys](http://readline.kablamo.org/emacs.html)
- - Readline history can be persistent between application runs via optional argument to `cmd2.Cmd` initializer
- `cmd2` `history` command provides flexible and powerful search
- - By design, this history does NOT persist between application runs
- If you wish to exclude some of your custom commands from the history, append their names to the list at `Cmd.exclude_from_history`.
- Do `help history` in any `cmd2` application for more information
+ - Both of the above types of history can be optionally persistent between application runs
+ - Via optional `persistent_history_file` argument to `cmd2.Cmd` initializer
- Simple scripting using text files with one command + arguments per line
- See the [Command Scripts](https://cmd2.readthedocs.io/en/latest/features/scripting.html#command-scripts) section of the `cmd2` docs for more info
diff --git a/docs/features/argument_processing.rst b/docs/features/argument_processing.rst
index a3d4a3aa..75d92c94 100644
--- a/docs/features/argument_processing.rst
+++ b/docs/features/argument_processing.rst
@@ -1,5 +1,3 @@
-.. _decorators:
-
Argument Processing
===================
@@ -33,6 +31,7 @@ applications.
.. _argprint: https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py
.. _decorator: https://github.com/python-cmd2/cmd2/blob/master/examples/decorator_example.py
+.. _decorators:
Decorators provided by cmd2 for argument processing
---------------------------------------------------
@@ -40,12 +39,12 @@ Decorators provided by cmd2 for argument processing
``cmd2`` provides the following decorators for assisting with parsing arguments
passed to commands:
-.. automethod:: cmd2.decorators.with_argument_list
- :noindex:
.. automethod:: cmd2.decorators.with_argparser
:noindex:
.. automethod:: cmd2.decorators.with_argparser_and_unknown_args
:noindex:
+.. automethod:: cmd2.decorators.with_argument_list
+ :noindex:
All of these decorators accept an optional **preserve_quotes** argument which
defaults to ``False``. Setting this argument to ``True`` is useful for cases
@@ -342,3 +341,20 @@ use subcommands in your ``cmd2`` application.
.. _subcommands: https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py
.. _tab_autocompletion: https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion.py
+
+
+Argparse Extensions
+-------------------
+
+``cmd2`` augments the standard ``argparse.nargs`` with range tuple capability:
+
+- ``nargs=(5,)`` - accept 5 or more items
+- ``nargs=(8, 12)`` - accept 8 to 12 items
+
+``cmd2`` also provides the ``Cmd2ArgumentParser`` class which inherits from
+``argparse.ArgumentParser`` and improves error and help output:
+
+.. autoclass:: cmd2.argparse_custom.Cmd2ArgumentParser
+ :members:
+
+
diff --git a/docs/features/completion.rst b/docs/features/completion.rst
index 5d2a722c..718fb3ba 100644
--- a/docs/features/completion.rst
+++ b/docs/features/completion.rst
@@ -31,3 +31,50 @@ similar to the following to your class which inherits from ``cmd2.Cmd``::
# Make sure you have an "import functools" somewhere at the top
complete_bar = functools.partialmethod(cmd2.Cmd.path_complete, path_filter=os.path.isdir)
+
+
+Tab Completion Using Argparse Decorators
+----------------------------------------
+
+When using one the Argparse-based :ref:`decorators`, ``cmd2`` provides
+automatic tab-completion of flag names.
+
+Tab-completion of argument values can be configured by using one of five
+parameters to ``argparse.ArgumentParser.add_argument()``
+
+- ``choices``
+- ``choices_function`` / ``choices_method``
+- ``completer_function`` / ``completer_method``
+
+See the arg_decorators_ or colors_ example for a demonstration of how to
+use the ``choices`` parameter. See the tab_autocompletion_ example for a
+demonstration of how to use the ``choices_function`` and ``choices_method``
+parameters. See the arg_decorators_ or tab_autocompletion_ example for a
+demonstration of how to use the ``completer_method`` parameter.
+
+When tab-completing flags and/or argument values for a ``cmd2`` command using
+one of these decorators, ``cmd2`` keeps track of state so that once a flag has
+already previously been provided, it won't attempt to tab-complete it again.
+When no completion results exists, a hint for the current argument will be
+displayed to help the user.
+
+.. _arg_decorators: https://github.com/python-cmd2/cmd2/blob/master/examples/arg_decorators.py
+.. _colors: https://github.com/python-cmd2/cmd2/blob/master/examples/colors.py
+.. _tab_autocompletion: https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion..py
+
+
+CompletionItem For Providing Extra Context
+------------------------------------------
+
+When tab-completing things like a unique ID from a database, it can often be
+beneficial to provide the user with some extra context about the item being
+completed, such as a description. To facilitate this, ``cmd2`` defines the
+``CompletionItem`` class which can be returned from any of the 4 completion
+functions: ``choices_function``, ``choices_method``, ``completion_function``,
+or ``completion_method``.
+
+.. autoclass:: cmd2.argparse_custom.CompletionItem
+ :members:
+
+See the tab_autocompletion_ example or the implementation of the built-in
+**set** command for demonstration of how this is used.
diff --git a/docs/features/embedded_python_shells.rst b/docs/features/embedded_python_shells.rst
index 6d00536a..9d721c2c 100644
--- a/docs/features/embedded_python_shells.rst
+++ b/docs/features/embedded_python_shells.rst
@@ -126,10 +126,12 @@ IPython_ provides many advantages, including:
* Get help on objects with ``?``
* Extensible tab completion, with support by default for completion of
python variables and keywords
+ * Good built-in ipdb_ debugger
The object introspection and tab completion make IPython particularly efficient
for debugging as well as for interactive experimentation and data analysis.
.. _IPython: http://ipython.readthedocs.io
+.. _ipdb: https://pypi.org/project/ipdb/
diff --git a/docs/features/generating_output.rst b/docs/features/generating_output.rst
index c03f8778..2ee820f1 100644
--- a/docs/features/generating_output.rst
+++ b/docs/features/generating_output.rst
@@ -42,40 +42,6 @@ messages. Users can control whether they would like to see these messages by
changing the value of the ``quiet`` setting.
-Output Redirection
-------------------
-
-As in a Unix shell, output of a command can be redirected:
-
- - sent to a file with ``>``, as in ``mycommand args > filename.txt``
- - appended to a file with ``>>``, as in ``mycommand args >> filename.txt``
- - piped (``|``) as input to operating-system commands, as in
- ``mycommand args | wc``
-
-
-
-.. note::
-
- If you wish to disable cmd2's output redirection and pipes features, you can
- do so by setting the ``allow_redirection`` attribute of your ``cmd2.Cmd``
- class instance to ``False``. This would be useful, for example, if you want
- to restrict the ability for an end user to write to disk or interact with
- shell commands for security reasons::
-
- from cmd2 import Cmd
- class App(Cmd):
- def __init__(self):
- self.allow_redirection = False
-
- cmd2's parser will still treat the ``>``, ``>>``, and `|` symbols as output
- redirection and pipe symbols and will strip arguments after them from the
- command line arguments accordingly. But output from a command will not be
- redirected to a file or piped to a shell command.
-
-If you need to include any of these redirection characters in your command, you
-can enclose them in quotation marks, ``mycommand 'with > in the argument'``.
-
-
Colored Output
--------------
diff --git a/docs/features/index.rst b/docs/features/index.rst
index a793efbd..c3f68107 100644
--- a/docs/features/index.rst
+++ b/docs/features/index.rst
@@ -20,6 +20,7 @@ Features
os
plugins
prompt
+ redirection
scripting
settings
shortcuts_aliases_macros
diff --git a/docs/features/initialization.rst b/docs/features/initialization.rst
index f167a55a..936208f1 100644
--- a/docs/features/initialization.rst
+++ b/docs/features/initialization.rst
@@ -1,5 +1,53 @@
Initialization
==============
-Show how to properly initialize a ``cmd2`` app, showing parameters, sequencing,
-etc.
+Here is a basic example ``cmd2`` application which demonstrates many
+capabilities which you may wish to utilize while initializing the app::
+
+ #!/usr/bin/env python3
+ # coding=utf-8
+ """A simple example cmd2 appliction demonstrating the following:
+ 1) Colorizing/stylizing output
+ 2) Using multiline commands
+ 3) Persistent history
+ 4) How to run an initialization script at startup
+ 5) How to group and categorize commands when displaying them in help
+ 6) Opting-in to using the ipy command to run an IPython shell
+ 7) Allowing access to your application in py and ipy
+ 8) Displaying an intro banner upon starting your application
+ 9) Using a custom prompt
+ """
+ import cmd2
+ from cmd2 import style
+
+
+ class BasicApp(cmd2.Cmd):
+ CUSTOM_CATEGORY = 'My Custom Commands'
+
+ def __init__(self):
+ super().__init__(multiline_commands=['echo'], persistent_history_file='cmd2_history.dat',
+ startup_script='scripts/startup.txt', use_ipython=True)
+
+ self.intro = style('Welcome to cmd2!', fg='red', bg='white', bold=True)
+ self.prompt = 'myapp> '
+
+ # Allow access to your application in py and ipy via self
+ self.locals_in_py = True
+
+ # Set the default category name
+ self.default_category = 'cmd2 Built-in Commands'
+
+ @cmd2.with_category(CUSTOM_CATEGORY)
+ def do_intro(self, _):
+ """Display the intro banner"""
+ self.poutput(self.intro)
+
+ @cmd2.with_category(CUSTOM_CATEGORY)
+ def do_echo(self, arg):
+ """Example of a multiline command"""
+ self.poutput(arg)
+
+
+ if __name__ == '__main__':
+ app = BasicApp()
+ app.cmdloop()
diff --git a/docs/features/misc.rst b/docs/features/misc.rst
index 92ab7537..68a92b6a 100644
--- a/docs/features/misc.rst
+++ b/docs/features/misc.rst
@@ -30,55 +30,6 @@ to type::
(Cmd) !ls -al
-Commands At Invocation
-----------------------
-
-.. _Argparse: https://docs.python.org/3/library/argparse.html
-
-You can send commands to your app as you invoke it by including them as extra
-arguments to the program. ``cmd2`` interprets each argument as a separate
-command, so you should enclose each command in quotation marks if it is more
-than a one-word command.
-
-.. code-block:: shell
-
- $ python examples/example.py "say hello" "say Gracie" quit
- hello
- Gracie
-
-
-.. note::
-
- If you wish to disable cmd2's consumption of command-line arguments, you can
- do so by setting the ``allow_cli_args`` argument of your ``cmd2.Cmd`` class
- instance to ``False``. This would be useful, for example, if you wish to
- use something like Argparse_ to parse the overall command line arguments for
- your application::
-
- from cmd2 import Cmd
- class App(Cmd):
- def __init__(self):
- super().__init__(allow_cli_args=False)
-
-
-Initialization Script
----------------------
-
-.. _AliasStartup: https://github.com/python-cmd2/cmd2/blob/master/examples/alias_startup.py
-
-You can execute commands from an initialization script by passing a file
-path to the ``startup_script`` argument to the ``cmd2.Cmd.__init__()`` method
-like so::
-
- class StartupApp(cmd2.Cmd):
- def __init__(self):
- cmd2.Cmd.__init__(self, startup_script='.cmd2rc')
-
-This text file should contain a :ref:`Command Script
-<features/scripting:Command Scripts>`. See the AliasStartup_ example for a
-demonstration.
-
-
select
------
diff --git a/docs/features/plugins.rst b/docs/features/plugins.rst
index 253666e7..caa46b8c 100644
--- a/docs/features/plugins.rst
+++ b/docs/features/plugins.rst
@@ -1,3 +1,157 @@
Plugins
=======
+``cmd2`` has a built-in plugin framework which allows developers to create a
+a ``cmd2`` plugin which can extend basic ``cmd2`` functionality and can be
+used by multiple applications.
+
+Adding functionality
+--------------------
+
+There are many ways to add functionality to ``cmd2`` using a plugin. Most
+plugins will be implemented as a mixin. A mixin is a class that encapsulates
+and injects code into another class. Developers who use a plugin in their
+``cmd2`` project, will inject the plugin's code into their subclass of
+``cmd2.Cmd``.
+
+
+Mixin and Initialization
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following short example shows how to mix in a plugin and how the plugin
+gets initialized.
+
+Here's the plugin::
+
+ class MyPlugin:
+ def __init__(self, *args, **kwargs):
+ # code placed here runs before cmd2.Cmd initializes
+ super().__init__(*args, **kwargs)
+ # code placed here runs after cmd2.Cmd initializes
+
+
+and an example app which uses the plugin::
+
+ import cmd2
+ import cmd2_myplugin
+
+ class Example(cmd2_myplugin.MyPlugin, cmd2.Cmd):
+ """An class to show how to use a plugin"""
+ def __init__(self, *args, **kwargs):
+ # code placed here runs before cmd2.Cmd or
+ # any plugins initialize
+ super().__init__(*args, **kwargs)
+ # code placed here runs after cmd2.Cmd and
+ # all plugins have initialized
+
+Note how the plugin must be inherited (or mixed in) before ``cmd2.Cmd``.
+This is required for two reasons:
+
+- The ``cmd.Cmd.__init__()`` method in the python standard library does not
+ call ``super().__init__()``. Because of this oversight, if you don't
+ inherit from ``MyPlugin`` first, the ``MyPlugin.__init__()`` method will
+ never be called.
+- You may want your plugin to be able to override methods from ``cmd2.Cmd``.
+ If you mixin the plugin after ``cmd2.Cmd``, the python method resolution
+ order will call ``cmd2.Cmd`` methods before it calls those in your plugin.
+
+Add commands
+~~~~~~~~~~~~
+
+Your plugin can add user visible commands. You do it the same way in a plugin
+that you would in a ``cmd2.Cmd`` app::
+
+ class MyPlugin:
+ def do_say(self, statement):
+ """Simple say command"""
+ self.poutput(statement)
+
+You have all the same capabilities within the plugin that you do inside a
+``cmd2.Cmd`` app, including argument parsing via decorators and custom help
+methods.
+
+Add (or hide) settings
+~~~~~~~~~~~~~~~~~~~~~~
+
+A plugin may add user controllable settings to the application. Here's an
+example::
+
+ class MyPlugin:
+ def __init__(self, *args, **kwargs):
+ # code placed here runs before cmd2.Cmd initializes
+ super().__init__(*args, **kwargs)
+ # code placed here runs after cmd2.Cmd initializes
+ self.mysetting = 'somevalue'
+ self.settable.update({'mysetting': 'short help message for mysetting'})
+
+You can also hide settings from the user by removing them from
+``self.settable``.
+
+Decorators
+~~~~~~~~~~
+
+Your plugin can provide a decorator which users of your plugin can use to
+wrap functionality around their own commands.
+
+Override methods
+~~~~~~~~~~~~~~~~
+
+Your plugin can override core ``cmd2.Cmd`` methods, changing their behavior.
+This approach should be used sparingly, because it is very brittle. If a
+developer chooses to use multiple plugins in their application, and several
+of the plugins override the same method, only the first plugin to be mixed in
+will have the overridden method called.
+
+Hooks are a much better approach.
+
+Hooks
+~~~~~
+
+Plugins can register hooks, which are called by ``cmd2.Cmd`` during various
+points in the application and command processing lifecycle. Plugins should
+not override any of the deprecated hook methods, instead they should register
+their hooks as described in the :ref:`features/hooks:Hooks` section.
+
+You should name your hooks so that they begin with the name of your plugin.
+Hook methods get mixed into the ``cmd2`` application and this naming
+convention helps avoid unintentional method overriding.
+
+Here's a simple example::
+
+ class MyPlugin:
+ def __init__(self, *args, **kwargs):
+ # code placed here runs before cmd2 initializes
+ super().__init__(*args, **kwargs)
+ # code placed here runs after cmd2 initializes
+ # this is where you register any hook functions
+ self.register_postparsing_hook(self.cmd2_myplugin_postparsing_hook)
+
+ def cmd2_myplugin_postparsing_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData:
+ """Method to be called after parsing user input, but before running the command"""
+ self.poutput('in postparsing_hook')
+ return data
+
+Registration allows multiple plugins (or even the application itself) to each
+inject code to be called during the application or command processing
+lifecycle.
+
+See the :ref:`features/hooks:Hooks` documentation for full details of the
+application and command lifecycle, including all available hooks and the
+ways hooks can influence the lifecycle.
+
+
+Classes and Functions
+~~~~~~~~~~~~~~~~~~~~~
+
+Your plugin can also provide classes and functions which can be used by
+developers of ``cmd2`` based applications. Describe these classes and
+functions in your documentation so users of your plugin will know what's
+available.
+
+
+Examples
+--------
+
+.. _cmd2_plugin_template: https://github.com/python-cmd2/cmd2-plugin-template
+
+See cmd2_plugin_template_ for more info.
diff --git a/docs/features/redirection.rst b/docs/features/redirection.rst
new file mode 100644
index 00000000..677c573d
--- /dev/null
+++ b/docs/features/redirection.rst
@@ -0,0 +1,80 @@
+Output Redirection and Pipes
+============================
+
+As in POSIX shells, output of a command can be redirected and/or piped. This
+feature is fully cross-platform and works identically on Windows, macOS, and
+Linux.
+
+Output Redirection
+------------------
+
+Redirect to a file
+~~~~~~~~~~~~~~~~~~
+
+Redirecting the output of a ``cmd2`` command to a file works just like in
+POSIX shells:
+
+ - send to a file with ``>``, as in ``mycommand args > filename.txt``
+ - append to a file with ``>>``, as in ``mycommand args >> filename.txt``
+
+If you need to include any of these redirection characters in your command, you
+can enclose them in quotation marks, ``mycommand 'with > in the argument'``.
+
+Redirect to the clipboard
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``cmd2`` output redirection supports an additional feature not found in most
+shells - if the file name following the ``>`` or ``>>`` is left blank, then
+the output is redirected to the operating system clipboard so that it can
+then be pasted into another program.
+
+ - overwrite the clipboard with ``mycommand args >``
+ - append to the clipboard with ``mycommand args >>``
+
+Pipes
+-----
+Piping the output of a ``cmd2`` command to a shell command works just like in
+POSIX shells:
+
+ - pipe as input to a shell command with ``|``, as in ``mycommand args | wc``
+
+Multiple Pipes and Redirection
+------------------------------
+Multiple pipes, optionally followed by a redirect, are supported. Thus, it is
+possible to do something like the following::
+
+ (Cmd) help | grep py | wc > output.txt
+
+The above runs the **help** command, pipes its output to **grep** searching for
+any lines containing *py*, then pipes the output of grep to the **wc**
+"word count" command, and finally writes redirects the output of that to a file
+called *output.txt*.
+
+Disabling Redirection
+---------------------
+
+.. note::
+
+ If you wish to disable cmd2's output redirection and pipes features, you can
+ do so by setting the ``allow_redirection`` attribute of your ``cmd2.Cmd``
+ class instance to ``False``. This would be useful, for example, if you want
+ to restrict the ability for an end user to write to disk or interact with
+ shell commands for security reasons::
+
+ from cmd2 import Cmd
+ class App(Cmd):
+ def __init__(self):
+ self.allow_redirection = False
+
+ cmd2's parser will still treat the ``>``, ``>>``, and `|` symbols as output
+ redirection and pipe symbols and will strip arguments after them from the
+ command line arguments accordingly. But output from a command will not be
+ redirected to a file or piped to a shell command.
+
+Limitations of Redirection
+--------------------------
+
+Some limitations apply to redirection and piping within ``cmd2`` applications:
+
+- Can only pipe to shell commands, not other ``cmd2`` application commands
+- **stdout** gets redirected/piped, **stderr** does not
diff --git a/docs/features/scripting.rst b/docs/features/scripting.rst
index 52fab405..b41855ca 100644
--- a/docs/features/scripting.rst
+++ b/docs/features/scripting.rst
@@ -32,8 +32,11 @@ line, exactly as you would type it inside a ``cmd2`` application.
Running Command Scripts
~~~~~~~~~~~~~~~~~~~~~~~
-Command script files can be executed using the built-in ``run_script`` command.
-Both ASCII and UTF-8 encoded unicode text files are supported.
+Command script files can be executed using the built-in ``run_script`` command
+or ``@`` shortcut. Both ASCII and UTF-8 encoded unicode text files are
+supported. The ``run_script`` command supports tab-completion of file system
+paths. There is a variant ``_relative_run_script`` command or ``@@``
+shortcut for use within a script which uses paths relative to the first script.
Comments
diff --git a/docs/features/settings.rst b/docs/features/settings.rst
index 21d5a9ee..b0575468 100644
--- a/docs/features/settings.rst
+++ b/docs/features/settings.rst
@@ -53,6 +53,7 @@ with::
editor: vim # Program used by ``edit``
feedback_to_output: False # include nonessentials in `|`, `>` results
locals_in_py: False # Allow access to your application in py via self
+ max_completion_items: 50 # Maximum number of CompletionItems to display during tab completion
prompt: (Cmd) # The prompt issued to solicit input
quiet: False # Don't print nonessential feedback
timing: False # Report execution times
diff --git a/docs/features/shortcuts_aliases_macros.rst b/docs/features/shortcuts_aliases_macros.rst
index b84403c8..e5b4bf1d 100644
--- a/docs/features/shortcuts_aliases_macros.rst
+++ b/docs/features/shortcuts_aliases_macros.rst
@@ -51,6 +51,14 @@ The syntax to create an alias is: ``alias create name command [args]``.
Ex: ``alias create ls !ls -lF``
+Redirectors and pipes should be quoted in alias definition to prevent the
+``alias create`` command from being redirected::
+
+ alias create save_results print_results ">" out.txt
+
+Tab completion recognizes an alias, and completes as if its actual value
+was on the command line.
+
For more details run: ``help alias create``
Use ``alias list`` to see all or some of your aliases. The output of this
@@ -85,6 +93,16 @@ command is run. For example:
my_macro beef broccoli ---> make_dinner -meat beef -veggie broccoli
+Similar to aliases, pipes and redirectors need to be quoted in the definition
+of a macro::
+
+ macro create lc !cat "{1}" "|" less
+
+To use the literal string ``{1}`` in your command, escape it this way:
+``{{1}}``. Because macros do not resolve until after hitting ``<Enter>``,
+tab completion will only complete paths while typing a macro.
+
+
For more details run: ``help macro create``
The macro command has ``list`` and ``delete`` subcommands that function
diff --git a/docs/features/startup_commands.rst b/docs/features/startup_commands.rst
index 1efcc014..93984db6 100644
--- a/docs/features/startup_commands.rst
+++ b/docs/features/startup_commands.rst
@@ -1,2 +1,66 @@
Startup Commands
================
+
+``cmd2`` provides a couple different ways for running commands immediately
+after your application starts up:
+
+1. Commands at Invocation
+1. Startup Script
+
+Commands run as part of a startup script are always run immediately after the
+application finishes initializing so they are guaranteed to run before any
+*Commands At Invocation*.
+
+
+Commands At Invocation
+----------------------
+
+.. _Argparse: https://docs.python.org/3/library/argparse.html
+
+You can send commands to your app as you invoke it by including them as extra
+arguments to the program. ``cmd2`` interprets each argument as a separate
+command, so you should enclose each command in quotation marks if it is more
+than a one-word command. You can use either single or double quotes for this
+purpose.
+
+.. code-block:: shell
+
+ $ python examples/example.py "say hello" "say Gracie" quit
+ hello
+ Gracie
+
+You can end your commands with a **quit** command so that your ``cmd2``
+application runs like a non-interactive command-line utility (CLU). This
+means that it can then be scripted from an external application and easily used
+in automation.
+
+.. note::
+
+ If you wish to disable cmd2's consumption of command-line arguments, you can
+ do so by setting the ``allow_cli_args`` argument of your ``cmd2.Cmd`` class
+ instance to ``False``. This would be useful, for example, if you wish to
+ use something like Argparse_ to parse the overall command line arguments for
+ your application::
+
+ from cmd2 import Cmd
+ class App(Cmd):
+ def __init__(self):
+ super().__init__(allow_cli_args=False)
+
+
+Startup Script
+--------------
+
+.. _AliasStartup: https://github.com/python-cmd2/cmd2/blob/master/examples/alias_startup.py
+
+You can execute commands from an initialization script by passing a file
+path to the ``startup_script`` argument to the ``cmd2.Cmd.__init__()`` method
+like so::
+
+ class StartupApp(cmd2.Cmd):
+ def __init__(self):
+ cmd2.Cmd.__init__(self, startup_script='.cmd2rc')
+
+This text file should contain a :ref:`Command Script
+<features/scripting:Command Scripts>`. See the AliasStartup_ example for a
+demonstration.
diff --git a/docs/features/transcripts.rst b/docs/features/transcripts.rst
index fe074cfa..9f524e0a 100644
--- a/docs/features/transcripts.rst
+++ b/docs/features/transcripts.rst
@@ -153,8 +153,8 @@ the path instead of specifying it verbatim, or we can escape the slashes::
This could make the actual data generated by your app different than the
text you pasted into the transcript, and it might not be readily obvious why
the transcript is not passing. Consider using
- :ref:`features/generating_output:Output Redirection` to the clipboard or to
- a file to ensure you accurately capture the output of your command.
+ :ref:`features/redirection:Output Redirection and Pipes` to the clipboard or
+ to a file to ensure you accurately capture the output of your command.
If you aren't using regular expressions, make sure the newlines at the end
of your transcript exactly match the output of your commands. A common cause
diff --git a/docs/overview/installation.rst b/docs/overview/installation.rst
index 9f1209b6..2bbe52a2 100644
--- a/docs/overview/installation.rst
+++ b/docs/overview/installation.rst
@@ -90,9 +90,9 @@ This will also install the required 3rd-party dependencies.
.. warning::
- Versions of ``cmd2`` before 0.7.0 should be considered to be of unstable
+ Versions of ``cmd2`` before 0.8.9 should be considered to be of unstable
"beta" quality and should not be relied upon for production use. If you
- cannot get a version >= 0.7 from your OS repository, then we recommend
+ cannot get a version >= 0.8.9 from your OS repository, then we recommend
installing from either pip or GitHub - see :ref:`pip_install` or
:ref:`github`.
diff --git a/examples/arg_decorators.py b/examples/arg_decorators.py
new file mode 100755
index 00000000..a085341d
--- /dev/null
+++ b/examples/arg_decorators.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+# coding=utf-8
+"""An example demonstrating how use one of cmd2's argument parsing decorators"""
+import argparse
+import os
+
+import cmd2
+
+
+class ArgparsingApp(cmd2.Cmd):
+ def __init__(self):
+ super().__init__(use_ipython=True)
+ self.intro = 'cmd2 has awesome decorators to make it easy to use Argparse to parse command arguments'
+
+ # do_fsize parser
+ fsize_parser = cmd2.Cmd2ArgumentParser(description='Obtain the size of a file')
+ fsize_parser.add_argument('-c', '--comma', action='store_true',
+ help='add comma for thousands separator')
+ fsize_parser.add_argument('-u', '--unit', choices=['MB', 'KB'], help='unit to display size in')
+ fsize_parser.add_argument('file_path', help='path of file',
+ completer_method=cmd2.Cmd.path_complete)
+
+ @cmd2.with_argparser(fsize_parser)
+ def do_fsize(self, args: argparse.Namespace) -> None:
+ """Obtain the size of a file"""
+ expanded_path = os.path.expanduser(args.file_path)
+
+ try:
+ size = os.path.getsize(expanded_path)
+ except OSError as ex:
+ self.perror("Error retrieving size: {}".format(ex))
+ return
+
+ if args.unit == 'KB':
+ size /= 1024
+ elif args.unit == 'MB':
+ size /= 1024 * 1024
+ else:
+ args.unit = 'bytes'
+ size = round(size, 2)
+
+ if args.comma:
+ size = '{:,}'.format(size)
+ self.poutput('{} {}'.format(size, args.unit))
+
+ # do_pow parser
+ pow_parser = argparse.ArgumentParser()
+ pow_parser.add_argument('base', type=int)
+ pow_parser.add_argument('exponent', type=int, choices=range(-5, 6))
+
+ @cmd2.with_argparser(pow_parser)
+ def do_pow(self, args: argparse.Namespace) -> None:
+ """Raise an integer to a small integer exponent, either positive or negative"""
+ self.poutput('{} ** {} == {}'.format(args.base, args.exponent, args.base ** args.exponent))
+
+
+if __name__ == '__main__':
+ app = ArgparsingApp()
+ app.cmdloop()
diff --git a/examples/basic.py b/examples/basic.py
new file mode 100755
index 00000000..75672a6b
--- /dev/null
+++ b/examples/basic.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+# coding=utf-8
+"""A simple example demonstrating the following:
+ 1) How to add a command
+ 2) How to add help for that command
+ 3) Persistent history
+ 4) How to run an initialization script at startup
+ 5) How to add custom command aliases using the alias command
+ 6) Shell-like capabilities
+"""
+import cmd2
+from cmd2 import style
+
+
+class BasicApp(cmd2.Cmd):
+ CUSTOM_CATEGORY = 'My Custom Commands'
+
+ def __init__(self):
+ super().__init__(multiline_commands=['echo'], persistent_history_file='cmd2_history.dat',
+ startup_script='scripts/startup.txt', use_ipython=True)
+
+ self.intro = style('Welcome to PyOhio 2019 and cmd2!', fg='red', bg='white', bold=True) + ' 😀'
+
+ # Allow access to your application in py and ipy via self
+ self.locals_in_py = True
+
+ # Set the default category name
+ self.default_category = 'cmd2 Built-in Commands'
+
+ @cmd2.with_category(CUSTOM_CATEGORY)
+ def do_intro(self, _):
+ """Display the intro banner"""
+ self.poutput(self.intro)
+
+ @cmd2.with_category(CUSTOM_CATEGORY)
+ def do_echo(self, arg):
+ """Example of a multiline command"""
+ self.poutput(arg)
+
+
+if __name__ == '__main__':
+ app = BasicApp()
+ app.cmdloop()
diff --git a/examples/python_scripting.py b/examples/python_scripting.py
index 3d0a54a9..8c680d33 100755
--- a/examples/python_scripting.py
+++ b/examples/python_scripting.py
@@ -22,7 +22,7 @@ from cmd2 import ansi
class CmdLineApp(cmd2.Cmd):
- """ Example cmd2 application to showcase conditional control flow in Python scripting within cmd2 aps. """
+ """ Example cmd2 application to showcase conditional control flow in Python scripting within cmd2 apps."""
def __init__(self):
# Enable the optional ipy command if IPython is installed by setting use_ipython=True