diff options
-rw-r--r-- | cmd2/cmd2.py | 2 | ||||
-rw-r--r-- | docs/features/argument_processing.rst | 7 | ||||
-rw-r--r-- | docs/features/clipboard.rst | 28 | ||||
-rw-r--r-- | docs/features/embedded_python_shells.rst | 133 | ||||
-rw-r--r-- | docs/features/generating_output.rst | 33 | ||||
-rw-r--r-- | docs/features/index.rst | 1 | ||||
-rw-r--r-- | docs/features/misc.rst | 15 | ||||
-rw-r--r-- | docs/freefeatures.rst | 186 | ||||
-rw-r--r-- | docs/index.rst | 3 | ||||
-rw-r--r-- | docs/migrating/free_features.rst | 5 | ||||
-rw-r--r-- | docs/migrating/incompatibilities.rst | 39 | ||||
-rw-r--r-- | docs/migrating/index.rst | 9 | ||||
-rw-r--r-- | docs/migrating/minimum.rst | 51 | ||||
-rw-r--r-- | docs/migrating/next_steps.rst | 62 | ||||
-rw-r--r-- | docs/migrating/nextsteps.rst | 6 | ||||
-rw-r--r-- | docs/migrating/summary.rst | 15 | ||||
-rw-r--r-- | docs/migrating/why.rst | 68 | ||||
-rwxr-xr-x | examples/example.py | 2 | ||||
-rw-r--r-- | examples/migrating.py | 49 |
19 files changed, 475 insertions, 239 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 2c37635d..5c03a9c5 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -2962,7 +2962,7 @@ class Cmd(cmd.Cmd): if orig_value != new_value: onchange_hook = getattr(self, '_onchange_{}'.format(param), None) if onchange_hook is not None: - onchange_hook(old=orig_value, new=new_value) + onchange_hook(old=orig_value, new=new_value) # pylint: disable=not-callable shell_parser = ArgParser() shell_parser.add_argument('command', help='the command to run', completer_method=shell_cmd_complete) diff --git a/docs/features/argument_processing.rst b/docs/features/argument_processing.rst index 5efc83ef..d0f2c137 100644 --- a/docs/features/argument_processing.rst +++ b/docs/features/argument_processing.rst @@ -4,8 +4,9 @@ Argument Processing =================== ``cmd2`` makes it easy to add sophisticated argument processing to your -commands using the ``argparse`` python module. ``cmd2`` handles the following -for you: +commands using the `argparse +<https://docs.python.org/3/library/argparse.html>`_ python module. ``cmd2`` +handles the following for you: 1. Parsing input and quoted strings like the Unix shell @@ -16,7 +17,9 @@ for you: The ``Namespace`` includes the ``Statement`` object that was created when parsing the command line. It is stored in the ``__statement__`` attribute of the ``Namespace``. + 4. Adds the usage message from the argument parser to your command. + 5. Checks if the ``-h/--help`` option is present, and if so, display the help message for the command diff --git a/docs/features/clipboard.rst b/docs/features/clipboard.rst index d5048cc0..73e206c2 100644 --- a/docs/features/clipboard.rst +++ b/docs/features/clipboard.rst @@ -1,5 +1,33 @@ Clipboard Integration ===================== +Nearly every operating system has some notion of a short-term storage area +which can be accessed by any program. Usually this is called the clipboard, but +sometimes people refer to it as the paste buffer. + +``cmd2`` integrates with the operating system clipboard using the `pyperclip +<https://github.com/asweigart/pyperclip>`_ module. Command output can be sent +to the clipboard by ending the command with a greater than symbol: + +.. code-block:: text + + mycommand args > + +Think of it as though you are redirecting output to an unnamed, ephemeral +place, you know, like the clipboard. You can also append output to the current +contents of the clipboard by ending the command with two greater than symbols: + +.. code-block:: text + + mycommand arg1 arg2 >> + + +Developers +---------- + +If you would like your ``cmd2`` based application to be able to use the +clipboard in additional or alternative ways, you can use the following methods +(which work uniformly on Windows, macOS, and Linux). + .. automodule:: cmd2.clipboard :members: diff --git a/docs/features/embedded_python_shells.rst b/docs/features/embedded_python_shells.rst index ace68877..7e8c027b 100644 --- a/docs/features/embedded_python_shells.rst +++ b/docs/features/embedded_python_shells.rst @@ -1,4 +1,135 @@ Embedded Python Shells ====================== -Describe ``py`` and optional ``ipy`` commands +The ``py`` command will run its arguments as a Python command. Entered without +arguments, it enters an interactive Python session. The session can call +"back" to your application through the name defined in ``self.pyscript_name`` +(defaults to ``app``). This wrapper provides access to execute commands in +your cmd2 application while maintaining isolation. + +You may optionally enable full access to to your application by setting +``locals_in_py`` to ``True``. Enabling this flag adds ``self`` to the python +session, which is a reference to your Cmd2 application. This can be useful for +debugging your application. To prevent users from enabling this ability +manually you'll need to remove ``locals_in_py`` from the ``settable`` +dictionary. + +The ``app`` object (or your custom name) provides access to application +commands through raw commands. For example, any application command call be +called with ``app("<command>")``. + +:: + + >>> app('say --piglatin Blah') + lahBay + +More Python examples: + +:: + + (Cmd) py print("-".join("spelling")) + s-p-e-l-l-i-n-g + (Cmd) py + Python 3.5.3 (default, Jan 19 2017, 14:11:04) + [GCC 6.3.0 20170118] on linux + Type "help", "copyright", "credits" or "license" for more information. + (CmdLineApp) + + End with `Ctrl-D` (Unix) / `Ctrl-Z` (Windows), `quit()`, `exit()`. + Non-python commands can be issued with: app("your command") + Run python code from external script files with: run("script.py") + + >>> import os + >>> os.uname() + ('Linux', 'eee', '2.6.31-19-generic', '#56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010', 'i686') + >>> app("say --piglatin {os}".format(os=os.uname()[0])) + inuxLay + >>> self.prompt + '(Cmd) ' + >>> self.prompt = 'Python was here > ' + >>> quit() + Python was here > + +Using the ``py`` command is tightly integrated with your main ``cmd2`` +application and any variables created or changed will persist for the life of +the application:: + + (Cmd) py x = 5 + (Cmd) py print(x) + 5 + +The ``py`` command also allows you to run Python scripts via ``py +run('myscript.py')``. This provides a more complicated and more powerful +scripting capability than that provided by the simple text file scripts +discussed in :ref:`scripts`. Python scripts can include conditional control +flow logic. See the **python_scripting.py** ``cmd2`` application and the +**script_conditional.py** script in the ``examples`` source code directory for +an example of how to achieve this in your own applications. + +Using ``py`` to run scripts directly is considered deprecated. The newer +``run_pyscript`` command is superior for doing this in two primary ways: + +- it supports tab-completion of file system paths +- it has the ability to pass command-line arguments to the scripts invoked + +There are no disadvantages to using ``run_pyscript`` as opposed to ``py +run()``. A simple example of using ``run_pyscript`` is shown below along with +the arg_printer_ script:: + + (Cmd) run_pyscript examples/scripts/arg_printer.py foo bar baz + Running Python script 'arg_printer.py' which was called with 3 arguments + arg 1: 'foo' + arg 2: 'bar' + arg 3: 'baz' + +.. note:: + + If you want to be able to pass arguments with spaces to commands, then we + strongly recommend using one of the decorators, such as + ``with_argument_list``. ``cmd2`` will pass your **do_*** methods a list of + arguments in this case. + + When using this decorator, you can then put arguments in quotes like so:: + + $ examples/arg_print.py + (Cmd) lprint foo "bar baz" + lprint was called with the following list of arguments: ['foo', 'bar baz'] + +.. _arg_printer: + https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/arg_printer.py + + +IPython (optional) +------------------ + +**If** IPython_ is installed on the system **and** the ``cmd2.Cmd`` class is +instantiated with ``use_ipython=True``, then the optional ``ipy`` command will +be present:: + + from cmd2 import Cmd + class App(Cmd): + def __init__(self): + Cmd.__init__(self, use_ipython=True) + +The ``ipy`` command enters an interactive IPython_ session. Similar to an +interactive Python session, this shell can access your application instance via +``self`` and any changes to your application made via ``self`` will persist. +However, any local or global variable created within the ``ipy`` shell will not +persist. Within the ``ipy`` shell, you cannot call "back" to your application +with ``cmd("")``, however you can run commands directly like so:: + + self.onecmd_plus_hooks('help') + +IPython_ provides many advantages, including: + + * Comprehensive object introspection + * Get help on objects with ``?`` + * Extensible tab completion, with support by default for completion of + python variables and keywords + +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 + + diff --git a/docs/features/generating_output.rst b/docs/features/generating_output.rst index 1dab6f64..5813322b 100644 --- a/docs/features/generating_output.rst +++ b/docs/features/generating_output.rst @@ -9,4 +9,37 @@ how to generate output - exceptions - color support +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'``. + diff --git a/docs/features/index.rst b/docs/features/index.rst index 3087031f..a793efbd 100644 --- a/docs/features/index.rst +++ b/docs/features/index.rst @@ -15,6 +15,7 @@ Features history hooks initialization + misc multiline_commands os plugins diff --git a/docs/features/misc.rst b/docs/features/misc.rst new file mode 100644 index 00000000..4db9f682 --- /dev/null +++ b/docs/features/misc.rst @@ -0,0 +1,15 @@ +Miscellaneous Features +====================== + + +Timer +----- + +Turn the timer setting on, and ``cmd2`` will show the wall time it takes for +each command to execute. + + +Exiting +------- + +Mention quit, exit, and EOF handling built into ``cmd2``. diff --git a/docs/freefeatures.rst b/docs/freefeatures.rst index 25fe3be9..cb693be8 100644 --- a/docs/freefeatures.rst +++ b/docs/freefeatures.rst @@ -76,174 +76,6 @@ quotation marks if it is more than a one-word command. .. _output_redirection: -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`` - - sent to the operating system paste buffer, by ending with a bare ``>``, as - in ``mycommand args >``. You can even append output to the current contents - of the paste buffer by ending your command with ``>>``. - - -.. 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'``. - -Python -====== - -The ``py`` command will run its arguments as a Python command. Entered without -arguments, it enters an interactive Python session. The session can call -"back" to your application through the name defined in ``self.pyscript_name`` -(defaults to ``app``). This wrapper provides access to execute commands in -your cmd2 application while maintaining isolation. - -You may optionally enable full access to to your application by setting -``locals_in_py`` to ``True``. Enabling this flag adds ``self`` to the python -session, which is a reference to your Cmd2 application. This can be useful for -debugging your application. To prevent users from enabling this ability -manually you'll need to remove ``locals_in_py`` from the ``settable`` -dictionary. - -The ``app`` object (or your custom name) provides access to application -commands through raw commands. For example, any application command call be -called with ``app("<command>")``. - -:: - - >>> app('say --piglatin Blah') - lahBay - -More Python examples: - -:: - - (Cmd) py print("-".join("spelling")) - s-p-e-l-l-i-n-g - (Cmd) py - Python 3.5.3 (default, Jan 19 2017, 14:11:04) - [GCC 6.3.0 20170118] on linux - Type "help", "copyright", "credits" or "license" for more information. - (CmdLineApp) - - End with `Ctrl-D` (Unix) / `Ctrl-Z` (Windows), `quit()`, `exit()`. - Non-python commands can be issued with: app("your command") - Run python code from external script files with: run("script.py") - - >>> import os - >>> os.uname() - ('Linux', 'eee', '2.6.31-19-generic', '#56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010', 'i686') - >>> app("say --piglatin {os}".format(os=os.uname()[0])) - inuxLay - >>> self.prompt - '(Cmd) ' - >>> self.prompt = 'Python was here > ' - >>> quit() - Python was here > - -Using the ``py`` command is tightly integrated with your main ``cmd2`` -application and any variables created or changed will persist for the life of -the application:: - - (Cmd) py x = 5 - (Cmd) py print(x) - 5 - -The ``py`` command also allows you to run Python scripts via ``py -run('myscript.py')``. This provides a more complicated and more powerful -scripting capability than that provided by the simple text file scripts -discussed in :ref:`scripts`. Python scripts can include conditional control -flow logic. See the **python_scripting.py** ``cmd2`` application and the -**script_conditional.py** script in the ``examples`` source code directory for -an example of how to achieve this in your own applications. - -Using ``py`` to run scripts directly is considered deprecated. The newer -``run_pyscript`` command is superior for doing this in two primary ways: - -- it supports tab-completion of file system paths -- it has the ability to pass command-line arguments to the scripts invoked - -There are no disadvantages to using ``run_pyscript`` as opposed to ``py -run()``. A simple example of using ``run_pyscript`` is shown below along with -the arg_printer_ script:: - - (Cmd) run_pyscript examples/scripts/arg_printer.py foo bar baz - Running Python script 'arg_printer.py' which was called with 3 arguments - arg 1: 'foo' - arg 2: 'bar' - arg 3: 'baz' - -.. note:: - - If you want to be able to pass arguments with spaces to commands, then we - strongly recommend using one of the decorators, such as - ``with_argument_list``. ``cmd2`` will pass your **do_*** methods a list of - arguments in this case. - - When using this decorator, you can then put arguments in quotes like so:: - - $ examples/arg_print.py - (Cmd) lprint foo "bar baz" - lprint was called with the following list of arguments: ['foo', 'bar baz'] - -.. _arg_printer: - https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/arg_printer.py - - -IPython (optional) -================== - -**If** IPython_ is installed on the system **and** the ``cmd2.Cmd`` class is -instantiated with ``use_ipython=True``, then the optional ``ipy`` command will -be present:: - - from cmd2 import Cmd - class App(Cmd): - def __init__(self): - Cmd.__init__(self, use_ipython=True) - -The ``ipy`` command enters an interactive IPython_ session. Similar to an -interactive Python session, this shell can access your application instance via -``self`` and any changes to your application made via ``self`` will persist. -However, any local or global variable created within the ``ipy`` shell will not -persist. Within the ``ipy`` shell, you cannot call "back" to your application -with ``cmd("")``, however you can run commands directly like so:: - - self.onecmd_plus_hooks('help') - -IPython_ provides many advantages, including: - - * Comprehensive object introspection - * Get help on objects with ``?`` - * Extensible tab completion, with support by default for completion of - python variables and keywords - -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 Quitting the application @@ -268,24 +100,6 @@ with automatically included ``do_`` methods. ( ``!`` is a shortcut for ``shell``; thus ``!ls`` is equivalent to ``shell ls``.) -Transcript-based testing -======================== - -A transcript is both the input and output of a successful session of a -``cmd2``-based app which is saved to a text file. The transcript can be played -back into the app as a unit test. - -.. code-block:: text - - $ python example.py --test transcript_regex.txt - . - ---------------------------------------------------------------------- - Ran 1 test in 0.013s - - OK - -See :doc:`features/transcripts` for more details. - Tab-Completion ============== diff --git a/docs/index.rst b/docs/index.rst index 5d316ed8..d9b5b14c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -40,8 +40,11 @@ Getting Started Migrating from cmd ================== +.. include:: migrating/summary.rst + .. toctree:: :maxdepth: 2 + :hidden: migrating/index diff --git a/docs/migrating/free_features.rst b/docs/migrating/free_features.rst deleted file mode 100644 index afb29fc3..00000000 --- a/docs/migrating/free_features.rst +++ /dev/null @@ -1,5 +0,0 @@ -What you get for free -===================== - -A brief list (with links to details) of major features you get for free once -you migrate. diff --git a/docs/migrating/incompatibilities.rst b/docs/migrating/incompatibilities.rst index 2804aeac..7526b51b 100644 --- a/docs/migrating/incompatibilities.rst +++ b/docs/migrating/incompatibilities.rst @@ -4,7 +4,7 @@ Incompatibilities .. _cmd: https://docs.python.org/3/library/cmd.html ``cmd2`` strives to be drop-in compatible with cmd_, however there are a few -things that are not. +incompatibilities. Cmd.emptyline() @@ -14,12 +14,10 @@ The `Cmd.emptyline() <https://docs.python.org/3/library/cmd.html#cmd.Cmd.emptyline>`_ function is called when an empty line is entered in response to the prompt. By default, in cmd_ if this method is not overridden, it repeats and executes the last -nonempty command entered. However, no end user we have encountered views this -as expected or desirable default behavior. Thus, the default behavior in -``cmd2`` is to simply go to the next line and issue the prompt again. At this -time, ``cmd2`` completely ignores empty lines and the base class -cmd.emptyline() method never gets called and thus the emptyline() behavior -cannot be overridden. +nonempty command entered. However, no end user we have encountered views this +as expected or desirable default behavior. ``cmd2`` completely ignores empty +lines and the base class ``cmd.emptyline()`` method never gets called and thus +the empty line behavior cannot be overridden. Cmd.identchars @@ -27,11 +25,23 @@ Cmd.identchars In cmd_, the `Cmd.identchars <https://docs.python.org/3/library/cmd.html#cmd.Cmd.identchars>`_ attribute -contains the string of characters accepted for command names. Since version -0.9.0, ``cmd2`` has ignored ``identchars``. cmd_ uses those characters to split -the first "word" of the input, but the parsing logic in ``cmd2`` parses on -whitespace. This has the added benefit of full unicode support, unlike cmd_ or -versions of ``cmd2`` prior to 0.9.0. +contains the string of characters accepted for command names. cmd_ uses those +characters to split the first "word" of the input, without requiring the user +to type a space. For example, if ``identchars`` contained a string of all +alphabetic characters, the user could enter a command like ``L20`` and it would +be interpreted as the command ``L`` with the first argument of ``20``. + +Since version 0.9.0, ``cmd2`` has ignored ``identchars``; the parsing logic in +``cmd2`` splits the command and arguments on whitespace. We opted for this +breaking change because while cmd_ supports unicode, using non-ascii unicode +characters in command names while simultaneously using ``identchars`` +functionality can be somewhat painful. Requiring white space to delimit +arguments also ensures reliable operation of many other useful ``cmd2`` +features, including :ref:`features/completion:Completion` and +:ref:`features/shortcuts_aliases_macros:Shortcuts, Aliases, and Macros`. + +If you really need this functionality in your app, you can add it back in by +writing a :ref:`Postparsing Hook <features/hooks:Postparsing Hooks>`. Cmd.cmdqueue @@ -48,8 +58,3 @@ scripts, Python scripts, transcripts, and history replays, the only way to preserve consistent behavior across these methods was to eliminate the command queue. Additionally, reasoning about application behavior is much easier without this queue present. - -If developers need this sort of thing, they can add it in their application. -However, if they are not extremely careful there would likely be unintended -consequences. - diff --git a/docs/migrating/index.rst b/docs/migrating/index.rst index 9c01b1bd..73d6b1c7 100644 --- a/docs/migrating/index.rst +++ b/docs/migrating/index.rst @@ -1,11 +1,14 @@ -Migrating from cmd +Migrating From cmd ================== .. toctree:: :maxdepth: 1 + :hidden: why incompatibilities minimum - free_features - nextsteps + next_steps + + +.. include:: summary.rst diff --git a/docs/migrating/minimum.rst b/docs/migrating/minimum.rst index d604cf7a..c23bbbd7 100644 --- a/docs/migrating/minimum.rst +++ b/docs/migrating/minimum.rst @@ -1,4 +1,51 @@ -Minimum required changes +Minimum Required Changes ======================== -The minimum required changes to move to cmd2 +``cmd2.Cmd`` subclasses ``Cmd.cmd`` from the standard library, and overrides +most of the methods. Most apps based on the standard library can be migrated to +``cmd2`` in just a couple of minutes. + + +Import and Inheritance +---------------------- + +You need to change your import from this:: + + import cmd + +to this:: + + import cmd2 + +Then you need to change your class definition from:: + + class CmdLineApp(cmd.Cmd): + +to:: + + class CmdLineApp(cmd2.Cmd): + + +Exiting +------- + +Have a look at the commands you created to exit your application. You probably +have one called ``exit`` and maybe a similar one called ``quit``. You also +might have implemented a ``do_EOF()`` method so your program exits like many +operating system shells. If all these commands do is quit the application, +you may be able to remove them. See :ref:`features/misc:Exiting`. + + +Distribution +------------ + +If you are distributing your application, you'll also need to ensure +that ``cmd2`` is properly installed. You will need to add this to +your ``setup()`` method in ``setup.py``:: + + install_requires=[ + 'cmd2>=1,<2` + ] + +See :ref:`overview/integrating:Integrate cmd2 Into Your Project` for more +details. diff --git a/docs/migrating/next_steps.rst b/docs/migrating/next_steps.rst new file mode 100644 index 00000000..f43c69c9 --- /dev/null +++ b/docs/migrating/next_steps.rst @@ -0,0 +1,62 @@ +Next Steps +========== + +Once your current application is using ``cmd2``, you can start to expand the +functionality by levering other ``cmd2`` features. The three ideas here will +get you started. Browse the rest of the :ref:`features/index:Features` to see +what else ``cmd2`` can help you do. + + +Argument Parsing +---------------- + +For all but the simplest of commands, it's probably easier to use `argparse +<https://docs.python.org/3/library/argparse.html>`_ to parse user input. +``cmd2`` provides a ``@with_argparser()`` decorator which associates an +``ArgumentParser`` object with one of your commands. Using this method will: + +1. Pass your command a `Namespace +<https://docs.python.org/3/library/argparse.html#argparse.Namespace>`_ +containing the arguments instead of a string of text. + +2. Properly handle quoted string input from your users. + +3. Create a help message for you based on the ``ArgumentParser``. + +4. Give you a big headstart adding :ref:`features/completion:Completion` to + your application. + +5. Make it much easier to implement subcommands (i.e. ``git`` has + a bunch of subcommands such as ``git pull``, ``git diff``, etc). + +There's a lot more about :ref:`features/argument_processing:Argument +Processing` if you want to dig in further. + + +Help +---- + +If you have lot of commands in your application, ``cmd2`` can categorize those +commands using a one line decorator ``@with_category()``. When a user types +``help`` the available commands will be organized by the category you +specified. + +If you were already using ``argparse`` or decided to switch to it, you can +easily :ref:`standardize all of your help messages +<features/argument_processing:Help Messages>` to be generated by your argument +parsers and displayed by ``cmd2``. No more help messages that don't match what +the code actually does. + + +Generating Output +----------------- + +If your program generates output by printing directly to ``sys.stdout``, you +should consider switching to :meth:`cmd2.cmd2.Cmd.poutput`, +:meth:`cmd2.cmd2.Cmd.perror`, and :meth:`cmd2.cmd2.Cmd.pfeedback`. These +methods work with several of the built in :ref:`features/settings:Settings` to +allow the user to view or suppress feedback (i.e. progress or status output). +They also properly handle ansi colored output according to user preference. +Speaking of colored output, you can use any color library you want, or use the +included :meth:`cmd2.ansi.style` function. These and other related topics are +covered in :ref:`features/generating_output:Generating Output`. diff --git a/docs/migrating/nextsteps.rst b/docs/migrating/nextsteps.rst deleted file mode 100644 index 3f560501..00000000 --- a/docs/migrating/nextsteps.rst +++ /dev/null @@ -1,6 +0,0 @@ -Next Steps -========== - -What features (with links to details) are easy to implement next - -:doc:`Help <../features/help>` diff --git a/docs/migrating/summary.rst b/docs/migrating/summary.rst new file mode 100644 index 00000000..5bde2d0c --- /dev/null +++ b/docs/migrating/summary.rst @@ -0,0 +1,15 @@ + +.. _cmd: https://docs.python.org/3/library/cmd.html + +If you're thinking of migrating your cmd_ app to ``cmd2``, this section +will help you decide if it's right for your app, and show you how to +do it. + +* :ref:`migrating/why:Why cmd2` - we try and convince you + to use ``cmd2`` instead of cmd_ +* :ref:`migrating/incompatibilities:Incompatibilities` - ``cmd2`` is not + quite 100% compatible with cmd_. +* :ref:`migrating/minimum:Minimum Required Changes` - the minimum changes + required to move from cmd_ to ``cmd2``. Start your migration here. +* :ref:`migrating/next_steps:Next Steps` - Once you've migrated, here a list + of things you can do next to add even more functionality to your app. diff --git a/docs/migrating/why.rst b/docs/migrating/why.rst index 1561bb91..a166d648 100644 --- a/docs/migrating/why.rst +++ b/docs/migrating/why.rst @@ -1,5 +1,5 @@ -Why Migrate to cmd2 -=================== +Why cmd2 +======== .. _cmd: https://docs.python.org/3/library/cmd.html @@ -7,17 +7,19 @@ cmd --- cmd_ is the Python Standard Library's module for creating simple interactive -command-line applications. -cmd_ is an extremely bare-bones framework which leaves a lot to be desired. It -doesn't even include a built-in way to exit from an application! +command-line applications. cmd_ is an extremely bare-bones framework which +leaves a lot to be desired. It doesn't even include a built-in way to exit +from an application! Since the API provided by cmd_ provides the foundation on which ``cmd2`` is based, understanding the use of cmd_ is the first step in learning the use of ``cmd2``. Once you have read the cmd_ docs, return here to learn the ways that ``cmd2`` differs from cmd_. + cmd2 ---- + ``cmd2`` is a batteries-included extension of cmd_, which provides a wealth of functionality to make it quicker and easier for developers to create feature-rich interactive command-line applications which delight customers. @@ -30,15 +32,51 @@ further modifications. Migrating to ``cmd2`` will also open many additional doors for making it possible for developers to provide a top-notch interactive command-line experience for their users. -``cmd2`` provides a full-featured framework for creating professional-quality -interactive command-line applications. A few of the highlights of ``cmd2`` -include: -* Applications created are full-featured shells in their own right with ability - to call shell commands, redirect command output, pipe command output to shell - commands, etc. -* Superior tab-completion capabilities, especially when using included argparse - decorators -* Both Python and ASCII text application scripting is built-in -* Ability to run non-interactively for automation purposes +Free Features +------------- + +After switching from cmd_ to ``cmd2``, your application will have the following +new features and capabilities, without you having to do anything: + +- More robust :ref:`features/history:History`. Both cmd_ and ``cmd2`` have + readline history, but ``cmd2`` also has a robust ``history`` command which + allows you to edit prior commands in a text editor of your choosing, re-run + multiple commands at a time, and save prior commands as a script to be + executed later. + +- Users can redirect output to a file or pipe it to some other operating system + command. You did remember to use ``self.stdout`` instead of ``sys.stdout`` in + all of your print functions, right? If you did, then this will work out of + the box. If you didn't, you'll have to go back and fix them. Before you do, + you might consider the various ways ``cmd2`` has of + :ref:`features/generating_output:Generating Output`. + +- Users can load script files, which contain a series of commands + to be executed. + +- Users can create :ref:`features/shortcuts_aliases_macros:Shortcuts, Aliases, + and Macros` to reduce the typing required for repetitive commands. + +- Embedded python shell allows a user to execute python code from within your + ``cmd2`` app. How meta. + +- :ref:`features/clipboard:Clipboard Integration` allows you to save command + output to the operating system clipboard. + +- A built-in :ref:`features/misc:Timer` can show how long it takes a command to + execute + +- A :ref:`Transcript <features/transcripts:Transcripts>` is a file which + contains both the input and output of a successful session of a + ``cmd2``-based app. The transcript can be played back into the app as a unit + test. + + +Next Steps +---------- +In addition to the features you get with no additional work, ``cmd2`` offers a +broad range of additional capabilties which can be easily added to your +application. :ref:`migrating/next_steps:Next Steps` has some ideas of where +you can start, or you can dig in to all the :ref:`features/index:Features`. diff --git a/examples/example.py b/examples/example.py index a62c258b..b8f8202c 100755 --- a/examples/example.py +++ b/examples/example.py @@ -66,7 +66,7 @@ class CmdLineApp(cmd2.Cmd): def do_mumble(self, args): """Mumbles what you tell me to.""" repetitions = args.repeat or 1 - for i in range(min(repetitions, self.maxrepeats)): + for _ in range(min(repetitions, self.maxrepeats)): output = [] if random.random() < .33: output.append(random.choice(self.MUMBLE_FIRST)) diff --git a/examples/migrating.py b/examples/migrating.py new file mode 100644 index 00000000..3a25b8c8 --- /dev/null +++ b/examples/migrating.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# coding=utf-8 +""" +A sample application for cmd which can be used to show how to migrate to cmd2. +""" +import random + +import cmd + + +class CmdLineApp(cmd.Cmd): + """ Example cmd application. """ + + MUMBLES = ['like', '...', 'um', 'er', 'hmmm', 'ahh'] + MUMBLE_FIRST = ['so', 'like', 'well'] + MUMBLE_LAST = ['right?'] + + def do_exit(self, line): + """Exit the application""" + return True + + do_EOF = do_exit + do_quit = do_exit + + def do_speak(self, line): + """Repeats what you tell me to.""" + print(line, file=self.stdout) + + do_say = do_speak + + def do_mumble(self, line): + """Mumbles what you tell me to.""" + words = line.split(' ') + output = [] + if random.random() < .33: + output.append(random.choice(self.MUMBLE_FIRST)) + for word in words: + if random.random() < .40: + output.append(random.choice(self.MUMBLES)) + output.append(word) + if random.random() < .25: + output.append(random.choice(self.MUMBLE_LAST)) + print(' '.join(output), file=self.stdout) + + +if __name__ == '__main__': + import sys + c = CmdLineApp() + sys.exit(c.cmdloop()) |