Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 30 additions & 21 deletions cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@ def _init_parser(self):

# noinspection PyMethodMayBeStatic
def preparse(self, raw):
"""Hook that runs before parsing the command-line and as the very first hook for a command.
"""Hook method executed just before the command line is interpreted, but after the input prompt is generated.

:param raw: str - raw command line input
:return: str - potentially modified raw command line input
Expand All @@ -842,7 +842,7 @@ def preparse(self, raw):

# noinspection PyMethodMayBeStatic
def postparse(self, parse_result):
"""Hook that runs immediately after parsing the command-line but before parsed() returns a ParsedString.
"""Hook that runs immediately after parsing the command-line but before ``parsed()`` returns a ParsedString.

:param parse_result: pyparsing.ParseResults - parsing results output by the pyparsing parser
:return: pyparsing.ParseResults - potentially modified ParseResults object
Expand Down Expand Up @@ -888,8 +888,9 @@ def postparsing_precmd(self, statement):
If you wish to fatally fail this command and exit the application entirely, set stop = True.

If you wish to just fail this command you can do so by raising an exception:
raise EmptyStatement - will silently fail and do nothing
raise <AnyOtherException> - will fail and print an error message

- raise EmptyStatement - will silently fail and do nothing
- raise <AnyOtherException> - will fail and print an error message

:param statement: - the parsed command-line statement
:return: (bool, statement) - (stop, statement) containing a potentially modified version of the statement
Expand All @@ -909,25 +910,13 @@ def postparsing_postcmd(self, stop):
"""
return stop

def func_named(self, arg):
"""Gets the method name associated with a given command.

If self.abbrev is False, it is always just looks for do_arg. However, if self.abbrev is True,
it allows abbreivated command names and looks for any commands which start with do_arg.
def precmd(self, statement):
"""Hook method executed just before the command is processed by ``onecmd()`` and after adding it to the history.

:param arg: str - command to look up method name which implements it
:return: str - method name which implements the given command
:param statement: ParsedString - subclass of str which also contains pyparsing ParseResults instance
:return: ParsedString - a potentially modified version of the input ParsedString statement
"""
result = None
target = 'do_' + arg
if target in dir(self):
result = target
else:
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
return statement

def onecmd_plus_hooks(self, line):
"""Top-level function called by cmdloop() to handle parsing a line and running the command and all of its hooks.
Expand Down Expand Up @@ -1039,6 +1028,26 @@ def restore_output(self, statement):
os.remove(self._temp_filename)
self._temp_filename = None

def func_named(self, arg):
"""Gets the method name associated with a given command.

If self.abbrev is False, it is always just looks for do_arg. However, if self.abbrev is True,
it allows abbreivated command names and looks for any commands which start with do_arg.

:param arg: str - command to look up method name which implements it
:return: str - method name which implements the given command
"""
result = None
target = 'do_' + arg
if target in dir(self):
result = target
else:
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(self, line):
""" This executes the actual do_* method for a command.

Expand Down
17 changes: 16 additions & 1 deletion docs/freefeatures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ quotation marks if it is more than a one-word command.

.. note::

if you wish to disable cmd2's consumption of command-line arguments, you can do so by setting the ``allow_cli_args``
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::

Expand Down Expand Up @@ -105,6 +105,21 @@ app's value of ``self.redirector`` to use a different string for output redirect
line1
line2

.. 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.

.. _pywin32: http://sourceforge.net/projects/pywin32/
.. _xclip: http://www.cyberciti.biz/faq/xclip-linux-insert-files-command-output-intoclipboard/

Expand Down
61 changes: 61 additions & 0 deletions docs/hooks.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
.. cmd2 documentation for application and command lifecycle and the hooks which are available

cmd2 Application Lifecyle and Hooks
===================================

The typical way of starting a cmd2 application is as follows::

from cmd2 import Cmd
class App(Cmd):
# customized attributes and methods here
app = App()
app.cmdloop()

There are several pre-existing methods and attributes which you can tweak to control the overall behavior of your
application before, during, and after the main loop.

Application Lifecycle Hook Methods
----------------------------------
The ``preloop`` and ``postloop`` methods run before and after the main loop, respectively.

.. automethod:: cmd2.Cmd.preloop

.. automethod:: cmd2.Cmd.postloop

Application Lifecycle Attributes
--------------------------------

There are numerous attributes (member variables of the ``cmd2.Cmd``) which have a signficiant effect on the applicaiton
behavior upon entering or during the main loop. A partial list of some of the more important ones is presented here:

- **intro**: *str* - if provided this serves as the intro banner printed once at start of application, after ``preloop`` runs
- **allow_cli_args**: *bool* - if True (default), then searches for -t or --test at command line to invoke transcript testing mode instead of a normal main loop
and also processes any commands provided as arguments on the command line just prior to entering the main loop
- **echo**: *bool* - if True, then the command line entered is echoed to the screen (most useful when running scripts)
- **prompt**: *str* - sets the prompt which is displayed, can be dynamically changed based on applicatoin state and/or
command results


Command Processing Hooks
------------------------

Inside the main loop, every time the user hits <Enter> the line is processed by the ``onecmd_plus_hooks`` method.

.. automethod:: cmd2.Cmd.onecmd_plus_hooks

As the ``onecmd_plus_hooks`` name implies, there are a number of *hook* methods that can be defined in order to inject
applicaiton-specific behavior at various points during the processing of a line of text entered by the user. ``cmd2``
increases the 2 hooks provided by ``cmd`` (**precmd** and **postcmd**) to 6 for greater flexibility. Here are
the various hook methods, presented in chronological order starting with the ones called earliest in the process.

.. automethod:: cmd2.Cmd.preparse

.. automethod:: cmd2.Cmd.postparse

.. automethod:: cmd2.Cmd.postparsing_precmd

.. automethod:: cmd2.Cmd.precmd

.. automethod:: cmd2.Cmd.postcmd

.. automethod:: cmd2.Cmd.postparsing_postcmd
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Contents:
settingchanges
unfreefeatures
integrating
hooks
alternatives

Compatibility
Expand Down
15 changes: 8 additions & 7 deletions docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@ install from PyPI_.
sudo pip install <package_name>


.. warning::

Versions of ``cmd2`` before 0.7.0 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 either pip or your OS repository, then we recommend
installing from GitHub - see :ref:`github`.


Requirements for Installing
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* If you have Python 2 >=2.7.9 or Python 3 >=3.4 installed from `python.org
Expand All @@ -51,6 +44,8 @@ Requirements for Installing
python -m pip install -U pip setuptools


.. _`pip_install`:

Use pip for Installing
~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -88,6 +83,12 @@ For Python 3::

This will also install the required 3rd-party dependencies.

.. warning::

Versions of ``cmd2`` before 0.7.0 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
installing from either pip or GitHub - see :ref:`pip_install` or :ref:`github`.


Deploy cmd2.py with your project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down