diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index c290a81a7..8d34420d4 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -2,17 +2,14 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. +In the interest of fostering an open and welcoming environment, we as contributors and maintainers +pledge to making participation in our project and our community a harassment-free experience for +everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level +of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences @@ -22,53 +19,47 @@ include: Examples of unacceptable behavior by participants include: -- The use of sexualized language or imagery and unwelcome sexual attention or - advances +- The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment -- Publishing others' private information, such as a physical or electronic - address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting +- Publishing others' private information, such as a physical or electronic address, without explicit + permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Project maintainers are responsible for clarifying the standards of acceptable behavior and are +expected to take appropriate and fair corrective action in response to any instances of unacceptable +behavior. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, +code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or +to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be +This Code of Conduct applies both within project spaces and in public spaces when an individual is +representing the project or its community. Examples of representing a project or community include +using an official project e-mail address, posting via an official social media account, or acting as +an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at todd.leonhardt at gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting +the project team at todd.leonhardt at gmail.com. All complaints will be reviewed and investigated +and will result in a response that is deemed necessary and appropriate to the circumstances. The +project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face +temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at +[http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6d9893554..c572727aa 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,13 +1,15 @@ # Contributor's guide -We welcome pull requests from `cmd2` users and seasoned Python developers alike! Follow these steps to contribute: +We welcome pull requests from `cmd2` users and seasoned Python developers alike! Follow these steps +to contribute: -1. Find an issue that needs assistance by searching for - the [Help Wanted](https://github.com/python-cmd2/cmd2/labels/help%20wanted) tag +1. Find an issue that needs assistance by searching for the + [Help Wanted](https://github.com/python-cmd2/cmd2/labels/help%20wanted) tag 2. Let us know you're working on it by posting a comment on the issue -3. Follow the [Contribution guidelines](#contribution-guidelines) below to start working on the issue +3. Follow the [Contribution guidelines](#contribution-guidelines) below to start working on the + issue Remember to feel free to ask for help by leaving a comment within the Issue. @@ -40,16 +42,19 @@ Working on your first pull request? You can learn how from the ### Prerequisites -`cmd2` development is heavily based around using [uv](https://github.com/astral-sh/uv) for Python package and project -management as well as creating and updating a local Python virtual environment. We also rely on [npm](https://www.npmjs.com/) -for installing a few dependencies like [prettier](https://prettier.io/) for formatting non-Python files. +`cmd2` development is heavily based around using [uv](https://github.com/astral-sh/uv) for Python +package and project management as well as creating and updating a local Python virtual environment. +We also rely on [npm](https://www.npmjs.com/) for installing a few dependencies like +[prettier](https://prettier.io/) for formatting non-Python files. -We have a [Makefile](../Makefile) with commands that make it quick and easy for developers to get everything setup and -perform common development tasks. +We have a [Makefile](../Makefile) with commands that make it quick and easy for developers to get +everything setup and perform common development tasks. -Nearly all project configuration, including for dependencies and quality tools is in the [pyproject.toml](../pyproject.toml) file. +Nearly all project configuration, including for dependencies and quality tools is in the +[pyproject.toml](../pyproject.toml) file. -> _Updating to the latest releases for all prerequisites via `uv` is recommended_. This can be done with `uv lock --upgrade` followed by `uv sync`. +> _Updating to the latest releases for all prerequisites via `uv` is recommended_. This can be done +> with `uv lock --upgrade` followed by `uv sync`. #### Prerequisites to run cmd2 applications @@ -61,11 +66,13 @@ See the `dependencies` list under the `[project]` heading in [pyproject.toml](.. | [pyperclip](https://github.com/asweigart/pyperclip) | `1.8` | Cross-platform clipboard functions | | [wcwidth](https://pypi.python.org/pypi/wcwidth) | `0.2.10` | Measure the displayed width of unicode | -> `macOS` and `Windows` each have an extra dependency to ensure they have a viable alternative to [readline](https://tiswww.case.edu/php/chet/readline/rltop.html) available. +> `macOS` and `Windows` each have an extra dependency to ensure they have a viable alternative to +> [readline](https://tiswww.case.edu/php/chet/readline/rltop.html) available. #### Additional prerequisites to build and publish cmd2 -See the `build` list under the `[dependency-groups]` heading in [pyproject.toml](../pyproject.toml) for a list of dependencies needed for building `cmd2`. +See the `build` list under the `[dependency-groups]` heading in [pyproject.toml](../pyproject.toml) +for a list of dependencies needed for building `cmd2`. | Prerequisite | Minimum Version | Purpose | | -------------------------------------------------------- | --------------- | -------------------------------- | @@ -73,11 +80,13 @@ See the `build` list under the `[dependency-groups]` heading in [pyproject.toml] | [setuptools](https://pypi.org/project/setuptools/) | `72.1.0` | Python package management | | [setuptools-scm](https://github.com/pypa/setuptools-scm) | `8.0.4` | Manage your versions by scm tags | -> [twine](https://github.com/pypa/twine) 5.1 or newer is also needed for publishing releases to PyPI, but that is something only core maintainers need to worry about. +> [twine](https://github.com/pypa/twine) 5.1 or newer is also needed for publishing releases to +> PyPI, but that is something only core maintainers need to worry about. #### Additional prerequisites for developing cmd2 -See the `dev` list under the `[dependency-groups]` heading in [pyproject.toml](../pyproject.toml) for a list of dependencies needed for building `cmd2`. +See the `dev` list under the `[dependency-groups]` heading in [pyproject.toml](../pyproject.toml) +for a list of dependencies needed for building `cmd2`. | Prerequisite | Minimum Version | Purpose | | ------------------------------------------------------------------------------------------ | --------------- | -------------------------------- | @@ -103,9 +112,10 @@ $ pip freeze | grep pyperclip If your versions are lower than the prerequisite versions, you should update. -If you do not already have Python installed on your machine, we recommend using [uv](https://github.com/astral-sh/uv) -for all of your Python needs because it is extremely fast, meets all Python installation and packaging needs, and works -on all platforms (Windows, Mac, and Linux). You can install `uv` using instructions at the link above. +If you do not already have Python installed on your machine, we recommend using +[uv](https://github.com/astral-sh/uv) for all of your Python needs because it is extremely fast, +meets all Python installation and packaging needs, and works on all platforms (Windows, Mac, and +Linux). You can install `uv` using instructions at the link above. You can then install multiple versions of Python using `uv` like so: @@ -117,24 +127,27 @@ uv python install 3.10 3.11 3.12 3.13 #### Setting up your system -1. Install [Git](https://git-scm.com/) or your favorite Git client. If you aren't comfortable with Git at the - command-line, then both [SmartGit](http://www.syntevo.com/smartgit/) and [GitKraken](https://www.gitkraken.com) are - excellent cross-platform graphical Git clients. -2. (Optional) [Set up an SSH key](https://help.github.com/articles/generating-an-ssh-key/) for GitHub. -3. Create a parent projects directory on your system. For this guide, it will be assumed that it is `~/src`. +1. Install [Git](https://git-scm.com/) or your favorite Git client. If you aren't comfortable with + Git at the command-line, then both [SmartGit](http://www.syntevo.com/smartgit/) and + [GitKraken](https://www.gitkraken.com) are excellent cross-platform graphical Git clients. +2. (Optional) [Set up an SSH key](https://help.github.com/articles/generating-an-ssh-key/) for + GitHub. +3. Create a parent projects directory on your system. For this guide, it will be assumed that it is + `~/src`. #### Forking cmd2 1. Go to the top-level cmd2 repository: 2. Click the "Fork" button in the upper right hand corner of the interface ([more details here](https://help.github.com/articles/fork-a-repo/)) -3. After the repository has been forked, you will be taken to your copy of the cmd2 repo at `yourUsername/cmd2` +3. After the repository has been forked, you will be taken to your copy of the cmd2 repo at + `yourUsername/cmd2` #### Cloning your fork 1. Open a terminal / command line / Bash shell in your projects directory (_e.g.: `~/src/`_) -2. Clone your fork of cmd2, making sure to replace `yourUsername` with your GitHub username. This will download the - entire cmd2 repo to your projects directory. +2. Clone your fork of cmd2, making sure to replace `yourUsername` with your GitHub username. This + will download the entire cmd2 repo to your projects directory. ```sh $ git clone https://github.com/yourUsername/cmd2.git @@ -179,8 +192,8 @@ Do this prior to every time you create a branch for a PR: > $ git pull --rebase upstream master > ``` -> This will pull down all of the changes to the official master branch, without making an additional commit in your -> local repo. +> This will pull down all of the changes to the official master branch, without making an additional +> commit in your local repo. 3. (_Optional_) Force push your updated master branch to your GitHub fork @@ -192,14 +205,14 @@ Do this prior to every time you create a branch for a PR: ### Creating a branch -Before you start working, you will need to create a separate branch specific to the issue or feature you're working on. -You will push your work to this branch. +Before you start working, you will need to create a separate branch specific to the issue or feature +you're working on. You will push your work to this branch. #### Naming your branch -Name the branch something like `fix/xxx` or `feature/xxx` where `xxx` is a short description of the changes or feature -you are attempting to add. For example `fix/script-files` would be a branch where you fix something specific to script -files. +Name the branch something like `fix/xxx` or `feature/xxx` where `xxx` is a short description of the +changes or feature you are attempting to add. For example `fix/script-files` would be a branch where +you fix something specific to script files. #### Adding your branch @@ -221,18 +234,20 @@ _[this](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git ### Setting up for cmd2 development -For doing `cmd2` development, it is strongly recommended you create a virtual environment `uv` using the instructions in the next section. +For doing `cmd2` development, it is strongly recommended you create a virtual environment `uv` using +the instructions in the next section. #### Create a new environment for cmd2 using uv `cmd2` has support for using [uv](https://github.com/astral-sh/uv) for development. -`uv` is single tool to replace `pip`, `pip-tools`, `pipx`, `poetry`, `pyenv`, `twine`, `virtualenv`, and more. `cmd2` -contains configuration for using `uv` in it's `pyproject.toml` file which makes it extremely easy to setup a `cmd2` -development environment using `uv`. +`uv` is single tool to replace `pip`, `pip-tools`, `pipx`, `poetry`, `pyenv`, `twine`, `virtualenv`, +and more. `cmd2` contains configuration for using `uv` in it's `pyproject.toml` file which makes it +extremely easy to setup a `cmd2` development environment using `uv`. -To create a virtual environment using the latest stable version of Python and install everything needed for `cmd2` development using `uv`, -do the following from the root of your cloned `cmd2` repository: +To create a virtual environment using the latest stable version of Python and install everything +needed for `cmd2` development using `uv`, do the following from the root of your cloned `cmd2` +repository: ```sh make install @@ -240,8 +255,8 @@ make install This will also install the recommended Git pre-commit hooks for auto-formatting and linting locally. -To create a new virtualenv, using a specific version of Python you have installed, use the ---python VERSION flag, like so: +To create a new virtualenv, using a specific version of Python you have installed, use the --python +VERSION flag, like so: ```sh uv venv --python 3.12 @@ -253,29 +268,32 @@ Then you can run commands in this isolated virtual environment using `uv` like s uv run examples/basic.py ``` -Alternatively you can activate the virtual environment using the OS-specific command such as this on Linux or macOS: +Alternatively you can activate the virtual environment using the OS-specific command such as this on +Linux or macOS: ```sh source .venv/bin/activate ``` -Assuming you cloned the repository to `~/src/cmd2` and setup a virtual environment using `uv`, `cmd2` in this venv in -[editable mode](https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs). -Changes to the source code are immediately available when the python interpreter -imports `cmd2`, there is no need to re-install the module after every change. This -command will also install all of the runtime dependencies for `cmd2` and modules used for development of `cmd2`: +Assuming you cloned the repository to `~/src/cmd2` and setup a virtual environment using `uv`, +`cmd2` in this venv in +[editable mode](https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs). Changes to +the source code are immediately available when the python interpreter imports `cmd2`, there is no +need to re-install the module after every change. This command will also install all of the runtime +dependencies for `cmd2` and modules used for development of `cmd2`: ```sh $ cd ~/src/cmd2 $ uv venv ``` -This project uses many python modules for various development tasks, including -testing, rendering documentation, and building and distributing releases. These -modules can be configured many different ways, which can make it difficult to -learn the specific incantations required for each project you're familiar with. +This project uses many python modules for various development tasks, including testing, rendering +documentation, and building and distributing releases. These modules can be configured many +different ways, which can make it difficult to learn the specific incantations required for each +project you're familiar with. -This project uses [make]() to provide a clean, high-level interface for these development tasks. To see the full list of make commands available: +This project uses [make]() to provide a clean, high-level interface for these development tasks. To +see the full list of make commands available: ```sh $ make help @@ -287,9 +305,11 @@ You can run multiple make commands in a single invocation, for example:: $ make test docs-test ``` -That one command will run all unit and integration tests and also ensure the documentation builds without any warnings. +That one command will run all unit and integration tests and also ensure the documentation builds +without any warnings. -If you want to see the details about what any of these commands are doing under the hood, just look at the [Makefile](../Makefile). +If you want to see the details about what any of these commands are doing under the hood, just look +at the [Makefile](../Makefile). Now you can check if everything is installed and working: @@ -298,8 +318,9 @@ $ cd ~src/cmd2 $ make check ``` -This will run all auto-formatters, linters, and type checkers to ensure code quality. You should run this every time before committing any code. -If this all runs successfully, then your virtual environment is setup and working properly. +This will run all auto-formatters, linters, and type checkers to ensure code quality. You should run +this every time before committing any code. If this all runs successfully, then your virtual +environment is setup and working properly. You can also run the example app and see a prompt that says "(Cmd)" running the command: @@ -307,11 +328,11 @@ You can also run the example app and see a prompt that says "(Cmd)" running the $ uv run examples/example.py ``` -You can type `help` to get help or `quit` to quit. If you see that, then congratulations -– you're all set. Otherwise, refer to the -cmd2 [installation instructions](https://cmd2.readthedocs.io/en/latest/overview/installation.html). -There also might be an error in the console of your Bash / terminal / command line -that will help identify the problem. +You can type `help` to get help or `quit` to quit. If you see that, then congratulations – you're +all set. Otherwise, refer to the cmd2 +[installation instructions](https://cmd2.readthedocs.io/en/latest/overview/installation.html). There +also might be an error in the console of your Bash / terminal / command line that will help identify +the problem. ### Making changes @@ -319,18 +340,17 @@ This bit is up to you! #### How to find code in the cmd2 codebase to fix/edit -The cmd2 project directory structure is pretty simple and straightforward. All -actual code for cmd2 is located underneath the `cmd2` directory. The code to -generate the documentation is in the `docs` directory. Unit tests are in the -`tests` directory. Integration tests are in the `tests_isolated` directory. -The `examples` directory contains examples of how to use cmd2. There are various -other files in the root directory, but these are primarily related to continuous -integration and release deployment. +The cmd2 project directory structure is pretty simple and straightforward. All actual code for cmd2 +is located underneath the `cmd2` directory. The code to generate the documentation is in the `docs` +directory. Unit tests are in the `tests` directory. Integration tests are in the `tests_isolated` +directory. The `examples` directory contains examples of how to use cmd2. There are various other +files in the root directory, but these are primarily related to continuous integration and release +deployment. #### Changes to the documentation files -If you made changes to any file in the `/docs` directory, you need to build the -MkDocs documentation and make sure your changes look good: +If you made changes to any file in the `/docs` directory, you need to build the MkDocs documentation +and make sure your changes look good: ```sh $ make docs-test @@ -338,26 +358,28 @@ $ make docs-test In order to see the changes, use your web browser of choice to open `~/cmd2/build/html/index.html`. -If you would rather use a webserver to view the documentation, including -automatic page refreshes as you edit the files, use: +If you would rather use a webserver to view the documentation, including automatic page refreshes as +you edit the files, use: ```sh $ make docs ``` -You will be shown the IP address and port number where the documents are now -served, usually [http://127.0.0.1:8000/](http://127.0.0.1:8000/). +You will be shown the IP address and port number where the documents are now served, usually +[http://127.0.0.1:8000/](http://127.0.0.1:8000/). ### Code Quality Checks -You should have idiomatic formatters and linters running in your IDE or at the command line before you commit code. -`cmd2` uses [ruff](https://github.com/astral-sh/ruff) as part of its continuous integration (CI) process for both linting and auto-formatting of -Python code. It also uses [prettier](https://prettier.io/) for auto-formatting other file types and [mypy](https://mypy-lang.org/) for doing -static type checking of Python code based on type annotations. +You should have idiomatic formatters and linters running in your IDE or at the command line before +you commit code. `cmd2` uses [ruff](https://github.com/astral-sh/ruff) as part of its continuous +integration (CI) process for both linting and auto-formatting of Python code. It also uses +[prettier](https://prettier.io/) for auto-formatting other file types and +[mypy](https://mypy-lang.org/) for doing static type checking of Python code based on type +annotations. -> Please do not ignore any linting errors in code you write or modify, as they are meant to **help** you and to ensure a -> clean and simple code base. Don't worry about linting errors in code you don't touch though - cleaning up the legacy -> code is a work in progress. +> Please do not ignore any linting errors in code you write or modify, as they are meant to **help** +> you and to ensure a clean and simple code base. Don't worry about linting errors in code you don't +> touch though - cleaning up the legacy code is a work in progress. You can quickly run all code quality stuff in one fell swoop using: @@ -400,35 +422,36 @@ $ make test and ensure all tests pass. -Running the test suite also calculates test code coverage. A summary of coverage -is shown on the screen. A full report is available in `~/cmd2/htmlcov/index.html`. +Running the test suite also calculates test code coverage. A summary of coverage is shown on the +screen. A full report is available in `~/cmd2/htmlcov/index.html`. ### Squashing your commits -While squashing your commits is best practice, don't worry about it. We do this automatically when we merge in Pull Requests (PRs). +While squashing your commits is best practice, don't worry about it. We do this automatically when +we merge in Pull Requests (PRs). -If you want to understand how to do this manually, see [this article](http://forum.freecodecamp.com/t/how-to-squash-multiple-commits-into-one-with-git/13231). +If you want to understand how to do this manually, see +[this article](http://forum.freecodecamp.com/t/how-to-squash-multiple-commits-into-one-with-git/13231). ### Creating a pull request #### What is a pull request? -A pull request (PR) is a method of submitting proposed changes to the cmd2 -repo (or any repo, for that matter). You will make changes to copies of the -files which make up cmd2 in a personal fork, then apply to have them -accepted by cmd2 proper. +A pull request (PR) is a method of submitting proposed changes to the cmd2 repo (or any repo, for +that matter). You will make changes to copies of the files which make up cmd2 in a personal fork, +then apply to have them accepted by cmd2 proper. #### Need help? -GitHub has a good guide on how to contribute to open source [here](https://opensource.guide/how-to-contribute/). +GitHub has a good guide on how to contribute to open source +[here](https://opensource.guide/how-to-contribute/). #### Important: ALWAYS EDIT ON A BRANCH -If you take away only one thing from this document, it should be this: Never, **EVER** -make edits to the `master` branch. ALWAYS make a new branch BEFORE you edit -files. This is critical, because if your PR is not accepted, your copy of -master will be forever sullied and the only way to fix it is to delete your -fork and re-fork. +If you take away only one thing from this document, it should be this: Never, **EVER** make edits to +the `master` branch. ALWAYS make a new branch BEFORE you edit files. This is critical, because if +your PR is not accepted, your copy of master will be forever sullied and the only way to fix it is +to delete your fork and re-fork. #### Methods @@ -439,8 +462,8 @@ There are two methods of creating a pull request for cmd2: ##### Method 1: Editing via your local fork _(recommended)_ -This is the recommended method. Read about [how to set up and maintain a local -instance of cmd2](#maintaining-your-fork). +This is the recommended method. Read about +[how to set up and maintain a local instance of cmd2](#maintaining-your-fork). 1. Perform the maintenance step of rebasing `master` 2. Ensure you're on the `master` branch using `git status`: @@ -453,23 +476,24 @@ Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean ``` -1. If you're not on master or your working directory is not clean, resolve - any outstanding files/commits and checkout master `git checkout master` +1. If you're not on master or your working directory is not clean, resolve any outstanding + files/commits and checkout master `git checkout master` -2. Create a branch off of `master` with git: `git checkout -B -branch/name-here` **Note:** Branch naming is important. Use a name like - `fix/short-fix-description` or `feature/short-feature-description`. Review - the [Contribution Guidelines](#contribution-guidelines) for more detail. +2. Create a branch off of `master` with git: `git checkout -B branch/name-here` **Note:** Branch + naming is important. Use a name like `fix/short-fix-description` or + `feature/short-feature-description`. Review the + [Contribution Guidelines](#contribution-guidelines) for more detail. 3. Edit your file(s) locally with the editor of your choice 4. Check your `git status` to see unstaged files -5. Add your edited files: `git add path/to/filename.ext` You can also do: `git -add .` to add all unstaged files. Take care, though, because you can - accidentally add files you don't want added. Review your `git status` first. +5. Add your edited files: `git add path/to/filename.ext` You can also do: `git add .` to add all + unstaged files. Take care, though, because you can accidentally add files you don't want added. + Review your `git status` first. -6. Commit your edits: `git commit -m "Brief description of commit"`. Do not add the issue number in the commit message. +6. Commit your edits: `git commit -m "Brief description of commit"`. Do not add the issue number in + the commit message. 7. Squash your commits, if there are more than one @@ -479,37 +503,33 @@ add .` to add all unstaged files. Take care, though, because you can ##### Method 2: Editing via the GitHub interface -Note: Editing via the GitHub Interface is not recommended, since it is not -possible to update your fork via GitHub's interface without deleting and -recreating your fork. +Note: Editing via the GitHub Interface is not recommended, since it is not possible to update your +fork via GitHub's interface without deleting and recreating your fork. -If you really want to go this route (which isn't recommended), you can Google for more information on -how to do it. +If you really want to go this route (which isn't recommended), you can Google for more information +on how to do it. ### Common steps -1. Once the edits have been committed, you will be prompted to create a pull - request on your fork's GitHub page +1. Once the edits have been committed, you will be prompted to create a pull request on your fork's + GitHub page -2. By default, all pull requests should be against the cmd2 main repo, `master` - branch +2. By default, all pull requests should be against the cmd2 main repo, `master` branch 3. Submit a pull request from your branch to cmd2's `master` branch -4. The title (also called the subject) of your PR should be descriptive of your - changes and succinctly indicate what is being fixed +4. The title (also called the subject) of your PR should be descriptive of your changes and + succinctly indicate what is being fixed - **Do not add the issue number in the PR title or commit message** - Examples: `Add test cases for Unicode support`; `Correct typo in overview documentation` -5. In the body of your PR include a more detailed summary of the changes you - made and why +5. In the body of your PR include a more detailed summary of the changes you made and why - - If the PR is meant to fix an existing bug/issue, then, at the end of - your PR's description, append the keyword `closes` and #xxxx (where xxxx - is the issue number). Example: `closes #1337`. This tells GitHub to - close the existing issue if the PR is merged. + - If the PR is meant to fix an existing bug/issue, then, at the end of your PR's description, + append the keyword `closes` and #xxxx (where xxxx is the issue number). Example: + `closes #1337`. This tells GitHub to close the existing issue if the PR is merged. 6. Indicate what local testing you have done (e.g. what OS and version(s) of Python did you run the unit test suite with) @@ -525,28 +545,31 @@ how to do it. ### How we review and merge pull requests -cmd2 has a team of volunteer Maintainers. These Maintainers routinely go through open pull requests in a process -called [Quality Assurance](https://en.wikipedia.org/wiki/Quality_assurance) (QA). We use [GitHub Actions](https://github.com/features/actions) -to automatically run all of the unit tests on multiple operating systems and versions of Python and to also run the code quality checks -on at least one version of Python. +cmd2 has a team of volunteer Maintainers. These Maintainers routinely go through open pull requests +in a process called [Quality Assurance](https://en.wikipedia.org/wiki/Quality_assurance) (QA). We +use [GitHub Actions](https://github.com/features/actions) to automatically run all of the unit tests +on multiple operating systems and versions of Python and to also run the code quality checks on at +least one version of Python. -1. If your changes can merge without conflicts and all unit tests pass for all OSes and supported versions of Python, - then your pull request (PR) will have a big green checkbox which says something like "All Checks Passed" next to it. - If this is not the case, there will be a link you can click on to get details regarding what the problem is. - It is your responsibility to make sure all unit tests are passing. Generally a Maintainer will not QA a - pull request unless it can merge without conflicts and all unit tests pass on all supported platforms. +1. If your changes can merge without conflicts and all unit tests pass for all OSes and supported + versions of Python, then your pull request (PR) will have a big green checkbox which says + something like "All Checks Passed" next to it. If this is not the case, there will be a link you + can click on to get details regarding what the problem is. It is your responsibility to make sure + all unit tests are passing. Generally a Maintainer will not QA a pull request unless it can merge + without conflicts and all unit tests pass on all supported platforms. -2. If a Maintainer QA's a pull request and confirms that the new code does what it is supposed to do without seeming to - introduce any new bugs, - and doesn't present any backward compatibility issues, they will merge the pull request. +2. If a Maintainer QA's a pull request and confirms that the new code does what it is supposed to do + without seeming to introduce any new bugs, and doesn't present any backward compatibility issues, + they will merge the pull request. -If you would like to apply to join our Maintainer team, message [@tleonhardt](https://github.com/tleonhardt) with links -to 5 of your pull requests that have been accepted. +If you would like to apply to join our Maintainer team, message +[@tleonhardt](https://github.com/tleonhardt) with links to 5 of your pull requests that have been +accepted. ### How we close stale issues -We will close any issues that have been inactive for more than 60 days or pull requests that have been -inactive for more than 30 days, except those that match any of the following criteria: +We will close any issues that have been inactive for more than 60 days or pull requests that have +been inactive for more than 30 days, except those that match any of the following criteria: - bugs that are confirmed - pull requests that are waiting on other pull requests to be merged @@ -556,25 +579,24 @@ inactive for more than 30 days, except those that match any of the following cri #### If your PR is accepted -Once your PR is accepted, you may delete the branch you created to submit it. -This keeps your working fork clean. +Once your PR is accepted, you may delete the branch you created to submit it. This keeps your +working fork clean. -You can do this with a press of a button on the GitHub PR interface. You can -delete the local copy of the branch with: `git branch -D branch/to-delete-name` +You can do this with a press of a button on the GitHub PR interface. You can delete the local copy +of the branch with: `git branch -D branch/to-delete-name` #### If your PR is rejected -Don't despair! You should receive solid feedback from the Maintainers as to -why it was rejected and what changes are needed. +Don't despair! You should receive solid feedback from the Maintainers as to why it was rejected and +what changes are needed. -Many pull requests, especially first pull requests, require correction or -updating. If you have used the GitHub interface to create your PR, you will need -to close your PR, create a new branch, and re-submit. +Many pull requests, especially first pull requests, require correction or updating. If you have used +the GitHub interface to create your PR, you will need to close your PR, create a new branch, and +re-submit. -If you have a local copy of the repo, you can make the requested changes and -amend your commit with: `git commit --amend` This will update your existing -commit. When you push it to your fork you will need to do a force push to -overwrite your old commit: `git push --force` +If you have a local copy of the repo, you can make the requested changes and amend your commit with: +`git commit --amend` This will update your existing commit. When you push it to your fork you will +need to do a force push to overwrite your old commit: `git push --force` Be sure to post in the PR conversation that you have made the requested changes. @@ -588,58 +610,79 @@ Be sure to post in the PR conversation that you have made the requested changes. ### Advice -Here is some advice regarding what makes a good pull request (PR) from the perspective of the cmd2 maintainers: +Here is some advice regarding what makes a good pull request (PR) from the perspective of the cmd2 +maintainers: -- Multiple smaller PRs divided by topic are better than a single large PR containing a bunch of unrelated changes +- Multiple smaller PRs divided by topic are better than a single large PR containing a bunch of + unrelated changes - Maintaining backward compatibility is important - Good unit/functional tests are very important - Accurate documentation is also important -- Adding new features is of the lowest importance, behind bug fixes, unit test additions/improvements, code cleanup, and - documentation -- It's best to create a dedicated branch for a PR, use it only for that PR, and delete it once the PR has been merged -- It's good if the branch name is related to the PR contents, even if it's just "fix123" or "add_more_tests" +- Adding new features is of the lowest importance, behind bug fixes, unit test + additions/improvements, code cleanup, and documentation +- It's best to create a dedicated branch for a PR, use it only for that PR, and delete it once the + PR has been merged +- It's good if the branch name is related to the PR contents, even if it's just "fix123" or + "add_more_tests" - Code coverage of the unit tests matters, so try not to decrease it -- Think twice before adding dependencies to third-party libraries (outside of the Python standard library) because it - could affect a lot of users +- Think twice before adding dependencies to third-party libraries (outside of the Python standard + library) because it could affect a lot of users ### Developing in an IDE -We recommend using [Visual Studio Code](https://code.visualstudio.com) with -the [Python extension](https://code.visualstudio.com/docs/languages/python) and -its [Integrated Terminal](https://code.visualstudio.com/docs/python/debugging) debugger for debugging since it has -excellent support for debugging console applications. +We recommend using [Visual Studio Code](https://code.visualstudio.com) with the +[Python extension](https://code.visualstudio.com/docs/languages/python) and its +[Integrated Terminal](https://code.visualstudio.com/docs/python/debugging) debugger for debugging +since it has excellent support for debugging console applications. -[PyCharm](https://www.jetbrains.com/pycharm/) is also quite good and has very -nice [code inspection](https://www.jetbrains.com/help/pycharm/code-inspection.html) capabilities. +[PyCharm](https://www.jetbrains.com/pycharm/) is also quite good and has very nice +[code inspection](https://www.jetbrains.com/help/pycharm/code-inspection.html) capabilities. #### PyCharm Settings -One of the best things about **PyCharm** is that it "just works" with essentially no configuration tweaks required. The -default out-of-the-box experience is excellent. +One of the best things about **PyCharm** is that it "just works" with essentially no configuration +tweaks required. The default out-of-the-box experience is excellent. -The one plugin we consider essential for PyCharm is [RyeCharm](https://plugins.jetbrains.com/plugin/25230-ryecharm). `RyeCharm` is an all-in-one PyCharm plugin for [Astral](https://astral.sh/)-backed Python tools: [uv](https://github.com/astral-sh/uv), [Ruff](https://github.com/astral-sh/ruff), and [ty](https://github.com/astral-sh/ty). NOTE: `ty` support is provisional as that new type checker is in early alpha developement. +The one plugin we consider essential for PyCharm is +[RyeCharm](https://plugins.jetbrains.com/plugin/25230-ryecharm). `RyeCharm` is an all-in-one PyCharm +plugin for [Astral](https://astral.sh/)-backed Python tools: [uv](https://github.com/astral-sh/uv), +[Ruff](https://github.com/astral-sh/ruff), and [ty](https://github.com/astral-sh/ty). NOTE: `ty` +support is provisional as that new type checker is in early alpha developement. #### VSCode Settings -While **VSCode** is a phenomenal IDE for developing in Python, the out-of-the-box experience leaves a lot to be desired. You will need to install a -number of extenstions and tweak the default configuration for many of them in order to get an optimal developer experience. +While **VSCode** is a phenomenal IDE for developing in Python, the out-of-the-box experience leaves +a lot to be desired. You will need to install a number of extenstions and tweak the default +configuration for many of them in order to get an optimal developer experience. Recommended VSCode extensions: -- [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) - Python language support with extension access points for IntelliSense (Pylance), Debugging (Python Debugger), linting, formatting, etc. -- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Code formatter for Markdown and YAML files -- [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) - Supercharges Git support in VSCode -- [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) - YAML language support -- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - Spell checker for source code -- [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) - All you need to write Markdown (keyboard shortcuts, table of contents, auto preview and more) -- [Makefile Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.makefile-tools) - Provide makefile support in VS Code -- [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) - Fully-featured TOML support -- [Markdown Preview Mermaid Support](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-mermaid) - Adds Mermaid diagram and flowchart support to VS Code's builtin markdown preview -- [Ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff) - Support for the Ruff linter and formatter +- [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) - Python language + support with extension access points for IntelliSense (Pylance), Debugging (Python Debugger), + linting, formatting, etc. +- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Code + formatter for Markdown and YAML files +- [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) - Supercharges Git + support in VSCode +- [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) - YAML language + support +- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - + Spell checker for source code +- [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) - + All you need to write Markdown (keyboard shortcuts, table of contents, auto preview and more) +- [Makefile Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.makefile-tools) - + Provide makefile support in VS Code +- [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) - + Fully-featured TOML support +- [Markdown Preview Mermaid Support](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-mermaid) - + Adds Mermaid diagram and flowchart support to VS Code's builtin markdown preview +- [Ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff) - Support for the + Ruff linter and formatter Depending on what file types you are editing, you may only need a subset of those extensions. -Here is an example of what your `User Settings JSON` file in VSCode might look like for a good experience, take it as a starting point and tweak as you see fit +Here is an example of what your `User Settings JSON` file in VSCode might look like for a good +experience, take it as a starting point and tweak as you see fit ```json { @@ -713,19 +756,19 @@ Given a version number `MAJOR`.`MINOR`.`PATCH`, increment the: ### Branching Strategy -We use the **master** branch for the upcoming `PATCH` release - i.e. if the current version -of `cmd2` is 1.0.2, then the **master** branch contains code which is planned for release -in 1.0.3. +We use the **master** branch for the upcoming `PATCH` release - i.e. if the current version of +`cmd2` is 1.0.2, then the **master** branch contains code which is planned for release in 1.0.3. -If work needs to be done for a `MAJOR` or `MINOR` release when we anticipate there will be -a `PATCH` release in-between, then a branch should be created named for the appropriate version -number for the work, e.g. if the current release of `cmd2` is 1.0.2 and a backwards-incompatible -change needs to be committed for an upcoming `MAJOR` release, then this work should be committed -to a **2.0.0** branch until such a time as we are ready to release version 2.0.0. +If work needs to be done for a `MAJOR` or `MINOR` release when we anticipate there will be a `PATCH` +release in-between, then a branch should be created named for the appropriate version number for the +work, e.g. if the current release of `cmd2` is 1.0.2 and a backwards-incompatible change needs to be +committed for an upcoming `MAJOR` release, then this work should be committed to a **2.0.0** branch +until such a time as we are ready to release version 2.0.0. Following this strategy, releases are always done from the **master** branch and `MAJOR` or `MINOR` -branches are merged to **master** immediately prior to doing a release. Once merged to **master**, the -other branches can be deleted. All releases are tagged so that they can be reproduced if necessary. +branches are merged to **master** immediately prior to doing a release. Once merged to **master**, +the other branches can be deleted. All releases are tagged so that they can be reproduced if +necessary. ## Publishing a new release @@ -738,10 +781,11 @@ mostly automated. The manual steps are all git operations. Here's the checklist: 1. Make sure `CHANGELOG.md` describes the version and has the correct release date 1. Add a git tag representing the version number using `invoke tag x.y.z` - Where x, y, and z are all small non-negative integers -1. (Optional) Run `invoke pypi-test` to clean, build, and upload a new release to [Test PyPi](https://test.pypi.org) +1. (Optional) Run `invoke pypi-test` to clean, build, and upload a new release to + [Test PyPi](https://test.pypi.org) 1. Run `invoke pypi` to clean, build, and upload a new release to [PyPi](https://pypi.org/) ## Acknowledgement -Thanks to the good folks at [freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) for creating -an excellent `CONTRIBUTING` file which we have borrowed heavily from. +Thanks to the good folks at [freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) for +creating an excellent `CONTRIBUTING` file which we have borrowed heavily from. diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a103561d2..4db4c3155 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,7 +39,8 @@ jobs: run: uv run python -m pytest --cov --cov-config=pyproject.toml --cov-report=xml tests - name: Run isolated tests - run: uv run python -m pytest --cov --cov-config=pyproject.toml --cov-report=xml tests_isolated + run: + uv run python -m pytest --cov --cov-config=pyproject.toml --cov-report=xml tests_isolated - name: Upload test results to Codecov if: ${{ !cancelled() }} diff --git a/.prettierrc b/.prettierrc index d903366cd..d87cca677 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,6 @@ { + "printWidth": 100, + "proseWrap": "always", "overrides": [ { "files": "*.md", diff --git a/CHANGELOG.md b/CHANGELOG.md index 8121a551e..d8b19c04b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.6.2 (June TBD, 2025) + +- Bug Fixes + - TBD + ## 2.6.1 (June 8, 2025) - Bug Fixes @@ -25,7 +30,8 @@ ## 2.5.9 (January 17, 2025) - Bug Fixes - - Fixed 'index out of range' error when passing no arguments to an argparse-based command function. + - Fixed 'index out of range' error when passing no arguments to an argparse-based command + function. ## 2.5.8 (December 17, 2024) @@ -41,8 +47,8 @@ ## 2.5.6 (November 14, 2024) - Bug Fixes - - Fixed type hint for `with_default_category` decorator which caused type checkers to mistype - a subclass of `CommandSet` as a plain `CommandSet`. + - Fixed type hint for `with_default_category` decorator which caused type checkers to mistype a + subclass of `CommandSet` as a plain `CommandSet`. ## 2.5.5 (November 13, 2024) @@ -58,14 +64,15 @@ ## 2.5.3 (November 5, 2024) - Enhancements - - Changed `CommandSet._cmd` to a read-only property which never returns `None` because it - is meant to be called after the `CommandSet` is registered. This addresses type checker - errors that occurred if `CommandSet._cmd` wasn't cast or checked if `None` before use. + - Changed `CommandSet._cmd` to a read-only property which never returns `None` because it is + meant to be called after the `CommandSet` is registered. This addresses type checker errors + that occurred if `CommandSet._cmd` wasn't cast or checked if `None` before use. ## 2.5.2 (November 3, 2024) - Bug Fixes - - Fixed default `pytest` execution when not using cmd2's custom `invoke` command via `inv pytest` + - Fixed default `pytest` execution when not using cmd2's custom `invoke` command via + `inv pytest` ## 2.5.1 (November 2, 2024) @@ -79,15 +86,18 @@ - Bug Fixes - Fixed issue where persistent history file was not saved upon SIGHUP and SIGTERM signals. - Multiline commands are no longer fragmented in up-arrow history. - - Fixed bug where `async_alert()` overwrites readline's incremental and non-incremental search prompts. + - Fixed bug where `async_alert()` overwrites readline's incremental and non-incremental search + prompts. - This fix introduces behavior where an updated prompt won't display after an aborted search - until a user presses Enter. - See [async_printing.py](https://github.com/python-cmd2/cmd2/blob/master/examples/async_printing.py) - example for how to handle this case using `Cmd.need_prompt_refresh()` and `Cmd.async_refresh_prompt()`. -- Enhancements - - Removed dependency on `attrs` and replaced with [dataclasses](https://docs.python.org/3/library/dataclasses.html) - - add `allow_clipboard` initialization parameter and attribute to disable ability to - add output to the operating system clipboard + until a user presses Enter. See + [async_printing.py](https://github.com/python-cmd2/cmd2/blob/master/examples/async_printing.py) + example for how to handle this case using `Cmd.need_prompt_refresh()` and + `Cmd.async_refresh_prompt()`. +- Enhancements + - Removed dependency on `attrs` and replaced with + [dataclasses](https://docs.python.org/3/library/dataclasses.html) + - add `allow_clipboard` initialization parameter and attribute to disable ability to add output + to the operating system clipboard - Updated unit tests to be Python 3.13 compliant. - Fall back to bz2 compression of history file when lzma is not installed. - Added settable called `scripts_add_to_history` which determines whether scripts and pyscripts @@ -101,12 +111,14 @@ - Fixed ValueError caused when passing `Cmd.columnize()` strings wider than `display_width`. - Enhancements - Renamed `utils.str_to_bool()` -> `utils.to_bool()`. - - Enhanced `utils.to_bool()` so that it accepts and converts `bool`, `int`, and `float` in addition to `str`. + - Enhanced `utils.to_bool()` so that it accepts and converts `bool`, `int`, and `float` in + addition to `str`. ## 2.4.2 (July 13, 2022) - Enhancements - - Updated argparse decorator to remove annotations when the docstring is used for a command's help text. + - Updated argparse decorator to remove annotations when the docstring is used for a command's + help text. - Updated unit test to be Python 3.11 compliant. ## 2.4.1 (April 13, 2022) @@ -128,7 +140,8 @@ - cmd2 now uses pyreadline3 when running any version of Python on Windows - Improved memory usage in certain use cases of tables (e.g. nested colored tables) - Deletions (potentially breaking changes) - - Deleted `cmd2.fg` and `cmd2.bg` which were deprecated in 2.3.0. Use `cmd2.Fg` and `cmd2.Bg` instead. + - Deleted `cmd2.fg` and `cmd2.bg` which were deprecated in 2.3.0. Use `cmd2.Fg` and `cmd2.Bg` + instead. ## 2.3.3 (November 29, 2021) @@ -138,18 +151,20 @@ ## 2.3.2 (November 22, 2021) - Bug Fixes - - Fixed issue where a `ns_provider` could be passed `None` instead of its correct `cmd2.Cmd` or `CommandSet` value. + - Fixed issue where a `ns_provider` could be passed `None` instead of its correct `cmd2.Cmd` or + `CommandSet` value. ## 2.3.1 (November 18, 2021) - Bug Fixes - - Fixed issue introduced in 2.3.0 with `AlternatingTable`, `BorderedTable`, and `SimpleTable` that caused - header alignment settings to be overridden by data alignment settings. + - Fixed issue introduced in 2.3.0 with `AlternatingTable`, `BorderedTable`, and `SimpleTable` + that caused header alignment settings to be overridden by data alignment settings. - Enhancements - `CompletionItems` now saves the original object from which it creates a string. - - Using `CompletionItems` as argparse choices is fully supported. `cmd2` patched `argparse` to compare input to - the original value instead of the `CompletionItems` instance. - - `ArgparseCompleter` now does the following if a list of `CompletionItems` was created with numerical types: + - Using `CompletionItems` as argparse choices is fully supported. `cmd2` patched `argparse` to + compare input to the original value instead of the `CompletionItems` instance. + - `ArgparseCompleter` now does the following if a list of `CompletionItems` was created with + numerical types: - Sorts completion hints numerically - Right-aligns the left-most column in completion hint table @@ -157,15 +172,18 @@ - Bug Fixes - Fixed `AttributeError` in `rl_get_prompt()` when prompt is `None`. - - Fixed bug where using choices on a Settable didn't verify that a valid choice had been entered. - - Fixed bug introduced in cmd2 2.0.0 in which `select()` converts return values to strings. It should never - have converted return values. + - Fixed bug where using choices on a Settable didn't verify that a valid choice had been + entered. + - Fixed bug introduced in cmd2 2.0.0 in which `select()` converts return values to strings. It + should never have converted return values. - Enhancements - Added settings to Column class which prevent a table from overriding existing styles in header - and/or data text. This allows for things like nesting an AlternatingTable in another AlternatingTable. - - AlternatingTable no longer automatically applies background color to borders. This was done to improve - appearance since the background color extended beyond the borders of the table. - - Added ability to colorize all aspects of `AlternatingTable`, `BorderedTable`, and `SimpleTable`. + and/or data text. This allows for things like nesting an AlternatingTable in another + AlternatingTable. + - AlternatingTable no longer automatically applies background color to borders. This was done to + improve appearance since the background color extended beyond the borders of the table. + - Added ability to colorize all aspects of `AlternatingTable`, `BorderedTable`, and + `SimpleTable`. - Added support for 8-bit/256-colors with the `cmd2.EightBitFg` and `cmd2.EightBitBg` classes. - Added support for 24-bit/RGB colors with the `cmd2.RgbFg` and `cmd2.RgbBg` classes. - Removed dependency on colorama. @@ -174,8 +192,8 @@ - Deprecated `cmd2.fg`. Use `cmd2.Fg` instead. - Deprecated `cmd2.bg`. Use `cmd2.Bg` instead. - Breaking Changes - - To support the color upgrade, all cmd2 colors now inherit from either `ansi.FgColor` or `ansi.BgColor`. - Therefore, `ansi.style()` no longer accepts colors as strings. + - To support the color upgrade, all cmd2 colors now inherit from either `ansi.FgColor` or + `ansi.BgColor`. Therefore, `ansi.style()` no longer accepts colors as strings. ## 2.2.0 (September 14, 2021) @@ -184,24 +202,27 @@ - Enhancements - New function `set_default_ap_completer_type()` allows developer to extend and modify the behavior of `ArgparseCompleter`. - - Added `ArgumentParser.get_ap_completer_type()` and `ArgumentParser.set_ap_completer_type()`. These - methods allow developers to enable custom tab completion behavior for a given parser by using a custom - `ArgparseCompleter`-based class. - - Added `ap_completer_type` keyword arg to `Cmd2ArgumentParser.__init__()` which saves a call - to `set_ap_completer_type()`. This keyword will also work with `add_parser()` when creating subcommands - if the base command's parser is a `Cmd2ArgumentParser`. + - Added `ArgumentParser.get_ap_completer_type()` and `ArgumentParser.set_ap_completer_type()`. + These methods allow developers to enable custom tab completion behavior for a given parser by + using a custom `ArgparseCompleter`-based class. + - Added `ap_completer_type` keyword arg to `Cmd2ArgumentParser.__init__()` which saves a call to + `set_ap_completer_type()`. This keyword will also work with `add_parser()` when creating + subcommands if the base command's parser is a `Cmd2ArgumentParser`. - New function `register_argparse_argument_parameter()` allows developers to specify custom - parameters to be passed to the argparse parser's `add_argument()` method. These parameters will - become accessible in the resulting argparse Action object when modifying `ArgparseCompleter` behavior. + parameters to be passed to the argparse parser's `add_argument()` method. These parameters + will become accessible in the resulting argparse Action object when modifying + `ArgparseCompleter` behavior. - Using `SimpleTable` in the output for the following commands to improve appearance. - help - set (command and tab completion of Settables) - alias tab completion - macro tab completion - - Tab completion of `CompletionItems` now includes divider row comprised of `Cmd.ruler` character. + - Tab completion of `CompletionItems` now includes divider row comprised of `Cmd.ruler` + character. - Removed `--verbose` flag from set command since descriptions always show now. - All cmd2 built-in commands now populate `self.last_result`. - - Argparse tab completer will complete remaining flag names if there are no more positionals to complete. + - Argparse tab completer will complete remaining flag names if there are no more positionals to + complete. - Updated `async_alert()` to account for `self.prompt` not matching Readline's current prompt. - Deletions (potentially breaking changes) - Deleted `set_choices_provider()` and `set_completer()` which were deprecated in 2.1.2 @@ -211,7 +232,8 @@ ## 2.1.2 (July 5, 2021) - Enhancements - - Added the following accessor methods for cmd2-specific attributes to the `argparse.Action` class + - Added the following accessor methods for cmd2-specific attributes to the `argparse.Action` + class - `get_choices_callable()` - `set_choices_provider()` - `set_completer()` @@ -233,7 +255,8 @@ - Bug Fixes - Fixed handling of argparse's default options group name which was changed in Python 3.10 - Enhancements - - Restored `plugins` and `tests_isolated` directories to tarball published to PyPI for `cmd2` release + - Restored `plugins` and `tests_isolated` directories to tarball published to PyPI for `cmd2` + release ## 2.1.0 (June 14, 2021) @@ -243,7 +266,8 @@ ## 2.0.1 (June 7, 2021) - Bug Fixes - - Exclude `plugins` and `tests_isolated` directories from tarball published to PyPI for `cmd2` release + - Exclude `plugins` and `tests_isolated` directories from tarball published to PyPI for `cmd2` + release ## 2.0.0 (June 6, 2021) @@ -256,66 +280,75 @@ - Argparse Completion / Settables - Replaced `choices_function` / `choices_method` with `choices_provider`. - Replaced `completer_function` / `completer_method` with `completer`. - - ArgparseCompleter now always passes `cmd2.Cmd` or `CommandSet` instance as the first positional - argument to choices_provider and completer functions. + - ArgparseCompleter now always passes `cmd2.Cmd` or `CommandSet` instance as the first + positional argument to choices_provider and completer functions. - Moved `basic_complete` from utils into `cmd2.Cmd` class. - Moved `CompletionError` to exceptions.py - `Namespace.__statement__` has been removed. Use `Namespace.cmd2_statement.get()` instead. - Removed `--silent` flag from `alias/macro create` since startup scripts can be run silently. - - Removed `--with_silent` flag from `alias/macro list` since startup scripts can be run silently. + - Removed `--with_silent` flag from `alias/macro list` since startup scripts can be run + silently. - Removed `with_argparser_and_unknown_args` since it was deprecated in 1.3.0. - Renamed `silent_startup_script` to `silence_startup_script` for clarity. - Replaced `cmd2.Cmd.completion_header` with `cmd2.Cmd.formatted_completions`. See Enhancements for description of this new class member. - - Settables now have new initialization parameters. It is now a required parameter to supply the reference to the - object that holds the settable attribute. `cmd2.Cmd.settables` is no longer a public dict attribute - it is now a - property that aggregates all Settables across all registered CommandSets. + - Settables now have new initialization parameters. It is now a required parameter to supply the + reference to the object that holds the settable attribute. `cmd2.Cmd.settables` is no longer a + public dict attribute - it is now a property that aggregates all Settables across all + registered CommandSets. - Failed transcript testing now sets self.exit_code to 1 instead of -1. - Renamed `use_ipython` keyword parameter of `cmd2.Cmd.__init__()` to `include_ipy`. - - `py` command is only enabled if `include_py` parameter is `True`. See Enhancements for a description - of this parameter. - - Removed ability to run Python commands from the command line with `py`. Now `py` takes no arguments - and just opens an interactive Python shell. - - Changed default behavior of `runcmds_plus_hooks()` to not stop when Ctrl-C is pressed and instead - run the next command in its list. - - Removed `cmd2.Cmd.quit_on_sigint` flag, which when `True`, quit the application when Ctrl-C was pressed at the - prompt. - - The history bug fix resulted in structure changes to the classes in `cmd2.history`. Therefore, persistent history - files created with versions older than 2.0.0 are not compatible. + - `py` command is only enabled if `include_py` parameter is `True`. See Enhancements for a + description of this parameter. + - Removed ability to run Python commands from the command line with `py`. Now `py` takes no + arguments and just opens an interactive Python shell. + - Changed default behavior of `runcmds_plus_hooks()` to not stop when Ctrl-C is pressed and + instead run the next command in its list. + - Removed `cmd2.Cmd.quit_on_sigint` flag, which when `True`, quit the application when Ctrl-C + was pressed at the prompt. + - The history bug fix resulted in structure changes to the classes in `cmd2.history`. Therefore, + persistent history files created with versions older than 2.0.0 are not compatible. - Enhancements - Added support for custom tab completion and up-arrow input history to `cmd2.Cmd2.read_input`. See [read_input.py](https://github.com/python-cmd2/cmd2/blob/master/examples/read_input.py) for an example. - - Added `cmd2.exceptions.PassThroughException` to raise unhandled command exceptions instead of printing them. - - Added support for ANSI styles and newlines in tab completion results using `cmd2.Cmd.formatted_completions`. - `cmd2` provides this capability automatically if you return argparse completion matches as `CompletionItems`. + - Added `cmd2.exceptions.PassThroughException` to raise unhandled command exceptions instead of + printing them. + - Added support for ANSI styles and newlines in tab completion results using + `cmd2.Cmd.formatted_completions`. `cmd2` provides this capability automatically if you return + argparse completion matches as `CompletionItems`. - Settables enhancements: - - Settables may be optionally scoped to a CommandSet. Settables added to CommandSets will appear when a - CommandSet is registered and disappear when a CommandSet is unregistered. Optionally, scoped Settables - may have a prepended prefix. - - Settables now allow changes to be applied to any arbitrary object attribute. It no longer needs to match an - attribute added to the cmd2 instance itself. - - Raising `SystemExit` or calling `sys.exit()` in a command or hook function will set `self.exit_code` - to the exit code used in those calls. It will also result in the command loop stopping. + - Settables may be optionally scoped to a CommandSet. Settables added to CommandSets will + appear when a CommandSet is registered and disappear when a CommandSet is unregistered. + Optionally, scoped Settables may have a prepended prefix. + - Settables now allow changes to be applied to any arbitrary object attribute. It no longer + needs to match an attribute added to the cmd2 instance itself. + - Raising `SystemExit` or calling `sys.exit()` in a command or hook function will set + `self.exit_code` to the exit code used in those calls. It will also result in the command loop + stopping. - ipy command now includes all of `self.py_locals` in the IPython environment - - Added `include_py` keyword parameter to `cmd2.Cmd.__init__()`. If `False`, then the `py` command will - not be available. Defaults to `False`. `run_pyscript` is not affected by this parameter. + - Added `include_py` keyword parameter to `cmd2.Cmd.__init__()`. If `False`, then the `py` + command will not be available. Defaults to `False`. `run_pyscript` is not affected by this + parameter. - Made the amount of space between columns in a SimpleTable configurable - - On POSIX systems, shell commands and processes being piped to are now run in the user's preferred shell - instead of /bin/sh. The preferred shell is obtained by reading the SHELL environment variable. If that - doesn't exist or is empty, then /bin/sh is used. + - On POSIX systems, shell commands and processes being piped to are now run in the user's + preferred shell instead of /bin/sh. The preferred shell is obtained by reading the SHELL + environment variable. If that doesn't exist or is empty, then /bin/sh is used. - Changed `cmd2.Cmd._run_editor()` to the public method `cmd2.Cmd.run_editor()` ## 1.5.0 (January 31, 2021) - Bug Fixes - - Fixed bug where setting `always_show_hint=True` did not show a hint when completing `Settables` + - Fixed bug where setting `always_show_hint=True` did not show a hint when completing + `Settables` - Fixed bug in editor detection logic on Linux systems that do not have `which` - - Fixed bug in table creator where column headers with tabs would result in an incorrect width calculation - - Fixed `FileNotFoundError` which occurred when running `history --clear` and no history file existed. + - Fixed bug in table creator where column headers with tabs would result in an incorrect width + calculation + - Fixed `FileNotFoundError` which occurred when running `history --clear` and no history file + existed. - Enhancements - - Added `silent_startup_script` option to `cmd2.Cmd.__init__()`. If `True`, then the startup script's - output will be suppressed. Anything written to stderr will still display. + - Added `silent_startup_script` option to `cmd2.Cmd.__init__()`. If `True`, then the startup + script's output will be suppressed. Anything written to stderr will still display. - cmd2 now uses pyreadline3 when running Python 3.8 or greater on Windows - Notes - This is the last release planned to support Python 3.5 @@ -332,36 +365,37 @@ - Bug Fixes - Fixed issue where quoted redirectors and terminators in aliases and macros were not being restored when read from a startup script. - - Fixed issue where instantiating more than one cmd2-based class which uses the `@as_subcommand_to` - decorator resulted in duplicated help text in the base command the subcommands belong to. + - Fixed issue where instantiating more than one cmd2-based class which uses the + `@as_subcommand_to` decorator resulted in duplicated help text in the base command the + subcommands belong to. ## 1.3.10 (September 17, 2020) - Enhancements - - Added user-settable option called `always_show_hint`. If True, then tab completion hints will always - display even when tab completion suggestions print. Arguments whose help or hint text is suppressed will - not display hints even when this setting is True. - - argparse tab completion now groups flag names which run the same action. Optional flags are wrapped - in brackets like it is done in argparse usage text. - - default category decorators are now heritable by default and will propagate the category down the - class hierarchy until overridden. There's a new optional flag to set heritable to false. - - Added `--silent` flag to `alias/macro create`. If used, then no confirmation message will be printed - when aliases and macros are created or overwritten. - - Added `--with_silent` flag to `alias/macro list`. Use this option when saving to a startup script - that should silently create aliases and macros. + - Added user-settable option called `always_show_hint`. If True, then tab completion hints will + always display even when tab completion suggestions print. Arguments whose help or hint text + is suppressed will not display hints even when this setting is True. + - argparse tab completion now groups flag names which run the same action. Optional flags are + wrapped in brackets like it is done in argparse usage text. + - default category decorators are now heritable by default and will propagate the category down + the class hierarchy until overridden. There's a new optional flag to set heritable to false. + - Added `--silent` flag to `alias/macro create`. If used, then no confirmation message will be + printed when aliases and macros are created or overwritten. + - Added `--with_silent` flag to `alias/macro list`. Use this option when saving to a startup + script that should silently create aliases and macros. - Bug Fixes - Fixed issue where flag names weren't always sorted correctly in argparse tab completion ## 1.3.9 (September 03, 2020) - Breaking Changes - - `CommandSet.on_unregister()` is now called as first step in unregistering a `CommandSet` and not - the last. `CommandSet.on_unregistered()` is now the last step. + - `CommandSet.on_unregister()` is now called as first step in unregistering a `CommandSet` and + not the last. `CommandSet.on_unregistered()` is now the last step. - Enhancements - - Added `CommandSet.on_registered()`. This is called by `cmd2.Cmd` after a `CommandSet` is registered - and all its commands have been added to the CLI. - - Added `CommandSet.on_unregistered()`. This is called by `cmd2.Cmd` after a `CommandSet` is unregistered - and all its commands have been removed from the CLI. + - Added `CommandSet.on_registered()`. This is called by `cmd2.Cmd` after a `CommandSet` is + registered and all its commands have been added to the CLI. + - Added `CommandSet.on_unregistered()`. This is called by `cmd2.Cmd` after a `CommandSet` is + unregistered and all its commands have been removed from the CLI. ## 1.3.8 (August 28, 2020) @@ -376,41 +410,43 @@ ## 1.3.7 (August 27, 2020) - Bug Fixes - - Fixes an issue introduced in 1.3.0 with processing command strings containing terminator/separator - character(s) that are manually passed to a command that uses argparse. + - Fixes an issue introduced in 1.3.0 with processing command strings containing + terminator/separator character(s) that are manually passed to a command that uses argparse. ## 1.3.6 (August 27, 2020) - Breaking changes - The functions cmd2 adds to Namespaces (`get_statement()` and `get_handler()`) are now - `Cmd2AttributeWrapper` objects named `cmd2_statement` and `cmd2_handler`. This makes it - easy to filter out which attributes in an `argparse.Namespace` were added by `cmd2`. + `Cmd2AttributeWrapper` objects named `cmd2_statement` and `cmd2_handler`. This makes it easy + to filter out which attributes in an `argparse.Namespace` were added by `cmd2`. - Deprecations - - `Namespace.__statement__` will be removed in `cmd2` 2.0.0. Use `Namespace.cmd2_statement.get()` - going forward. + - `Namespace.__statement__` will be removed in `cmd2` 2.0.0. Use + `Namespace.cmd2_statement.get()` going forward. ## 1.3.5 (August 25, 2020) - Bug Fixes - - Fixed `RecursionError` when printing an `argparse.Namespace` caused by custom attribute cmd2 was adding + - Fixed `RecursionError` when printing an `argparse.Namespace` caused by custom attribute cmd2 + was adding - Enhancements - - Added `get_statement()` function to `argparse.Namespace` which returns `__statement__` attribute + - Added `get_statement()` function to `argparse.Namespace` which returns `__statement__` + attribute ## 1.3.4 (August 20, 2020) - Bug Fixes - - Fixed `AttributeError` when `CommandSet` that uses `as_subcommand_to` decorator is loaded during - `cmd2.Cmd.__init__()`. + - Fixed `AttributeError` when `CommandSet` that uses `as_subcommand_to` decorator is loaded + during `cmd2.Cmd.__init__()`. - Enhancements - - Improved exception messages when using mock without `spec=True`. - See [testing](https://cmd2.readthedocs.io/en/latest/testing.html) documentation for more details on testing - cmd2-based applications with mock. + - Improved exception messages when using mock without `spec=True`. See + [testing](https://cmd2.readthedocs.io/en/latest/testing.html) documentation for more details + on testing cmd2-based applications with mock. ## 1.3.3 (August 13, 2020) - Breaking changes - - CommandSet command functions (do*, complete*, help\_) will no longer have the cmd2 app - passed in as the first parameter after `self` since this is already a class member. + - CommandSet command functions (do*, complete*, help\_) will no longer have the cmd2 app passed + in as the first parameter after `self` since this is already a class member. - Renamed `install_command_set()` and `uninstall_command_set()` to `register_command_set()` and `unregister_command_set()` for better name consistency. - Bug Fixes @@ -418,19 +454,20 @@ - Fixed tab completion bug when using `CompletionItem` on an argument whose `metavar` is a tuple - Added explicit testing against python 3.5.2 for Ubuntu 16.04, and 3.5.3 for Debian 9 - Added fallback definition of typing.Deque (taken from 3.5.4) - - Removed explicit type hints that fail due to a bug in 3.5.2 favoring comment-based hints instead + - Removed explicit type hints that fail due to a bug in 3.5.2 favoring comment-based hints + instead - When passing a ns_provider to an argparse command, will now attempt to resolve the correct CommandSet instance for self. If not, it'll fall back and pass in the cmd2 app - Other - - Added missing doc-string for new cmd2.Cmd **init** parameters - introduced by CommandSet enhancement + - Added missing doc-string for new cmd2.Cmd **init** parameters introduced by CommandSet + enhancement ## 1.3.2 (August 10, 2020) - Bug Fixes - Fixed `prog` value of subcommands added with `as_subcommand_to()` decorator. - - Fixed missing settings in subcommand parsers created with `as_subcommand_to()` decorator. These settings - include things like description and epilog text. + - Fixed missing settings in subcommand parsers created with `as_subcommand_to()` decorator. + These settings include things like description and epilog text. - Fixed issue with CommandSet auto-discovery only searching direct sub-classes - Enhancements - Added functions to fetch registered CommandSets by type and command name @@ -438,19 +475,19 @@ ## 1.3.1 (August 6, 2020) - Bug Fixes - - Fixed issue determining whether an argparse completer function required a reference to a containing - CommandSet. Also resolves issues determining the correct CommandSet instance when calling the argparse - argument completer function. Manifested as a TypeError when using `cmd2.Cmd.path_complete` as a completer - for an argparse-based command defined in a CommandSet + - Fixed issue determining whether an argparse completer function required a reference to a + containing CommandSet. Also resolves issues determining the correct CommandSet instance when + calling the argparse argument completer function. Manifested as a TypeError when using + `cmd2.Cmd.path_complete` as a completer for an argparse-based command defined in a CommandSet ## 1.3.0 (August 4, 2020) - Enhancements - - Added CommandSet - Enables defining a separate loadable module of commands to register/unregister - with your cmd2 application. + - Added CommandSet - Enables defining a separate loadable module of commands to + register/unregister with your cmd2 application. - Other - - Marked with_argparser_and_unknown_args pending deprecation and consolidated implementation into - with_argparser + - Marked with_argparser_and_unknown_args pending deprecation and consolidated implementation + into with_argparser ## 1.2.1 (July 14, 2020) @@ -463,44 +500,49 @@ - Fixed `typing` module compatibility issue with Python 3.5 prior to 3.5.4 - Enhancements - Switched to getting version using `importlib.metadata` instead of using `pkg_resources` - - Improves `cmd2` application launch time on systems that have a lot of Python packages on `sys.path` + - Improves `cmd2` application launch time on systems that have a lot of Python packages on + `sys.path` - Added dependency on `importlib_metadata` when running on versions of Python prior to 3.8 ## 1.1.0 (June 6, 2020) - Bug Fixes - - Fixed issue where subcommand usage text could contain a subcommand alias instead of the actual name - - Fixed bug in `ArgparseCompleter` where `fill_width` could become negative if `token_width` was large - relative to the terminal width. + - Fixed issue where subcommand usage text could contain a subcommand alias instead of the actual + name + - Fixed bug in `ArgparseCompleter` where `fill_width` could become negative if `token_width` was + large relative to the terminal width. - Enhancements - Made `ipy` consistent with `py` in the following ways - `ipy` returns whether any of the commands run in it returned True to stop command loop - `Cmd.in_pyscript()` returns True while in `ipy`. - Starting `ipy` when `Cmd.in_pyscript()` is already True is not allowed. - - `with_argument_list`, `with_argparser`, and `with_argparser_and_unknown_args` wrappers now pass - `kwargs` through to their wrapped command function. - - Added `table_creator` module for creating richly formatted tables. This module is in beta and subject - to change. + - `with_argument_list`, `with_argparser`, and `with_argparser_and_unknown_args` wrappers now + pass `kwargs` through to their wrapped command function. + - Added `table_creator` module for creating richly formatted tables. This module is in beta and + subject to change. - See [table_creation](https://cmd2.readthedocs.io/en/latest/features/table_creation.html) documentation for an overview. - - See [table_creation.py](https://github.com/python-cmd2/cmd2/blob/master/examples/table_creation.py) + - See + [table_creation.py](https://github.com/python-cmd2/cmd2/blob/master/examples/table_creation.py) for an example. - Added the following exceptions to the public API - - `SkipPostcommandHooks` - Custom exception class for when a command has a failure bad enough to skip - post command hooks, but not bad enough to print the exception to the user. - - `Cmd2ArgparseError` - A `SkipPostcommandHooks` exception for when a command fails to parse its arguments. - Normally argparse raises a `SystemExit` exception in these cases. To avoid stopping the command - loop, catch the `SystemExit` and raise this instead. If you still need to run post command hooks - after parsing fails, just return instead of raising an exception. - - Added explicit handling of `SystemExit`. If a command raises this exception, the command loop will be - gracefully stopped. + - `SkipPostcommandHooks` - Custom exception class for when a command has a failure bad + enough to skip post command hooks, but not bad enough to print the exception to the user. + - `Cmd2ArgparseError` - A `SkipPostcommandHooks` exception for when a command fails to parse + its arguments. Normally argparse raises a `SystemExit` exception in these cases. To avoid + stopping the command loop, catch the `SystemExit` and raise this instead. If you still + need to run post command hooks after parsing fails, just return instead of raising an + exception. + - Added explicit handling of `SystemExit`. If a command raises this exception, the command loop + will be gracefully stopped. ## 1.0.2 (April 06, 2020) - Bug Fixes - Ctrl-C now stops a running text script instead of just the current `run_script` command - Enhancements - - `do_shell()` now saves the return code of the command it runs in `self.last_result` for use in pyscripts + - `do_shell()` now saves the return code of the command it runs in `self.last_result` for use in + pyscripts ## 1.0.1 (March 13, 2020) @@ -512,30 +554,33 @@ - Enhancements - The documentation at [cmd2.rftd.io](https://cmd2.readthedocs.io) received a major overhaul - Other - - Moved [categorize](https://cmd2.readthedocs.io/en/latest/api/utils.html#miscellaneous) utility function from \* - \*decorators** module to **utils\*\* module + - Moved [categorize](https://cmd2.readthedocs.io/en/latest/api/utils.html#miscellaneous) utility + function from \* \*decorators** module to **utils\*\* module - Notes - - Now that the 1.0 release is out, `cmd2` intends to follow [Semantic Versioning](https://semver.org) + - Now that the 1.0 release is out, `cmd2` intends to follow + [Semantic Versioning](https://semver.org) ## 0.10.1 (February 19, 2020) - Bug Fixes - - Corrected issue where the actual new value was not always being printed in do_set. This occurred in cases where - the typed value differed from what the setter had converted it to. + - Corrected issue where the actual new value was not always being printed in do_set. This + occurred in cases where the typed value differed from what the setter had converted it to. - Fixed bug where ANSI style sequences were not correctly handled in `utils.truncate_line()`. - Fixed bug where pyscripts could edit `cmd2.Cmd.py_locals` dictionary. - - Fixed bug where cmd2 set `sys.path[0]` for a pyscript to cmd2's working directory instead of the - script file's directory. + - Fixed bug where cmd2 set `sys.path[0]` for a pyscript to cmd2's working directory instead of + the script file's directory. - Fixed bug where `sys.path` was not being restored after a pyscript ran. - Enhancements - - Renamed set command's `-l/--long` flag to `-v/--verbose` for consistency with help and history commands. + - Renamed set command's `-l/--long` flag to `-v/--verbose` for consistency with help and history + commands. - Setting the following pyscript variables: - `__name__`: **main** - `__file__`: script path (as typed, ~ will be expanded) - Only tab complete after redirection tokens if redirection is allowed - Made `CompletionError` exception available to non-argparse tab completion - - Added `apply_style` to `CompletionError` initializer. It defaults to True, but can be set to False if - you don't want the error text to have `ansi.style_error()` applied to it when printed. + - Added `apply_style` to `CompletionError` initializer. It defaults to True, but can be set to + False if you don't want the error text to have `ansi.style_error()` applied to it when + printed. - Other - Removed undocumented `py run` command since it was replaced by `run_pyscript` a while ago - Renamed `AutoCompleter` to `ArgparseCompleter` for clarity @@ -550,7 +595,8 @@ - Enhancements - Changed the default help text to make `help -v` more discoverable - **set** command now supports tab completion of values - - Added `add_settable()` and `remove_settable()` convenience methods to update `self.settable` dictionary + - Added `add_settable()` and `remove_settable()` convenience methods to update `self.settable` + dictionary - Added convenience `ansi.fg` and `ansi.bg` enums of foreground and background colors - `ansi.style()` `fg` argument can now either be of type `str` or `ansi.fg` - `ansi.style()` `bg` argument can now either be of type `str` or `ansi.bg` @@ -566,8 +612,8 @@ - `prompt` - `self.settable` changed to `self.settables` - It is now a Dict[str, Settable] instead of Dict[str, str] - - setting onchange callbacks have a new method signature and must be added to the - Settable instance in order to be called + - setting onchange callbacks have a new method signature and must be added to the Settable + instance in order to be called - Removed `cast()` utility function - Removed `ansi.FG_COLORS` and `ansi.BG_COLORS` dictionaries - Replaced with `ansi.fg` and `ansi.bg` enums providing similar but improved functionality @@ -579,27 +625,31 @@ ## 0.9.25 (January 26, 2020) - Enhancements - - Reduced what gets put in package downloadable from PyPI (removed irrelevant CI config files and such) + - Reduced what gets put in package downloadable from PyPI (removed irrelevant CI config files + and such) ## 0.9.24 (January 23, 2020) - Enhancements - - Flushing stderr when setting the window title and printing alerts for better responsiveness in cases where - stderr is not unbuffered. - - Added function to truncate a single line to fit within a given display width. `cmd2.utils.truncate_line` - supports characters with display widths greater than 1 and ANSI style sequences. + - Flushing stderr when setting the window title and printing alerts for better responsiveness in + cases where stderr is not unbuffered. + - Added function to truncate a single line to fit within a given display width. + `cmd2.utils.truncate_line` supports characters with display widths greater than 1 and ANSI + style sequences. - Added line truncation support to `cmd2.utils` text alignment functions. - Added support for Python 3.9 alpha ## 0.9.23 (January 9, 2020) - Bug Fixes - - Fixed bug where startup script containing a single quote in its file name was incorrectly quoted + - Fixed bug where startup script containing a single quote in its file name was incorrectly + quoted - Added missing implicit dependency on `setuptools` due to build with `setuptools_scm` - Enhancements - Added dim text style support via `style()` function and `ansi.INTENSITY_DIM` setting. - Breaking changes - - Renamed the following `ansi` members for accuracy in what types of ANSI escape sequences are handled + - Renamed the following `ansi` members for accuracy in what types of ANSI escape sequences are + handled - `ansi.allow_ansi` -> `ansi.allow_style` - `ansi.ansi_safe_wcswidth()` -> `ansi.style_aware_wcswidth()` - `ansi.ansi_aware_write()` -> `ansi.style_aware_write()` @@ -613,22 +663,23 @@ - Fixed bug where a redefined `ansi.style_error` was not being used in all `cmd2` files - Enhancements - Enabled line buffering when redirecting output to a file - - Added `align_left()`, `align_center()`, and `align_right()` to utils.py. All 3 of these functions support - ANSI escape sequences and characters with display widths greater than 1. They wrap `align_text()` which - is also in utils.py. + - Added `align_left()`, `align_center()`, and `align_right()` to utils.py. All 3 of these + functions support ANSI escape sequences and characters with display widths greater than 1. + They wrap `align_text()` which is also in utils.py. ## 0.9.21 (November 26, 2019) - Bug Fixes - Fixed bug where pipe processes were not being stopped by Ctrl-C - - Added exception handling to account for non-standard Python environments in which readline is not loaded - dynamically from a shared library file -- Enhancements - - Added `read_input()` function that is used to read from stdin. Unlike the Python built-in `input()`, it also has - an argument to disable tab completion while input is being entered. - - Added capability to override the argument parser class used by cmd2 built-in commands. See override_parser.py - example for more details. - - Added `end` argument to `pfeedback()` to be consistent with the other print functions like `poutput()`. + - Added exception handling to account for non-standard Python environments in which readline is + not loaded dynamically from a shared library file +- Enhancements + - Added `read_input()` function that is used to read from stdin. Unlike the Python built-in + `input()`, it also has an argument to disable tab completion while input is being entered. + - Added capability to override the argument parser class used by cmd2 built-in commands. See + override_parser.py example for more details. + - Added `end` argument to `pfeedback()` to be consistent with the other print functions like + `poutput()`. - Added `apply_style` to `pwarning()`. - Breaking changes - For consistency between all the print functions: @@ -638,42 +689,41 @@ ## 0.9.20 (November 12, 2019) - Bug Fixes - - Fixed bug where setting `use_ipython` to False removed ipy command from the entire `cmd2.Cmd` class instead of - just the instance being created + - Fixed bug where setting `use_ipython` to False removed ipy command from the entire `cmd2.Cmd` + class instead of just the instance being created - Fix bug where cmd2 ran 'stty sane' command when stdin was not a terminal - Enhancements - - Send all startup script paths to run_script. Previously we didn't do this if the file was empty, but that - showed no record of the run_script command in history. - - Made it easier for developers to override `edit` command by having `do_history` no longer call `do_edit`. This - also removes the need to exclude `edit` command from history list. - - It is no longer necessary to set the `prog` attribute of an argparser with subcommands. cmd2 now automatically - sets the prog value of it and all its subparsers so that all usage statements contain the top level command name - and not sys.argv[0]. + - Send all startup script paths to run_script. Previously we didn't do this if the file was + empty, but that showed no record of the run_script command in history. + - Made it easier for developers to override `edit` command by having `do_history` no longer call + `do_edit`. This also removes the need to exclude `edit` command from history list. + - It is no longer necessary to set the `prog` attribute of an argparser with subcommands. cmd2 + now automatically sets the prog value of it and all its subparsers so that all usage + statements contain the top level command name and not sys.argv[0]. - Breaking changes - Some constants were moved from cmd2.py to constants.py - - cmd2 command decorators were moved to decorators.py. If you were importing them via cmd2's \_\_init\_\_.py, then - there will be no issues. + - cmd2 command decorators were moved to decorators.py. If you were importing them via cmd2's + \_\_init\_\_.py, then there will be no issues. ## 0.9.19 (October 14, 2019) - Bug Fixes - - Fixed `ValueError` exception which could occur when an old format persistent history file is loaded with new - `cmd2` + - Fixed `ValueError` exception which could occur when an old format persistent history file is + loaded with new `cmd2` - Enhancements - Improved displaying multiline CompletionErrors by indenting all lines ## 0.9.18 (October 1, 2019) - Bug Fixes - - Fixed bug introduced in 0.9.17 where help functions for hidden and disabled commands were not being filtered - out as help topics + - Fixed bug introduced in 0.9.17 where help functions for hidden and disabled commands were not + being filtered out as help topics - Enhancements - - `AutoCompleter` now handles argparse's mutually exclusive groups. It will not tab complete flag names or - positionals - for already completed groups. It also will print an error if you try tab completing a flag's value if the flag - belongs to a completed group. - - `AutoCompleter` now uses the passed-in parser's help formatter to generate hint text. This gives help and - hint text for an argument consistent formatting. + - `AutoCompleter` now handles argparse's mutually exclusive groups. It will not tab complete + flag names or positionals for already completed groups. It also will print an error if you try + tab completing a flag's value if the flag belongs to a completed group. + - `AutoCompleter` now uses the passed-in parser's help formatter to generate hint text. This + gives help and hint text for an argument consistent formatting. ## 0.9.17 (September 23, 2019) @@ -683,11 +733,12 @@ - Enhancements - No longer treating empty text scripts as an error condition - Allow dynamically extending a `cmd2.Cmd` object instance with a `do_xxx` method at runtime - - Choices/Completer functions can now be passed a dictionary that maps command-line tokens to their - argparse argument. This is helpful when one argument determines what is tab completed for another argument. - If these functions have an argument called `arg_tokens`, then AutoCompleter will automatically pass this - dictionary to them. - - Added CompletionError class that can be raised during argparse-based tab completion and printed to the user + - Choices/Completer functions can now be passed a dictionary that maps command-line tokens to + their argparse argument. This is helpful when one argument determines what is tab completed + for another argument. If these functions have an argument called `arg_tokens`, then + AutoCompleter will automatically pass this dictionary to them. + - Added CompletionError class that can be raised during argparse-based tab completion and + printed to the user - Added the following convenience methods - `Cmd.in_script()` - return whether a text script is running - `Cmd.in_pyscript()` - return whether a pyscript is running @@ -695,14 +746,16 @@ ## 0.9.16 (August 7, 2019) - Bug Fixes - - Fixed inconsistent parsing/tab completion behavior based on the value of `allow_redirection`. This flag is - only meant to be a security setting that prevents redirection of stdout and should not alter parsing logic. + - Fixed inconsistent parsing/tab completion behavior based on the value of `allow_redirection`. + This flag is only meant to be a security setting that prevents redirection of stdout and + should not alter parsing logic. - Enhancements - - Raise `TypeError` if trying to set choices/completions on argparse action that accepts no arguments + - Raise `TypeError` if trying to set choices/completions on argparse action that accepts no + arguments - Create directory for the persistent history file if it does not already exist - - Added `set_choices_function()`, `set_choices_method()`, `set_completer_function()`, and `set_completer_method()` - to support cases where this functionality needs to be added to an argparse action outside of the normal - `parser.add_argument()` call. + - Added `set_choices_function()`, `set_choices_method()`, `set_completer_function()`, and + `set_completer_method()` to support cases where this functionality needs to be added to an + argparse action outside of the normal `parser.add_argument()` call. - Breaking Changes - Aliases and macros can no longer have the same name as a command @@ -710,16 +763,19 @@ - Bug Fixes - Fixed exception caused by tab completing after an invalid subcommand was entered - - Fixed bug where `history -v` was sometimes showing raw and expanded commands when they weren't different - - Fixed bug where multiline commands were having leading and ending spaces stripped. This would mess up quoted - strings that crossed multiple lines. + - Fixed bug where `history -v` was sometimes showing raw and expanded commands when they weren't + different + - Fixed bug where multiline commands were having leading and ending spaces stripped. This would + mess up quoted strings that crossed multiple lines. - Fixed a bug when appending to the clipboard where contents were in reverse order - - Fixed issue where run_pyscript failed if the script's filename had 2 or more consecutive spaces + - Fixed issue where run_pyscript failed if the script's filename had 2 or more consecutive + spaces - Fixed issue where completer function of disabled command would still run - Enhancements - - Greatly simplified using argparse-based tab completion. The new interface is a complete overhaul that breaks - the previous way of specifying completion and choices functions. See header - of [argparse_custom.py](https://github.com/python-cmd2/cmd2/blob/master/cmd2/argparse_custom.py) + - Greatly simplified using argparse-based tab completion. The new interface is a complete + overhaul that breaks the previous way of specifying completion and choices functions. See + header of + [argparse_custom.py](https://github.com/python-cmd2/cmd2/blob/master/cmd2/argparse_custom.py) for more information. - Enabled tab completion on multiline commands - **Renamed Commands Notice** @@ -731,21 +787,22 @@ - Lots of end users were confused particularly about what exactly `load` should be loading - Breaking Changes - Restored `cmd2.Cmd.statement_parser` to be a public attribute (no underscore) - - Since it can be useful for - creating [post-parsing hooks](https://cmd2.readthedocs.io/en/latest/features/hooks.html#postparsing-hooks) - - Completely overhauled the interface for adding tab completion to argparse arguments. See enhancements for more - details. + - Since it can be useful for creating + [post-parsing hooks](https://cmd2.readthedocs.io/en/latest/features/hooks.html#postparsing-hooks) + - Completely overhauled the interface for adding tab completion to argparse arguments. See + enhancements for more details. - `ACArgumentParser` is now called `Cmd2ArgumentParser` - Moved `basic_complete` to utils.py - - Made optional arguments on the following completer methods keyword-only: - `delimiter_complete`, `flag_based_complete`, `index_based_complete`, `path_complete`, `shell_cmd_complete` + - Made optional arguments on the following completer methods keyword-only: `delimiter_complete`, + `flag_based_complete`, `index_based_complete`, `path_complete`, `shell_cmd_complete` - Renamed history option from `--output-file` to `--output_file` - - Renamed `matches_sort_key` to `default_sort_key`. This value determines the default sort ordering of string - results like alias, command, category, macro, settable, and shortcut names. Unsorted tab completion results - also are sorted with this key. Its default value (ALPHABETICAL_SORT_KEY) performs a case-insensitive alphabetical - sort, but it can be changed to a natural sort by setting the value to NATURAL_SORT_KEY. - - `StatementParser` now expects shortcuts to be passed in as dictionary. This eliminates the step of converting the - shortcuts dictionary into a tuple before creating `StatementParser`. + - Renamed `matches_sort_key` to `default_sort_key`. This value determines the default sort + ordering of string results like alias, command, category, macro, settable, and shortcut names. + Unsorted tab completion results also are sorted with this key. Its default value + (ALPHABETICAL_SORT_KEY) performs a case-insensitive alphabetical sort, but it can be changed + to a natural sort by setting the value to NATURAL_SORT_KEY. + - `StatementParser` now expects shortcuts to be passed in as dictionary. This eliminates the + step of converting the shortcuts dictionary into a tuple before creating `StatementParser`. - Renamed `Cmd.pyscript_name` to `Cmd.py_bridge_name` - Renamed `Cmd.pystate` to `Cmd.py_locals` - Renamed `PyscriptBridge` to `PyBridge` @@ -755,38 +812,43 @@ - Enhancements - Added support for and testing with Python 3.8, starting with 3.8 beta - Improved information displayed during transcript testing - - Added `ansi` module with functions and constants to support ANSI escape sequences which are used for things - like applying style to text - - Added support for applying styles (color, bold, underline) to text via `style()` function in `ansi` module - - Added default styles to ansi.py for printing `success`, `warning`. and `error` text. These are the styles used - by cmd2 and can be overridden to match the color scheme of your application. - - Added `ansi_aware_write()` function to `ansi` module. This function takes into account the value of `allow_ansi` - to determine if ANSI escape sequences should be stripped when not writing to a tty. See documentation for more - information on the `allow_ansi` setting. + - Added `ansi` module with functions and constants to support ANSI escape sequences which are + used for things like applying style to text + - Added support for applying styles (color, bold, underline) to text via `style()` function in + `ansi` module + - Added default styles to ansi.py for printing `success`, `warning`. and `error` text. These are + the styles used by cmd2 and can be overridden to match the color scheme of your application. + - Added `ansi_aware_write()` function to `ansi` module. This function takes into account the + value of `allow_ansi` to determine if ANSI escape sequences should be stripped when not + writing to a tty. See documentation for more information on the `allow_ansi` setting. - Breaking Changes - - Python 3.4 reached its [end of life](https://www.python.org/dev/peps/pep-0429/) on March 18, 2019 and is no longer - supported by `cmd2` + - Python 3.4 reached its [end of life](https://www.python.org/dev/peps/pep-0429/) on March 18, + 2019 and is no longer supported by `cmd2` - If you need to use Python 3.4, you should pin your requirements to use `cmd2` 0.9.13 - Made lots of changes to minimize the public API of the `cmd2.Cmd` class - Attributes and methods we do not intend to be public now all begin with an underscore - We make no API stability guarantees about these internal functions - Split `perror` into 2 functions: - `perror` - print a message to sys.stderr - - `pexcept` - print Exception message to sys.stderr. If debug is true, print exception traceback if one exists + - `pexcept` - print Exception message to sys.stderr. If debug is true, print exception + traceback if one exists - Signature of `poutput` and `perror` significantly changed - Removed color parameters `color`, `err_color`, and `war_color` from `poutput` and `perror` - - See the docstrings of these methods or - the [cmd2 docs](https://cmd2.readthedocs.io/en/latest/features/generating_output.html) for more info on - applying styles to output messages + - See the docstrings of these methods or the + [cmd2 docs](https://cmd2.readthedocs.io/en/latest/features/generating_output.html) for + more info on applying styles to output messages - `end` argument is now keyword-only and cannot be specified positionally - - `traceback_war` no longer exists as an argument since it isn't needed now that `perror` and `pexcept` exist - - Moved `cmd2.Cmd.colors` to ansi.py and renamed it to `allow_ansi`. This is now an application-wide setting. + - `traceback_war` no longer exists as an argument since it isn't needed now that `perror` + and `pexcept` exist + - Moved `cmd2.Cmd.colors` to ansi.py and renamed it to `allow_ansi`. This is now an + application-wide setting. - Renamed the following constants and moved them to ansi.py - `COLORS_ALWAYS` --> `ANSI_ALWAYS` - `COLORS_NEVER` --> `ANSI_NEVER` - `COLORS_TERMINAL` --> `ANSI_TERMINAL` - **Renamed Commands Notice** - - The following commands have been renamed. The old names will be supported until the next release. + - The following commands have been renamed. The old names will be supported until the next + release. - `load` --> `run_script` - `_relative_load` --> `_relative_run_script` - `pyscript` --> `run_pyscript` @@ -794,98 +856,119 @@ ## 0.9.13 (June 14, 2019) - Bug Fixes - - Fixed issue where the wrong terminator was being appended by `Statement.expanded_command_line()` + - Fixed issue where the wrong terminator was being appended by + `Statement.expanded_command_line()` - Fixed issue where aliases and macros could not contain terminator characters in their values - - History now shows what was typed for macros and not the resolved value by default. This is consistent with - the behavior of aliases. Use the `expanded` or `verbose` arguments to `history` to see the resolved value for - the macro. - - Fixed parsing issue in case where output redirection appears before a pipe. In that case, the pipe was given - precedence even though it appeared later in the command. - - Fixed issue where quotes around redirection file paths were being lost in `Statement.expanded_command_line()` + - History now shows what was typed for macros and not the resolved value by default. This is + consistent with the behavior of aliases. Use the `expanded` or `verbose` arguments to + `history` to see the resolved value for the macro. + - Fixed parsing issue in case where output redirection appears before a pipe. In that case, the + pipe was given precedence even though it appeared later in the command. + - Fixed issue where quotes around redirection file paths were being lost in + `Statement.expanded_command_line()` - Fixed a bug in how line numbers were calculated for transcript testing - - Fixed issue where `_cmdloop()` suppressed exceptions by returning from within its `finally` code - - Fixed UnsupportedOperation on fileno error when a shell command was one of the commands run while generating - a transcript + - Fixed issue where `_cmdloop()` suppressed exceptions by returning from within its `finally` + code + - Fixed UnsupportedOperation on fileno error when a shell command was one of the commands run + while generating a transcript - Fixed bug where history was displaying expanded multiline commands when -x was not specified - Enhancements - - **Added capability to chain pipe commands and redirect their output (e.g. !ls -l | grep user | wc -l > out.txt)** + - **Added capability to chain pipe commands and redirect their output (e.g. !ls -l | grep user | + wc -l > out.txt)** - `pyscript` limits a command's stdout capture to the same period that redirection does. - Therefore output from a command's postparsing and finalization hooks isn't saved in the StdSim object. - - `StdSim.buffer.write()` now flushes when the wrapped stream uses line buffering and the bytes being written - contain a newline or carriage return. This helps when `pyscript` is echoing the output of a shell command - since the output will print at the same frequency as when the command is run in a terminal. - - **ACArgumentParser** no longer prints complete help text when a parsing error occurs since long help messages - scroll the actual error message off the screen. - - Exceptions occurring in tab completion functions are now printed to stderr before returning control back to - readline. This makes debugging a lot easier since readline suppresses these exceptions. - - Added support for custom Namespaces in the argparse decorators. See description of `ns_provider` argument - for more information. + Therefore output from a command's postparsing and finalization hooks isn't saved in the StdSim + object. + - `StdSim.buffer.write()` now flushes when the wrapped stream uses line buffering and the bytes + being written contain a newline or carriage return. This helps when `pyscript` is echoing the + output of a shell command since the output will print at the same frequency as when the + command is run in a terminal. + - **ACArgumentParser** no longer prints complete help text when a parsing error occurs since + long help messages scroll the actual error message off the screen. + - Exceptions occurring in tab completion functions are now printed to stderr before returning + control back to readline. This makes debugging a lot easier since readline suppresses these + exceptions. + - Added support for custom Namespaces in the argparse decorators. See description of + `ns_provider` argument for more information. - Transcript testing now sets the `exit_code` returned from `cmdloop` based on Success/Failure - The history of entered commands previously was saved using the readline persistence mechanism, - and only persisted if you had readline installed. Now history is persisted independent of readline; user - input from previous invocations of `cmd2` based apps now shows in the `history` command. - - Text scripts now run immediately instead of adding their commands to `cmdqueue`. This allows easy capture of - the entire script's output. - - Added member to `CommandResult` called `stop` which is the return value of `onecmd_plus_hooks` after it runs - the given command line. + and only persisted if you had readline installed. Now history is persisted independent of + readline; user input from previous invocations of `cmd2` based apps now shows in the `history` + command. + - Text scripts now run immediately instead of adding their commands to `cmdqueue`. This allows + easy capture of the entire script's output. + - Added member to `CommandResult` called `stop` which is the return value of `onecmd_plus_hooks` + after it runs the given command line. - Breaking changes - - Replaced `unquote_redirection_tokens()` with `unquote_specific_tokens()`. This was to support the fix - that allows terminators in alias and macro values. + - Replaced `unquote_redirection_tokens()` with `unquote_specific_tokens()`. This was to support + the fix that allows terminators in alias and macro values. - Changed `Statement.pipe_to` to a string instead of a list - `preserve_quotes` is now a keyword-only argument in the argparse decorators - - Refactored so that `cmd2.Cmd.cmdloop()` returns the `exit_code` instead of a call to `sys.exit()` - It is now application developer's responsibility to treat the return value from `cmdloop()` accordingly - - Only valid commands are persistent in history between invocations of `cmd2` based apps. Previously - all user input was persistent in history. If readline is installed, the history available with the up and - down arrow keys (readline history) may not match that shown in the `history` command, because `history` - only tracks valid input, while readline history captures all input. - - History is now persisted in a binary format, not plain text format. Previous history files are destroyed - on first launch of a `cmd2` based app of version 0.9.13 or higher. - - HistoryItem class is no longer a subclass of `str`. If you are directly accessing the `.history` attribute - of a `cmd2` based app, you will need to update your code to use `.history.get(1).statement.raw` instead. - - Removed internally used `eos` command that was used to keep track of when a text script's commands ended - - Removed `cmd2` member called `_STOP_AND_EXIT` since it was just a boolean value that should always be True + - Refactored so that `cmd2.Cmd.cmdloop()` returns the `exit_code` instead of a call to + `sys.exit()` It is now application developer's responsibility to treat the return value from + `cmdloop()` accordingly + - Only valid commands are persistent in history between invocations of `cmd2` based apps. + Previously all user input was persistent in history. If readline is installed, the history + available with the up and down arrow keys (readline history) may not match that shown in the + `history` command, because `history` only tracks valid input, while readline history captures + all input. + - History is now persisted in a binary format, not plain text format. Previous history files are + destroyed on first launch of a `cmd2` based app of version 0.9.13 or higher. + - HistoryItem class is no longer a subclass of `str`. If you are directly accessing the + `.history` attribute of a `cmd2` based app, you will need to update your code to use + `.history.get(1).statement.raw` instead. + - Removed internally used `eos` command that was used to keep track of when a text script's + commands ended + - Removed `cmd2` member called `_STOP_AND_EXIT` since it was just a boolean value that should + always be True - Removed `cmd2` member called `_should_quit` since `PyBridge` now handles this logic - Removed support for `cmd.cmdqueue` - `allow_cli_args` is now an argument to **init** instead of a `cmd2` class member - **Python 3.4 EOL notice** - - Python 3.4 reached its [end of life](https://www.python.org/dev/peps/pep-0429/) on March 18, 2019 + - Python 3.4 reached its [end of life](https://www.python.org/dev/peps/pep-0429/) on March 18, + 2019 - This is the last release of `cmd2` which will support Python 3.4 ## 0.9.12 (April 22, 2019) - Bug Fixes - Fixed a bug in how redirection and piping worked inside `py` or `pyscript` commands - - Fixed bug in `async_alert` where it didn't account for prompts that contained newline characters - - Fixed path completion case when CWD is just a slash. Relative path matches were incorrectly prepended with a - slash. + - Fixed bug in `async_alert` where it didn't account for prompts that contained newline + characters + - Fixed path completion case when CWD is just a slash. Relative path matches were incorrectly + prepended with a slash. - Enhancements - - Added ability to include command name placeholders in the message printed when trying to run a disabled command. + - Added ability to include command name placeholders in the message printed when trying to run a + disabled command. - See docstring for `disable_command()` or `disable_category()` for more details. - - Added instance attributes to customize error messages without having to override methods. These messages can - also be colored. - _ `help_error` - the error that prints when no help information can be found - _ `default_error` - the error that prints when a non-existent command is run - - The `with_argparser` decorators now add the Statement object created when parsing the command line to the - `argparse.Namespace` object they pass to the `do_*` methods. It is stored in an attribute called `__statement__`. - This can be useful if a command function needs to know the command line for things like logging. - - Added a `-t` option to the `load` command for automatically generating a transcript based on a script file - - When in a **pyscript**, the stdout and stderr streams of shell commands and processes being piped to are now - captured and included in the `CommandResult` structure. + - Added instance attributes to customize error messages without having to override methods. + These messages can also be colored. _ `help_error` - the error that prints when no help + information can be found _ `default_error` - the error that prints when a non-existent command + is run + - The `with_argparser` decorators now add the Statement object created when parsing the command + line to the `argparse.Namespace` object they pass to the `do_*` methods. It is stored in an + attribute called `__statement__`. This can be useful if a command function needs to know the + command line for things like logging. + - Added a `-t` option to the `load` command for automatically generating a transcript based on a + script file + - When in a **pyscript**, the stdout and stderr streams of shell commands and processes being + piped to are now captured and included in the `CommandResult` structure. - Potentially breaking changes - - The following commands now write to stderr instead of stdout when printing an error. This will make catching - errors easier in pyscript. - _ `do_help()` - when no help information can be found + - The following commands now write to stderr instead of stdout when printing an error. This will + make catching errors easier in pyscript. _ `do_help()` - when no help information can be found _ `default()` - in all cases since this is called when an invalid command name is run \* - `_report_disabled_command_usage()` - in all cases since this is called when a disabled command is run + `_report_disabled_command_usage()` - in all cases since this is called when a disabled command + is run - Removed \*\*\* from beginning of error messages printed by `do_help()` and `default()` - - Significantly refactored `cmd.Cmd` class so that all class attributes got converted to instance attributes, also: - - Added `allow_redirection`, `terminators`, `multiline_commands`, and `shortcuts` as optional arguments - to `cmd2.Cmd.__init__()` - - A few instance attributes were moved inside `StatementParser` and properties were created for accessing them + - Significantly refactored `cmd.Cmd` class so that all class attributes got converted to + instance attributes, also: + - Added `allow_redirection`, `terminators`, `multiline_commands`, and `shortcuts` as + optional arguments to `cmd2.Cmd.__init__()` + - A few instance attributes were moved inside `StatementParser` and properties were created + for accessing them - `self.pipe_proc` is now called `self.cur_pipe_proc_reader` and is a `ProcReader` class. - - Shell commands and commands being piped to while in a _pyscript_ will function as if their output is going - to a pipe and not a tty. This was necessary to be able to capture their output. + - Shell commands and commands being piped to while in a _pyscript_ will function as if their + output is going to a pipe and not a tty. This was necessary to be able to capture their + output. - Removed `reserved_words` class attribute due to lack of use - Removed `keywords` instance attribute due to lack of use @@ -893,44 +976,47 @@ - Bug Fixes - Fixed bug in how **history** command deals with multiline commands when output to a script - - Fixed a bug when the `with_argument_list` decorator is called with the optional `preserve_quotes` argument + - Fixed a bug when the `with_argument_list` decorator is called with the optional + `preserve_quotes` argument - Fix bug in `perror()` where it would try to print an exception Traceback even if none existed - Enhancements - Improvements to the **history** command - Simplified the display format and made it more similar to **bash** - Added **-x**, **--expanded** flag - - output expanded commands instead of entered command (expands aliases, macros, and shortcuts) + - output expanded commands instead of entered command (expands aliases, macros, and + shortcuts) - Added **-v**, **--verbose** flag - display history and include expanded commands if they differ from the typed command - Added support for negative indices - Added `matches_sort_key` to override the default way tab completion matches are sorted - - Added `StdSim.pause_storage` member which when True will cause `StdSim` to not save the output sent to it. - See documentation for `CommandResult` in `pyscript_bridge.py` for reasons pausing the storage can be useful. - - Added ability to disable/enable individual commands and entire categories of commands. When a command - is disabled, it will not show up in the help menu or tab complete. If a user tries to run the command - or call help on it, a command-specific message supplied by the developer will be printed. The following - commands were added to support this feature. + - Added `StdSim.pause_storage` member which when True will cause `StdSim` to not save the output + sent to it. See documentation for `CommandResult` in `pyscript_bridge.py` for reasons pausing + the storage can be useful. + - Added ability to disable/enable individual commands and entire categories of commands. When a + command is disabled, it will not show up in the help menu or tab complete. If a user tries to + run the command or call help on it, a command-specific message supplied by the developer will + be printed. The following commands were added to support this feature. - `enable_command()` - `enable_category()` - `disable_command()` - `disable_category()` - Potentially breaking changes - - Made `cmd2_app` a positional and required argument of `AutoCompleter` since certain functionality now - requires that it can't be `None`. - - `AutoCompleter` no longer assumes `CompletionItem` results are sorted. Therefore you should follow the - `cmd2` convention of setting `self.matches_sorted` to True before returning the results if you have already - sorted the `CompletionItem` list. Otherwise it will be sorted using `self.matches_sort_key`. + - Made `cmd2_app` a positional and required argument of `AutoCompleter` since certain + functionality now requires that it can't be `None`. + - `AutoCompleter` no longer assumes `CompletionItem` results are sorted. Therefore you should + follow the `cmd2` convention of setting `self.matches_sorted` to True before returning the + results if you have already sorted the `CompletionItem` list. Otherwise it will be sorted + using `self.matches_sort_key`. - Removed support for bash completion since this feature had slow performance. Also it relied on `AutoCompleter` which has since developed a dependency on `cmd2` methods. - - Removed ability to call commands in `pyscript` as if they were functions (e.g. `app.help()`) in favor - of only supporting one `pyscript` interface. This simplifies future maintenance. + - Removed ability to call commands in `pyscript` as if they were functions (e.g. `app.help()`) + in favor of only supporting one `pyscript` interface. This simplifies future maintenance. - No longer supporting C-style comments. Hash (#) is the only valid comment marker. - No longer supporting comments embedded in a command. Only command line input where the first - non-whitespace character is a # will be treated as a comment. This means any # character appearing - later in the command will be treated as a literal. The same applies to a # in the middle of a multiline - command, even if it is the first character on a line. - _ \# this is a comment - _ this # is not a comment + non-whitespace character is a # will be treated as a comment. This means any # character + appearing later in the command will be treated as a literal. The same applies to a # in the + middle of a multiline command, even if it is the first character on a line. _ \# this is a + comment _ this # is not a comment ## 0.9.10 (February 22, 2019) @@ -940,42 +1026,47 @@ ## 0.9.9 (February 21, 2019) - Bug Fixes - - Fixed bug where the `set` command was not tab completing from the current `settable` dictionary. + - Fixed bug where the `set` command was not tab completing from the current `settable` + dictionary. - Enhancements - Changed edit command to use do_shell() instead of calling os.system() ## 0.9.8 (February 06, 2019) - Bug Fixes - - Fixed issue with echoing strings in StdSim. Because they were being sent to a binary buffer, line buffering - was being ignored. + - Fixed issue with echoing strings in StdSim. Because they were being sent to a binary buffer, + line buffering was being ignored. - Enhancements - - Made quit() and exit() functions available to scripts run with pyscript. This allows those scripts to exit - back to the console's prompt instead of exiting the whole application. + - Made quit() and exit() functions available to scripts run with pyscript. This allows those + scripts to exit back to the console's prompt instead of exiting the whole application. ## 0.9.7 (January 08, 2019) - Bug Fixes - Fixed bug when user chooses a zero or negative index when calling `Cmd.select()` - - Restored behavior where `cmd_echo` always starts as False in a py script. This was broken in 0.9.5. + - Restored behavior where `cmd_echo` always starts as False in a py script. This was broken in + 0.9.5. - Enhancements - - **cmdloop** now only attempts to register a custom signal handler for SIGINT if running in the main thread - - commands run as a result of `default_to_shell` being **True** now run via `do_shell()` and are saved - to history. + - **cmdloop** now only attempts to register a custom signal handler for SIGINT if running in the + main thread + - commands run as a result of `default_to_shell` being **True** now run via `do_shell()` and are + saved to history. - Added more tab completion to pyscript command. - Deletions (potentially breaking changes) - Deleted `Cmd.colorize()` and `Cmd._colorcodes` which were deprecated in 0.9.5 - - Replaced `dir_exe_only` and `dir_only` flags in `path_complete` with optional `path_filter` function - that is used to filter paths out of completion results. + - Replaced `dir_exe_only` and `dir_only` flags in `path_complete` with optional `path_filter` + function that is used to filter paths out of completion results. - `perror()` no longer prepends "ERROR: " to the error message being printed ## 0.9.6 (October 13, 2018) - Bug Fixes - - Fixed bug introduced in 0.9.5 caused by backing up and restoring `self.prompt` in `pseudo_raw_input`. - As part of this fix, continuation prompts will not be redrawn with `async_update_prompt` or `async_alert`. + - Fixed bug introduced in 0.9.5 caused by backing up and restoring `self.prompt` in + `pseudo_raw_input`. As part of this fix, continuation prompts will not be redrawn with + `async_update_prompt` or `async_alert`. - Enhancements - - All platforms now depend on [wcwidth](https://pypi.python.org/pypi/wcwidth) to assist with asynchronous alerts. + - All platforms now depend on [wcwidth](https://pypi.python.org/pypi/wcwidth) to assist with + asynchronous alerts. - Macros now accept extra arguments when called. These will be tacked onto the resolved command. - All cmd2 commands run via `py` now go through `onecmd_plus_hooks`. @@ -986,49 +1077,52 @@ - Fixed bug where **alias** command was dropping quotes around arguments - Fixed bug where running help on argparse commands didn't work if they didn't support -h - Fixed transcript testing bug where last command in transcript has no expected output - - Fixed bugs with how AutoCompleter and ArgparseFunctor handle argparse - arguments with nargs=argparse.REMAINDER. Tab completion now correctly - matches how argparse will parse the values. Command strings generated by - ArgparseFunctor should now be compliant with how argparse expects - REMAINDER arguments to be ordered. - - Fixed bugs with how AutoCompleter handles flag prefixes. It is no - longer hard-coded to use '-' and will check against the prefix_chars in - the argparse object. Also, single-character tokens that happen to be a - prefix char are not treated as flags by argparse and AutoCompleter now + - Fixed bugs with how AutoCompleter and ArgparseFunctor handle argparse arguments with + nargs=argparse.REMAINDER. Tab completion now correctly matches how argparse will parse the + values. Command strings generated by ArgparseFunctor should now be compliant with how argparse + expects REMAINDER arguments to be ordered. + - Fixed bugs with how AutoCompleter handles flag prefixes. It is no longer hard-coded to use '-' + and will check against the prefix_chars in the argparse object. Also, single-character tokens + that happen to be a prefix char are not treated as flags by argparse and AutoCompleter now matches that behavior. - Fixed bug where AutoCompleter was not distinguishing between a negative number and a flag - - Fixed bug where AutoCompleter did not handle -- the same way argparse does (all args after -- are non-options) + - Fixed bug where AutoCompleter did not handle -- the same way argparse does (all args after -- + are non-options) - Enhancements - Added `exit_code` attribute of `cmd2.Cmd` class - Enables applications to return a non-zero exit code when exiting from `cmdloop` - - `ACHelpFormatter` now inherits from `argparse.RawTextHelpFormatter` to make it easier - for formatting help/description text + - `ACHelpFormatter` now inherits from `argparse.RawTextHelpFormatter` to make it easier for + formatting help/description text - Aliases are now sorted alphabetically - The **set** command now tab completes settable parameter names - Added `async_alert`, `async_update_prompt`, and `set_window_title` functions - - These allow you to provide feedback to the user in an asynchronous fashion, meaning alerts can - display when the user is still entering text at the prompt. - See [async_printing.py](https://github.com/python-cmd2/cmd2/blob/master/examples/async_printing.py) + - These allow you to provide feedback to the user in an asynchronous fashion, meaning alerts + can display when the user is still entering text at the prompt. See + [async_printing.py](https://github.com/python-cmd2/cmd2/blob/master/examples/async_printing.py) for an example. - Cross-platform colored output support - `colorama` gets initialized properly in `Cmd.__init()` - The `Cmd.colors` setting is no longer platform dependent and now has three values: - - Terminal (default) - output methods do not strip any ANSI escape sequences when output is a terminal, but - if the output is a pipe or a file the escape sequences are stripped - - Always - output methods **never** strip ANSI escape sequences, regardless of the output destination + - Terminal (default) - output methods do not strip any ANSI escape sequences when output + is a terminal, but if the output is a pipe or a file the escape sequences are stripped + - Always - output methods **never** strip ANSI escape sequences, regardless of the + output destination - Never - output methods strip all ANSI escape sequences - - Added `macro` command to create macros, which are similar to aliases, but can take arguments when called + - Added `macro` command to create macros, which are similar to aliases, but can take arguments + when called - All cmd2 command functions have been converted to use argparse. - Renamed argparse_example.py to decorator_example.py to help clarify its intent - Deprecations - - Deprecated the built-in `cmd2` support for colors including `Cmd.colorize()` and `Cmd._colorcodes` + - Deprecated the built-in `cmd2` support for colors including `Cmd.colorize()` and + `Cmd._colorcodes` - Deletions (potentially breaking changes) - - The `preparse`, `postparsing_precmd`, and `postparsing_postcmd` methods _deprecated_ in the previous release - have been deleted \* The new application lifecycle hook system allows for registration of callbacks to be called - at various points - in the lifecycle and is more powerful and flexible than the previous system - - `alias` is now a command with subcommands to create, list, and delete aliases. Therefore its syntax - has changed. All current alias commands in startup scripts or transcripts will break with this release. + - The `preparse`, `postparsing_precmd`, and `postparsing_postcmd` methods _deprecated_ in the + previous release have been deleted \* The new application lifecycle hook system allows for + registration of callbacks to be called at various points in the lifecycle and is more powerful + and flexible than the previous system + - `alias` is now a command with subcommands to create, list, and delete aliases. Therefore its + syntax has changed. All current alias commands in startup scripts or transcripts will break + with this release. - `unalias` was deleted since `alias delete` replaced it ## 0.9.4 (August 21, 2018) @@ -1037,21 +1131,22 @@ - Fixed bug where `preparse` was not getting called - Fixed bug in parsing of multiline commands where matching quote is on another line - Enhancements - - Improved implementation of lifecycle hooks to support a plugin - framework, see `docs/hooks.rst` for details. + - Improved implementation of lifecycle hooks to support a plugin framework, see `docs/hooks.rst` + for details. - New dependency on `attrs` third party module - Added `matches_sorted` member to support custom sorting of tab completion matches - - Added [tab_autocomp_dynamic.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocomp_dynamic.py) + - Added + [tab_autocomp_dynamic.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocomp_dynamic.py) example - Demonstrates updating the argparse object during init instead of during class construction - Deprecations - Deprecated the following hook methods, see `hooks.rst` for full details: - - `cmd2.Cmd.preparse()` - equivalent functionality available - via `cmd2.Cmd.register_postparsing_hook()` - - `cmd2.Cmd.postparsing_precmd()` - equivalent functionality available - via `cmd2.Cmd.register_postparsing_hook()` - - `cmd2.Cmd.postparsing_postcmd()` - equivalent functionality available - via `cmd2.Cmd.register_postcmd_hook()` + - `cmd2.Cmd.preparse()` - equivalent functionality available via + `cmd2.Cmd.register_postparsing_hook()` + - `cmd2.Cmd.postparsing_precmd()` - equivalent functionality available via + `cmd2.Cmd.register_postparsing_hook()` + - `cmd2.Cmd.postparsing_postcmd()` - equivalent functionality available via + `cmd2.Cmd.register_postcmd_hook()` ## 0.8.9 (August 20, 2018) @@ -1066,7 +1161,8 @@ - Enhancements - Added `--clear` flag to `history` command that clears both the command and readline history. - Deletions - - The `CmdResult` helper class which was _deprecated_ in the previous release has now been deleted + - The `CmdResult` helper class which was _deprecated_ in the previous release has now been + deleted - It has been replaced by the improved `CommandResult` class ## 0.9.2 (June 28, 2018) @@ -1074,19 +1170,22 @@ - Bug Fixes - Fixed issue where piping and redirecting did not work correctly with paths that had spaces - Enhancements - - Added ability to print a header above tab completion suggestions using `completion_header` member + - Added ability to print a header above tab completion suggestions using `completion_header` + member - Added `pager` and `pager_chop` attributes to the `cmd2.Cmd` class - `pager` defaults to **less -RXF** on POSIX and **more** on Windows - `pager_chop` defaults to **less -SRXF** on POSIX and **more** on Windows - Added `chop` argument to `cmd2.Cmd.ppaged()` method for displaying output using a pager - If `chop` is `False`, then `self.pager` is used as the pager - Otherwise `self.pager_chop` is used as the pager - - Greatly improved the [table_display.py](https://github.com/python-cmd2/cmd2/blob/master/examples/table_display.py) + - Greatly improved the + [table_display.py](https://github.com/python-cmd2/cmd2/blob/master/examples/table_display.py) example - - Now uses the new [tableformatter](https://github.com/python-tableformatter/tableformatter) module which looks - better than `tabulate` + - Now uses the new [tableformatter](https://github.com/python-tableformatter/tableformatter) + module which looks better than `tabulate` - Deprecations - - The `CmdResult` helper class is _deprecated_ and replaced by the improved `CommandResult` class + - The `CmdResult` helper class is _deprecated_ and replaced by the improved `CommandResult` + class - `CommandResult` has the following attributes: **stdout**, **stderr**, and **data** - `CmdResult` had attributes of: **out**, **err**, **war** - `CmdResult` will be deleted in the next release @@ -1094,59 +1193,65 @@ ## 0.8.8 (June 28, 2018) - Bug Fixes - - Prevent crashes that could occur attempting to open a file in non-existent directory or with very long filename + - Prevent crashes that could occur attempting to open a file in non-existent directory or with + very long filename - Enhancements - `display_matches` is no longer restricted to delimited strings ## 0.9.1 (May 28, 2018) - Bug Fixes - - fix packaging error for 0.8.x versions (yes we had to deploy a new version - of the 0.9.x series to fix a packaging error with the 0.8.x version) + - fix packaging error for 0.8.x versions (yes we had to deploy a new version of the 0.9.x series + to fix a packaging error with the 0.8.x version) ## 0.9.0 (May 28, 2018) - Bug Fixes - - If self.default_to_shell is true, then redirection and piping are now properly passed to the shell. Previously it - was truncated. + - If self.default_to_shell is true, then redirection and piping are now properly passed to the + shell. Previously it was truncated. - Submenus now call all hooks, it used to just call precmd and postcmd. - Enhancements - Automatic completion of `argparse` arguments via `cmd2.argparse_completer.AutoCompleter` - - See - the [tab_autocompletion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion.py) + - See the + [tab_autocompletion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion.py) example for a demonstration of how to use this feature - `cmd2` no longer depends on the `six` module - `cmd2` is now a multi-file Python package instead of a single-file module - New pyscript approach that provides a pythonic interface to commands in the cmd2 application. - Switch command parsing from pyparsing to custom code which utilizes shlex. - - The object passed to do*\* methods has changed. It no longer is the pyparsing object, it's a new Statement - object, which is a subclass of `str`. The statement object has many attributes which give you access to - various components of the parsed input. If you were using anything but the string in your do*\* methods, this - change will require you to update your code. - - `commentGrammars` is no longer supported or available. Comments are C-style or python style. + - The object passed to do*\* methods has changed. It no longer is the pyparsing object, it's + a new Statement object, which is a subclass of `str`. The statement object has many + attributes which give you access to various components of the parsed input. If you were + using anything but the string in your do*\* methods, this change will require you to + update your code. + - `commentGrammars` is no longer supported or available. Comments are C-style or python + style. - Input redirection no longer supported. Use the load command instead. - `multilineCommand` attribute is `now multiline_command` - - `identchars` is now ignored. The standardlibrary cmd uses those characters to split the first "word" of the - input, but cmd2 hasn't used those for a while, and the new parsing logic parses on whitespace, which has the - added benefit of full unicode support, unlike cmd or prior versions of cmd2. - - `set_posix_shlex` function and `POSIX_SHLEX` variable have been removed. Parsing behavior is now always the - more forgiving `posix=false`. - - `set_strip_quotes` function and `STRIP_QUOTES_FOR_NON_POSIX` have been removed. Quotes are stripped from - arguments when presented as a list (a la `sys.argv`), and present when arguments are presented as a string ( - like the string passed to do\_\*). + - `identchars` is now ignored. The standardlibrary cmd uses those characters to split the + first "word" of the input, but cmd2 hasn't used those for a while, and the new parsing + logic parses on whitespace, which has the added benefit of full unicode support, unlike + cmd or prior versions of cmd2. + - `set_posix_shlex` function and `POSIX_SHLEX` variable have been removed. Parsing behavior + is now always the more forgiving `posix=false`. + - `set_strip_quotes` function and `STRIP_QUOTES_FOR_NON_POSIX` have been removed. Quotes are + stripped from arguments when presented as a list (a la `sys.argv`), and present when + arguments are presented as a string ( like the string passed to do\_\*). - Changes - `strip_ansi()` and `strip_quotes()` functions have moved to new utils module - Several constants moved to new constants module - - Submenu support has been moved to a new [cmd2-submenu](https://github.com/python-cmd2/cmd2-submenu) plugin. If you - use submenus, you will need to update your dependencies and modify your imports. + - Submenu support has been moved to a new + [cmd2-submenu](https://github.com/python-cmd2/cmd2-submenu) plugin. If you use submenus, you + will need to update your dependencies and modify your imports. - Deletions (potentially breaking changes) - Deleted all `optparse` code which had previously been deprecated in release 0.8.0 - The `options` decorator no longer exists - All `cmd2` code should be ported to use the new `argparse`-based decorators - - See the [Argument Processing](http://cmd2.readthedocs.io/en/latest/argument_processing.html) section of the - documentation for more information on these decorators - - Alternatively, see - the [argparse_example.py](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_example.py) + - See the + [Argument Processing](http://cmd2.readthedocs.io/en/latest/argument_processing.html) + section of the documentation for more information on these decorators + - Alternatively, see the + [argparse_example.py](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_example.py) - Deleted `cmd_with_subs_completer`, `get_subcommands`, and `get_subcommand_completer` - Replaced by default AutoCompleter implementation for all commands using argparse - Deleted support for old method of calling application commands with `cmd()` and `self` @@ -1161,10 +1266,11 @@ ## 0.8.6 (May 27, 2018) - Bug Fixes - - Commands using the @with_argparser_and_unknown_args were not correctly recognized when tab completing + - Commands using the @with_argparser_and_unknown_args were not correctly recognized when tab + completing - Fixed issue where completion display function was overwritten when a submenu quits - - Fixed `AttributeError` on Windows when running a `select` command cause by **pyreadline** not implementing - `remove_history_item` + - Fixed `AttributeError` on Windows when running a `select` command cause by **pyreadline** not + implementing `remove_history_item` - Enhancements - Added warning about **libedit** variant of **readline** not being supported on macOS - Added tab completion of alias names in value field of **alias** command @@ -1176,27 +1282,32 @@ - Bug Fixes - - Fixed a bug with all argument decorators where the wrapped function wasn't returning a value and thus couldn't - cause the cmd2 app to quit + - Fixed a bug with all argument decorators where the wrapped function wasn't returning a value + and thus couldn't cause the cmd2 app to quit - Enhancements - - Added support for verbose help with -v where it lists a brief summary of what each command does + - Added support for verbose help with -v where it lists a brief summary of what each command + does - Added support for categorizing commands into groups within the help menu - - See - the [Grouping Commands](http://cmd2.readthedocs.io/en/latest/argument_processing.html?highlight=verbose#grouping-commands) + - See the + [Grouping Commands](http://cmd2.readthedocs.io/en/latest/argument_processing.html?highlight=verbose#grouping-commands) section of the docs for more info - - See [help_categories.py](https://github.com/python-cmd2/cmd2/blob/master/examples/help_categories.py) for an - example + - See + [help_categories.py](https://github.com/python-cmd2/cmd2/blob/master/examples/help_categories.py) + for an example - Tab completion of paths now supports ~user user path expansion - - Simplified implementation of various tab completion functions so they no longer require `ctypes` - - Expanded documentation of `display_matches` list to clarify its purpose. See cmd2.py for this documentation. + - Simplified implementation of various tab completion functions so they no longer require + `ctypes` + - Expanded documentation of `display_matches` list to clarify its purpose. See cmd2.py for this + documentation. - Adding opening quote to tab completion if any of the completion suggestions have a space. - **Python 2 EOL notice** - This is the last release where new features will be added to `cmd2` for Python 2.7 - The 0.9.0 release of `cmd2` will support Python 3.4+ only - - Additional 0.8.x releases may be created to supply bug fixes for Python 2.7 up until August 31, 2018 + - Additional 0.8.x releases may be created to supply bug fixes for Python 2.7 up until August + 31, 2018 - After August 31, 2018 not even bug fixes will be provided for Python 2.7 ## 0.8.4 (April 10, 2018) @@ -1213,49 +1324,56 @@ - Enhancements - - Tab completion has been overhauled and now supports completion of strings with quotes and spaces. + - Tab completion has been overhauled and now supports completion of strings with quotes and + spaces. - Tab completion will automatically add an opening quote if a string with a space is completed. - Added `delimiter_complete` function for tab completing delimited strings - - Added more control over tab completion behavior including the following flags. The use of these flags is - documented in cmd2.py + - Added more control over tab completion behavior including the following flags. The use of + these flags is documented in cmd2.py - `allow_appended_space` - `allow_closing_quote` - - Due to the tab completion changes, non-Windows platforms now depend - on [wcwidth](https://pypi.python.org/pypi/wcwidth). + - Due to the tab completion changes, non-Windows platforms now depend on + [wcwidth](https://pypi.python.org/pypi/wcwidth). - An alias name can now match a command name. - An alias can now resolve to another alias. - Attribute Changes (Breaks backward compatibility) - - `exclude_from_help` is now called `hidden_commands` since these commands are hidden from things other than help, - including tab completion - - This list also no longer takes the function names of commands (`do_history`), but instead uses the command - names themselves (`history`) + - `exclude_from_help` is now called `hidden_commands` since these commands are hidden from + things other than help, including tab completion + - This list also no longer takes the function names of commands (`do_history`), but instead + uses the command names themselves (`history`) - `excludeFromHistory` is now called `exclude_from_history` - - `cmd_with_subs_completer()` no longer takes an argument called `base`. Adding tab completion to subcommands has - been simplified to declaring it in the - subcommand parser's default settings. This easily allows arbitrary completers like path_complete to be used. - See [subcommands.py](https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py) for an example of - how to use - tab completion in subcommands. In addition, the docstring for `cmd_with_subs_completer()` offers more details. + - `cmd_with_subs_completer()` no longer takes an argument called `base`. Adding tab completion + to subcommands has been simplified to declaring it in the subcommand parser's default + settings. This easily allows arbitrary completers like path_complete to be used. See + [subcommands.py](https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py) for + an example of how to use tab completion in subcommands. In addition, the docstring for + `cmd_with_subs_completer()` offers more details. ## 0.8.2 (March 21, 2018) - Bug Fixes - Fixed a bug in tab completion of command names within sub-menus - Fixed a bug when using persistent readline history in Python 2.7 - - Fixed a bug where the `AddSubmenu` decorator didn't work with a default value for `shared_attributes` - - Added a check to `ppaged()` to only use a pager when running in a real fully functional terminal -- Enhancements - - Added [quit_on_sigint](http://cmd2.readthedocs.io/en/latest/settingchanges.html#quit-on-sigint) attribute to - enable canceling current line instead of quitting when Ctrl+C is typed + - Fixed a bug where the `AddSubmenu` decorator didn't work with a default value for + `shared_attributes` + - Added a check to `ppaged()` to only use a pager when running in a real fully functional + terminal +- Enhancements + - Added + [quit_on_sigint](http://cmd2.readthedocs.io/en/latest/settingchanges.html#quit-on-sigint) + attribute to enable canceling current line instead of quitting when Ctrl+C is typed - Added possibility of having readline history preservation in a SubMenu - - Added [table_display.py](https://github.com/python-cmd2/cmd2/blob/master/examples/table_display.py) example to - demonstrate how to display tabular data + - Added + [table_display.py](https://github.com/python-cmd2/cmd2/blob/master/examples/table_display.py) + example to demonstrate how to display tabular data - Added command aliasing with `alias` and `unalias` commands - Added the ability to load an initialization script at startup - - See [alias_startup.py](https://github.com/python-cmd2/cmd2/blob/master/examples/alias_startup.py) for an - example - - Added a default SIGINT handler which terminates any open pipe subprocesses and re-raises a KeyboardInterrupt + - See + [alias_startup.py](https://github.com/python-cmd2/cmd2/blob/master/examples/alias_startup.py) + for an example + - Added a default SIGINT handler which terminates any open pipe subprocesses and re-raises a + KeyboardInterrupt - For macOS, will load the `gnureadline` module if available and `readline` if not ## 0.8.1 (March 9, 2018) @@ -1264,27 +1382,33 @@ - Fixed a bug if a non-existent **do\_\*** method was added to the `exclude_from_help` list - Fixed a bug in a unit test which would fail if your home directory was empty on a Linux system - Fixed outdated help text for the **edit** command - - Fixed outdated [remove_unused.py](https://github.com/python-cmd2/cmd2/blob/master/examples/remove_unused.py) + - Fixed outdated + [remove_unused.py](https://github.com/python-cmd2/cmd2/blob/master/examples/remove_unused.py) - Enhancements - Added support for sub-menus. - - See [submenus.py](https://github.com/python-cmd2/cmd2/blob/master/examples/submenus.py) for an example of how - to use it + - See [submenus.py](https://github.com/python-cmd2/cmd2/blob/master/examples/submenus.py) + for an example of how to use it - Added option for persistent readline history - - See [persistent_history.py](https://github.com/python-cmd2/cmd2/blob/master/examples/persistent_history.py) - for an example - See - the [Searchable command history](http://cmd2.readthedocs.io/en/latest/freefeatures.html#searchable-command-history) + [persistent_history.py](https://github.com/python-cmd2/cmd2/blob/master/examples/persistent_history.py) + for an example + - See the + [Searchable command history](http://cmd2.readthedocs.io/en/latest/freefeatures.html#searchable-command-history) section of the documentation for more info - Improved PyPI packaging by including unit tests and examples in the tarball - - Improved documentation to make it more obvious that **poutput()** should be used instead of **print()** + - Improved documentation to make it more obvious that **poutput()** should be used instead of + **print()** - `exclude_from_help` and `excludeFromHistory` are now instance instead of class attributes - Added flag and index based tab completion helper functions - - See [tab_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_completion.py) + - See + [tab_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_completion.py) - Added support for displaying output which won't fit on the screen via a pager using `ppaged()` - - See [paged_output.py](https://github.com/python-cmd2/cmd2/blob/master/examples/paged_output.py) + - See + [paged_output.py](https://github.com/python-cmd2/cmd2/blob/master/examples/paged_output.py) - Attributes Removed (**can cause breaking changes**) - `abbrev` - Removed support for abbreviated commands - - Good tab completion makes this unnecessary and its presence could cause harmful unintended actions + - Good tab completion makes this unnecessary and its presence could cause harmful unintended + actions - `case_insensitive` - Removed support for case-insensitive command parsing - Its presence wasn't very helpful and could cause harmful unintended actions @@ -1296,42 +1420,56 @@ - Enhancements - Three new decorators for **do\_\*** commands to make argument parsing easier - **with_argument_list** decorator to change argument type from str to List[str] - - **do\_\*** commands get a single argument which is a list of strings, as pre-parsed by shlex.split() - - **with_arparser** decorator for strict argparse-based argument parsing of command arguments + - **do\_\*** commands get a single argument which is a list of strings, as pre-parsed by + shlex.split() + - **with_arparser** decorator for strict argparse-based argument parsing of command + arguments - **do\_\*** commands get a single argument which is the output of argparse.parse_args() - - **with_argparser_and_unknown_args** decorator for argparse-based argument parsing, but allows unknown args + - **with_argparser_and_unknown_args** decorator for argparse-based argument parsing, but + allows unknown args - **do\_\*** commands get two arguments, the output of argparse.parse_known_args() - - See the [Argument Processing](http://cmd2.readthedocs.io/en/latest/argument_processing.html) section of the - documentation for more information on these decorators - - Alternatively, see - the [argparse_example.py](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_example.py) - and [arg_print.py](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py) examples + - See the [Argument Processing](http://cmd2.readthedocs.io/en/latest/argument_processing.html) + section of the documentation for more information on these decorators + - Alternatively, see the + [argparse_example.py](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_example.py) + and [arg_print.py](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py) + examples - Added support for Argparse subcommands when using the **with_argument_parser** or \* \*with_argparser_and_unknown_args\*\* decorators - - See [subcommands.py](https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py) for an example - of how to use subcommands + - See + [subcommands.py](https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py) + for an example of how to use subcommands - Tab completion of subcommand names is automatically supported - The **\_\_relative_load** command is now hidden from the help menu by default - This command is not intended to be called from the command line, only from within scripts - - The **set** command now has an additional **-a/--all** option to also display read-only settings - - The **history** command can now run, edit, and save prior commands, in addition to displaying prior commands. - - The **history** command can now automatically generate a transcript file for regression testing + - The **set** command now has an additional **-a/--all** option to also display read-only + settings + - The **history** command can now run, edit, and save prior commands, in addition to displaying + prior commands. + - The **history** command can now automatically generate a transcript file for regression + testing - This makes creating regression tests for your `cmd2` application trivial - Commands Removed - - The **cmdenvironment** has been removed and its functionality incorporated into the **-a/--all** argument to **set - ** - - The **show** command has been removed. Its functionality has always existing within **set** and continues to do so - - The **save** command has been removed. The capability to save commands is now part of the **history** command. - - The **run** command has been removed. The capability to run prior commands is now part of the **history** command. + - The **cmdenvironment** has been removed and its functionality incorporated into the + **-a/--all** argument to **set ** + - The **show** command has been removed. Its functionality has always existing within **set** + and continues to do so + - The **save** command has been removed. The capability to save commands is now part of the + **history** command. + - The **run** command has been removed. The capability to run prior commands is now part of the + **history** command. - Other changes - - The **edit** command no longer allows you to edit prior commands. The capability to edit prior commands is now - part of the **history** command. The **edit** command still allows you to edit arbitrary files. + - The **edit** command no longer allows you to edit prior commands. The capability to edit prior + commands is now part of the **history** command. The **edit** command still allows you to edit + arbitrary files. - the **autorun_on_edit** setting has been removed. - - For Python 3.4 and earlier, `cmd2` now has an additional dependency on the `contextlib2` module + - For Python 3.4 and earlier, `cmd2` now has an additional dependency on the `contextlib2` + module - Deprecations - The old **options** decorator for optparse-based argument parsing is now _deprecated_ - The old decorator is still present for now, but will be removed in a future release - - `cmd2` no longer includes **optparse.make_option**, so if your app needs it import directly from optparse + - `cmd2` no longer includes **optparse.make_option**, so if your app needs it import + directly from optparse ## 0.7.9 (January 4, 2018) @@ -1341,14 +1479,16 @@ - Improved documentation for modifying shortcuts (command aliases) - Made `pyreadline` a dependency on Windows to ensure tab completion works - Other changes - - Abandoned official support for Python 3.3. It should still work, just don't have an easy way to test it anymore. + - Abandoned official support for Python 3.3. It should still work, just don't have an easy way + to test it anymore. ## 0.7.8 (November 8, 2017) - Bug Fixes - Fixed `poutput()` so it can print an integer zero and other **falsy** things - Fixed a bug which was causing autodoc to fail for building docs on Readthedocs - - Fixed bug due to `pyperclip` dependency radically changing its project structure in latest version + - Fixed bug due to `pyperclip` dependency radically changing its project structure in latest + version - Enhancements - Improved documentation for user-settable environment parameters - Improved documentation for overriding the default supported comment styles @@ -1365,7 +1505,8 @@ - `feedback_to_output` now defaults to `False` so info like command timing won't redirect - Transcript regular expressions now have predictable, tested, and documented behavior - This makes a breaking change to the format and expectations of transcript testing - - The prior behavior removed whitespace before making the comparison, now whitespace must match exactly + - The prior behavior removed whitespace before making the comparison, now whitespace must + match exactly - Prior version did not allow regexes with whitespace, new version allows any regex - Improved display for `load` command and input redirection when **echo** is `True` @@ -1386,14 +1527,17 @@ - Bug Fixes - `case_insensitive` is no longer a runtime-settable parameter, but it was still listed as such - - Fixed a recursive loop bug when abbreviated commands are enabled and it could get stuck in the editor forever + - Fixed a recursive loop bug when abbreviated commands are enabled and it could get stuck in the + editor forever - Added additional command abbreviations to the "exclude from history" list - Fixed argparse_example.py and pirate.py examples and transcript_regex.txt transcript - Fixed a bug in a unit test which occurred under unusual circumstances - Enhancements - Organized all attributes used to configure the ParserManager into a single location - - Set the default value of `abbrev` to `False` (which controls whether or not abbreviated commands are allowed) - - With good tab completion of command names, using abbreviated commands isn't particularly useful + - Set the default value of `abbrev` to `False` (which controls whether or not abbreviated + commands are allowed) + - With good tab completion of command names, using abbreviated commands isn't particularly + useful - And it can create complications if you are't careful - Improved implementation of `load` to use command queue instead of nested inner loop @@ -1402,7 +1546,8 @@ - Bug fixes - Fixed a couple bugs in interacting with pastebuffer/clipboard on macOS and Linux - Fixed a couple bugs in edit and save commands if called when history is empty - - Ability to pipe `cmd2` command output to a shell command is now more reliable, particularly on Windows + - Ability to pipe `cmd2` command output to a shell command is now more reliable, particularly on + Windows - Fixed a bug in `pyscript` command on Windows related to `\` being interpreted as an escape - Enhancements - Ensure that path and shell command tab completion results are alphabetically sorted @@ -1428,35 +1573,42 @@ - Enhancements - Added the ability to exclude commands from the help menu (**eof** included by default) - Redundant **list** command removed and features merged into **history** command - - Added **pyscript** command which supports tab completion and running Python scripts with arguments + - Added **pyscript** command which supports tab completion and running Python scripts with + arguments - Improved tab completion of file system paths, command names, and shell commands - Thanks to Kevin Van Brunt for all of the help with debugging and testing this - - Changed default value of USE_ARG_LIST to True - this affects the beavhior of all **@options** commands - - **WARNING**: This breaks backwards compatibility, to restore backwards compatibility, add this to the \*\* - \*\*init\*\*()\*\* method in your custom class derived from cmd2.Cmd: + - Changed default value of USE_ARG_LIST to True - this affects the beavhior of all **@options** + commands + - **WARNING**: This breaks backwards compatibility, to restore backwards compatibility, add + this to the \*\* \*\*init\*\*()\*\* method in your custom class derived from cmd2.Cmd: - cmd2.set_use_arg_list(False) - This change improves argument parsing for all new applications - Refactored code to encapsulate most of the pyparsing logic into a ParserManager class ## 0.7.2 (May 22, 2017) -- Added a MANIFEST.ini file to make sure a few extra files get included in the PyPI source distribution +- Added a MANIFEST.ini file to make sure a few extra files get included in the PyPI source + distribution ## 0.7.1 (May 22, 2017) - Bug fixes - `-` wasn't being treated as a legal character - - The allow_cli_args attribute wasn't properly disabling parsing of args at invocation when False - - py command wasn't allowing scripts which used _cmd_ function prior to entering an interactive Python session + - The allow_cli_args attribute wasn't properly disabling parsing of args at invocation when + False + - py command wasn't allowing scripts which used _cmd_ function prior to entering an interactive + Python session - Don't throw exception when piping output to a shell command - Transcript testing now properly calls `preloop` before and `postloop` after - Fixed readline bug related to ANSI color escape codes in the prompt - Added CONTRIBUTING.md and CODE_OF_CONDUCT.md files - Added unicode parsing unit tests and listed unicode support as a feature when using Python 3 - Added more examples and improved documentation - - Example for how use cmd2 in a way where it doesn't own the main loop so it can integrate with external event loops + - Example for how use cmd2 in a way where it doesn't own the main loop so it can integrate with + external event loops - Example for how to use argparse for parsing command-line args at invocation - - Example for how to use the **py** command to run Python scripts which use conditional control flow + - Example for how to use the **py** command to run Python scripts which use conditional control + flow - Example of how to use regular expressions in a transcript test - Added CmdResult namedtumple for returning and storing results - Added local file system path completion for `edit`, `load`, `save`, and `shell` commands @@ -1466,7 +1618,8 @@ ## 0.7.0 (February 23, 2017) - Refactored to use six module for a unified codebase which supports both Python 2 and Python 3 -- Stabilized on all platforms (Windows, Mac, Linux) and all supported Python versions (2.7, 3.3, 3.4, 3.5, 3.6, PyPy) +- Stabilized on all platforms (Windows, Mac, Linux) and all supported Python versions (2.7, 3.3, + 3.4, 3.5, 3.6, PyPy) - Added lots of unit tests and fixed a number of bugs - Improved documentation and moved it to cmd2.readthedocs.io @@ -1483,8 +1636,8 @@ ## 0.6.6.1 (August 14, 2013) -- No changes to code trunk. Generated sdist from Python 2.7 to avoid 2to3 changes being applied to source. ( - Issue https://bitbucket.org/catherinedevlin/cmd2/issue/6/packaging-bug) +- No changes to code trunk. Generated sdist from Python 2.7 to avoid 2to3 changes being applied to + source. ( Issue https://bitbucket.org/catherinedevlin/cmd2/issue/6/packaging-bug) ## 0.6.6 (August 6, 2013) @@ -1493,7 +1646,8 @@ ## 0.6.5.1 (March 18, 2013) -- Bugfix for setup.py version check for Python 2.6, contributed by Tomaz Muraus (https://bitbucket.org/kami) +- Bugfix for setup.py version check for Python 2.6, contributed by Tomaz Muraus + (https://bitbucket.org/kami) ## 0.6.5 (February 29, 2013) diff --git a/Makefile b/Makefile index 290a17b8e..9c851c146 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ install: ## Install the virtual environment with dependencies @echo "🚀 Installing Git pre-commit hooks locally" @uv run pre-commit install @echo "🚀 Installing Prettier using npm" - @npm install + @npm install -q --no-fund --include=dev .PHONY: check check: ## Run code quality tools. diff --git a/README.md b/README.md index 6a54136a1..f3aea16b4 100755 --- a/README.md +++ b/README.md @@ -29,22 +29,22 @@ when using cmd. ![system schema](https://raw.githubusercontent.com/python-cmd2/cmd2/master/.github/images/graph.drawio.png) -When creating solutions developers have no shortage of tools to create rich and smart user interfaces. -System administrators have long been duct taping together brittle workflows based on a menagerie of simple command line -tools created by strangers on github and the guy down the hall. -Unfortunately, when CLIs become significantly complex the ease of command discoverability tends to fade quickly. -On the other hand, Web and traditional desktop GUIs are first in class when it comes to easily discovering -functionality. -The price we pay for beautifully colored displays is complexity required to aggregate disperate applications into larger -systems. -`cmd2` fills the niche between high [ease of command discovery](https://clig.dev/#ease-of-discovery) applications and -smart workflow automation systems. - -The `cmd2` framework provides a great mixture of both worlds. Application designers can easily create complex -applications and rely on the cmd2 library to offer effortless user facing help and extensive tab completion. -When users become comfortable with functionality, cmd2 turns into a feature rich library enabling a smooth transition to -full automation. If designed with enough forethought, a well implemented cmd2 application can serve as a boutique -workflow tool. `cmd2` pulls off this flexibility based on two pillars of philosophy: +When creating solutions developers have no shortage of tools to create rich and smart user +interfaces. System administrators have long been duct taping together brittle workflows based on a +menagerie of simple command line tools created by strangers on github and the guy down the hall. +Unfortunately, when CLIs become significantly complex the ease of command discoverability tends to +fade quickly. On the other hand, Web and traditional desktop GUIs are first in class when it comes +to easily discovering functionality. The price we pay for beautifully colored displays is complexity +required to aggregate disperate applications into larger systems. `cmd2` fills the niche between +high [ease of command discovery](https://clig.dev/#ease-of-discovery) applications and smart +workflow automation systems. + +The `cmd2` framework provides a great mixture of both worlds. Application designers can easily +create complex applications and rely on the cmd2 library to offer effortless user facing help and +extensive tab completion. When users become comfortable with functionality, cmd2 turns into a +feature rich library enabling a smooth transition to full automation. If designed with enough +forethought, a well implemented cmd2 application can serve as a boutique workflow tool. `cmd2` pulls +off this flexibility based on two pillars of philosophy: - Tab Completion - Automation Transition @@ -53,8 +53,8 @@ workflow tool. `cmd2` pulls off this flexibility based on two pillars of philoso -Deep extensive tab completion and help text generation based on the argparse library create the first pillar of 'ease of -command discovery'. The following is a list of features in this category. +Deep extensive tab completion and help text generation based on the argparse library create the +first pillar of 'ease of command discovery'. The following is a list of features in this category. - Great tab completion of commands, subcommands, file system paths, and shell commands. - Custom tab completion for user designed commands via simple function overloading. @@ -65,13 +65,15 @@ command discovery'. The following is a list of features in this category. -cmd2 creates the second pillar of 'ease of transition to automation' through alias/macro creation, command line argument -parsing and execution of cmd2 scripting. +cmd2 creates the second pillar of 'ease of transition to automation' through alias/macro creation, +command line argument parsing and execution of cmd2 scripting. - Flexible alias and macro creation for quick abstraction of commands. - Text file scripting of your application with `run_script` (`@`) and `_relative_run_script` (`@@`) -- Powerful and flexible built-in Python scripting of your application using the `run_pyscript` command -- Transcripts for use with built-in regression can be automatically generated from `history -t` or `run_script -t` +- Powerful and flexible built-in Python scripting of your application using the `run_pyscript` + command +- Transcripts for use with built-in regression can be automatically generated from `history -t` or + `run_script -t` ## Installation @@ -81,11 +83,12 @@ On all operating systems, the latest stable version of `cmd2` can be installed u pip install -U cmd2 ``` -cmd2 works with Python 3.9+ on Windows, macOS, and Linux. It is pure Python code with few 3rd-party dependencies. +cmd2 works with Python 3.9+ on Windows, macOS, and Linux. It is pure Python code with few 3rd-party +dependencies. For information on other installation options, see -[Installation Instructions](https://cmd2.readthedocs.io/en/latest/overview/installation.html) in the cmd2 -documentation. +[Installation Instructions](https://cmd2.readthedocs.io/en/latest/overview/installation.html) in the +cmd2 documentation. ## Documentation @@ -93,7 +96,8 @@ The latest documentation for cmd2 can be read online here: https://cmd2.readthed It is available in HTML, PDF, and ePub formats. -The best way to learn the cmd2 api is to delve into the example applications located in source under examples. +The best way to learn the cmd2 api is to delve into the example applications located in source under +examples. ## Tutorials @@ -102,13 +106,15 @@ The best way to learn the cmd2 api is to delve into the example applications loc - [slides](https://github.com/python-cmd2/talks/blob/master/PyOhio_2019/cmd2-PyOhio_2019.pdf) - [example code](https://github.com/python-cmd2/talks/tree/master/PyOhio_2019/examples) - [Cookiecutter](https://github.com/cookiecutter/cookiecutter) Templates from community - - Basic cookiecutter template for cmd2 application : https://github.com/jayrod/cookiecutter-python-cmd2 - - Advanced cookiecutter template with external plugin - support : https://github.com/jayrod/cookiecutter-python-cmd2-ext-plug + - Basic cookiecutter template for cmd2 application : + https://github.com/jayrod/cookiecutter-python-cmd2 + - Advanced cookiecutter template with external plugin support : + https://github.com/jayrod/cookiecutter-python-cmd2-ext-plug - [cmd2 example applications](https://github.com/python-cmd2/cmd2/tree/master/examples) - Basic cmd2 examples to demonstrate how to use various features - [Advanced Examples](https://github.com/jayrod/cmd2-example-apps) - - More complex examples that demonstrate more featuers about how to put together a complete application + - More complex examples that demonstrate more featuers about how to put together a complete + application ## Hello World @@ -136,10 +142,10 @@ if __name__ == '__main__': ## Found a bug? -If you think you've found a bug, please first read through the -open [Issues](https://github.com/python-cmd2/cmd2/issues). If you're confident it's a new bug, go ahead and create a new -GitHub issue. Be sure to include as much information as possible so we can reproduce the bug. At a minimum, please state -the following: +If you think you've found a bug, please first read through the open +[Issues](https://github.com/python-cmd2/cmd2/issues). If you're confident it's a new bug, go ahead +and create a new GitHub issue. Be sure to include as much information as possible so we can +reproduce the bug. At a minimum, please state the following: - `cmd2` version - Python version @@ -181,4 +187,5 @@ Possibly defunct but still good examples | [FLASHMINGO](https://github.com/mandiant/flashmingo) | Automatic analysis of SWF files based on some heuristics. Extensible via plugins. | [Mandiant](https://github.com/mandiant) | | [psiTurk](https://github.com/NYUCCL/psiTurk) | An open platform for science on Amazon Mechanical Turk | [NYU Computation and Cognition Lab](https://github.com/NYUCCL) | -Note: If you have created an application based on `cmd2` that you would like us to mention here, please get in touch. +Note: If you have created an application based on `cmd2` that you would like us to mention here, +please get in touch. diff --git a/docs/api/index.md b/docs/api/index.md index a427e00b9..291bcbccd 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -1,22 +1,30 @@ # API Reference -These pages document the public API for `cmd2`. If a method, class, function, attribute, or constant is not documented here, consider it private and subject to change. There are many classes, methods, functions, and constants in the source code which do not begin with an underscore but are not documented here. When looking at the source code for this library, you cannot safely assume that because something doesn't start with an underscore, it is a public API. +These pages document the public API for `cmd2`. If a method, class, function, attribute, or constant +is not documented here, consider it private and subject to change. There are many classes, methods, +functions, and constants in the source code which do not begin with an underscore but are not +documented here. When looking at the source code for this library, you cannot safely assume that +because something doesn't start with an underscore, it is a public API. -If a release of this library changes any of the items documented here, the version number will be incremented according to the [Semantic Version Specification](https://semver.org). +If a release of this library changes any of the items documented here, the version number will be +incremented according to the [Semantic Version Specification](https://semver.org). ## Modules - [cmd2.Cmd](./cmd.md) - functions and attributes of the main class in this library -- [cmd2.ansi](./ansi.md) - convenience classes and functions for generating ANSI escape sequences to style text in the terminal +- [cmd2.ansi](./ansi.md) - convenience classes and functions for generating ANSI escape sequences to + style text in the terminal - [cmd2.argparse_completer](./argparse_completer.md) - classes for `argparse`-based tab completion - [cmd2.argparse_custom](./argparse_custom.md) - classes and functions for extending `argparse` -- [cmd2.command_definition](./command_definition.md) - supports the definition of commands in separate classes to be composed into cmd2.Cmd +- [cmd2.command_definition](./command_definition.md) - supports the definition of commands in + separate classes to be composed into cmd2.Cmd - [cmd2.constants](./constants.md) - just like it says on the tin - [cmd2.decorators](./decorators.md) - decorators for `cmd2` commands - [cmd2.exceptions](./exceptions.md) - custom `cmd2` exceptions - [cmd2.history](./history.md) - classes for storing the history of previously entered commands - [cmd2.parsing](./parsing.md) - classes for parsing and storing user input - [cmd2.plugin](./plugin.md) - data classes for hook methods -- [cmd2.py_bridge](./py_bridge.md) - classes for bridging calls from the embedded python environment to the host app +- [cmd2.py_bridge](./py_bridge.md) - classes for bridging calls from the embedded python environment + to the host app - [cmd2.table_creator](./table_creator.md) - table creation module - [cmd2.utils](./utils.md) - various utility classes and functions diff --git a/docs/doc_conventions.md b/docs/doc_conventions.md index 072d690e1..85c43e8f3 100644 --- a/docs/doc_conventions.md +++ b/docs/doc_conventions.md @@ -2,18 +2,25 @@ ## Guiding Principles -Follow the [Documentation Principles](http://www.writethedocs.org/guide/writing/docs-principles/) described by [Write The Docs](http://www.writethedocs.org) +Follow the [Documentation Principles](http://www.writethedocs.org/guide/writing/docs-principles/) +described by [Write The Docs](http://www.writethedocs.org) In addition: -- We have gone to great lengths to retain compatibility with the standard library cmd, the documentation should make it easy for developers to understand how to move from cmd to cmd2, and what benefits that will provide +- We have gone to great lengths to retain compatibility with the standard library cmd, the + documentation should make it easy for developers to understand how to move from cmd to cmd2, and + what benefits that will provide - We should provide both descriptive and reference documentation. - API reference documentation should be generated from docstrings in the code -- Documentation should include rich hyperlinking to other areas of the documentation, and to the API reference +- Documentation should include rich hyperlinking to other areas of the documentation, and to the API + reference ## Style Checker -We strongly encourage all developers to use [Prettier](https://prettier.io/) for formatting all **Markdown** and YAML files. The easiest way to do this is to integrated it with your IDE and configure your IDE to format on save. You can also install `prettier` either using `npm` or OS package manager such as `brew` or `apt`. +We strongly encourage all developers to use [Prettier](https://prettier.io/) for formatting all +**Markdown** and YAML files. The easiest way to do this is to integrated it with your IDE and +configure your IDE to format on save. You can also install `prettier` either using `npm` or OS +package manager such as `brew` or `apt`. ## Naming Files @@ -29,20 +36,25 @@ In Markdown all indenting is significant. Use 4 spaces per indenting level. ## Wrapping -Hard wrap all text so that line lengths are no greater than 120 characters. It makes everything easier when editing documentation, and has no impact on reading documentation because we render to html. +Hard wrap all text so that line lengths are no greater than 120 characters. It makes everything +easier when editing documentation, and has no impact on reading documentation because we render to +html. ## Titles and Headings -Reference the [Markdown Basic Syntax](https://www.markdownguide.org/basic-syntax/) for synatx basics or [The Markdown Guide](https://www.markdownguide.org/) for a more complete reference. +Reference the [Markdown Basic Syntax](https://www.markdownguide.org/basic-syntax/) for synatx basics +or [The Markdown Guide](https://www.markdownguide.org/) for a more complete reference. ## Inline Code Code blocks can be created in two ways: - Indent the block - this will show as a monospace code block, but won't include highighting -- use the triple backticks followed by the code language, e.e. `python` and close with triple backticks +- use the triple backticks followed by the code language, e.e. `python` and close with triple + backticks -If you want to show non-Python code, like shell commands, then use a different language such as `javascript`, `shell`, `json`, etc. +If you want to show non-Python code, like shell commands, then use a different language such as +`javascript`, `shell`, `json`, etc. ## Links @@ -50,7 +62,8 @@ See the [Links](https://www.markdownguide.org/basic-syntax/) Markdown syntax doc ## API Documentation -The API documentation is mostly pulled from docstrings in the source code using the MkDocs [mkdocstrings](https://mkdocstrings.github.io/) plugin. +The API documentation is mostly pulled from docstrings in the source code using the MkDocs +[mkdocstrings](https://mkdocstrings.github.io/) plugin. When using `mkdocstinrgs`, it must be preceded by a blank line before and after, i.e.: @@ -68,4 +81,5 @@ TODO: Figure out how to do this ## Referencing cmd2 -Whenever you reference `cmd2` in the documentation, enclose it in backticks. This indicates to Markdown that this words represents code and will stand out when rendered as HTML. +Whenever you reference `cmd2` in the documentation, enclose it in backticks. This indicates to +Markdown that this words represents code and will stand out when rendered as HTML. diff --git a/docs/examples/alternate_event_loops.md b/docs/examples/alternate_event_loops.md index 8fb024a66..fb13c450c 100644 --- a/docs/examples/alternate_event_loops.md +++ b/docs/examples/alternate_event_loops.md @@ -1,6 +1,9 @@ # Alternate Event Loops -Throughout this documentation we have focused on the **90%** use case, that is the use case we believe around **90+%** of our user base is looking for. This focuses on ease of use and the best out-of-the-box experience where developers get the most functionality for the least amount of effort. We are talking about running `cmd2` applications with the `cmdloop()` method: +Throughout this documentation we have focused on the **90%** use case, that is the use case we +believe around **90+%** of our user base is looking for. This focuses on ease of use and the best +out-of-the-box experience where developers get the most functionality for the least amount of +effort. We are talking about running `cmd2` applications with the `cmdloop()` method: ```py from cmd2 import Cmd @@ -10,11 +13,16 @@ app = App() app.cmdloop() ``` -However, there are some limitations to this way of using `cmd2`, mainly that `cmd2` owns the inner loop of a program. This can be unnecessarily restrictive and can prevent using libraries which depend on controlling their own event loop. +However, there are some limitations to this way of using `cmd2`, mainly that `cmd2` owns the inner +loop of a program. This can be unnecessarily restrictive and can prevent using libraries which +depend on controlling their own event loop. -Many Python concurrency libraries involve or require an event loop which they are in control of such as [asyncio](https://docs.python.org/3/library/asyncio.html), [gevent](http://www.gevent.org/), [Twisted](https://twistedmatrix.com), etc. +Many Python concurrency libraries involve or require an event loop which they are in control of such +as [asyncio](https://docs.python.org/3/library/asyncio.html), [gevent](http://www.gevent.org/), +[Twisted](https://twistedmatrix.com), etc. -`cmd2` applications can be executed in a fashion where `cmd2` doesn't own the main loop for the program by using code like the following: +`cmd2` applications can be executed in a fashion where `cmd2` doesn't own the main loop for the +program by using code like the following: ```py import cmd2 @@ -38,7 +46,8 @@ if __name__ == '__main__': The `cmd2.Cmd.runcmds_plus_hooks()` method runs multiple commands via `cmd2.Cmd.onecmd_plus_hooks`. -The `cmd2.Cmd.onecmd_plus_hooks()` method will do the following to execute a single command in a normal fashion: +The `cmd2.Cmd.onecmd_plus_hooks()` method will do the following to execute a single command in a +normal fashion: 1. Parse user input into a `cmd2.Statement` object 1. Call methods registered with `cmd2.Cmd.register_postparsing_hook()` @@ -54,7 +63,9 @@ The `cmd2.Cmd.onecmd_plus_hooks()` method will do the following to execute a sin 1. Stop redirecting output if it was redirected 1. Call methods registered with `cmd2.Cmd.register_cmdfinalization_hook()` -Running in this fashion enables the ability to integrate with an external event loop. However, how to integrate with any specific event loop is beyond the scope of this documentation. Please note that running in this fashion comes with several disadvantages, including: +Running in this fashion enables the ability to integrate with an external event loop. However, how +to integrate with any specific event loop is beyond the scope of this documentation. Please note +that running in this fashion comes with several disadvantages, including: - Requires the developer to write more code - Does not support transcript testing diff --git a/docs/examples/first_app.md b/docs/examples/first_app.md index bd55225d3..86efd70ff 100644 --- a/docs/examples/first_app.md +++ b/docs/examples/first_app.md @@ -11,7 +11,8 @@ Here's a quick walkthrough of a simple application which demonstrates 8 features - [Multiline Commands](../features/multiline_commands.md) - [History](../features/history.md) -If you don't want to type as we go, here is the complete source (you can click to expand and then click the **Copy** button in the top-right): +If you don't want to type as we go, here is the complete source (you can click to expand and then +click the **Copy** button in the top-right): ??? example @@ -23,7 +24,8 @@ If you don't want to type as we go, here is the complete source (you can click t ## Basic Application -First we need to create a new `cmd2` application. Create a new file `first_app.py` with the following contents: +First we need to create a new `cmd2` application. Create a new file `first_app.py` with the +following contents: ```py #!/usr/bin/env python @@ -41,19 +43,24 @@ if __name__ == '__main__': sys.exit(c.cmdloop()) ``` -We have a new class `FirstApp` which is a subclass of [cmd2.Cmd][]. When we tell python to run our file like this: +We have a new class `FirstApp` which is a subclass of [cmd2.Cmd][]. When we tell python to run our +file like this: ```shell $ python first_app.py ``` -it creates an instance of our class, and calls the `cmd2.Cmd.cmdloop` method. This method accepts user input and runs commands based on that input. Because we subclassed `cmd2.Cmd`, our new app already has a bunch of features built in. +it creates an instance of our class, and calls the `cmd2.Cmd.cmdloop` method. This method accepts +user input and runs commands based on that input. Because we subclassed `cmd2.Cmd`, our new app +already has a bunch of features built in. Congratulations, you have a working `cmd2` app. You can run it, and then type `quit` to exit. ## Create a New Setting -Before we create our first command, we are going to add a setting to this app. `cmd2` includes robust support for [Settings](../features/settings.md). You configure settings during object initialization, so we need to add an initializer to our class: +Before we create our first command, we are going to add a setting to this app. `cmd2` includes +robust support for [Settings](../features/settings.md). You configure settings during object +initialization, so we need to add an initializer to our class: ```py def __init__(self): @@ -64,7 +71,10 @@ def __init__(self): self.add_settable(cmd2.Settable('maxrepeats', int, 'max repetitions for speak command', self)) ``` -In that initializer, the first thing to do is to make sure we initialize `cmd2`. That's what the `super().__init__()` line does. Next create an attribute to hold the setting. Finally, call the [cmd2.Cmd.add_settable][] method with a new instance of a [cmd2.utils.Settable][] class. Now if you run the script, and enter the `set` command to see the settings, like this: +In that initializer, the first thing to do is to make sure we initialize `cmd2`. That's what the +`super().__init__()` line does. Next create an attribute to hold the setting. Finally, call the +[cmd2.Cmd.add_settable][] method with a new instance of a [cmd2.utils.Settable][] class. Now if you +run the script, and enter the `set` command to see the settings, like this: ```shell $ python first_app.py @@ -75,7 +85,11 @@ you will see our `maxrepeats` setting show up with it's default value of `3`. ## Create A Command -Now we will create our first command, called `speak` which will echo back whatever we tell it to say. We are going to use an [argument processor](../features/argument_processing.md) so the `speak` command can shout and talk piglatin. We will also use some built in methods for [generating output](../features/generating_output.md). Add this code to `first_app.py`, so that the `speak_parser` attribute and the `do_speak()` method are part of the `CmdLineApp()` class: +Now we will create our first command, called `speak` which will echo back whatever we tell it to +say. We are going to use an [argument processor](../features/argument_processing.md) so the `speak` +command can shout and talk piglatin. We will also use some built in methods for +[generating output](../features/generating_output.md). Add this code to `first_app.py`, so that the +`speak_parser` attribute and the `do_speak()` method are part of the `CmdLineApp()` class: ```py speak_parser = cmd2.Cmd2ArgumentParser() @@ -106,34 +120,56 @@ Up at the top of the script, you'll also need to add: import argparse ``` -There's a bit to unpack here, so let's walk through it. We created `speak_parser`, which uses the [argparse](https://docs.python.org/3/library/argparse.html) module from the Python standard library to parse command line input from a user. There is nothing thus far that is specific to `cmd2`. +There's a bit to unpack here, so let's walk through it. We created `speak_parser`, which uses the +[argparse](https://docs.python.org/3/library/argparse.html) module from the Python standard library +to parse command line input from a user. There is nothing thus far that is specific to `cmd2`. -There is also a new method called `do_speak()`. In both [cmd](https://docs.python.org/3/library/cmd.html) and `cmd2`, methods that start with `do_` become new commands, so by defining this method we have created a command called `speak`. +There is also a new method called `do_speak()`. In both +[cmd](https://docs.python.org/3/library/cmd.html) and `cmd2`, methods that start with `do_` become +new commands, so by defining this method we have created a command called `speak`. -Note the `cmd2.decorators.with_argparser` decorator on the `do_speak()` method. This decorator does 3 useful things for us: +Note the `cmd2.decorators.with_argparser` decorator on the `do_speak()` method. This decorator does +3 useful things for us: -1. It tells `cmd2` to process all input for the `speak` command using the argparser we defined. If the user input doesn't meet the requirements defined by the argparser, then an error will be displayed for the user. -1. It alters our `do_speak` method so that instead of receiving the raw user input as a parameter, we receive the namespace from the argparser. +1. It tells `cmd2` to process all input for the `speak` command using the argparser we defined. If + the user input doesn't meet the requirements defined by the argparser, then an error will be + displayed for the user. +1. It alters our `do_speak` method so that instead of receiving the raw user input as a parameter, + we receive the namespace from the argparser. 1. It creates a help message for us based on the argparser. -You can see in the body of the method how we use the namespace from the argparser (passed in as the variable `args`). We build an array of words which we will output, honoring both the `--piglatin` and `--shout` options. +You can see in the body of the method how we use the namespace from the argparser (passed in as the +variable `args`). We build an array of words which we will output, honoring both the `--piglatin` +and `--shout` options. -At the end of the method, we use our `maxrepeats` setting as an upper limit to the number of times we will print the output. +At the end of the method, we use our `maxrepeats` setting as an upper limit to the number of times +we will print the output. -The last thing you'll notice is that we used the `self.poutput()` method to display our output. `poutput()` is a method provided by `cmd2`, which I strongly recommend you use anytime you want to [generate output](../features/generating_output.md). It provides the following benefits: +The last thing you'll notice is that we used the `self.poutput()` method to display our output. +`poutput()` is a method provided by `cmd2`, which I strongly recommend you use anytime you want to +[generate output](../features/generating_output.md). It provides the following benefits: 1. Allows the user to redirect output to a text file or pipe it to a shell process 1. Gracefully handles `BrokenPipeWarning` exceptions for redirected output 1. Makes the output show up in a [transcript](../features/transcripts.md) -1. Honors the setting to [strip embedded ansi sequences](../features/settings.md#allow_style) (typically used for background and foreground colors) +1. Honors the setting to [strip embedded ansi sequences](../features/settings.md#allow_style) + (typically used for background and foreground colors) -Go run the script again, and try out the `speak` command. Try typing `help speak`, and you will see a lovely usage message describing the various options for the command. +Go run the script again, and try out the `speak` command. Try typing `help speak`, and you will see +a lovely usage message describing the various options for the command. -With those few lines of code, we created a [command](../features/commands.md), used an [Argument Processor](../features/argument_processing.md), added a nice [help message](../features/help.md) for our users, and [generated some output](../features/generating_output.md). +With those few lines of code, we created a [command](../features/commands.md), used an +[Argument Processor](../features/argument_processing.md), added a nice +[help message](../features/help.md) for our users, and +[generated some output](../features/generating_output.md). ## Shortcuts -`cmd2` has several capabilities to simplify repetitive user input: [Shortcuts, Aliases, and Macros](../features/shortcuts_aliases_macros.md). Let's add a shortcut to our application. Shortcuts are character strings that can be used instead of a command name. For example, `cmd2` has support for a shortcut `!` which runs the `shell` command. So instead of typing this: +`cmd2` has several capabilities to simplify repetitive user input: +[Shortcuts, Aliases, and Macros](../features/shortcuts_aliases_macros.md). Let's add a shortcut to +our application. Shortcuts are character strings that can be used instead of a command name. For +example, `cmd2` has support for a shortcut `!` which runs the `shell` command. So instead of typing +this: ```shell (Cmd) shell ls -al @@ -158,7 +194,12 @@ def __init__(self): self.add_settable(cmd2.Settable('maxrepeats', int, 'max repetitions for speak command', self)) ``` -Shortcuts are passed to the `cmd2` initializer, and if you want the built-in shortcuts of `cmd2` you have to pass them. These shortcuts are defined as a dictionary, with the key being the shortcut, and the value containing the command. When using the default shortcuts and also adding your own, it's a good idea to use the `.update()` method to modify the dictionary. This way if you add a shortcut that happens to already be in the default set, yours will override, and you won't get any errors at runtime. +Shortcuts are passed to the `cmd2` initializer, and if you want the built-in shortcuts of `cmd2` you +have to pass them. These shortcuts are defined as a dictionary, with the key being the shortcut, and +the value containing the command. When using the default shortcuts and also adding your own, it's a +good idea to use the `.update()` method to modify the dictionary. This way if you add a shortcut +that happens to already be in the default set, yours will override, and you won't get any errors at +runtime. Run your app again, and type: @@ -170,7 +211,12 @@ to see the list of all of the shortcuts, including the one for speak that we jus ## Multiline Commands -Some use cases benefit from the ability to have commands that span more than one line. For example, you might want the ability for your user to type in a SQL command, which can often span lines and which are terminated with a semicolon. Let's add a [multiline command](../features/multiline_commands.md) to our application. First we'll create a new command called `orate`. This code shows both the definition of our `speak`command, and the`orate` command: +Some use cases benefit from the ability to have commands that span more than one line. For example, +you might want the ability for your user to type in a SQL command, which can often span lines and +which are terminated with a semicolon. Let's add a +[multiline command](../features/multiline_commands.md) to our application. First we'll create a new +command called `orate`. This code shows both the definition of our `speak`command, and the`orate` +command: ```py @cmd2.with_argparser(speak_parser) @@ -192,7 +238,8 @@ def do_speak(self, args): do_orate = do_speak ``` -With the new command created, we need to tell `cmd2` to treat that command as a multi-line command. Modify the super initialization line to look like this: +With the new command created, we need to tell `cmd2` to treat that command as a multi-line command. +Modify the super initialization line to look like this: ```py super().__init__(multiline_commands=['orate'], shortcuts=shortcuts) @@ -207,31 +254,44 @@ Now when you run the example, you can type something like this: > And monarchs to behold the swelling scene! ; ``` -Notice the prompt changes to indicate that input is still ongoing. `cmd2` will continue prompting for input until it sees an unquoted semicolon (the default multi-line command termination character). +Notice the prompt changes to indicate that input is still ongoing. `cmd2` will continue prompting +for input until it sees an unquoted semicolon (the default multi-line command termination +character). ## History -`cmd2` tracks the history of the commands that users enter. As a developer, you don't need to do anything to enable this functionality, you get it for free. If you want the history of commands to persist between invocations of your application, you'll need to do a little work. The [History](../features/history.md) page has all the details. +`cmd2` tracks the history of the commands that users enter. As a developer, you don't need to do +anything to enable this functionality, you get it for free. If you want the history of commands to +persist between invocations of your application, you'll need to do a little work. The +[History](../features/history.md) page has all the details. Users can access command history using two methods: -- the [readline](https://docs.python.org/3/library/readline.html) library which provides a python interface to the [GNU readline library](https://en.wikipedia.org/wiki/GNU_Readline) +- the [readline](https://docs.python.org/3/library/readline.html) library which provides a python + interface to the [GNU readline library](https://en.wikipedia.org/wiki/GNU_Readline) - the `history` command which is built-in to `cmd2` -From the prompt in a `cmd2`-based application, you can press `Control-p` to move to the previously entered command, and `Control-n` to move to the next command. You can also search through the command history using `Control-r`. The [GNU Readline User Manual](http://man7.org/linux/man-pages/man3/readline.3.html) has all the details, including all the available commands, and instructions for customizing the key bindings. +From the prompt in a `cmd2`-based application, you can press `Control-p` to move to the previously +entered command, and `Control-n` to move to the next command. You can also search through the +command history using `Control-r`. The +[GNU Readline User Manual](http://man7.org/linux/man-pages/man3/readline.3.html) has all the +details, including all the available commands, and instructions for customizing the key bindings. -The `history` command allows a user to view the command history, and select commands from history by number, range, string search, or regular expression. With the selected commands, users can: +The `history` command allows a user to view the command history, and select commands from history by +number, range, string search, or regular expression. With the selected commands, users can: - re-run the commands - edit the selected commands in a text editor, and run them after the text editor exits - save the commands to a file - run the commands, saving both the commands and their output to a file -Learn more about the `history` command by typing `history -h` at any `cmd2` input prompt, or by exploring [Command History For Users](../features/history.md#for-users). +Learn more about the `history` command by typing `history -h` at any `cmd2` input prompt, or by +exploring [Command History For Users](../features/history.md#for-users). ## Conclusion -You've just created a simple, but functional command line application. With minimal work on your part, the application leverages many robust features of `cmd2`. To learn more you can: +You've just created a simple, but functional command line application. With minimal work on your +part, the application leverages many robust features of `cmd2`. To learn more you can: - Dive into all of the [Features](../features/index.md) that `cmd2` provides - Look at more [Examples](../examples/index.md) diff --git a/docs/features/argument_processing.md b/docs/features/argument_processing.md index 7c7073308..086608495 100644 --- a/docs/features/argument_processing.md +++ b/docs/features/argument_processing.md @@ -1,27 +1,41 @@ # Argument Processing -`cmd2` makes it easy to add sophisticated argument processing to your commands using the [argparse](https://docs.python.org/3/library/argparse.html) python module. `cmd2` handles the following for you: +`cmd2` makes it easy to add sophisticated argument processing to your 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 1. Parse the resulting argument list using an instance of `argparse.ArgumentParser` that you provide -1. Passes the resulting `argparse.Namespace` object to your command function. The `Namespace` includes the `Statement` object that was created when parsing the command line. It can be retrieved by calling `cmd2_statement.get()` on the `Namespace`. +1. Passes the resulting `argparse.Namespace` object to your command function. The `Namespace` + includes the `Statement` object that was created when parsing the command line. It can be + retrieved by calling `cmd2_statement.get()` on the `Namespace`. 1. Adds the usage message from the argument parser to your command. 1. Checks if the `-h/--help` option is present, and if so, display the help message for the command These features are all provided by the `@with_argparser` decorator which is importable from `cmd2`. -See the either the [argprint](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py) or [decorator](https://github.com/python-cmd2/cmd2/blob/master/examples/decorator_example.py) example to learn more about how to use the various `cmd2` argument processing decorators in your `cmd2` applications. +See the either the [argprint](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py) +or [decorator](https://github.com/python-cmd2/cmd2/blob/master/examples/decorator_example.py) +example to learn more about how to use the various `cmd2` argument processing decorators in your +`cmd2` applications. -`cmd2` provides the following [decorators](../api/decorators.md) for assisting with parsing arguments passed to commands: +`cmd2` provides the following [decorators](../api/decorators.md) for assisting with parsing +arguments passed to commands: - `cmd2.decorators.with_argparser` - `cmd2.decorators.with_argument_list` -All of these decorators accept an optional **preserve_quotes** argument which defaults to `False`. Setting this argument to `True` is useful for cases where you are passing the arguments to another command which might have its own argument parsing. +All of these decorators accept an optional **preserve_quotes** argument which defaults to `False`. +Setting this argument to `True` is useful for cases where you are passing the arguments to another +command which might have its own argument parsing. ## Argument Parsing -For each command in the `cmd2` subclass which requires argument parsing, create a unique instance of `argparse.ArgumentParser()` which can parse the input appropriately for the command. Then decorate the command method with the `@with_argparser` decorator, passing the argument parser as the first parameter to the decorator. This changes the second argument to the command method, which will contain the results of `ArgumentParser.parse_args()`. +For each command in the `cmd2` subclass which requires argument parsing, create a unique instance of +`argparse.ArgumentParser()` which can parse the input appropriately for the command. Then decorate +the command method with the `@with_argparser` decorator, passing the argument parser as the first +parameter to the decorator. This changes the second argument to the command method, which will +contain the results of `ArgumentParser.parse_args()`. Here's what it looks like: @@ -53,7 +67,9 @@ def do_speak(self, opts) ## Help Messages -By default, `cmd2` uses the docstring of the command method when a user asks for help on the command. When you use the `@with_argparser` decorator, the docstring for the `do_*` method is used to set the description for the `argparse.ArgumentParser`. +By default, `cmd2` uses the docstring of the command method when a user asks for help on the +command. When you use the `@with_argparser` decorator, the docstring for the `do_*` method is used +to set the description for the `argparse.ArgumentParser`. With this code: @@ -85,7 +101,8 @@ optional arguments: -h, --help show this help message and exit ``` -If you would prefer you can set the `description` while instantiating the `argparse.ArgumentParser` and leave the docstring on your method empty: +If you would prefer you can set the `description` while instantiating the `argparse.ArgumentParser` +and leave the docstring on your method empty: ```py from cmd2 import Cmd2ArgumentParser, with_argparser @@ -152,7 +169,9 @@ This command cannot generate tags with no content, like
## Argument List -The default behavior of `cmd2` is to pass the user input directly to your `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`: +The default behavior of `cmd2` is to pass the user input directly to your `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`: ```py class CmdLineApp(cmd2.Cmd): @@ -176,7 +195,10 @@ class CmdLineApp(cmd2.Cmd): 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: +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: ```py from cmd2 import with_argument_list @@ -196,7 +218,8 @@ class CmdLineApp(cmd2.Cmd): ## Unknown Positional Arguments -If you want all unknown arguments to be passed to your command as a list of strings, then decorate the command method with the `@with_argparser(..., with_unknown_args=True)` decorator. +If you want all unknown arguments to be passed to your command as a list of strings, then decorate +the command method with the `@with_argparser(..., with_unknown_args=True)` decorator. Here's what it looks like: @@ -225,9 +248,12 @@ def do_dir(self, args, unknown): ## Using A Custom Namespace -In some cases, it may be necessary to write custom `argparse` code that is dependent on state data of your application. To support this ability while still allowing use of the decorators, `@with_argparser` has an optional argument called `ns_provider`. +In some cases, it may be necessary to write custom `argparse` code that is dependent on state data +of your application. To support this ability while still allowing use of the decorators, +`@with_argparser` has an optional argument called `ns_provider`. -`ns_provider` is a Callable that accepts a `cmd2.Cmd` object as an argument and returns an `argparse.Namespace`: +`ns_provider` is a Callable that accepts a `cmd2.Cmd` object as an argument and returns an +`argparse.Namespace`: ```py Callable[[cmd2.Cmd], argparse.Namespace] @@ -249,15 +275,19 @@ To use this function with the argparse decorators, do the following: @with_argparser(my_parser, ns_provider=settings_ns_provider) ``` -The Namespace is passed by the decorators to the `argparse` parsing functions which gives your custom code access to the state data it needs for its parsing logic. +The Namespace is passed by the decorators to the `argparse` parsing functions which gives your +custom code access to the state data it needs for its parsing logic. ## Subcommands -Subcommands are supported for commands using the `@with_argparser` decorator. The syntax is based on argparse sub-parsers. +Subcommands are supported for commands using the `@with_argparser` decorator. The syntax is based on +argparse sub-parsers. -You may add multiple layers of subcommands for your command. `cmd2` will automatically traverse and tab complete subcommands for all commands using argparse. +You may add multiple layers of subcommands for your command. `cmd2` will automatically traverse and +tab complete subcommands for all commands using argparse. -See the [subcommands](https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py) example to learn more about how to use subcommands in your `cmd2` application. +See the [subcommands](https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py) +example to learn more about how to use subcommands in your `cmd2` application. ## Argparse Extensions @@ -266,13 +296,19 @@ See the [subcommands](https://github.com/python-cmd2/cmd2/blob/master/examples/s - `nargs=(5,)` - accept 5 or more items - `nargs=(8, 12)` - accept 8 to 12 items -`cmd2` also provides the `cmd2.argparse_custom.Cmd2ArgumentParser` class which inherits from `argparse.ArgumentParser` and improves error and help output. +`cmd2` also provides the `cmd2.argparse_custom.Cmd2ArgumentParser` class which inherits from +`argparse.ArgumentParser` and improves error and help output. ## Decorator Order -If you are using custom decorators in combination with `@cmd2.with_argparser`, then the order of your custom decorator(s) relative to the `cmd2` decorator matters when it comes to runtime behavior and `argparse` errors. There is nothing `cmd2`-specific here, this is just a side-effect of how decorators work in Python. To learn more about how decorators work, see [decorator_primer](https://realpython.com/primer-on-python-decorators). +If you are using custom decorators in combination with `@cmd2.with_argparser`, then the order of +your custom decorator(s) relative to the `cmd2` decorator matters when it comes to runtime behavior +and `argparse` errors. There is nothing `cmd2`-specific here, this is just a side-effect of how +decorators work in Python. To learn more about how decorators work, see +[decorator_primer](https://realpython.com/primer-on-python-decorators). -If you want your custom decorator's runtime behavior to occur in the case of an `argparse` error, then that decorator needs to go **after** the `argparse` one, e.g.: +If you want your custom decorator's runtime behavior to occur in the case of an `argparse` error, +then that decorator needs to go **after** the `argparse` one, e.g.: ```py @cmd2.with_argparser(foo_parser) @@ -282,7 +318,8 @@ def do_foo(self, args: argparse.Namespace) -> None: pass ``` -However, if you do NOT want the custom decorator runtime behavior to occur even in the case of an `argparse` error, then that decorator needs to go **before** the `arpgarse` one, e.g.: +However, if you do NOT want the custom decorator runtime behavior to occur even in the case of an +`argparse` error, then that decorator needs to go **before** the `arpgarse` one, e.g.: ```py @my_decorator @@ -292,12 +329,17 @@ def do_bar(self, args: argparse.Namespace) -> None: pass ``` -The [help_categories](https://github.com/python-cmd2/cmd2/blob/master/examples/help_categories.py) example demonstrates both above cases in a concrete fashion. +The [help_categories](https://github.com/python-cmd2/cmd2/blob/master/examples/help_categories.py) +example demonstrates both above cases in a concrete fashion. ## Reserved Argument Names -`cmd2` argparse decorators add the following attributes to argparse Namespaces. To avoid naming collisions, do not use any of the names for your argparse arguments. +`cmd2` argparse decorators add the following attributes to argparse Namespaces. To avoid naming +collisions, do not use any of the names for your argparse arguments. -- `cmd2_statement` - `cmd2.Cmd2AttributeWrapper` object containing `cmd2.Statement` object that was created when parsing the command line. -- `cmd2_handler` - `cmd2.Cmd2AttributeWrapper` object containing a subcommand handler function or `None` if one was not set. -- `__subcmd_handler__` - used by cmd2 to identify the handler for a subcommand created with `@cmd2.as_subcommand_to` decorator. +- `cmd2_statement` - `cmd2.Cmd2AttributeWrapper` object containing `cmd2.Statement` object that was + created when parsing the command line. +- `cmd2_handler` - `cmd2.Cmd2AttributeWrapper` object containing a subcommand handler function or + `None` if one was not set. +- `__subcmd_handler__` - used by cmd2 to identify the handler for a subcommand created with + `@cmd2.as_subcommand_to` decorator. diff --git a/docs/features/builtin_commands.md b/docs/features/builtin_commands.md index 1fdb09c05..ed0e24796 100644 --- a/docs/features/builtin_commands.md +++ b/docs/features/builtin_commands.md @@ -1,16 +1,20 @@ # Builtin Commands -Applications which subclass `cmd2.Cmd` inherit a number of commands which may be useful to your users. Developers can [Remove Builtin Commands](#remove-builtin-commands) if they do not want them to be part of the application. +Applications which subclass `cmd2.Cmd` inherit a number of commands which may be useful to your +users. Developers can [Remove Builtin Commands](#remove-builtin-commands) if they do not want them +to be part of the application. ## List of Builtin Commands ### alias -This command manages aliases via subcommands `create`, `delete`, and `list`. See [Aliases](shortcuts_aliases_macros.md#aliases) for more information. +This command manages aliases via subcommands `create`, `delete`, and `list`. See +[Aliases](shortcuts_aliases_macros.md#aliases) for more information. ### edit -This command launches an editor program and instructs it to open the given file name. Here's an example: +This command launches an editor program and instructs it to open the given file name. Here's an +example: ```sh (Cmd) edit ~/.ssh/config @@ -20,23 +24,30 @@ The program to be launched is determined by the value of the [editor](settings.m ### help -This command lists available commands or provides detailed help for a specific command. When called with the `-v/--verbose` argument, it shows a brief description of each command. See [Help](help.md) for more information. +This command lists available commands or provides detailed help for a specific command. When called +with the `-v/--verbose` argument, it shows a brief description of each command. See [Help](help.md) +for more information. ### history -This command allows you to view, run, edit, save, or clear previously entered commands from the history. See [History](history.md) for more information. +This command allows you to view, run, edit, save, or clear previously entered commands from the +history. See [History](history.md) for more information. ### ipy -This optional opt-in command enters an interactive IPython shell. See [IPython (optional)](./embedded_python_shells.md#ipython-optional) for more information. +This optional opt-in command enters an interactive IPython shell. See +[IPython (optional)](./embedded_python_shells.md#ipython-optional) for more information. ### macro -This command manages macros via subcommands `create`, `delete`, and `list`. A macro is similar to an alias, but it can contain argument placeholders. See [Macros](./shortcuts_aliases_macros.md#macros) for more information. +This command manages macros via subcommands `create`, `delete`, and `list`. A macro is similar to an +alias, but it can contain argument placeholders. See [Macros](./shortcuts_aliases_macros.md#macros) +for more information. ### py -This command invokes a Python command or shell. See [Embedded Python Shells](./embedded_python_shells.md) for more information. +This command invokes a Python command or shell. See +[Embedded Python Shells](./embedded_python_shells.md) for more information. ### quit @@ -44,19 +55,25 @@ This command exits the `cmd2` application. ### run_pyscript -This command runs a Python script file inside the `cmd2` application. See [Python Scripts](./scripting.md#python-scripts) for more information. +This command runs a Python script file inside the `cmd2` application. See +[Python Scripts](./scripting.md#python-scripts) for more information. ### run_script -This command runs commands in a script file that is encoded as either ASCII or UTF-8 text. See [Command Scripts](./scripting.md#command-scripts) for more information. +This command runs commands in a script file that is encoded as either ASCII or UTF-8 text. See +[Command Scripts](./scripting.md#command-scripts) for more information. ### \_relative_run_script -This command is hidden from the help that's visible to end users. It runs a script like [run_script](#run_script) but does so using a path relative to the script that is currently executing. This is useful when you have scripts that run other scripts. See [Running Command Scripts](../features/scripting.md#running-command-scripts) for more information. +This command is hidden from the help that's visible to end users. It runs a script like +[run_script](#run_script) but does so using a path relative to the script that is currently +executing. This is useful when you have scripts that run other scripts. See +[Running Command Scripts](../features/scripting.md#running-command-scripts) for more information. ### set -A list of all user-settable parameters, with brief comments, is viewable from within a running application: +A list of all user-settable parameters, with brief comments, is viewable from within a running +application: ```text (Cmd) set @@ -77,7 +94,8 @@ scripts_add_to_history True Scripts and pyscripts ad timing False Report execution times ``` -Any of these user-settable parameters can be set while running your app with the `set` command like so: +Any of these user-settable parameters can be set while running your app with the `set` command like +so: ```text (Cmd) set allow_style Never @@ -96,11 +114,15 @@ Execute a command as if at the operating system shell prompt: ### shortcuts -This command lists available shortcuts. See [Shortcuts](./shortcuts_aliases_macros.md#shortcuts) for more information. +This command lists available shortcuts. See [Shortcuts](./shortcuts_aliases_macros.md#shortcuts) for +more information. ## Remove Builtin Commands -Developers may not want to offer the commands builtin to [cmd2.Cmd][] to users of their application. To remove a command you must delete the method implementing that command from the [cmd2.Cmd][] object at runtime. For example, if you wanted to remove the [shell](#shell) command from your application: +Developers may not want to offer the commands builtin to [cmd2.Cmd][] to users of their application. +To remove a command you must delete the method implementing that command from the [cmd2.Cmd][] +object at runtime. For example, if you wanted to remove the [shell](#shell) command from your +application: ```py class NoShellApp(cmd2.Cmd): diff --git a/docs/features/clipboard.md b/docs/features/clipboard.md index 4181022d1..d177b31bf 100644 --- a/docs/features/clipboard.md +++ b/docs/features/clipboard.md @@ -1,14 +1,20 @@ # 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. +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: +`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: ```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: +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: ```text mycommand arg1 arg2 >> @@ -16,12 +22,20 @@ mycommand arg1 arg2 >> ## Developers -You can control whether the above user features of adding output to the operating system clipboard are allowed for the user by setting the [cmd2.Cmd.allow_clipboard][] attribute. The default value is `True`. Set it to `False` and the above functionality will generate an error message instead of adding the output to the clipboard. [cmd2.Cmd.allow_clipboard][] can be set upon initialization, and you can change it at any time from within your code. +You can control whether the above user features of adding output to the operating system clipboard +are allowed for the user by setting the [cmd2.Cmd.allow_clipboard][] attribute. The default value is +`True`. Set it to `False` and the above functionality will generate an error message instead of +adding the output to the clipboard. [cmd2.Cmd.allow_clipboard][] can be set upon initialization, and +you can change it at any time from within your code. -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). +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). + ::: cmd2.clipboard handler: python options: show_root_heading: false show_source: false + diff --git a/docs/features/commands.md b/docs/features/commands.md index 5a1249fd9..5497ce44c 100644 --- a/docs/features/commands.md +++ b/docs/features/commands.md @@ -1,6 +1,12 @@ # Commands -`cmd2` is designed to make it easy for you to create new commands. These commands form the backbone of your application. If you started writing your application using [cmd](https://docs.python.org/3/library/cmd.html), all the commands you have built will work when you move to `cmd2`. However, there are many more capabilities available in `cmd2` which you can take advantage of to add more robust features to your commands, and which makes your commands easier to write. Before we get to all the good stuff, let's briefly discuss how to create a new command in your application. +`cmd2` is designed to make it easy for you to create new commands. These commands form the backbone +of your application. If you started writing your application using +[cmd](https://docs.python.org/3/library/cmd.html), all the commands you have built will work when +you move to `cmd2`. However, there are many more capabilities available in `cmd2` which you can take +advantage of to add more robust features to your commands, and which makes your commands easier to +write. Before we get to all the good stuff, let's briefly discuss how to create a new command in +your application. ## Basic Commands @@ -22,14 +28,22 @@ if __name__ == '__main__': sys.exit(c.cmdloop()) ``` -This application subclasses `cmd2.Cmd` but has no code of it's own, so all functionality (and there's quite a bit) is inherited. Lets create a simple command in this application called `echo` which outputs any arguments given to it. Add this method to the class: +This application subclasses `cmd2.Cmd` but has no code of it's own, so all functionality (and +there's quite a bit) is inherited. Lets create a simple command in this application called `echo` +which outputs any arguments given to it. Add this method to the class: ```py def do_echo(self, line): self.poutput(line) ``` -When you type input into the `cmd2` prompt, the first space delimited word is treated as the command name. `cmd2` looks for a method called `do_commandname`. If it exists, it calls the method, passing the rest of the user input as the first argument. If it doesn't exist `cmd2` prints an error message. As a result of this behavior, the only thing you have to do to create a new command is to define a new method in the class with the appropriate name. This is exactly how you would create a command using the [cmd](https://docs.python.org/3/library/cmd.html) module which is part of the python standard library. +When you type input into the `cmd2` prompt, the first space delimited word is treated as the command +name. `cmd2` looks for a method called `do_commandname`. If it exists, it calls the method, passing +the rest of the user input as the first argument. If it doesn't exist `cmd2` prints an error +message. As a result of this behavior, the only thing you have to do to create a new command is to +define a new method in the class with the appropriate name. This is exactly how you would create a +command using the [cmd](https://docs.python.org/3/library/cmd.html) module which is part of the +python standard library. !!! note @@ -37,34 +51,49 @@ When you type input into the `cmd2` prompt, the first space delimited word is tr ## Statements -A command is passed one argument: a string which contains all the rest of the user input. However, in `cmd2` this string is actually a `Statement` object, which is a subclass of `str` to retain backwards compatibility. +A command is passed one argument: a string which contains all the rest of the user input. However, +in `cmd2` this string is actually a `Statement` object, which is a subclass of `str` to retain +backwards compatibility. -`cmd2` has a much more sophsticated parsing engine than what's included in the [cmd](https://docs.python.org/3/library/cmd.html) module. This parsing handles: +`cmd2` has a much more sophsticated parsing engine than what's included in the +[cmd](https://docs.python.org/3/library/cmd.html) module. This parsing handles: - quoted arguments - output redirection and piping - multi-line commands - shortcut, macro, and alias expansion -In addition to parsing all of these elements from the user input, `cmd2` also has code to make all of these items work; it's almost transparent to you and to the commands you write in your own application. However, by passing your command the `Statement` object instead of just a plain string, you can get visibility into what `cmd2` has done with the user input before your command got it. You can also avoid writing a bunch of parsing code, because `cmd2` gives you access to what it has already parsed. +In addition to parsing all of these elements from the user input, `cmd2` also has code to make all +of these items work; it's almost transparent to you and to the commands you write in your own +application. However, by passing your command the `Statement` object instead of just a plain string, +you can get visibility into what `cmd2` has done with the user input before your command got it. You +can also avoid writing a bunch of parsing code, because `cmd2` gives you access to what it has +already parsed. A `Statement` object is a subclass of `str` that contains the following attributes: command -: Name of the command called. You already know this because of the method `cmd2` called, but it can sometimes be nice to have it in a string, i.e. if you want your error messages to contain the command name. +: Name of the command called. You already know this because of the method `cmd2` called, but it can +sometimes be nice to have it in a string, i.e. if you want your error messages to contain the +command name. args -: A string containing the arguments to the command with output redirection or piping to shell commands removed. It turns out that the "string" value of the `Statement` object has all the output redirection and piping clauses removed as well. Quotes remain in the string. +: A string containing the arguments to the command with output redirection or piping to shell +commands removed. It turns out that the "string" value of the `Statement` object has all the output +redirection and piping clauses removed as well. Quotes remain in the string. command[and_args]{#and_args} -: A string of just the command and the arguments, with output redirection or piping to shell commands removed. +: A string of just the command and the arguments, with output redirection or piping to shell +commands removed. argv -: A list of arguments a-la `sys.argv`, including the command as `argv[0]` and the subsequent arguments as additional items in the list. Quotes around arguments will be stripped as will any output redirection or piping portions of the command. +: A list of arguments a-la `sys.argv`, including the command as `argv[0]` and the subsequent +arguments as additional items in the list. Quotes around arguments will be stripped as will any +output redirection or piping portions of the command. raw @@ -72,15 +101,24 @@ raw terminator -: Character used to end a multiline command. You can configure multiple termination characters, and this attribute will tell you which one the user typed. +: Character used to end a multiline command. You can configure multiple termination characters, and +this attribute will tell you which one the user typed. -For many simple commands, like the `echo` command above, you can ignore the `Statement` object and all of it's attributes and just use the passed value as a string. You might choose to use the `argv` attribute to do more sophisticated argument processing. Before you go too far down that path, you should check out the [Argument Processing](./argument_processing.md) functionality included with `cmd2`. +For many simple commands, like the `echo` command above, you can ignore the `Statement` object and +all of it's attributes and just use the passed value as a string. You might choose to use the `argv` +attribute to do more sophisticated argument processing. Before you go too far down that path, you +should check out the [Argument Processing](./argument_processing.md) functionality included with +`cmd2`. ## Return Values -Most commands should return nothing (either by omitting a `return` statement, or by `return None`. This indicates that your command is finished (with or without errors), and that `cmd2` should prompt the user for more input. +Most commands should return nothing (either by omitting a `return` statement, or by `return None`. +This indicates that your command is finished (with or without errors), and that `cmd2` should prompt +the user for more input. -If you return `True` from a command method, that indicates to `cmd2` that it should stop prompting for user input and cleanly exit. `cmd2` already includes a `quit` command, but if you wanted to make another one called `finish` you could: +If you return `True` from a command method, that indicates to `cmd2` that it should stop prompting +for user input and cleanly exit. `cmd2` already includes a `quit` command, but if you wanted to make +another one called `finish` you could: ```py def do_finish(self, line): @@ -90,7 +128,11 @@ def do_finish(self, line): ## Exit Codes -`cmd2` has basic infrastructure to support sh/ksh/csh/bash type exit codes. The `cmd2.Cmd` object sets an `exit_code` attribute to zero when it is instantiated. The value of this attribute is returned from the `cmdloop()` call. Therefore, if you don't do anything with this attribute in your code, `cmdloop()` will (almost) always return zero. There are a few built-in `cmd2` commands which set `exit_code` to `1` if an error occurs. +`cmd2` has basic infrastructure to support sh/ksh/csh/bash type exit codes. The `cmd2.Cmd` object +sets an `exit_code` attribute to zero when it is instantiated. The value of this attribute is +returned from the `cmdloop()` call. Therefore, if you don't do anything with this attribute in your +code, `cmdloop()` will (almost) always return zero. There are a few built-in `cmd2` commands which +set `exit_code` to `1` if an error occurs. You can use this capability to easily return your own values to the operating system shell: @@ -115,7 +157,8 @@ if __name__ == '__main__': sys.exit(c.cmdloop()) ``` -If the app was run from the `bash` operating system shell, then you would see the following interaction: +If the app was run from the `bash` operating system shell, then you would see the following +interaction: ```sh (Cmd) bail @@ -124,18 +167,24 @@ $ echo $? 2 ``` -Raising `SystemExit(code)` or calling `sys.exit(code)` in a command or hook function also sets `self.exit_code` and stops the program. +Raising `SystemExit(code)` or calling `sys.exit(code)` in a command or hook function also sets +`self.exit_code` and stops the program. ## Exception Handling -You may choose to catch and handle any exceptions which occur in a command method. If the command method raises an exception, `cmd2` will catch it and display it for you. The [debug setting](./settings.md#debug) controls how the exception is displayed. If `debug` is `false`, which is the default, `cmd2` will display the exception name and message. If `debug` is `true`, `cmd2` will display a traceback, and then display the exception name and message. +You may choose to catch and handle any exceptions which occur in a command method. If the command +method raises an exception, `cmd2` will catch it and display it for you. The +[debug setting](./settings.md#debug) controls how the exception is displayed. If `debug` is `false`, +which is the default, `cmd2` will display the exception name and message. If `debug` is `true`, +`cmd2` will display a traceback, and then display the exception name and message. There are a few exceptions which commands can raise that do not print as described above: - `cmd2.exceptions.SkipPostcommandHooks` - all postcommand hooks are skipped and no exception prints - `cmd2.exceptions.Cmd2ArgparseError` - behaves like `SkipPostcommandHooks` - `SystemExit` - `stop` will be set to `True` in an attempt to stop the command loop -- `KeyboardInterrupt` - raised if running in a text script and `stop` isn't already True to stop the script +- `KeyboardInterrupt` - raised if running in a text script and `stop` isn't already True to stop the + script All other `BaseExceptions` are not caught by `cmd2` and will be raised diff --git a/docs/features/completion.md b/docs/features/completion.md index b3b7ccc03..ac0bf3fab 100644 --- a/docs/features/completion.md +++ b/docs/features/completion.md @@ -1,23 +1,32 @@ # Completion -`cmd2.Cmd` adds tab completion of file system paths for all built-in commands where it makes sense, including: +`cmd2.Cmd` adds tab completion of file system paths for all built-in commands where it makes sense, +including: - [edit](./builtin_commands.md#edit) - [run_pyscript](./builtin_commands.md#run_pyscript) - [run_script](./builtin_commands.md#run_script) - [shell](./builtin_commands.md#shell) -`cmd2.Cmd` also adds tab completion of shell commands to the [shell](./builtin_commands.md#shell) command. +`cmd2.Cmd` also adds tab completion of shell commands to the [shell](./builtin_commands.md#shell) +command. -It is easy to add identical file system path completion to your own custom commands. Suppose you have defined a custom command `foo` by implementing the `do_foo` method. To enable path completion for the `foo` command, then add a line of code similar to the following to your class which inherits from `cmd2.Cmd`: +It is easy to add identical file system path completion to your own custom commands. Suppose you +have defined a custom command `foo` by implementing the `do_foo` method. To enable path completion +for the `foo` command, then add a line of code similar to the following to your class which inherits +from `cmd2.Cmd`: ```py complete_foo = cmd2.Cmd.path_complete ``` -This will effectively define the `complete_foo` readline completer method in your class and make it utilize the same path completion logic as the built-in commands. +This will effectively define the `complete_foo` readline completer method in your class and make it +utilize the same path completion logic as the built-in commands. -The built-in logic allows for a few more advanced path completion capabilities, such as cases where you only want to match directories. Suppose you have a custom command `bar` implemented by the `do_bar` method. You can enable path completion of directories only for this command by adding a line of code similar to the following to your class which inherits from `cmd2.Cmd`: +The built-in logic allows for a few more advanced path completion capabilities, such as cases where +you only want to match directories. Suppose you have a custom command `bar` implemented by the +`do_bar` method. You can enable path completion of directories only for this command by adding a +line of code similar to the following to your class which inherits from `cmd2.Cmd`: ```py # Make sure you have an "import functools" somewhere at the top @@ -32,54 +41,94 @@ complete_bar = functools.partialmethod(cmd2.Cmd.path_complete, path_filter=os.pa - `cmd2.Cmd.path_complete` - helper method provides flexible tab completion of file system paths - > - See the [paged_output](https://github.com/python-cmd2/cmd2/blob/master/examples/paged_output.py) example for a simple use case - > - See the [python_scripting](https://github.com/python-cmd2/cmd2/blob/master/examples/python_scripting.py) example for a more full-featured use case + > - See the + > [paged_output](https://github.com/python-cmd2/cmd2/blob/master/examples/paged_output.py) + > example for a simple use case + > - See the + > [python_scripting](https://github.com/python-cmd2/cmd2/blob/master/examples/python_scripting.py) + > example for a more full-featured use case -- `cmd2.Cmd.delimiter_complete` - helper method for tab completion against a list but each match is split on a delimiter +- `cmd2.Cmd.delimiter_complete` - helper method for tab completion against a list but each match is + split on a delimiter - > - See the [basic_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/basic_completion.py) example for a demonstration of how to use this feature + > - See the + > [basic_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/basic_completion.py) + > example for a demonstration of how to use this feature -- `cmd2.Cmd.flag_based_complete` - helper method for tab completion based on a particular flag preceding the token being completed +- `cmd2.Cmd.flag_based_complete` - helper method for tab completion based on a particular flag + preceding the token being completed -- `cmd2.Cmd.index_based_complete` - helper method for tab completion based on a fixed position in the input string +- `cmd2.Cmd.index_based_complete` - helper method for tab completion based on a fixed position in + the input string - > - See the [basic_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/basic_completion.py) example for a demonstration of how to use these features - > - `flag_based_complete()` and `index_based_complete()` are basic methods and should only be used if you are not familiar with argparse. The recommended approach for tab completing positional tokens and flags is to use [argparse-based](#argparse-based) completion. + > - See the + > [basic_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/basic_completion.py) + > example for a demonstration of how to use these features + > - `flag_based_complete()` and `index_based_complete()` are basic methods and should only be + > used if you are not familiar with argparse. The recommended approach for tab completing + > positional tokens and flags is to use [argparse-based](#argparse-based) completion. ## Raising Exceptions During Completion -There are times when an error occurs while tab completing and a message needs to be reported to the user. These include the following example cases: +There are times when an error occurs while tab completing and a message needs to be reported to the +user. These include the following example cases: - Reading a database to retrieve a tab completion data set failed - A previous command line argument that determines the data set being completed is invalid - Tab completion hints -`cmd2` provides the `cmd2.exceptions.CompletionError` exception class for this capability. If an error occurs in which it is more desirable to display a message than a stack trace, then raise a `CompletionError`. By default, the message displays in red like an error. However, `CompletionError` has a member called `apply_style`. Set this False if the error style should not be applied. For instance, `ArgparseCompleter` sets it to False when displaying completion hints. +`cmd2` provides the `cmd2.exceptions.CompletionError` exception class for this capability. If an +error occurs in which it is more desirable to display a message than a stack trace, then raise a +`CompletionError`. By default, the message displays in red like an error. However, `CompletionError` +has a member called `apply_style`. Set this False if the error style should not be applied. For +instance, `ArgparseCompleter` sets it to False when displaying completion hints. ## Tab Completion Using argparse Decorators {: #argparse-based } -When using one the argparse-based [cmd2.decorators](../api/decorators.md), `cmd2` provides automatic tab completion of flag names. +When using one the argparse-based [cmd2.decorators](../api/decorators.md), `cmd2` provides automatic +tab completion of flag names. -Tab completion of argument values can be configured by using one of three parameters to `argparse.ArgumentParser.add_argument` +Tab completion of argument values can be configured by using one of three parameters to +`argparse.ArgumentParser.add_argument` - `choices` - `choices_provider` - `completer` -See the [arg_decorators](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_decorators.py) or [colors](https://github.com/python-cmd2/cmd2/blob/master/examples/colors.py) example for a demonstration of how to use the `choices` parameter. See the [argparse_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_completion.py) example for a demonstration of how to use the `choices_provider` parameter. See the [arg_decorators](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_decorators.py) or [argparse_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_completion.py) example for a demonstration of how to use the `completer` parameter. +See the [arg_decorators](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_decorators.py) +or [colors](https://github.com/python-cmd2/cmd2/blob/master/examples/colors.py) example for a +demonstration of how to use the `choices` parameter. See the +[argparse_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_completion.py) +example for a demonstration of how to use the `choices_provider` parameter. See the +[arg_decorators](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_decorators.py) or +[argparse_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_completion.py) +example for a demonstration of how to use the `completer` parameter. -When tab completing flags 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. +When tab completing flags 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. ## 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 `cmd2.argparse_custom.CompletionItem` class which can be returned from any of the 3 completion parameters: `choices`, `choices_provider`, and `completer`. +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 `cmd2.argparse_custom.CompletionItem` class which can be +returned from any of the 3 completion parameters: `choices`, `choices_provider`, and `completer`. -See the [argparse_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_completion.py) example or the implementation of the built-in [set](./builtin_commands.md#set) command for demonstration of how this is used. +See the +[argparse_completion](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_completion.py) +example or the implementation of the built-in [set](./builtin_commands.md#set) command for +demonstration of how this is used. ## Custom Completion with `read_input()` -`cmd2` provides `cmd2.Cmd.read_input` as an alternative to Python's `input()` function. `read_input` supports configurable tab completion and up-arrow history at the prompt. See [read_input](https://github.com/python-cmd2/cmd2/blob/master/examples/read_input.py) example for a demonstration. +`cmd2` provides `cmd2.Cmd.read_input` as an alternative to Python's `input()` function. `read_input` +supports configurable tab completion and up-arrow history at the prompt. See +[read_input](https://github.com/python-cmd2/cmd2/blob/master/examples/read_input.py) example for a +demonstration. ## For More Information -See [cmd2's argparse_custom API](../api/argparse_custom.md) for a more detailed discussion of argparse completion. +See [cmd2's argparse_custom API](../api/argparse_custom.md) for a more detailed discussion of +argparse completion. diff --git a/docs/features/disable_commands.md b/docs/features/disable_commands.md index a44709718..3dcb0255d 100644 --- a/docs/features/disable_commands.md +++ b/docs/features/disable_commands.md @@ -8,7 +8,10 @@ ## Remove A Command -When a command has been removed, the command method has been deleted from the object. The command doesn't show up in help, and it can't be executed. This approach is appropriate if you never want a built-in command to be part of your application. Delete the command method in your initialization code: +When a command has been removed, the command method has been deleted from the object. The command +doesn't show up in help, and it can't be executed. This approach is appropriate if you never want a +built-in command to be part of your application. Delete the command method in your initialization +code: ```py class RemoveBuiltinCommand(cmd2.Cmd): @@ -23,7 +26,9 @@ When a command has been removed, the command method has been deleted from the ob ## Hide A Command -When a command is hidden, it won't show up in the help menu, but if the user knows it's there and types the command, it will be executed. You hide a command by adding it to the `hidden_commands` list: +When a command is hidden, it won't show up in the help menu, but if the user knows it's there and +types the command, it will be executed. You hide a command by adding it to the `hidden_commands` +list: ```py class HiddenCommands(cmd2.Cmd): @@ -33,7 +38,8 @@ class HiddenCommands(cmd2.Cmd): self.hidden_commands.append('py') ``` -As shown above, you would typically do this as part of initializing your application. If you decide you want to unhide a command later in the execution of your application, you can by doing: +As shown above, you would typically do this as part of initializing your application. If you decide +you want to unhide a command later in the execution of your application, you can by doing: ```py self.hidden_commands = [cmd for cmd in self.hidden_commands if cmd != 'py'] @@ -45,13 +51,17 @@ You might be thinking that the list comprehension is overkill and you'd rather d self.hidden_commands.remove('py') ``` -You may be right, but `remove()` will raise a `ValueError` if `py` isn't in the list, and it will only remove the first one if it's in the list multiple times. +You may be right, but `remove()` will raise a `ValueError` if `py` isn't in the list, and it will +only remove the first one if it's in the list multiple times. ## Disable A Command -One way to disable a command is to add code to the command method which determines whether the command should be executed or not. If the command should not be executed, your code can print an appropriate error message and return. +One way to disable a command is to add code to the command method which determines whether the +command should be executed or not. If the command should not be executed, your code can print an +appropriate error message and return. -`cmd2` also provides another way to accomplish the same thing. Here's a simple app which disables the `open` command if the door is locked: +`cmd2` also provides another way to accomplish the same thing. Here's a simple app which disables +the `open` command if the door is locked: ```py class DisabledCommands(cmd2.Cmd): @@ -70,11 +80,16 @@ class DisabledCommands(cmd2.Cmd): self.poutput('opening the door') ``` -This method has the added benefit of removing disabled commands from the help menu. But, this method only works if you know in advance that the command should be disabled, and if the conditions for re-enabling it are likewise known in advance. +This method has the added benefit of removing disabled commands from the help menu. But, this method +only works if you know in advance that the command should be disabled, and if the conditions for +re-enabling it are likewise known in advance. ## Disable A Category of Commands -You can group or categorize commands as shown in [Categorizing Command](./help.md#categorizing-commands). If you do so, you can disable and enable all the commands in a category with a single method call. Say you have created a category of commands called "Server Information". You can disable all commands in that category: +You can group or categorize commands as shown in +[Categorizing Command](./help.md#categorizing-commands). If you do so, you can disable and enable +all the commands in a category with a single method call. Say you have created a category of +commands called "Server Information". You can disable all commands in that category: ```py not_connected_msg = 'You must be connected to use this command' diff --git a/docs/features/embedded_python_shells.md b/docs/features/embedded_python_shells.md index 3419ca917..c71e57917 100644 --- a/docs/features/embedded_python_shells.md +++ b/docs/features/embedded_python_shells.md @@ -2,7 +2,8 @@ ## Python (optional) -If the `cmd2.Cmd` class is instantiated with `include_py=True`, then the optional `py` command will be present and run an interactive Python shell: +If the `cmd2.Cmd` class is instantiated with `include_py=True`, then the optional `py` command will +be present and run an interactive Python shell: ```py from cmd2 import Cmd @@ -11,22 +12,35 @@ class App(Cmd): Cmd.__init__(self, include_py=True) ``` -The Python shell can run CLI commands from you application using the object named in `self.pyscript_name` (defaults to `app`). This wrapper provides access to execute commands in your `cmd2` application while maintaining isolation from the full `Cmd` instance. For example, any application command can be run with `app("command ...")`. +The Python shell can run CLI commands from you application using the object named in +`self.pyscript_name` (defaults to `app`). This wrapper provides access to execute commands in your +`cmd2` application while maintaining isolation from the full `Cmd` instance. For example, any +application command can be run with `app("command ...")`. -You may optionally enable full access to to your application by setting `self.self_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. +You may optionally enable full access to to your application by setting `self.self_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. -Any local or global variable created within the Python session will not persist in the CLI's environment. +Any local or global variable created within the Python session will not persist in the CLI's +environment. Anything in `self.py_locals` is always available in the Python environment. -All of these parameters are also available to Python scripts which run in your application via the `run_pyscript` command: +All of these parameters are also available to Python scripts which run in your application via the +`run_pyscript` command: - supports tab completion of file system paths - has the ability to pass command-line arguments to the scripts invoked -This command provides a more complicated and more powerful scripting capability than that provided by the simple text file 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. See [Scripting](./scripting.md) for an explanation of both scripting methods in **cmd2** applications. +This command provides a more complicated and more powerful scripting capability than that provided +by the simple text file 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. See +[Scripting](./scripting.md) for an explanation of both scripting methods in **cmd2** applications. -A simple example of using `run_pyscript` is shown below along with the [arg_printer](https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/arg_printer.py) script: +A simple example of using `run_pyscript` is shown below along with the +[arg_printer](https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/arg_printer.py) +script: ```sh (Cmd) run_pyscript examples/scripts/arg_printer.py foo bar baz @@ -38,7 +52,9 @@ arg 3: 'baz' ## IPython (optional) -**If** [IPython](http://ipython.readthedocs.io) is installed on the system **and** the `cmd2.Cmd` class is instantiated with `include_ipy=True`, then the optional `ipy` command will run an interactive IPython shell: +**If** [IPython](http://ipython.readthedocs.io) is installed on the system **and** the `cmd2.Cmd` +class is instantiated with `include_ipy=True`, then the optional `ipy` command will run an +interactive IPython shell: ```py from cmd2 import Cmd @@ -47,15 +63,23 @@ class App(Cmd): Cmd.__init__(self, include_ipy=True) ``` -The `ipy` command enters an interactive [IPython](http://ipython.readthedocs.io) session. Similar to an interactive Python session, this shell can access your application instance via `self` if `self.self_in_py` is `True` 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 in the CLI's environment +The `ipy` command enters an interactive [IPython](http://ipython.readthedocs.io) session. Similar to +an interactive Python session, this shell can access your application instance via `self` if +`self.self_in_py` is `True` 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 in the CLI's +environment -Also, as in the interactive Python session, the `ipy` shell has access to the contents of `self.py_locals` and can call back into the application using the `app` object (or your custom name). +Also, as in the interactive Python session, the `ipy` shell has access to the contents of +`self.py_locals` and can call back into the application using the `app` object (or your custom +name). [IPython](http://ipython.readthedocs.io) 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 +> - Extensible tab completion, with support by default for completion of python variables and +> keywords > - Good built-in [ipdb](https://pypi.org/project/ipdb/) debugger -The object introspection and tab completion make IPython particularly efficient for debugging as well as for interactive experimentation and data analysis. +The object introspection and tab completion make IPython particularly efficient for debugging as +well as for interactive experimentation and data analysis. diff --git a/docs/features/generating_output.md b/docs/features/generating_output.md index d832dc45b..4892dd7e6 100644 --- a/docs/features/generating_output.md +++ b/docs/features/generating_output.md @@ -7,16 +7,30 @@ print("Greetings, Professor Falken.", file=self.stdout) self.stdout.write("Shall we play a game?\n") ``` -While you could send output directly to `sys.stdout`, [cmd2.Cmd][] can be initialized with a `stdin` and `stdout` variables, which it stores as `self.stdin` and `self.stdout`. By using these variables every time you produce output, you can trivially change where all the output goes by changing how you initialize your class. - -`cmd2.Cmd` extends this approach in a number of convenient ways. See [Output Redirection and Pipes](./redirection.md#output-redirection-and-pipes) for information on how users can change where the output of a command is sent. In order for those features to work, the output you generate must be sent to `self.stdout`. You can use the methods described above, and everything will work fine. [cmd2.Cmd][] also includes a number of output related methods which you may use to enhance the output your application produces. +While you could send output directly to `sys.stdout`, [cmd2.Cmd][] can be initialized with a `stdin` +and `stdout` variables, which it stores as `self.stdin` and `self.stdout`. By using these variables +every time you produce output, you can trivially change where all the output goes by changing how +you initialize your class. + +`cmd2.Cmd` extends this approach in a number of convenient ways. See +[Output Redirection and Pipes](./redirection.md#output-redirection-and-pipes) for information on how +users can change where the output of a command is sent. In order for those features to work, the +output you generate must be sent to `self.stdout`. You can use the methods described above, and +everything will work fine. [cmd2.Cmd][] also includes a number of output related methods which you +may use to enhance the output your application produces. ## Ordinary Output -The `cmd2.Cmd.poutput` method is similar to the Python [built-in print function](https://docs.python.org/3/library/functions.html#print). `cmd2.Cmd.poutput` adds two conveniences: +The `cmd2.Cmd.poutput` method is similar to the Python +[built-in print function](https://docs.python.org/3/library/functions.html#print). +`cmd2.Cmd.poutput` adds two conveniences: -1. Since users can pipe output to a shell command, it catches `BrokenPipeError` and outputs the contents of `self.broken_pipe_warning` to `stderr`. `self.broken_pipe_warning` defaults to an empty string so this method will just swallow the exception. If you want to show an error message, put it in `self.broken_pipe_warning` when you initialize `cmd2.Cmd`. -2. It examines and honors the [allow_style](./settings.md#allow_style) setting. See [Colored Output](#colored-output) below for more details. +1. Since users can pipe output to a shell command, it catches `BrokenPipeError` and outputs the + contents of `self.broken_pipe_warning` to `stderr`. `self.broken_pipe_warning` defaults to an + empty string so this method will just swallow the exception. If you want to show an error + message, put it in `self.broken_pipe_warning` when you initialize `cmd2.Cmd`. +2. It examines and honors the [allow_style](./settings.md#allow_style) setting. See + [Colored Output](#colored-output) below for more details. Here's a simple command that shows this method in action: @@ -28,33 +42,53 @@ def do_echo(self, args): ## Error Messages -When an error occurs in your program, you can display it on `sys.stderr` by calling the `.cmd2.Cmd.perror` method. By default this method applies `cmd2.ansi.style_error` to the output. +When an error occurs in your program, you can display it on `sys.stderr` by calling the +`.cmd2.Cmd.perror` method. By default this method applies `cmd2.ansi.style_error` to the output. ## Warning Messages -`cmd2.Cmd.pwarning` is just like `cmd2.Cmd.perror` but applies `cmd2.ansi.style_warning` to the output. +`cmd2.Cmd.pwarning` is just like `cmd2.Cmd.perror` but applies `cmd2.ansi.style_warning` to the +output. ## Feedback -You may have the need to display information to the user which is not intended to be part of the generated output. This could be debugging information or status information about the progress of long running commands. It's not output, it's not error messages, it's feedback. If you use the [Timing](./settings.md#timing) setting, the output of how long it took the command to run will be output as feedback. You can use the `cmd2.Cmd.pfeedback` method to produce this type of output, and several [Settings](./settings.md) control how it is handled. +You may have the need to display information to the user which is not intended to be part of the +generated output. This could be debugging information or status information about the progress of +long running commands. It's not output, it's not error messages, it's feedback. If you use the +[Timing](./settings.md#timing) setting, the output of how long it took the command to run will be +output as feedback. You can use the `cmd2.Cmd.pfeedback` method to produce this type of output, and +several [Settings](./settings.md) control how it is handled. -If the [quiet](./settings.md#quiet) setting is `True`, then calling `cmd2.Cmd.pfeedback` produces no output. If [quiet](./settings.md#quiet) is `False`, the [feedback_to_output](./settings.md#feedback_to_output) setting is consulted to determine whether to send the output to `stdout` or `stderr`. +If the [quiet](./settings.md#quiet) setting is `True`, then calling `cmd2.Cmd.pfeedback` produces no +output. If [quiet](./settings.md#quiet) is `False`, the +[feedback_to_output](./settings.md#feedback_to_output) setting is consulted to determine whether to +send the output to `stdout` or `stderr`. ## Exceptions -If your app catches an exception and you would like to display the exception to the user, the `cmd2.Cmd.pexcept` method can help. The default behavior is to just display the message contained within the exception. However, if the [debug](./settings.md#debug) setting is `True`, then the entire stack trace will be displayed. +If your app catches an exception and you would like to display the exception to the user, the +`cmd2.Cmd.pexcept` method can help. The default behavior is to just display the message contained +within the exception. However, if the [debug](./settings.md#debug) setting is `True`, then the +entire stack trace will be displayed. ## Paging Output -If you know you are going to generate a lot of output, you may want to display it in a way that the user can scroll forwards and backwards through it. If you pass all of the output to be displayed in a single call to `.cmd2.Cmd.ppaged`, it will be piped to an operating system appropriate shell command to page the output. On Windows, the output is piped to `more`; on Unix-like operating systems like MacOS and Linux, it is piped to `less`. +If you know you are going to generate a lot of output, you may want to display it in a way that the +user can scroll forwards and backwards through it. If you pass all of the output to be displayed in +a single call to `.cmd2.Cmd.ppaged`, it will be piped to an operating system appropriate shell +command to page the output. On Windows, the output is piped to `more`; on Unix-like operating +systems like MacOS and Linux, it is piped to `less`. ## Colored Output -You can add your own [ANSI escape sequences](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) to your output which tell the terminal to change the foreground and background colors. +You can add your own [ANSI escape sequences](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) +to your output which tell the terminal to change the foreground and background colors. -`cmd2` provides a number of convenience functions and classes for adding color and other styles to text. These are all documented in [cmd2.ansi][]. +`cmd2` provides a number of convenience functions and classes for adding color and other styles to +text. These are all documented in [cmd2.ansi][]. -After adding the desired escape sequences to your output, you should use one of these methods to present the output to the user: +After adding the desired escape sequences to your output, you should use one of these methods to +present the output to the user: - `cmd2.Cmd.poutput` - `cmd2.Cmd.perror` @@ -63,31 +97,45 @@ After adding the desired escape sequences to your output, you should use one of - `cmd2.Cmd.pfeedback` - `cmd2.Cmd.ppaged` -These methods all honor the [allow_style](./settings.md#allow_style) setting, which users can modify to control whether these escape codes are passed through to the terminal or not. +These methods all honor the [allow_style](./settings.md#allow_style) setting, which users can modify +to control whether these escape codes are passed through to the terminal or not. ## Aligning Text -If you would like to generate output which is left, center, or right aligned within a specified width or the terminal width, the following functions can help: +If you would like to generate output which is left, center, or right aligned within a specified +width or the terminal width, the following functions can help: - `cmd2.utils.align_left` - `cmd2.utils.align_center` - `cmd2.utils.align_right` -These functions differ from Python's string justifying functions in that they support characters with display widths greater than 1. Additionally, ANSI style sequences are safely ignored and do not count toward the display width. This means colored text is supported. If text has line breaks, then each line is aligned independently. +These functions differ from Python's string justifying functions in that they support characters +with display widths greater than 1. Additionally, ANSI style sequences are safely ignored and do not +count toward the display width. This means colored text is supported. If text has line breaks, then +each line is aligned independently. ## Columnar Output -When generating output in multiple columns, you often need to calculate the width of each item so you can pad it appropriately with spaces. However, there are categories of Unicode characters that occupy 2 cells, and other that occupy 0. To further complicate matters, you might have included ANSI escape sequences in the output to generate colors on the terminal. +When generating output in multiple columns, you often need to calculate the width of each item so +you can pad it appropriately with spaces. However, there are categories of Unicode characters that +occupy 2 cells, and other that occupy 0. To further complicate matters, you might have included ANSI +escape sequences in the output to generate colors on the terminal. -The `cmd2.ansi.style_aware_wcswidth` function solves both of these problems. Pass it a string, and regardless of which Unicode characters and ANSI text style escape sequences it contains, it will tell you how many characters on the screen that string will consume when printed. +The `cmd2.ansi.style_aware_wcswidth` function solves both of these problems. Pass it a string, and +regardless of which Unicode characters and ANSI text style escape sequences it contains, it will +tell you how many characters on the screen that string will consume when printed. ## Pretty Printing Data Structures -The `cmd2.Cmd.ppretty` method is similar to the Python [pprint](https://docs.python.org/3/library/pprint.html) function from the standard `pprint` module. `cmd2.Cmd.pprint` adds the same conveniences as `cmd2.Cmd.poutput`. +The `cmd2.Cmd.ppretty` method is similar to the Python +[pprint](https://docs.python.org/3/library/pprint.html) function from the standard `pprint` module. +`cmd2.Cmd.pprint` adds the same conveniences as `cmd2.Cmd.poutput`. -This method provides a capability to “pretty-print” arbitrary Python data structures in a form which can be used as input to the interpreter and is easy for humans -to read. +This method provides a capability to “pretty-print” arbitrary Python data structures in a form which +can be used as input to the interpreter and is easy for humans to read. -The formatted representation keeps objects on a single line if it can, and breaks them onto multiple lines if they don’t fit within the allowed width, adjustable by the width parameter defaulting to 80 characters. +The formatted representation keeps objects on a single line if it can, and breaks them onto multiple +lines if they don’t fit within the allowed width, adjustable by the width parameter defaulting to 80 +characters. Dictionaries are sorted by key before the display is computed. diff --git a/docs/features/help.md b/docs/features/help.md index 52f00eb6e..56a47b3bc 100644 --- a/docs/features/help.md +++ b/docs/features/help.md @@ -1,10 +1,13 @@ # Help -From our experience, end users rarely read documentation no matter how high-quality or useful that documentation might be. So it is important that you provide good built-in help within your application. Fortunately, `cmd2` makes this easy. +From our experience, end users rarely read documentation no matter how high-quality or useful that +documentation might be. So it is important that you provide good built-in help within your +application. Fortunately, `cmd2` makes this easy. ## Getting Help -`cmd2` makes it easy for end users of `cmd2` applications to get help via the built-in `help` command. The `help` command by itself displays a list of the commands available: +`cmd2` makes it easy for end users of `cmd2` applications to get help via the built-in `help` +command. The `help` command by itself displays a list of the commands available: ```text (Cmd) help @@ -29,11 +32,20 @@ optional arguments: ## Providing Help -`cmd2` makes it easy for developers of `cmd2` applications to provide this help. By default, the help for a command is the docstring for the `do_*` method defining the command - e.g. for a command **foo**, that command is implemented by defining the `do_foo` method and the docstring for that method is the help. +`cmd2` makes it easy for developers of `cmd2` applications to provide this help. By default, the +help for a command is the docstring for the `do_*` method defining the command - e.g. for a command +**foo**, that command is implemented by defining the `do_foo` method and the docstring for that +method is the help. -For commands which use one of the `argparse` decorators to parse arguments, help is provided by `argparse`. See [Help Messages](./argument_processing.md#help-messages) for more information. +For commands which use one of the `argparse` decorators to parse arguments, help is provided by +`argparse`. See [Help Messages](./argument_processing.md#help-messages) for more information. -Occasionally there might be an unusual circumstance where providing static help text isn't good enough and you want to provide dynamic information in the help text for a command. To meet this need, if a `help_foo` method is defined to match the `do_foo` method, then that method will be used to provide the help for command **foo**. This dynamic help is only supported for commands which do not use an `argparse` decorator because didn't want different output for `help cmd` than for `cmd -h`. +Occasionally there might be an unusual circumstance where providing static help text isn't good +enough and you want to provide dynamic information in the help text for a command. To meet this +need, if a `help_foo` method is defined to match the `do_foo` method, then that method will be used +to provide the help for command **foo**. This dynamic help is only supported for commands which do +not use an `argparse` decorator because didn't want different output for `help cmd` than for +`cmd -h`. ## Categorizing Commands @@ -44,7 +56,8 @@ By default, the `help` command displays: alias help ipy py run_pyscript set shortcuts edit history macro quit run_script shell -If you have a large number of commands, you can optionally group your commands into categories. Here's the output from the example `help_categories.py`: +If you have a large number of commands, you can optionally group your commands into categories. +Here's the output from the example `help_categories.py`: Documented commands (use 'help -v' for verbose/'help ' for details): @@ -70,7 +83,10 @@ If you have a large number of commands, you can optionally group your commands i alias edit history py run_pyscript set shortcuts config help macro quit run_script shell version -There are 2 methods of specifying command categories, using the `@with_category` decorator or with the `categorize()` function. Once a single command category is detected, the help output switches to a categorized mode of display. All commands with an explicit category defined default to the category `Other`. +There are 2 methods of specifying command categories, using the `@with_category` decorator or with +the `categorize()` function. Once a single command category is detected, the help output switches to +a categorized mode of display. All commands with an explicit category defined default to the +category `Other`. Using the `@with_category` decorator: @@ -115,7 +131,8 @@ categorize((do_undeploy, do_findleakers), CMD_CAT_APP_MGMT) ``` -The `help` command also has a verbose option (`help -v` or `help --verbose`) that combines the help categories with per-command Help Messages: +The `help` command also has a verbose option (`help -v` or `help --verbose`) that combines the help +categories with per-command Help Messages: Documented commands (use 'help -v' for verbose/'help ' for details): @@ -166,4 +183,5 @@ The `help` command also has a verbose option (`help -v` or `help --verbose`) tha shortcuts List available shortcuts version Version command -When called with the `-v` flag for verbose help, the one-line description for each command is provided by the first line of the docstring for that command's associated `do_*` method. +When called with the `-v` flag for verbose help, the one-line description for each command is +provided by the first line of the docstring for that command's associated `do_*` method. diff --git a/docs/features/history.md b/docs/features/history.md index 549111e9e..59ecf5f19 100644 --- a/docs/features/history.md +++ b/docs/features/history.md @@ -4,11 +4,19 @@ The `cmd` module from the Python standard library includes `readline` history. -[cmd2.Cmd][] offers the same `readline` capabilities, but also maintains its own data structures for the history of all commands entered by the user. When the class is initialized, it creates an instance of the [cmd2.history.History][] class (which is a subclass of `list`) as `cmd2.Cmd.history`. +[cmd2.Cmd][] offers the same `readline` capabilities, but also maintains its own data structures for +the history of all commands entered by the user. When the class is initialized, it creates an +instance of the [cmd2.history.History][] class (which is a subclass of `list`) as +`cmd2.Cmd.history`. -Each time a command is executed (this gets complex, see [Command Processing Loop](./hooks.md#command-processing-loop) for exactly when) the parsed [cmd2.Statement][] is appended to `cmd2.Cmd.history`. +Each time a command is executed (this gets complex, see +[Command Processing Loop](./hooks.md#command-processing-loop) for exactly when) the parsed +[cmd2.Statement][] is appended to `cmd2.Cmd.history`. -`cmd2` adds the option of making this history persistent via optional arguments to `cmd2.Cmd.__init__`. If you pass a filename in the `persistent_history_file` argument, the contents of `cmd2.Cmd.history` will be written as compressed JSON to that history file. We chose this format instead of plain text to preserve the complete `cmd2.Statement` object for each command. +`cmd2` adds the option of making this history persistent via optional arguments to +`cmd2.Cmd.__init__`. If you pass a filename in the `persistent_history_file` argument, the contents +of `cmd2.Cmd.history` will be written as compressed JSON to that history file. We chose this format +instead of plain text to preserve the complete `cmd2.Statement` object for each command. !!! note @@ -16,17 +24,26 @@ Each time a command is executed (this gets complex, see [Command Processing Loop However, this design choice causes an inconsistency between the `readline` history and the `cmd2` history when you enter an invalid command: it is saved to the `readline` history, but not to the `cmd2` history. -The `cmd2.Cmd.history` attribute, the `cmd2.history.History` class, and the `cmd2.history.HistoryItem` class are all part of the public API for `cmd2.Cmd`. You could use these classes to implement write your own `history` command (see below for documentation on how the included `history` command works). +The `cmd2.Cmd.history` attribute, the `cmd2.history.History` class, and the +`cmd2.history.HistoryItem` class are all part of the public API for `cmd2.Cmd`. You could use these +classes to implement write your own `history` command (see below for documentation on how the +included `history` command works). ## For Users You can use the up and down arrow keys to move through the history of previously entered commands. -If the `readline` module is installed, you can press `Control-p` to move to the previously entered command, and `Control-n` to move to the next command. You can also search through the command history using `Control-r`. +If the `readline` module is installed, you can press `Control-p` to move to the previously entered +command, and `Control-n` to move to the next command. You can also search through the command +history using `Control-r`. -Eric Johnson hosts a nice [readline cheat sheet](http://readline.kablamo.org/emacs.html), or you can dig into the [GNU Readline User Manual](http://man7.org/linux/man-pages/man3/readline.3.html) for all the details, including instructions for customizing the key bindings. +Eric Johnson hosts a nice [readline cheat sheet](http://readline.kablamo.org/emacs.html), or you can +dig into the [GNU Readline User Manual](http://man7.org/linux/man-pages/man3/readline.3.html) for +all the details, including instructions for customizing the key bindings. -`cmd2` makes a third type of history access available with the `history` command. Each time the user enters a command, `cmd2` saves the input. The `history` command lets you do interesting things with that saved input. The examples to follow all assume that you have entered the following commands: +`cmd2` makes a third type of history access available with the `history` command. Each time the user +enters a command, `cmd2` saves the input. The `history` command lets you do interesting things with +that saved input. The examples to follow all assume that you have entered the following commands: (Cmd) alias create one !echo one Alias 'one' created @@ -37,7 +54,8 @@ Eric Johnson hosts a nice [readline cheat sheet](http://readline.kablamo.org/ema (Cmd) alias create four !echo four Alias 'four' created -In it's simplest form, the `history` command displays previously entered commands. With no additional arguments, it displays all previously entered commands: +In it's simplest form, the `history` command displays previously entered commands. With no +additional arguments, it displays all previously entered commands: (Cmd) history 1 alias create one !echo one @@ -50,19 +68,23 @@ If you give a positive integer as an argument, then it only displays the specifi (Cmd) history 4 4 alias create four !echo four -If you give a negative integer _N_ as an argument, then it display the _Nth_ last command. For example, if you give `-1` it will display the last command you entered. If you give `-2` it will display the next to last command you entered, and so forth: +If you give a negative integer _N_ as an argument, then it display the _Nth_ last command. For +example, if you give `-1` it will display the last command you entered. If you give `-2` it will +display the next to last command you entered, and so forth: (Cmd) history -2 3 alias create three !echo three -You can use a similar mechanism to display a range of commands. Simply give two command numbers separated by `..` or `:`, and you will see all commands between, and including, those two numbers: +You can use a similar mechanism to display a range of commands. Simply give two command numbers +separated by `..` or `:`, and you will see all commands between, and including, those two numbers: (Cmd) history 1:3 1 alias create one !echo one 2 alias create two !echo two 3 alias create three !echo three -If you omit the first number, it will start at the beginning. If you omit the last number, it will continue to the end: +If you omit the first number, it will start at the beginning. If you omit the last number, it will +continue to the end: (Cmd) history :2 1 alias create one !echo one @@ -79,13 +101,21 @@ If you want to display the last three commands entered: 3 alias create three !echo three 4 alias create four !echo four -Notice the double dashes. These are required because the history command uses `argparse` to parse the command line arguments. As described in the [argparse documentation](https://docs.python.org/3/library/argparse.html) , `-3:` is an option, not an argument: +Notice the double dashes. These are required because the history command uses `argparse` to parse +the command line arguments. As described in the +[argparse documentation](https://docs.python.org/3/library/argparse.html) , `-3:` is an option, not +an argument: -> If you have positional arguments that must begin with - and don't look like negative numbers, you can insert the pseudo-argument '--' which tells parse[args]{#args}() that everything after that is a positional argument: +> If you have positional arguments that must begin with - and don't look like negative numbers, you +> can insert the pseudo-argument '--' which tells parse[args]{#args}() that everything after that is +> a positional argument: -There is no zeroth command, so don't ask for it. If you are a python programmer, you've probably noticed this looks a lot like the slice syntax for lists and arrays. It is, with the exception that the first history command is 1, where the first element in a python array is 0. +There is no zeroth command, so don't ask for it. If you are a python programmer, you've probably +noticed this looks a lot like the slice syntax for lists and arrays. It is, with the exception that +the first history command is 1, where the first element in a python array is 0. -Besides selecting previous commands by number, you can also search for them. You can use a simple string search: +Besides selecting previous commands by number, you can also search for them. You can use a simple +string search: (Cmd) history two 2 alias create two !echo two @@ -95,9 +125,12 @@ Or a regular expression search by enclosing your regex in slashes: (Cmd) history '/te\ +th/' 3 alias create three !echo three -If your regular expression contains any characters that `argparse` finds interesting, like dash or plus, you also need to enclose your regular expression in quotation marks. +If your regular expression contains any characters that `argparse` finds interesting, like dash or +plus, you also need to enclose your regular expression in quotation marks. -This all sounds great, but doesn't it seem like a bit of overkill to have all these ways to select commands if all we can do is display them? Turns out, displaying history commands is just the beginning. The history command can perform many other actions: +This all sounds great, but doesn't it seem like a bit of overkill to have all these ways to select +commands if all we can do is display them? Turns out, displaying history commands is just the +beginning. The history command can perform many other actions: - running previously entered commands - saving previously entered commands to a text file @@ -105,45 +138,68 @@ This all sounds great, but doesn't it seem like a bit of overkill to have all th - running previously entered commands, saving the commands and their output to a text file - clearing the history of entered commands -Each of these actions is invoked using a command line option. The `-r` or `--run` option runs one or more previously entered commands. To run command number 1: +Each of these actions is invoked using a command line option. The `-r` or `--run` option runs one or +more previously entered commands. To run command number 1: (Cmd) history --run 1 -To rerun the last two commands (there's that double dash again to make argparse stop looking for options): +To rerun the last two commands (there's that double dash again to make argparse stop looking for +options): (Cmd) history -r -- -2: -Say you want to re-run some previously entered commands, but you would really like to make a few changes to them before doing so. When you use the `-e` or `--edit` option, `history` will write the selected commands out to a text file, and open that file with a text editor. You make whatever changes, additions, or deletions, you want. When you leave the text editor, all the commands in the file are executed. To edit and then re-run commands 2-4 you would: +Say you want to re-run some previously entered commands, but you would really like to make a few +changes to them before doing so. When you use the `-e` or `--edit` option, `history` will write the +selected commands out to a text file, and open that file with a text editor. You make whatever +changes, additions, or deletions, you want. When you leave the text editor, all the commands in the +file are executed. To edit and then re-run commands 2-4 you would: (Cmd) history --edit 2:4 -If you want to save the commands to a text file, but not edit and re-run them, use the `-o` or `--output-file` option. This is a great way to create [Scripts](./scripting.md), which can be executed using the `run_script` command. To save the first 5 commands entered in this session to a text file: +If you want to save the commands to a text file, but not edit and re-run them, use the `-o` or +`--output-file` option. This is a great way to create [Scripts](./scripting.md), which can be +executed using the `run_script` command. To save the first 5 commands entered in this session to a +text file: (Cmd) history :5 -o history.txt -The `history` command can also save both the commands and their output to a text file. This is called a transcript. See [Transcripts](./transcripts.md) for more information on how transcripts work, and what you can use them for. To create a transcript use the `-t` or `--transcription` option: +The `history` command can also save both the commands and their output to a text file. This is +called a transcript. See [Transcripts](./transcripts.md) for more information on how transcripts +work, and what you can use them for. To create a transcript use the `-t` or `--transcription` +option: (Cmd) history 2:3 --transcript transcript.txt -The `--transcript` option implies `--run`: the commands must be re-run in order to capture their output to the transcript file. +The `--transcript` option implies `--run`: the commands must be re-run in order to capture their +output to the transcript file. !!! warning Unlike the `-o`/`--output-file` option, the `-t`/`--transcript` option will actually run the selected history commands again. This is necessary for creating a transcript file since the history saves the commands themselves but does not save their output. Please note that a side-effect of this is that the commands will appear again at the end of the history. -The last action the history command can perform is to clear the command history using `-c` or `--clear`: +The last action the history command can perform is to clear the command history using `-c` or +`--clear`: (Cmd) history -c -In addition to these five actions, the `history` command also has some options to control how the output is formatted. With no arguments, the `history` command displays the command number before each command. This is great when displaying history to the screen because it gives you an easy reference to identify previously entered commands. However, when creating a script or a transcript, the command numbers would prevent the script from loading properly. The `-s` or `--script` option instructs the `history` command to suppress the line numbers. This option is automatically set by the `--output_file`, `--transcript`, and `--edit` options. If you want to output the history commands with line numbers to a file, you can do it with output redirection: +In addition to these five actions, the `history` command also has some options to control how the +output is formatted. With no arguments, the `history` command displays the command number before +each command. This is great when displaying history to the screen because it gives you an easy +reference to identify previously entered commands. However, when creating a script or a transcript, +the command numbers would prevent the script from loading properly. The `-s` or `--script` option +instructs the `history` command to suppress the line numbers. This option is automatically set by +the `--output_file`, `--transcript`, and `--edit` options. If you want to output the history +commands with line numbers to a file, you can do it with output redirection: (Cmd) history 1:4 > history.txt -You might use `-s` or `--script` on it's own if you want to display history commands to the screen without line numbers, so you can copy them to the clipboard: +You might use `-s` or `--script` on it's own if you want to display history commands to the screen +without line numbers, so you can copy them to the clipboard: (Cmd) history -s 1:3 -`cmd2` supports both aliases and macros, which allow you to substitute a short, more convenient input string with a longer replacement string. Say we create an alias like this, and then use it: +`cmd2` supports both aliases and macros, which allow you to substitute a short, more convenient +input string with a longer replacement string. Say we create an alias like this, and then use it: (Cmd) alias create ls shell ls -aF Alias 'ls' created @@ -156,17 +212,22 @@ By default, the `history` command shows exactly what we typed: 1 alias create ls shell ls -aF 2 ls -d h* -There are two ways to modify that display so you can see what aliases and macros were expanded to. The first is to use `-x` or `--expanded`. These options show the expanded command instead of the entered command: +There are two ways to modify that display so you can see what aliases and macros were expanded to. +The first is to use `-x` or `--expanded`. These options show the expanded command instead of the +entered command: (Cmd) history -x 1 alias create ls shell ls -aF 2 shell ls -aF -d h* -If you want to see both the entered command and the expanded command, use the `-v` or `--verbose` option: +If you want to see both the entered command and the expanded command, use the `-v` or `--verbose` +option: (Cmd) history -v 1 alias create ls shell ls -aF 2 ls -d h* 2x shell ls -aF -d h* -If the entered command had no expansion, it is displayed as usual. However, if there is some change as the result of expanding macros and aliases, then the entered command is displayed with the number, and the expanded command is displayed with the number followed by an `x`. +If the entered command had no expansion, it is displayed as usual. However, if there is some change +as the result of expanding macros and aliases, then the entered command is displayed with the +number, and the expanded command is displayed with the number followed by an `x`. diff --git a/docs/features/hooks.md b/docs/features/hooks.md index 7ce385598..9755f3eef 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -12,11 +12,13 @@ if __name__ == '__main__': 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 command processing loop. +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 command processing loop. ## Application Lifecycle Hooks -You can run a script on initialization by passing the script filename in the `startup_script` parameter of `cmd2.Cmd.__init__`. +You can run a script on initialization by passing the script filename in the `startup_script` +parameter of `cmd2.Cmd.__init__`. You can also register methods to be called at the beginning of the command loop: @@ -30,9 +32,11 @@ You can also register methods to be called at the beginning of the command loop: self.poutput("before the loop begins") ``` -To retain backwards compatibility with `cmd.Cmd`, after all registered preloop hooks have been called, the `cmd2.Cmd.preloop` method is called. +To retain backwards compatibility with `cmd.Cmd`, after all registered preloop hooks have been +called, the `cmd2.Cmd.preloop` method is called. -A similar approach allows you to register functions to be called after the command loop has finished: +A similar approach allows you to register functions to be called after the command loop has +finished: ```py class App(cmd2.Cmd): @@ -44,30 +48,39 @@ A similar approach allows you to register functions to be called after the comma self.poutput("after the loop ends") ``` -To retain backwards compatibility with `cmd.Cmd`, after all registered postloop hooks have been called, the `cmd2.Cmd.postloop` method is called. +To retain backwards compatibility with `cmd.Cmd`, after all registered postloop hooks have been +called, the `cmd2.Cmd.postloop` method is called. Preloop and postloop hook methods are not passed any parameters and any return value is ignored. -The approach of registering hooks instead of overriding methods allows multiple hooks to be called before the command loop begins or ends. Plugin authors should review [Hooks](./hooks.md) for best practices writing hooks. +The approach of registering hooks instead of overriding methods allows multiple hooks to be called +before the command loop begins or ends. Plugin authors should review [Hooks](./hooks.md) for best +practices writing hooks. ## Application Lifecycle Attributes -There are numerous attributes on `cmd2.Cmd` which affect application behavior upon entering or during the command loop: +There are numerous attributes on `cmd2.Cmd` which affect application behavior upon entering or +during the command loop: -- `cmd2.Cmd.intro` - if provided this serves as the intro banner printed once at start of application, after `cmd2.Cmd.preloop` is called +- `cmd2.Cmd.intro` - if provided this serves as the intro banner printed once at start of + application, after `cmd2.Cmd.preloop` is called - `cmd2.Cmd.prompt` - see [Prompt](./prompt.md) for more information -- `cmd2.Cmd.continuation_prompt` - The prompt issued to solicit input for the 2nd and subsequent lines of a `multiline command [Multiline Commands](./multiline_commands.md) +- `cmd2.Cmd.continuation_prompt` - The prompt issued to solicit input for the 2nd and subsequent + lines of a `multiline command [Multiline Commands](./multiline_commands.md) - `cmd2.Cmd.echo` - if `True` write the prompt and the command into the output stream In addition, several arguments to `cmd2.Cmd.__init__` also affect the command loop behavior: -- `allow_cli_args` - allows commands to be specified on the operating system command line which are executed before the command processing loop begins +- `allow_cli_args` - allows commands to be specified on the operating system command line which are + executed before the command processing loop begins - `transcript_files` - see [Transcripts](./transcripts.md) for more information -- `startup_script` - run a script on initialization. See [Scripting](./scripting.md) for more information +- `startup_script` - run a script on initialization. See [Scripting](./scripting.md) for more + information ## Command Processing Loop -When you call [cmd2.Cmd.cmdloop][], the following sequence of events are repeated until the application exits: +When you call [cmd2.Cmd.cmdloop][], the following sequence of events are repeated until the +application exits: 1. Output the prompt 1. Accept user input @@ -85,9 +98,14 @@ When you call [cmd2.Cmd.cmdloop][], the following sequence of events are repeate 1. Stop redirecting output if it was redirected 1. Call methods registered with `cmd2.Cmd.register_cmdfinalization_hook()` -By registering hook methods, multiple steps allow you to run code during, and control the flow of the command processing loop. Be aware that plugins also utilize these hooks, so there may be code running that is not part of your application. Methods registered for a hook are called in the order they were registered. You can register a function more than once, and it will be called each time it was registered. +By registering hook methods, multiple steps allow you to run code during, and control the flow of +the command processing loop. Be aware that plugins also utilize these hooks, so there may be code +running that is not part of your application. Methods registered for a hook are called in the order +they were registered. You can register a function more than once, and it will be called each time it +was registered. -Postparsing, precommand, and postcommand hook methods share some common ways to influence the command processing loop. +Postparsing, precommand, and postcommand hook methods share some common ways to influence the +command processing loop. If a hook raises an exception: @@ -99,14 +117,16 @@ Specific types of hook methods have additional options as described below. ## Postparsing Hooks -Postparsing hooks are called after the user input has been parsed but before execution of the command. These hooks can be used to: +Postparsing hooks are called after the user input has been parsed but before execution of the +command. These hooks can be used to: - modify the user input - run code before every command executes - cancel execution of the current command - exit the application -When postparsing hooks are called, output has not been redirected, nor has the timer for command execution been started. +When postparsing hooks are called, output has not been redirected, nor has the timer for command +execution been started. To define and register a postparsing hook, do the following: @@ -122,15 +142,30 @@ class App(cmd2.Cmd): return params ``` -`cmd2.Cmd.register_postparsing_hook` checks the method signature of the passed callable, and raises a `TypeError` if it has the wrong number of parameters. It will also raise a `TypeError` if the passed parameter and return value are not annotated as `PostparsingData`. +`cmd2.Cmd.register_postparsing_hook` checks the method signature of the passed callable, and raises +a `TypeError` if it has the wrong number of parameters. It will also raise a `TypeError` if the +passed parameter and return value are not annotated as `PostparsingData`. -The hook method will be passed one parameter, a `cmd2.plugin.PostparsingData` object which we will refer to as `params`. `params` contains two attributes. `params.statement` is a `cmd2.Statement` object which describes the parsed user input. There are many useful attributes in the `cmd2.Statement` object, including `.raw` which contains exactly what the user typed. `params.stop` is set to `False` by default. +The hook method will be passed one parameter, a `cmd2.plugin.PostparsingData` object which we will +refer to as `params`. `params` contains two attributes. `params.statement` is a `cmd2.Statement` +object which describes the parsed user input. There are many useful attributes in the +`cmd2.Statement` object, including `.raw` which contains exactly what the user typed. `params.stop` +is set to `False` by default. -The hook method must return a `cmd2.plugin.PostparsingData` object, and it is very convenient to just return the object passed into the hook method. The hook method may modify the attributes of the object to influence the behavior of the application. If `params.stop` is set to true, a fatal failure is triggered prior to execution of the command, and the application exits. +The hook method must return a `cmd2.plugin.PostparsingData` object, and it is very convenient to +just return the object passed into the hook method. The hook method may modify the attributes of the +object to influence the behavior of the application. If `params.stop` is set to true, a fatal +failure is triggered prior to execution of the command, and the application exits. -To modify the user input, you create a new `cmd2.Statement` object and return it in `params.statement`. Don't try and directly modify the contents of a `cmd2.Statement` object, there be dragons. Instead, use the various attributes in a `cmd2.Statement` object to construct a new string, and then parse that string to create a new `cmd2.Statement` object. +To modify the user input, you create a new `cmd2.Statement` object and return it in +`params.statement`. Don't try and directly modify the contents of a `cmd2.Statement` object, there +be dragons. Instead, use the various attributes in a `cmd2.Statement` object to construct a new +string, and then parse that string to create a new `cmd2.Statement` object. -`cmd2.Cmd` uses an instance of `cmd2.parsing.StatementParser` to parse user input. This instance has been configured with the proper command terminators, multiline commands, and other parsing related settings. This instance is available as the `cmd2.Cmd.statement_parser` attribute. Here's a simple example which shows the proper technique: +`cmd2.Cmd` uses an instance of `cmd2.parsing.StatementParser` to parse user input. This instance has +been configured with the proper command terminators, multiline commands, and other parsing related +settings. This instance is available as the `cmd2.Cmd.statement_parser` attribute. Here's a simple +example which shows the proper technique: ```py def myhookmethod(self, params: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData: @@ -140,18 +175,22 @@ def myhookmethod(self, params: cmd2.plugin.PostparsingData) -> cmd2.plugin.Postp return params ``` -If a postparsing hook returns a `cmd2.plugin.PostparsingData` object with the `cmd2.plugin.PostparsingData.stop` attribute set to `True`: +If a postparsing hook returns a `cmd2.plugin.PostparsingData` object with the +`cmd2.plugin.PostparsingData.stop` attribute set to `True`: -- no more hooks of any kind (except [Command Finalization Hooks](#command-finalization-hooks)) will be called +- no more hooks of any kind (except [Command Finalization Hooks](#command-finalization-hooks)) will + be called - the command will not be executed - no error message will be displayed to the user - the application will exit ## Precommand Hooks -Precommand hooks can modify the user input, but cannot request the application terminate. If your hook needs to be able to exit the application, you should implement it as a postparsing hook. +Precommand hooks can modify the user input, but cannot request the application terminate. If your +hook needs to be able to exit the application, you should implement it as a postparsing hook. -Once output is redirected and the timer started, all the hooks registered with `cmd2.Cmd.register_precmd_hook` are called. Here's how to do it: +Once output is redirected and the timer started, all the hooks registered with +`cmd2.Cmd.register_precmd_hook` are called. Here's how to do it: ```py class App(cmd2.Cmd): @@ -165,17 +204,25 @@ class App(cmd2.Cmd): return data ``` -`cmd2.Cmd.register_precmd_hook` checks the method signature of the passed callable, and raises a `TypeError` if it has the wrong number of parameters. It will also raise a `TypeError` if the parameters and return value are not annotated as `PrecommandData`. +`cmd2.Cmd.register_precmd_hook` checks the method signature of the passed callable, and raises a +`TypeError` if it has the wrong number of parameters. It will also raise a `TypeError` if the +parameters and return value are not annotated as `PrecommandData`. -You may choose to modify the user input by creating a new `cmd2.Statement` with different properties (see above). If you do so, assign your new `cmd2.Statement` object to `data.statement`. +You may choose to modify the user input by creating a new `cmd2.Statement` with different properties +(see above). If you do so, assign your new `cmd2.Statement` object to `data.statement`. -The precommand hook must return a `cmd2.plugin.PrecommandData` object. You don't have to create this object from scratch, you can just return the one passed into the hook. +The precommand hook must return a `cmd2.plugin.PrecommandData` object. You don't have to create this +object from scratch, you can just return the one passed into the hook. -After all registered precommand hooks have been called, `cmd2.Cmd.precmd` will be called. To retain full backward compatibility with `cmd.Cmd`, this method is passed a `cmd2.Statement`, not a `cmd2.plugin.PrecommandData` object. +After all registered precommand hooks have been called, `cmd2.Cmd.precmd` will be called. To retain +full backward compatibility with `cmd.Cmd`, this method is passed a `cmd2.Statement`, not a +`cmd2.plugin.PrecommandData` object. ## Postcommand Hooks -Once the command method has returned (i.e. the `do_command(self, statement) method` has been called and returns, all postcommand hooks are called. If output was redirected by the user, it is still redirected, and the command timer is still running. +Once the command method has returned (i.e. the `do_command(self, statement) method` has been called +and returns, all postcommand hooks are called. If output was redirected by the user, it is still +redirected, and the command timer is still running. Here's how to define and register a postcommand hook: @@ -189,24 +236,40 @@ class App(cmd2.Cmd): return data ``` -Your hook will be passed a `cmd2.plugin.PostcommandData` object, which has a `cmd2.plugin.PostcommandData.statement` attribute that describes the command which was executed. If your postcommand hook method gets called, you are guaranteed that the command method was called, and that it didn't raise an exception. +Your hook will be passed a `cmd2.plugin.PostcommandData` object, which has a +`cmd2.plugin.PostcommandData.statement` attribute that describes the command which was executed. If +your postcommand hook method gets called, you are guaranteed that the command method was called, and +that it didn't raise an exception. -If any postcommand hook raises an exception, the exception will be displayed to the user, and no further postcommand hook methods will be called. Command finalization hooks, if any, will be called. +If any postcommand hook raises an exception, the exception will be displayed to the user, and no +further postcommand hook methods will be called. Command finalization hooks, if any, will be called. -After all registered postcommand hooks have been called, `self.postcmd` will be called to retain full backward compatibility with `cmd.Cmd`. +After all registered postcommand hooks have been called, `self.postcmd` will be called to retain +full backward compatibility with `cmd.Cmd`. -If any postcommand hook (registered or `self.postcmd`) returns a `cmd2.plugin.PostcommandData` object with the stop attribute set to `True`, subsequent postcommand hooks will still be called, as will the command finalization hooks, but once those hooks have all been called, the application will terminate. Likewise, if :`self.postcmd` returns `True`, the command finalization hooks will be called before the application terminates. +If any postcommand hook (registered or `self.postcmd`) returns a `cmd2.plugin.PostcommandData` +object with the stop attribute set to `True`, subsequent postcommand hooks will still be called, as +will the command finalization hooks, but once those hooks have all been called, the application will +terminate. Likewise, if :`self.postcmd` returns `True`, the command finalization hooks will be +called before the application terminates. -Any postcommand hook can change the value of the `stop` attribute before returning it, and the modified value will be passed to the next postcommand hook. The value returned by the final postcommand hook will be passed to the command finalization hooks, which may further modify the value. If your hook blindly returns `False`, a prior hook's request to exit the application will not be honored. It's best to return the value you were passed unless you have a compelling reason to do otherwise. +Any postcommand hook can change the value of the `stop` attribute before returning it, and the +modified value will be passed to the next postcommand hook. The value returned by the final +postcommand hook will be passed to the command finalization hooks, which may further modify the +value. If your hook blindly returns `False`, a prior hook's request to exit the application will not +be honored. It's best to return the value you were passed unless you have a compelling reason to do +otherwise. -To purposefully and silently skip postcommand hooks, commands can raise any of of the following exceptions. +To purposefully and silently skip postcommand hooks, commands can raise any of of the following +exceptions. - `cmd2.exceptions.SkipPostcommandHooks` - `cmd2.exceptions.Cmd2ArgparseError` ## Command Finalization Hooks -Command finalization hooks are called even if one of the other types of hooks or the command method raise an exception. Here's how to create and register a command finalization hook: +Command finalization hooks are called even if one of the other types of hooks or the command method +raise an exception. Here's how to create and register a command finalization hook: ```py class App(cmd2.Cmd): @@ -218,10 +281,22 @@ class App(cmd2.Cmd): return data ``` -Command Finalization hooks must check whether the `cmd2.plugin.CommandFinalizationData.statement` attribute of the passed `cmd2.plugin.CommandFinalizationData` object contains a value. There are certain circumstances where these hooks may be called before the user input has been parsed, so you can't always rely on having a `cmd2.plugin.CommandFinalizationData.statement`. - -If any prior postparsing or precommand hook has requested the application to terminate, the value of the `cmd2.plugin.CommandFinalizationData.stop` attribute passed to the first command finalization hook will be `True`. Any command finalization hook can change the value of the `cmd2.plugin.CommandFinalizationData.stop` attribute before returning it, and the modified value will be passed to the next command finalization hook. The value returned by the final command finalization hook will determine whether the application terminates or not. - -This approach to command finalization hooks can be powerful, but it can also cause problems. If your hook blindly returns `False`, a prior hook's request to exit the application will not be honored. It's best to return the value you were passed unless you have a compelling reason to do otherwise. - -If any command finalization hook raises an exception, no more command finalization hooks will be called. If the last hook to return a value returned `True`, then the exception will be rendered, and the application will terminate. +Command Finalization hooks must check whether the `cmd2.plugin.CommandFinalizationData.statement` +attribute of the passed `cmd2.plugin.CommandFinalizationData` object contains a value. There are +certain circumstances where these hooks may be called before the user input has been parsed, so you +can't always rely on having a `cmd2.plugin.CommandFinalizationData.statement`. + +If any prior postparsing or precommand hook has requested the application to terminate, the value of +the `cmd2.plugin.CommandFinalizationData.stop` attribute passed to the first command finalization +hook will be `True`. Any command finalization hook can change the value of the +`cmd2.plugin.CommandFinalizationData.stop` attribute before returning it, and the modified value +will be passed to the next command finalization hook. The value returned by the final command +finalization hook will determine whether the application terminates or not. + +This approach to command finalization hooks can be powerful, but it can also cause problems. If your +hook blindly returns `False`, a prior hook's request to exit the application will not be honored. +It's best to return the value you were passed unless you have a compelling reason to do otherwise. + +If any command finalization hook raises an exception, no more command finalization hooks will be +called. If the last hook to return a value returned `True`, then the exception will be rendered, and +the application will terminate. diff --git a/docs/features/misc.md b/docs/features/misc.md index 3e450868a..52c908772 100644 --- a/docs/features/misc.md +++ b/docs/features/misc.md @@ -12,7 +12,8 @@ Mention quit, and EOF handling built into `cmd2`. Presents numbered options to user, as bash `select`. -`app.select` is called from within a method (not by the user directly; it is `app.select`, not `app.do_select`). +`app.select` is called from within a method (not by the user directly; it is `app.select`, not +`app.do_select`). ::: cmd2.Cmd.select @@ -34,31 +35,37 @@ wheaties with salty sauce, yum! ## Disabling Commands -`cmd2` supports disabling commands during runtime. This is useful if certain commands should only be available when the application is in a specific state. When a command is disabled, it will not show up in the help menu or tab complete. If a user tries to run the command, a command-specific message supplied by the developer will be printed. The following functions support this feature. +`cmd2` supports disabling commands during runtime. This is useful if certain commands should only be +available when the application is in a specific state. When a command is disabled, it will not show +up in the help menu or tab complete. If a user tries to run the command, a command-specific message +supplied by the developer will be printed. The following functions support this feature. -- **enable_command** - : Enable an individual command -- **enable_category** - : Enable an entire category of commands -- **disable_command** - : Disable an individual command and set the message that will print when this command is run or help is called on it while disabled -- **disable_category** - : Disable an entire category of commands and set the message that will print when anything in this category is run or help is called on it while disabled +- **enable_command** : Enable an individual command +- **enable_category** : Enable an entire category of commands +- **disable_command** : Disable an individual command and set the message that will print when this + command is run or help is called on it while disabled +- **disable_category** : Disable an entire category of commands and set the message that will print + when anything in this category is run or help is called on it while disabled See the definitions of these functions for descriptions of their arguments. -See the `do_enable_commands()` and `do_disable_commands()` functions in the [HelpCategories](https://github.com/python-cmd2/cmd2/blob/master/examples/help_categories.py) example for a demonstration. +See the `do_enable_commands()` and `do_disable_commands()` functions in the +[HelpCategories](https://github.com/python-cmd2/cmd2/blob/master/examples/help_categories.py) +example for a demonstration. ## Default to shell -Every `cmd2` application can execute operating-system level (shell) commands with `shell` or a `!` shortcut: +Every `cmd2` application can execute operating-system level (shell) commands with `shell` or a `!` +shortcut: (Cmd) shell which python /usr/bin/python (Cmd) !which python /usr/bin/python -However, if the parameter `default_to_shell` is `True`, then _every_ command will be attempted on the operating system. Only if that attempt fails (i.e., produces a nonzero return value) will the application's own `default` method be called. +However, if the parameter `default_to_shell` is `True`, then _every_ command will be attempted on +the operating system. Only if that attempt fails (i.e., produces a nonzero return value) will the +application's own `default` method be called. (Cmd) which python /usr/bin/python diff --git a/docs/features/modular_commands.md b/docs/features/modular_commands.md index e4d25cd6d..503cac202 100644 --- a/docs/features/modular_commands.md +++ b/docs/features/modular_commands.md @@ -2,31 +2,53 @@ ## Overview -Cmd2 also enables developers to modularize their command definitions into `CommandSet` objects. CommandSets represent a logical grouping of commands within an cmd2 application. By default, all CommandSets will be discovered and loaded automatically when the cmd2.Cmd class is instantiated with this mixin. This also enables the developer to dynamically add/remove commands from the cmd2 application. This could be useful for loadable plugins that add additional capabilities. Additionally, it allows for object-oriented encapsulation and garbage collection of state that is specific to a CommandSet. +Cmd2 also enables developers to modularize their command definitions into `CommandSet` objects. +CommandSets represent a logical grouping of commands within an cmd2 application. By default, all +CommandSets will be discovered and loaded automatically when the cmd2.Cmd class is instantiated with +this mixin. This also enables the developer to dynamically add/remove commands from the cmd2 +application. This could be useful for loadable plugins that add additional capabilities. +Additionally, it allows for object-oriented encapsulation and garbage collection of state that is +specific to a CommandSet. ### Features -- Modular Command Sets - Commands can be broken into separate modules rather than in one god class holding all commands. -- Automatic Command Discovery - In your application, merely defining and importing a CommandSet is sufficient for cmd2 to discover and load your command. No manual registration is necessary. -- Dynamically Loadable/Unloadable Commands - Command functions and CommandSets can both be loaded and unloaded dynamically during application execution. This can enable features such as dynamically loaded modules that add additional commands. -- Events handlers - Four event handlers are provided in `CommandSet` class for custom initialization and cleanup steps. See [Event Handlers](#event-handlers). -- Subcommand Injection - Subcommands can be defined separately from the base command. This allows for a more action-centric instead of object-centric command system while still organizing your code and handlers around the objects being managed. +- Modular Command Sets - Commands can be broken into separate modules rather than in one god class + holding all commands. +- Automatic Command Discovery - In your application, merely defining and importing a CommandSet is + sufficient for cmd2 to discover and load your command. No manual registration is necessary. +- Dynamically Loadable/Unloadable Commands - Command functions and CommandSets can both be loaded + and unloaded dynamically during application execution. This can enable features such as + dynamically loaded modules that add additional commands. +- Events handlers - Four event handlers are provided in `CommandSet` class for custom initialization + and cleanup steps. See [Event Handlers](#event-handlers). +- Subcommand Injection - Subcommands can be defined separately from the base command. This allows + for a more action-centric instead of object-centric command system while still organizing your + code and handlers around the objects being managed. See API documentation for `cmd2.command_definition.CommandSet`. -See [the examples](https://github.com/python-cmd2/cmd2/tree/master/examples/modular_commands) for more details. +See [the examples](https://github.com/python-cmd2/cmd2/tree/master/examples/modular_commands) for +more details. ## Defining Commands ### Command Sets -CommandSets group multiple commands together. The plugin will inspect functions within a `CommandSet` using the same rules as when they're defined in `cmd2.Cmd`. Commands must be prefixed with `do_`, help functions with `help_`, and completer functions with `complete_`. +CommandSets group multiple commands together. The plugin will inspect functions within a +`CommandSet` using the same rules as when they're defined in `cmd2.Cmd`. Commands must be prefixed +with `do_`, help functions with `help_`, and completer functions with `complete_`. -A new decorator `with_default_category` is provided to categorize all commands within a CommandSet in the same command category. Individual commands in a CommandSet may be override the default category by specifying a specific category with `cmd2.with_category`. +A new decorator `with_default_category` is provided to categorize all commands within a CommandSet +in the same command category. Individual commands in a CommandSet may be override the default +category by specifying a specific category with `cmd2.with_category`. -CommandSet command methods will always expect the same parameters as when defined in a `cmd2.Cmd` sub-class, except that `self` will now refer to the `CommandSet` instead of the cmd2 instance. The cmd2 instance can be accessed through `self._cmd` that is populated when the `CommandSet` is registered. +CommandSet command methods will always expect the same parameters as when defined in a `cmd2.Cmd` +sub-class, except that `self` will now refer to the `CommandSet` instead of the cmd2 instance. The +cmd2 instance can be accessed through `self._cmd` that is populated when the `CommandSet` is +registered. -CommandSets will only be auto-loaded if the constructor takes no arguments. If you need to provide constructor arguments, see [Manual CommandSet Construction](#manual-commandset-construction). +CommandSets will only be auto-loaded if the constructor takes no arguments. If you need to provide +constructor arguments, see [Manual CommandSet Construction](#manual-commandset-construction). ```py import cmd2 @@ -56,7 +78,8 @@ class ExampleApp(cmd2.Cmd): ### Manual CommandSet Construction -If a CommandSet class requires parameters to be provided to the constructor, you man manually construct CommandSets and pass in the constructor to Cmd2. +If a CommandSet class requires parameters to be provided to the constructor, you man manually +construct CommandSets and pass in the constructor to Cmd2. ```py import cmd2 @@ -97,7 +120,9 @@ def main(): ### Dynamic Commands -You can also dynamically load and unload commands by installing and removing CommandSets at runtime. For example, if you could support runtime loadable plugins or add/remove commands based on your state. +You can also dynamically load and unload commands by installing and removing CommandSets at runtime. +For example, if you could support runtime loadable plugins or add/remove commands based on your +state. You may need to disable command auto-loading if you need dynamically load commands at runtime. @@ -183,25 +208,44 @@ if __name__ == '__main__': The following functions are called at different points in the `CommandSet` life cycle. -`on_register(self, cmd) -> None` - Called by cmd2.Cmd as the first step to registering a CommandSet. The commands defined in this class have not be added to the CLI object at this point. Subclasses can override this to perform any initialization requiring access to the Cmd object (e.g. configure commands and their parsers based on CLI state data). +`on_register(self, cmd) -> None` - Called by cmd2.Cmd as the first step to registering a CommandSet. +The commands defined in this class have not be added to the CLI object at this point. Subclasses can +override this to perform any initialization requiring access to the Cmd object (e.g. configure +commands and their parsers based on CLI state data). -`on_registered(self) -> None` - Called by cmd2.Cmd after a CommandSet is registered and all its commands have been added to the CLI. Subclasses can override this to perform custom steps related to the newly added commands (e.g. setting them to a disabled state). +`on_registered(self) -> None` - Called by cmd2.Cmd after a CommandSet is registered and all its +commands have been added to the CLI. Subclasses can override this to perform custom steps related to +the newly added commands (e.g. setting them to a disabled state). -`on_unregister(self) -> None` - Called by `cmd2.Cmd` as the first step to unregistering a CommandSet. Subclasses can override this to perform any cleanup steps which require their commands being registered in the CLI. +`on_unregister(self) -> None` - Called by `cmd2.Cmd` as the first step to unregistering a +CommandSet. Subclasses can override this to perform any cleanup steps which require their commands +being registered in the CLI. -`on_unregistered(self) -> None` - Called by `cmd2.Cmd` after a CommandSet has been unregistered and all its commands removed from the CLI. Subclasses can override this to perform remaining cleanup steps. +`on_unregistered(self) -> None` - Called by `cmd2.Cmd` after a CommandSet has been unregistered and +all its commands removed from the CLI. Subclasses can override this to perform remaining cleanup +steps. ## Injecting Subcommands ### Description -Using the `with_argparse` decorator, it is possible to define subcommands for your command. This has a tendency to either drive your interface into an object-centric interface. For example, imagine you have a tool that manages your media collection and you want to manage movies or shows. An object-centric approach would push you to have base commands such as `movies` and `shows` which each have subcommands `add`, `edit`, `list`, `delete`. If you wanted to present an action-centric command set, so that `add`, `edit`, `list`, and `delete` are the base commands, you'd have to organize your code around these similar actions rather than organizing your code around similar objects being managed. +Using the `with_argparse` decorator, it is possible to define subcommands for your command. This has +a tendency to either drive your interface into an object-centric interface. For example, imagine you +have a tool that manages your media collection and you want to manage movies or shows. An +object-centric approach would push you to have base commands such as `movies` and `shows` which each +have subcommands `add`, `edit`, `list`, `delete`. If you wanted to present an action-centric command +set, so that `add`, `edit`, `list`, and `delete` are the base commands, you'd have to organize your +code around these similar actions rather than organizing your code around similar objects being +managed. -Subcommand injection allows you to inject subcommands into a base command to present an interface that is sensible to a user while still organizing your code in whatever structure make more logical sense to the developer. +Subcommand injection allows you to inject subcommands into a base command to present an interface +that is sensible to a user while still organizing your code in whatever structure make more logical +sense to the developer. ### Example -This example is a variation on the Dynamic Commands example above. A `cut` command is introduced as a base command and each CommandSet +This example is a variation on the Dynamic Commands example above. A `cut` command is introduced as +a base command and each CommandSet ```py import argparse diff --git a/docs/features/multiline_commands.md b/docs/features/multiline_commands.md index 3156d191c..8a4d76c18 100644 --- a/docs/features/multiline_commands.md +++ b/docs/features/multiline_commands.md @@ -1,17 +1,29 @@ # Multiline Commands -Command input may span multiple lines for the commands whose names are listed in the `multiline_commands` argument to `cmd2.Cmd.__init__()`. These commands will be executed only after the user has entered a _terminator_. By default, the command terminator is `;`; specifying the `terminators` optional argument to `cmd2.Cmd.__init__()` allows different terminators. A blank line is _always_ considered a command terminator (cannot be overridden). +Command input may span multiple lines for the commands whose names are listed in the +`multiline_commands` argument to `cmd2.Cmd.__init__()`. These commands will be executed only after +the user has entered a _terminator_. By default, the command terminator is `;`; specifying the +`terminators` optional argument to `cmd2.Cmd.__init__()` allows different terminators. A blank line +is _always_ considered a command terminator (cannot be overridden). -In multiline commands, output redirection characters like `>` and `|` are part of the command arguments unless they appear after the terminator. +In multiline commands, output redirection characters like `>` and `|` are part of the command +arguments unless they appear after the terminator. ## Continuation prompt -When a user types a **Multiline Command** it may span more than one line of input. The prompt for the first line of input is specified by the [cmd2.Cmd.prompt][] instance attribute - see [Customizing the Prompt](./prompt.md#customizing-the-prompt). The prompt for subsequent lines of input is defined by the `cmd2.Cmd.continuation_prompt` attribute. +When a user types a **Multiline Command** it may span more than one line of input. The prompt for +the first line of input is specified by the [cmd2.Cmd.prompt][] instance attribute - see +[Customizing the Prompt](./prompt.md#customizing-the-prompt). The prompt for subsequent lines of +input is defined by the `cmd2.Cmd.continuation_prompt` attribute. ## Use cases -Multiline commands should probably be used sparingly in order to preserve a good user experience for your `cmd2`-based line-oriented command interpreter application. +Multiline commands should probably be used sparingly in order to preserve a good user experience for +your `cmd2`-based line-oriented command interpreter application. -However, some use cases benefit significantly from the ability to have commands that span more than one line. For example, you might want the ability for your user to type in a SQL command, which can often span lines and which are terminated with a semicolon. +However, some use cases benefit significantly from the ability to have commands that span more than +one line. For example, you might want the ability for your user to type in a SQL command, which can +often span lines and which are terminated with a semicolon. -We estimate that less than 5 percent of `cmd2` applications use this feature. But it is here for those use cases where it provides value. +We estimate that less than 5 percent of `cmd2` applications use this feature. But it is here for +those use cases where it provides value. diff --git a/docs/features/os.md b/docs/features/os.md index c113f57c3..d1da31bf5 100644 --- a/docs/features/os.md +++ b/docs/features/os.md @@ -10,37 +10,48 @@ See [Output Redirection and Pipes](./redirection.md#output-redirection-and-pipes (Cmd) shell ls -al -If you use the default [Shortcuts](./shortcuts_aliases_macros.md#shortcuts) defined in `cmd2` you'll get a `!` shortcut for `shell`, which allows you to type: +If you use the default [Shortcuts](./shortcuts_aliases_macros.md#shortcuts) defined in `cmd2` you'll +get a `!` shortcut for `shell`, which allows you to type: (Cmd) !ls -al -NOTE: `cmd2` provides user-friendly tab completion throughout the process of running a shell command - first for the shell command name itself, and then for file paths in the argument section. +NOTE: `cmd2` provides user-friendly tab completion throughout the process of running a shell +command - first for the shell command name itself, and then for file paths in the argument section. ## Editors -`cmd2` includes the built-in `edit` command which runs a text editor and optionally opens a file with it: +`cmd2` includes the built-in `edit` command which runs a text editor and optionally opens a file +with it: (Cmd) edit foo.txt -The editor used is determined by the `editor` settable parameter and can be either a text editor such as **vim** or a graphical editor such as **VSCode**. To set it: +The editor used is determined by the `editor` settable parameter and can be either a text editor +such as **vim** or a graphical editor such as **VSCode**. To set it: set editor -If you have the `EDITOR` environment variable set, then this will be the default value for `editor`. If not, then `cmd2` will attempt to search for any in a list of common editors for your operating system. +If you have the `EDITOR` environment variable set, then this will be the default value for `editor`. +If not, then `cmd2` will attempt to search for any in a list of common editors for your operating +system. ## Terminal pagers Output of any command can be displayed one page at a time using the `cmd2.Cmd.ppaged` method. -Alternatively, a terminal pager can be invoked directly using the ability to run shell commands with the `!` shortcut like so: +Alternatively, a terminal pager can be invoked directly using the ability to run shell commands with +the `!` shortcut like so: (Cmd) !less foo.txt -NOTE: Once you are in a terminal pager, that program temporarily has control of your terminal, **NOT** `cmd2`. Typically you can use either the arrow keys or ``/`` keys to scroll around or type `q` to quit the pager and return control to your `cmd2` application. +NOTE: Once you are in a terminal pager, that program temporarily has control of your terminal, +**NOT** `cmd2`. Typically you can use either the arrow keys or ``/`` keys to +scroll around or type `q` to quit the pager and return control to your `cmd2` application. ## Exit codes -The `self.exit_code` attribute of your `cmd2` application controls what exit code is returned from `cmdloop()` when it completes. It is your job to make sure that this exit code gets sent to the shell when your application exits by calling `sys.exit(app.cmdloop())`. +The `self.exit_code` attribute of your `cmd2` application controls what exit code is returned from +`cmdloop()` when it completes. It is your job to make sure that this exit code gets sent to the +shell when your application exits by calling `sys.exit(app.cmdloop())`. ## Invoking With Arguments @@ -52,19 +63,27 @@ or: $ mycmd2program.py -Either of these methods will launch your program and enter the `cmd2` command loop, which allows the user to enter commands, which are then executed by your program. +Either of these methods will launch your program and enter the `cmd2` command loop, which allows the +user to enter commands, which are then executed by your program. -You may want to execute commands in your program without prompting the user for any input. There are several ways you might accomplish this task. The easiest one is to pipe commands and their arguments into your program via standard input. You don't need to do anything to your program in order to use this technique. Here's a demonstration using the `examples/example.py` included in the source code of `cmd2`: +You may want to execute commands in your program without prompting the user for any input. There are +several ways you might accomplish this task. The easiest one is to pipe commands and their arguments +into your program via standard input. You don't need to do anything to your program in order to use +this technique. Here's a demonstration using the `examples/example.py` included in the source code +of `cmd2`: $ echo "speak -p some words" | python examples/example.py omesay ordsway -Using this same approach you could create a text file containing the commands you would like to run, one command per line in the file. Say your file was called `somecmds.txt`. To run the commands in the text file using your `cmd2` program (from a Windows command prompt): +Using this same approach you could create a text file containing the commands you would like to run, +one command per line in the file. Say your file was called `somecmds.txt`. To run the commands in +the text file using your `cmd2` program (from a Windows command prompt): c:\cmd2> type somecmds.txt | python.exe examples/example.py omesay ordsway -By default, `cmd2` programs also look for commands pass as arguments from the operating system shell, and execute those commands before entering the command loop: +By default, `cmd2` programs also look for commands pass as arguments from the operating system +shell, and execute those commands before entering the command loop: $ python examples/example.py help @@ -75,7 +94,10 @@ By default, `cmd2` programs also look for commands pass as arguments from the op (Cmd) -You may need more control over command line arguments passed from the operating system shell. For example, you might have a command inside your `cmd2` program which itself accepts arguments, and maybe even option strings. Say you wanted to run the `speak` command from the operating system shell, but have it say it in pig latin: +You may need more control over command line arguments passed from the operating system shell. For +example, you might have a command inside your `cmd2` program which itself accepts arguments, and +maybe even option strings. Say you wanted to run the `speak` command from the operating system +shell, but have it say it in pig latin: $ python example/example.py speak -p hello there python example.py speak -p hello there @@ -86,16 +108,19 @@ You may need more control over command line arguments passed from the operating *** Unknown syntax: there (Cmd) -Uh-oh, that's not what we wanted. `cmd2` treated `-p`, `hello`, and `there` as commands, which don't exist in that program, thus the syntax errors. +Uh-oh, that's not what we wanted. `cmd2` treated `-p`, `hello`, and `there` as commands, which don't +exist in that program, thus the syntax errors. -There is an easy way around this, which is demonstrated in `examples/cmd_as_argument.py`. By setting `allow_cli_args=False` you can so your own argument parsing of the command line: +There is an easy way around this, which is demonstrated in `examples/cmd_as_argument.py`. By setting +`allow_cli_args=False` you can so your own argument parsing of the command line: $ python examples/cmd_as_argument.py speak -p hello there ellohay heretay Check the source code of this example, especially the `main()` function, to see the technique. -Alternatively you can simply wrap the command plus arguments in quotes (either single or double quotes): +Alternatively you can simply wrap the command plus arguments in quotes (either single or double +quotes): $ python example/example.py "speak -p hello there" ellohay heretay @@ -103,7 +128,9 @@ Alternatively you can simply wrap the command plus arguments in quotes (either s ### Automating cmd2 apps from other CLI/CLU tools -While `cmd2` is designed to create **interactive** command-line applications which enter a Read-Evaluate-Print-Loop (REPL), there are a great many times when it would be useful to use a `cmd2` application as a run-and-done command-line utility for purposes of automation and scripting. +While `cmd2` is designed to create **interactive** command-line applications which enter a +Read-Evaluate-Print-Loop (REPL), there are a great many times when it would be useful to use a +`cmd2` application as a run-and-done command-line utility for purposes of automation and scripting. This is easily achieved by combining the following capabilities of `cmd2`: @@ -111,7 +138,8 @@ This is easily achieved by combining the following capabilities of `cmd2`: 2. Ability to set an exit code when leaving a `cmd2` application 3. Ability to exit a `cmd2` application with the `quit` command -Here is a simple example which doesn't require the quit command since the custom `exit` command quits while returning an exit code: +Here is a simple example which doesn't require the quit command since the custom `exit` command +quits while returning an exit code: $ python examples/exit_code.py "exit 23" 'examples/exit_code.py' exiting with code: 23 diff --git a/docs/features/packaging.md b/docs/features/packaging.md index bfbf7b6a2..0c9262699 100644 --- a/docs/features/packaging.md +++ b/docs/features/packaging.md @@ -1,22 +1,37 @@ # Packaging a cmd2 application for distribution -As a general-purpose tool for building interactive command-line applications, `cmd2` is designed to be used in many ways. How you distribute your `cmd2` application to customers or end users is up to you. See the [Overview of Packaging for Python](https://packaging.python.org/overview/) from the Python Packaging Authority for a thorough discussion of the extensive options within the Python ecosystem. +As a general-purpose tool for building interactive command-line applications, `cmd2` is designed to +be used in many ways. How you distribute your `cmd2` application to customers or end users is up to +you. See the [Overview of Packaging for Python](https://packaging.python.org/overview/) from the +Python Packaging Authority for a thorough discussion of the extensive options within the Python +ecosystem. ## Publishing to the Python Package Index (PyPI) -The easiest way is to use to follow the tutorial for [Packaging Python Projects](https://packaging.python.org/en/latest/tutorials/packaging-projects/). This will show you how to package your application as a Python package and uploadi to the Python Package Index ([PyPI](https://pypi.org/)). Once published there, users will be able to install it using idiomatic Python packaging tools such as [pip](https://pip.pypa.io/) or [uv](https://github.com/astral-sh/uv). +The easiest way is to use to follow the tutorial for +[Packaging Python Projects](https://packaging.python.org/en/latest/tutorials/packaging-projects/). +This will show you how to package your application as a Python package and uploadi to the Python +Package Index ([PyPI](https://pypi.org/)). Once published there, users will be able to install it +using idiomatic Python packaging tools such as [pip](https://pip.pypa.io/) or +[uv](https://github.com/astral-sh/uv). -Small tweaks on this process can allow you to publish to private PyPI mirror such as one hosted on [AWS CodeArtifact](https://aws.amazon.com/codeartifact/). +Small tweaks on this process can allow you to publish to private PyPI mirror such as one hosted on +[AWS CodeArtifact](https://aws.amazon.com/codeartifact/). ## Packaging your application in a container using Docker -Packing your Python application in a [Docker](https://www.docker.com/) container is a great when it comes to cross-platform portability and convenience since your this container will inlude all dependencies for your application and run them in an isolated environment which won't conflict with operating system dependencies. +Packing your Python application in a [Docker](https://www.docker.com/) container is a great when it +comes to cross-platform portability and convenience since your this container will inlude all +dependencies for your application and run them in an isolated environment which won't conflict with +operating system dependencies. -This convenient blog post will show you [How to "Dockerize" Your Python Applications](https://www.docker.com/blog/how-to-dockerize-your-python-applications/). +This convenient blog post will show you +[How to "Dockerize" Your Python Applications](https://www.docker.com/blog/how-to-dockerize-your-python-applications/). ## Packing your application along with Python in an installer -For developers wishing to package a `cmd2` application into a single binary image or compressed file, we can recommend all of the following based on personal and professional experience: +For developers wishing to package a `cmd2` application into a single binary image or compressed +file, we can recommend all of the following based on personal and professional experience: - [PyInstaller](https://www.pyinstaller.org) - Freeze (package) Python programs into stand-alone executables @@ -24,14 +39,19 @@ For developers wishing to package a `cmd2` application into a single binary imag - The user can run the packaged app without installing a Python interpreter or any modules - [Nuitka](https://nuitka.net) - Nuitka is a Python compiler written in Python - - You feed it your Python app, it does a lot of clever things, and spits out an executable or extension module - - This can be particularly convenient if you wish to obfuscate the Python source code behind your application + - You feed it your Python app, it does a lot of clever things, and spits out an executable or + extension module + - This can be particularly convenient if you wish to obfuscate the Python source code behind + your application - [Conda Constructor](https://github.com/conda/constructor) - - Allows you to create a custom Python distro based on [Miniconda](https://docs.conda.io/en/latest/miniconda.html) + - Allows you to create a custom Python distro based on + [Miniconda](https://docs.conda.io/en/latest/miniconda.html) - [PyOxidizer](https://github.com/indygreg/PyOxidizer) - PyOxidizer is a utility for producing binaries that embed Python - - PyOxidizer is capable of producing a single file executable - with a copy of Python and all its dependencies statically linked and all resources embedded in the executable - - You can copy a single executable file to another machine and run a Python application contained within. It just works. + - PyOxidizer is capable of producing a single file executable - with a copy of Python and all + its dependencies statically linked and all resources embedded in the executable + - You can copy a single executable file to another machine and run a Python application + contained within. It just works. !!! warning diff --git a/docs/features/plugins.md b/docs/features/plugins.md index e7a91abe5..4c6a60cbf 100644 --- a/docs/features/plugins.md +++ b/docs/features/plugins.md @@ -1,8 +1,12 @@ # 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. +`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. -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`. +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 @@ -34,14 +38,20 @@ class Example(cmd2_myplugin.MyPlugin, cmd2.Cmd): # all plugins have initialized ``` -Note how the plugin must be inherited (or mixed in) before `cmd2.Cmd`. This is required for two reasons: +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. +- 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: +Your plugin can add user visible commands. You do it the same way in a plugin that you would in a +`cmd2.Cmd` app: ```py class MyPlugin: @@ -50,7 +60,8 @@ class MyPlugin: 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. +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 @@ -66,23 +77,31 @@ class MyPlugin: self.add_settable(cmd2.Settable('mysetting', str, 'short help message for mysetting', self)) ``` -You can hide settings from the user by calling `cmd2.Cmd.remove_settable`. See [Settings](./settings.md) for more information. +You can hide settings from the user by calling `cmd2.Cmd.remove_settable`. See +[Settings](./settings.md) for more information. ## Decorators -Your plugin can provide a decorator which users of your plugin can use to wrap functionality around their own commands. +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. +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 hook methods, 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 [Hooks](./hooks.md) section. +Plugins can register hook methods, 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 [Hooks](./hooks.md) 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. +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: @@ -101,13 +120,17 @@ class MyPlugin: 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. +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 [Hooks](./hooks.md) documentation for full details of the application and command lifecycle, including all available hooks and the ways hooks can influence the lifecycle. +See the [Hooks](./hooks.md) 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. +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 diff --git a/docs/features/prompt.md b/docs/features/prompt.md index f2804f40d..6340f49f5 100644 --- a/docs/features/prompt.md +++ b/docs/features/prompt.md @@ -4,19 +4,35 @@ ## Customizing the Prompt -This prompt can be configured by setting the `cmd2.Cmd.prompt` instance attribute. This contains the string which should be printed as a prompt for user input. See the [Pirate](https://github.com/python-cmd2/cmd2/blob/master/examples/pirate.py#L39) example for the simple use case of statically setting the prompt. +This prompt can be configured by setting the `cmd2.Cmd.prompt` instance attribute. This contains the +string which should be printed as a prompt for user input. See the +[Pirate](https://github.com/python-cmd2/cmd2/blob/master/examples/pirate.py#L39) example for the +simple use case of statically setting the prompt. ## Continuation Prompt -When a user types a [Multiline Command](./multiline_commands.md) it may span more than one line of input. The prompt for the first line of input is specified by the `cmd2.Cmd.prompt` instance attribute. The prompt for subsequent lines of input is defined by the `cmd2.Cmd.continuation_prompt` attribute.See the [Initialization](https://github.com/python-cmd2/cmd2/blob/master/examples/initialization.py#L42) example for a demonstration of customizing the continuation prompt. +When a user types a [Multiline Command](./multiline_commands.md) it may span more than one line of +input. The prompt for the first line of input is specified by the `cmd2.Cmd.prompt` instance +attribute. The prompt for subsequent lines of input is defined by the `cmd2.Cmd.continuation_prompt` +attribute.See the +[Initialization](https://github.com/python-cmd2/cmd2/blob/master/examples/initialization.py#L42) +example for a demonstration of customizing the continuation prompt. ## Updating the prompt -If you wish to update the prompt between commands, you can do so using one of the [Application Lifecycle Hooks](./hooks.md#application-lifecycle-hooks) such as a [Postcommand hook](./hooks.md#postcommand-hooks). See [PythonScripting](https://github.com/python-cmd2/cmd2/blob/master/examples/python_scripting.py#L38-L55) for an example of dynamically updating the prompt. +If you wish to update the prompt between commands, you can do so using one of the +[Application Lifecycle Hooks](./hooks.md#application-lifecycle-hooks) such as a +[Postcommand hook](./hooks.md#postcommand-hooks). See +[PythonScripting](https://github.com/python-cmd2/cmd2/blob/master/examples/python_scripting.py#L38-L55) +for an example of dynamically updating the prompt. ## Asynchronous Feedback -`cmd2` provides these functions to provide asynchronous feedback to the user without interfering with the command line. This means the feedback is provided to the user when they are still entering text at the prompt. To use this functionality, the application must be running in a terminal that supports VT100 control characters and readline. Linux, Mac, and Windows 10 and greater all support these. +`cmd2` provides these functions to provide asynchronous feedback to the user without interfering +with the command line. This means the feedback is provided to the user when they are still entering +text at the prompt. To use this functionality, the application must be running in a terminal that +supports VT100 control characters and readline. Linux, Mac, and Windows 10 and greater all support +these. ::: cmd2.Cmd.async_alert @@ -26,8 +42,12 @@ If you wish to update the prompt between commands, you can do so using one of th ::: cmd2.Cmd.need_prompt_refresh -`cmd2` also provides a function to change the title of the terminal window. This feature requires the application be running in a terminal that supports VT100 control characters. Linux, Mac, and Windows 10 and greater all support these. +`cmd2` also provides a function to change the title of the terminal window. This feature requires +the application be running in a terminal that supports VT100 control characters. Linux, Mac, and +Windows 10 and greater all support these. ::: cmd2.Cmd.set_window_title -The easiest way to understand these functions is to see the [AsyncPrinting](https://github.com/python-cmd2/cmd2/blob/master/examples/async_printing.py) example for a demonstration. +The easiest way to understand these functions is to see the +[AsyncPrinting](https://github.com/python-cmd2/cmd2/blob/master/examples/async_printing.py) example +for a demonstration. diff --git a/docs/features/redirection.md b/docs/features/redirection.md index e92eec3ac..53234c704 100644 --- a/docs/features/redirection.md +++ b/docs/features/redirection.md @@ -1,6 +1,7 @@ # 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. +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 @@ -11,11 +12,14 @@ Redirecting the output of a `cmd2` command to a file works just like in POSIX sh - 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'`. +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. +`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 >>` @@ -28,11 +32,14 @@ Piping the output of a `cmd2` command to a shell command works just like in POSI ## Multiple Pipes and Redirection -Multiple pipes, optionally followed by a redirect, are supported. Thus, it is possible to do something like the following: +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_. +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 diff --git a/docs/features/scripting.md b/docs/features/scripting.md index 940a50da6..02f19d2d3 100644 --- a/docs/features/scripting.md +++ b/docs/features/scripting.md @@ -1,28 +1,42 @@ # Scripting -Operating system shells have long had the ability to execute a sequence of commands saved in a text file. These script files make long sequences of commands easier to repeatedly execute. `cmd2` supports two similar mechanisms: command scripts and python scripts. +Operating system shells have long had the ability to execute a sequence of commands saved in a text +file. These script files make long sequences of commands easier to repeatedly execute. `cmd2` +supports two similar mechanisms: command scripts and python scripts. ## Command Scripts -A command script contains a sequence of commands typed at the the prompt of a `cmd2` based application. Unlike operating system shell scripts, command scripts can't contain logic or loops. +A command script contains a sequence of commands typed at the the prompt of a `cmd2` based +application. Unlike operating system shell scripts, command scripts can't contain logic or loops. ### Creating Command Scripts Command scripts can be created in several ways: - creating a text file using any method of your choice -- using the built-in [edit](./builtin_commands.md#edit) command to create or edit an existing text file +- using the built-in [edit](./builtin_commands.md#edit) command to create or edit an existing text + file - saving previously entered commands to a script file using [history -s](./history.md#for-users) -If you create create a text file from scratch, just include one command per line, exactly as you would type it inside a `cmd2` application. +If you create create a text file from scratch, just include one command per 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](./builtin_commands.md#run_script) command or the `@` shortcut (if your application is using the default shortcuts). Both ASCII and UTF-8 encoded unicode text files are supported. The [run_script](./builtin_commands.md#run_script) command supports tab completion of file system paths. There is a variant [\_relative_run_script](./builtin_commands.md#_relative_run_script) command or `@@` shortcut (if using the default shortcuts) for use within a script which uses paths relative to the first script. +Command script files can be executed using the built-in +[run_script](./builtin_commands.md#run_script) command or the `@` shortcut (if your application is +using the default shortcuts). Both ASCII and UTF-8 encoded unicode text files are supported. The +[run_script](./builtin_commands.md#run_script) command supports tab completion of file system paths. +There is a variant [\_relative_run_script](./builtin_commands.md#_relative_run_script) command or +`@@` shortcut (if using the default shortcuts) for use within a script which uses paths relative to +the first script. ### Comments -Any command line input where the first non-whitespace character is a `\#` will be treated as a comment. This means any `\#` character appearing later in the command will be treated as a literal. The same applies to a `\#` in the middle of a multiline command, even if it is the first character on a line. +Any command line input where the first non-whitespace character is a `\#` will be treated as a +comment. This means any `\#` character appearing later in the command will be treated as a literal. +The same applies to a `\#` in the middle of a multiline command, even if it is the first character +on a line. Comments are useful in scripts, but would be pointless within an interactive session. @@ -31,7 +45,11 @@ Comments are useful in scripts, but would be pointless within an interactive ses ## Python Scripts -If you require logic flow, loops, branching, or other advanced features, you can write a python script which executes in the context of your `cmd2` app. This script is run using the [run_pyscript](./builtin_commands.md#run_pyscript) command. Here's a simple example that uses the [arg_printer](https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/arg_printer.py) script: +If you require logic flow, loops, branching, or other advanced features, you can write a python +script which executes in the context of your `cmd2` app. This script is run using the +[run_pyscript](./builtin_commands.md#run_pyscript) command. Here's a simple example that uses the +[arg_printer](https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/arg_printer.py) +script: (Cmd) run_pyscript examples/scripts/arg_printer.py foo bar 'baz 23' Running Python script 'arg_printer.py' which was called with 3 arguments @@ -39,19 +57,31 @@ If you require logic flow, loops, branching, or other advanced features, you can arg 2: 'bar' arg 3: 'baz 23' -[run_pyscript](./builtin_commands.md#run_pyscript) supports tab completion of file system paths, and as shown above it has the ability to pass command-line arguments to the scripts invoked. +[run_pyscript](./builtin_commands.md#run_pyscript) supports tab completion of file system paths, and +as shown above it has the ability to pass command-line arguments to the scripts invoked. ## Developing a cmd2 API -If you as an app designer have not explicitly disabled the `run_pyscript` command it must be assumed that your application is structured for use in higher level python scripting. The following sections are meant as guidelines and highlight possible pitfalls with both production and consumption of API functionality. For clarity when speaking of "scripter" we are referring to those writing scripts to be run by pyscript and "designer" as the `cmd2` application author. +If you as an app designer have not explicitly disabled the `run_pyscript` command it must be assumed +that your application is structured for use in higher level python scripting. The following sections +are meant as guidelines and highlight possible pitfalls with both production and consumption of API +functionality. For clarity when speaking of "scripter" we are referring to those writing scripts to +be run by pyscript and "designer" as the `cmd2` application author. ### Basics -Without any work on the part of the designer, a scripter can take advantage of piecing together workflows using simple `app` calls. The result of a `run_pyscript` app call yields a `CommandResult` object exposing four members: `Stdout`, `Stderr`, `Stop`, and `Data`. +Without any work on the part of the designer, a scripter can take advantage of piecing together +workflows using simple `app` calls. The result of a `run_pyscript` app call yields a `CommandResult` +object exposing four members: `Stdout`, `Stderr`, `Stop`, and `Data`. -`Stdout` and `Stderr` are fairly straightforward representations of normal data streams and accurately reflect what is seen by the user during normal cmd2 interaction. `Stop` contains information about how the invoked command has ended its lifecycle. Lastly `Data` contains any information the designer sets via `self.last_result` or `self._cmd.last_result` if called from inside a CommandSet. +`Stdout` and `Stderr` are fairly straightforward representations of normal data streams and +accurately reflect what is seen by the user during normal cmd2 interaction. `Stop` contains +information about how the invoked command has ended its lifecycle. Lastly `Data` contains any +information the designer sets via `self.last_result` or `self._cmd.last_result` if called from +inside a CommandSet. -Python scripts executed with [run_pyscript](./builtin_commands.md#run_pyscript) can run `cmd2` application commands by using the syntax: +Python scripts executed with [run_pyscript](./builtin_commands.md#run_pyscript) can run `cmd2` +application commands by using the syntax: ```py app(‘command args’) @@ -59,7 +89,8 @@ app(‘command args’) where: -- `app` is a configurable name which can be changed by setting the `cmd2.Cmd.py_bridge_name` attribute +- `app` is a configurable name which can be changed by setting the `cmd2.Cmd.py_bridge_name` + attribute - `command` and `args` are entered exactly like they would be entered by a user of your application. Using fstrings tends to be the most straight forward and easily readable way to provide parameters.: @@ -71,11 +102,19 @@ second = 'second' app(f'command {first} -t {second}) ``` -See [python_scripting](https://github.com/python-cmd2/cmd2/blob/master/examples/python_scripting.py) example and associated [conditional](https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/conditional.py) script for more information. +See [python_scripting](https://github.com/python-cmd2/cmd2/blob/master/examples/python_scripting.py) +example and associated +[conditional](https://github.com/python-cmd2/cmd2/blob/master/examples/scripts/conditional.py) +script for more information. ### Design principles -If the cmd2 application follows the [unix_design_philosophy](https://en.wikipedia.org/wiki/Unix_philosophy) a scriptor will have the most flexibility to piece together workflows using different commands. If the designers' application is more complete and less likely to be augmented in the future a scripter may opt for simple serial scripts with little control flow. In either case, choices made by the designer will have effects on scripters. +If the cmd2 application follows the +[unix_design_philosophy](https://en.wikipedia.org/wiki/Unix_philosophy) a scriptor will have the +most flexibility to piece together workflows using different commands. If the designers' application +is more complete and less likely to be augmented in the future a scripter may opt for simple serial +scripts with little control flow. In either case, choices made by the designer will have effects on +scripters. The following diagram illustrates the different boundaries to keep in mind. @@ -107,7 +146,8 @@ flowchart LR ### Developing a Basic API -CMD2 out of the box allows scripters to take advantage of all exposed `do_*` commands. As a scripter one can easily interact with the application via `stdout` and `stderr`. +CMD2 out of the box allows scripters to take advantage of all exposed `do_*` commands. As a scripter +one can easily interact with the application via `stdout` and `stderr`. As a baseline lets start off with the familiar FirstApp @@ -182,7 +222,8 @@ When executing the `speak` command without parameters you see the following erro Usage: speak [-h] [-p] [-s] [-r REPEAT] words [...] Error: the following arguments are required: words -Even though this is a fully qualified CMD2 error the py[script]{#script} must look for this error and perform error checking.: +Even though this is a fully qualified CMD2 error the py[script]{#script} must look for this error +and perform error checking.: ```py app('speak') @@ -193,7 +234,8 @@ print("Working") Working (Cmd) -You should notice that no error message is printed. Let's utilize the `CommandResult` object to inspect the actual returned data.: +You should notice that no error message is printed. Let's utilize the `CommandResult` object to +inspect the actual returned data.: ```py result = app('speak') @@ -232,7 +274,8 @@ print("Continuing along..") (Cmd) run_pyscript script.py Continuing along.. -We changed the input to be a valid `speak` command but no output. Again we must inspect the `CommandResult`: +We changed the input to be a valid `speak` command but no output. Again we must inspect the +`CommandResult`: ```py import sys @@ -249,11 +292,14 @@ print(result.stdout) (Cmd) run_pyscript script.py TRUTH!!! -By just using `stdout` and `stderr` it is possible to string together commands with rudimentary control flow. In the next section we will show how to take advantage of `cmd_result` data. +By just using `stdout` and `stderr` it is possible to string together commands with rudimentary +control flow. In the next section we will show how to take advantage of `cmd_result` data. ### Developing an Advanced API -Until now the application designer has paid little attention to scripters and their needs. Wouldn't it be nice if while creating py*scripts one did not have to parse data from `stdout`? We can accommodate the weary scripter by adding one small line at the end of our `do*\*` commands. +Until now the application designer has paid little attention to scripters and their needs. Wouldn't +it be nice if while creating py*scripts one did not have to parse data from `stdout`? We can +accommodate the weary scripter by adding one small line at the end of our `do*\*` commands. `self.last_result = ` @@ -305,11 +351,22 @@ Results: Cmd) run_pyscript script.py ['.venv', 'app.py', 'script.py'] -As a rule of thumb it is safer for the designer to return simple scalar types as command results instead of complex objects. If there is benefit in providing class objects designers should choose immutable over mutable types and never provide direct access to class members as this could potentially lead to violation of the [open_closed_principle](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle). - -When possible, a dataclass is a lightweight solution perfectly suited for data manipulation. Lets dive into an example. - -The following fictitional application has two commands: `build` and `status`. We can pretend that the build action happens somewhere else in the world at an REST API endpoint and has significant computational cost. The status command for all intents and purposes will only show the current status of a build task. The application has provided all that is needed for a user to start a build and then determine it's status. The problem however is that with a long running process the user may want to wait for it to finish. A designer may be tempted to create a command to start a build and then poll for status until finished but this scenario is better solved as an extensible script. +As a rule of thumb it is safer for the designer to return simple scalar types as command results +instead of complex objects. If there is benefit in providing class objects designers should choose +immutable over mutable types and never provide direct access to class members as this could +potentially lead to violation of the +[open_closed_principle](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle). + +When possible, a dataclass is a lightweight solution perfectly suited for data manipulation. Lets +dive into an example. + +The following fictitional application has two commands: `build` and `status`. We can pretend that +the build action happens somewhere else in the world at an REST API endpoint and has significant +computational cost. The status command for all intents and purposes will only show the current +status of a build task. The application has provided all that is needed for a user to start a build +and then determine it's status. The problem however is that with a long running process the user may +want to wait for it to finish. A designer may be tempted to create a command to start a build and +then poll for status until finished but this scenario is better solved as an extensible script. app.py: diff --git a/docs/features/settings.md b/docs/features/settings.md index 78bc96f13..3191bb0d7 100644 --- a/docs/features/settings.md +++ b/docs/features/settings.md @@ -1,14 +1,24 @@ # Settings -Settings provide a mechanism for a user to control the behavior of a `cmd2` based application. A setting is stored in an instance attribute on your subclass of `cmd2.Cmd` and must also appear in the `cmd2.Cmd.settable` dictionary. Developers may set default values for these settings and users can modify them at runtime using the [set](./builtin_commands.md#set) command. Developers can [Create New Settings](#create-new-settings) and can also [Hide Builtin Settings](#hide-builtin-settings) from the user. +Settings provide a mechanism for a user to control the behavior of a `cmd2` based application. A +setting is stored in an instance attribute on your subclass of `cmd2.Cmd` and must also appear in +the `cmd2.Cmd.settable` dictionary. Developers may set default values for these settings and users +can modify them at runtime using the [set](./builtin_commands.md#set) command. Developers can +[Create New Settings](#create-new-settings) and can also +[Hide Builtin Settings](#hide-builtin-settings) from the user. ## Builtin Settings -`cmd2` has a number of builtin settings. These settings control the behavior of certain application features and [Buildin Commands](./builtin_commands.md). Users can use the [set](./builtin_commands.md#set) command to show all settings and to modify the value of any setting. +`cmd2` has a number of builtin settings. These settings control the behavior of certain application +features and [Buildin Commands](./builtin_commands.md). Users can use the +[set](./builtin_commands.md#set) command to show all settings and to modify the value of any +setting. ### allow_style -Output generated by `cmd2` programs may contain ANSI escape sequences which instruct the terminal to apply colors or text styling (i.e. bold) to the output. The `allow_style` setting controls the behavior of these escape sequences in output generated with any of the following methods: +Output generated by `cmd2` programs may contain ANSI escape sequences which instruct the terminal to +apply colors or text styling (i.e. bold) to the output. The `allow_style` setting controls the +behavior of these escape sequences in output generated with any of the following methods: - **`cmd2.Cmd.poutput`** - **`cmd2.Cmd.perror`** @@ -20,45 +30,62 @@ Output generated by `cmd2` programs may contain ANSI escape sequences which inst This setting can be one of three values: -- `Never` - all ANSI escape sequences which instruct the terminal to style output are stripped from the output. -- `Terminal` - (the default value) pass through ANSI escape sequences when the output is being sent to the terminal, but if the output is redirected to a pipe or a file the escape sequences are stripped. +- `Never` - all ANSI escape sequences which instruct the terminal to style output are stripped from + the output. +- `Terminal` - (the default value) pass through ANSI escape sequences when the output is being sent + to the terminal, but if the output is redirected to a pipe or a file the escape sequences are + stripped. - `Always` - ANSI escape sequences are always passed through to the output ### always_show_hint -If `True`, display tab completion hint even when completion suggestions print. The default value of this setting is `False`. +If `True`, display tab completion hint even when completion suggestions print. The default value of +this setting is `False`. ### debug -The default value of this setting is `False`, which causes the `cmd2.Cmd.pexcept` method to only display the message from an exception. However, if the debug setting is `True`, then the entire stack trace will be printed. +The default value of this setting is `False`, which causes the `cmd2.Cmd.pexcept` method to only +display the message from an exception. However, if the debug setting is `True`, then the entire +stack trace will be printed. ### echo -If `True`, each command the user issues will be repeated to the screen before it is executed. This is particularly useful when running scripts. This behavior does not occur when running a command at the prompt. +If `True`, each command the user issues will be repeated to the screen before it is executed. This +is particularly useful when running scripts. This behavior does not occur when running a command at +the prompt. ### editor -Similar to the `EDITOR` shell variable, this setting contains the name of the program which should be run by the [edit](./builtin_commands.md#edit) command. +Similar to the `EDITOR` shell variable, this setting contains the name of the program which should +be run by the [edit](./builtin_commands.md#edit) command. ### feedback_to_output -Controls whether feedback generated with the `cmd2.Cmd.pfeedback` method is sent to `sys.stdout` or `sys.stderr`. If `False` the output will be sent to `sys.stderr` +Controls whether feedback generated with the `cmd2.Cmd.pfeedback` method is sent to `sys.stdout` or +`sys.stderr`. If `False` the output will be sent to `sys.stderr` -If `True` the output is sent to `stdout` (which is often the screen but may be [redirected](./redirection.md#output-redirection-and-pipes)). The feedback output will be mixed in with and indistinguishable from output generated with `cmd2.Cmd.poutput`. +If `True` the output is sent to `stdout` (which is often the screen but may be +[redirected](./redirection.md#output-redirection-and-pipes)). The feedback output will be mixed in +with and indistinguishable from output generated with `cmd2.Cmd.poutput`. ### max_completion_items -Maximum number of CompletionItems to display during tab completion. A CompletionItem is a special kind of tab completion hint which displays both a value and description and uses one line for each hint. Tab complete the `set` command for an example. +Maximum number of CompletionItems to display during tab completion. A CompletionItem is a special +kind of tab completion hint which displays both a value and description and uses one line for each +hint. Tab complete the `set` command for an example. -If the number of tab completion hints exceeds `max_completion_items`, then they will be displayed in the typical columnized format and will not include the description text of the CompletionItem. +If the number of tab completion hints exceeds `max_completion_items`, then they will be displayed in +the typical columnized format and will not include the description text of the CompletionItem. ### quiet -If `True`, output generated by calling `cmd2.Cmd.pfeedback` is suppressed. If `False`, the [feedback_to_output](#feedback_to_output) setting controls where the output is sent. +If `True`, output generated by calling `cmd2.Cmd.pfeedback` is suppressed. If `False`, the +[feedback_to_output](#feedback_to_output) setting controls where the output is sent. ### scripts_add_to_history -If `True`, scripts and pyscripts add commands to history. The default value of this setting is `True`. +If `True`, scripts and pyscripts add commands to history. The default value of this setting is +`True`. ### timing @@ -66,13 +93,15 @@ If `True`, the elapsed time is reported for each command executed. ## Create New Settings -Your application can define user-settable parameters which your code can reference. In your initialization code: +Your application can define user-settable parameters which your code can reference. In your +initialization code: 1. Create an instance attribute with a default value 1. Create a `Settable` object which describes your setting 1. Pass the `Settable` object to `cmd2.Cmd.add_settable` -Here's an example, from [examples/environment.py](https://github.com/python-cmd2/cmd2/blob/master/examples/environment.py): +Here's an example, from +[examples/environment.py](https://github.com/python-cmd2/cmd2/blob/master/examples/environment.py): ```py {% @@ -80,7 +109,9 @@ Here's an example, from [examples/environment.py](https://github.com/python-cmd2 %} ``` -If you want to be notified when a setting changes (as we do above), then be sure to supply a method to the `onchange_cb` parameter of the `cmd2.utils.Settable`. This method will be called after the user changes a setting, and will receive both the old value and the new value. +If you want to be notified when a setting changes (as we do above), then be sure to supply a method +to the `onchange_cb` parameter of the `cmd2.utils.Settable`. This method will be called after the +user changes a setting, and will receive both the old value and the new value. ```text (Cmd) set | grep sunny @@ -105,9 +136,14 @@ It's 13 C - are you a penguin? ## Hide Builtin Settings -You may want to prevent a user from modifying a builtin setting. A setting must appear in the `cmd2.Cmd.settable` dictionary in order for it to be available to the [set](./builtin_commands.md#set) command. +You may want to prevent a user from modifying a builtin setting. A setting must appear in the +`cmd2.Cmd.settable` dictionary in order for it to be available to the +[set](./builtin_commands.md#set) command. -Let's say that you never want end users of your program to be able to enable full debug tracebacks to print out if an error occurs. You might want to hide the [debug](#debug) setting. To do so, remove it from the `cmd2.Cmd.settable` dictionary after you initialize your object. The `cmd2.Cmd.remove_settable` convenience method makes this easy: +Let's say that you never want end users of your program to be able to enable full debug tracebacks +to print out if an error occurs. You might want to hide the [debug](#debug) setting. To do so, +remove it from the `cmd2.Cmd.settable` dictionary after you initialize your object. The +`cmd2.Cmd.remove_settable` convenience method makes this easy: ```py class MyApp(cmd2.Cmd): diff --git a/docs/features/shortcuts_aliases_macros.md b/docs/features/shortcuts_aliases_macros.md index 5bef8955b..9c87ec445 100644 --- a/docs/features/shortcuts_aliases_macros.md +++ b/docs/features/shortcuts_aliases_macros.md @@ -2,14 +2,17 @@ ## Shortcuts -Command shortcuts for long command names and common commands can make life more convenient for your users. Shortcuts are used without a space separating them from their arguments, like `!ls`. By default, the following shortcuts are defined: +Command shortcuts for long command names and common commands can make life more convenient for your +users. Shortcuts are used without a space separating them from their arguments, like `!ls`. By +default, the following shortcuts are defined: - **`?`** - help - **`!`** - shell: run as OS-level command - **`@`** - run script file - **`@@`** - run script file; filename is relative to current script location -To define more shortcuts, update the dict `App.shortcuts` with the `{'shortcut': 'command_name'}` (omit `do_`): +To define more shortcuts, update the dict `App.shortcuts` with the `{'shortcut': 'command_name'}` +(omit `do_`): ```py class App(Cmd): @@ -27,11 +30,14 @@ Note: Command, alias, and macro names cannot start with a shortcut ## Aliases -In addition to shortcuts, `cmd2` provides a full alias feature via the `alias` command. Aliases work in a similar fashion to aliases in the Bash shell. +In addition to shortcuts, `cmd2` provides a full alias feature via the `alias` command. Aliases work +in a similar fashion to aliases in the Bash shell. -The syntax to create an alias is: `alias create name command [args]`, e.g. `alias create ls !ls -lF`. +The syntax to create an alias is: `alias create name command [args]`, e.g. +`alias create ls !ls -lF`. -Redirectors and pipes should be quoted in alias definition to prevent the `alias create` command from being redirected: +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 @@ -39,7 +45,9 @@ Tab completion recognizes an alias, and completes as if its actual value was on For more details run: `help alias create` -Use `alias list` to see all or some of your aliases. The output of this command displays your aliases using the same command that was used to create them. Therefore you can place this output in a `cmd2` startup script to recreate your aliases each time you start the application +Use `alias list` to see all or some of your aliases. The output of this command displays your +aliases using the same command that was used to create them. Therefore you can place this output in +a `cmd2` startup script to recreate your aliases each time you start the application > Ex: `alias list` @@ -53,13 +61,16 @@ Note: Aliases cannot have the same name as a command or macro ## Macros -`cmd2` provides a feature that is similar to aliases called macros. The major difference between macros and aliases is that macros can contain argument placeholders. Arguments are expressed when creating a macro using {#} notation where {1} means the first argument. +`cmd2` provides a feature that is similar to aliases called macros. The major difference between +macros and aliases is that macros can contain argument placeholders. Arguments are expressed when +creating a macro using {#} notation where {1} means the first argument. The following creates a macro called my[macro]{#macro} that expects two arguments: macro create my[macro]{#macro} make[dinner]{#dinner} -meat {1} -veggie {2} -When the macro is called, the provided arguments are resolved and the assembled command is run. For example: +When the macro is called, the provided arguments are resolved and the assembled command is run. For +example: my[macro]{#macro} beef broccoli ---> make[dinner]{#dinner} -meat beef -veggie broccoli @@ -67,11 +78,14 @@ Similar to aliases, pipes and redirectors need to be quoted in the definition of 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 ``, tab completion will only complete paths while typing a macro. +To use the literal string `{1}` in your command, escape it this way: `{{1}}`. Because macros do not +resolve until after hitting ``, 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 identically to the alias subcommands of the same name. Like aliases, macros can be created via a `cmd2` startup script to preserve them across application sessions. +The macro command has `list` and `delete` subcommands that function identically to the alias +subcommands of the same name. Like aliases, macros can be created via a `cmd2` startup script to +preserve them across application sessions. For more details on listing macros run: `help macro list` diff --git a/docs/features/startup_commands.md b/docs/features/startup_commands.md index e9eaffb68..fd5391b91 100644 --- a/docs/features/startup_commands.md +++ b/docs/features/startup_commands.md @@ -1,21 +1,28 @@ # Startup Commands -`cmd2` provides a couple different ways for running commands immediately after your application starts up: +`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 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 -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. +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. $ 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. +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 @@ -30,7 +37,8 @@ You can end your commands with a **quit** command so that your `cmd2` applicatio ## Startup Script -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: +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: ```py class StartupApp(cmd2.Cmd): @@ -38,7 +46,9 @@ class StartupApp(cmd2.Cmd): cmd2.Cmd.__init__(self, startup_script='.cmd2rc') ``` -This text file should contain a [Command Script](./scripting.md#command-scripts). See the [AliasStartup](https://github.com/python-cmd2/cmd2/blob/master/examples/alias_startup.py) example for a demonstration. +This text file should contain a [Command Script](./scripting.md#command-scripts). See the +[AliasStartup](https://github.com/python-cmd2/cmd2/blob/master/examples/alias_startup.py) example +for a demonstration. You can silence a startup script's output by setting `silence_startup_script` to True: @@ -46,4 +56,5 @@ You can silence a startup script's output by setting `silence_startup_script` to cmd2.Cmd.__init__(self, startup_script='.cmd2rc', silence_startup_script=True) ``` -Anything written to stderr will still print. Additionally, a startup script cannot be silenced if `allow_redirection` is False since silencing works by redirecting a script's output to `os.devnull`. +Anything written to stderr will still print. Additionally, a startup script cannot be silenced if +`allow_redirection` is False since silencing works by redirecting a script's output to `os.devnull`. diff --git a/docs/features/table_creation.md b/docs/features/table_creation.md index eeba57cea..c25166b7d 100644 --- a/docs/features/table_creation.md +++ b/docs/features/table_creation.md @@ -1,17 +1,33 @@ # Table Creation -`cmd2` provides a table creation class called `cmd2.table_creator.TableCreator`. This class handles ANSI style sequences and characters with display widths greater than 1 when performing width calculations. It was designed with the ability to build tables one row at a time. This helps when you have large data sets that you don't want to hold in memory or when you receive portions of the data set incrementally. +`cmd2` provides a table creation class called `cmd2.table_creator.TableCreator`. This class handles +ANSI style sequences and characters with display widths greater than 1 when performing width +calculations. It was designed with the ability to build tables one row at a time. This helps when +you have large data sets that you don't want to hold in memory or when you receive portions of the +data set incrementally. `TableCreator` has one public method: `cmd2.table_creator.TableCreator.generate_row()`. -This function and the `cmd2.table_creator.Column` class provide all features needed to build tables with headers, borders, colors, horizontal and vertical alignment, and wrapped text. However, it's generally easier to inherit from this class and implement a more granular API rather than use `TableCreator` directly. +This function and the `cmd2.table_creator.Column` class provide all features needed to build tables +with headers, borders, colors, horizontal and vertical alignment, and wrapped text. However, it's +generally easier to inherit from this class and implement a more granular API rather than use +`TableCreator` directly. -The following table classes build upon `TableCreator` and are provided in the [cmd2.table_creater](../api/table_creator.md) module. They can be used as is or as examples for how to build your own table classes. +The following table classes build upon `TableCreator` and are provided in the +[cmd2.table_creater](../api/table_creator.md) module. They can be used as is or as examples for how +to build your own table classes. -`cmd2.table_creator.SimpleTable` - Implementation of TableCreator which generates a borderless table with an optional divider row after the header. This class can be used to create the whole table at once or one row at a time. +`cmd2.table_creator.SimpleTable` - Implementation of TableCreator which generates a borderless table +with an optional divider row after the header. This class can be used to create the whole table at +once or one row at a time. -`cmd2.table_creator.BorderedTable` - Implementation of TableCreator which generates a table with borders around the table and between rows. Borders between columns can also be toggled. This class can be used to create the whole table at once or one row at a time. +`cmd2.table_creator.BorderedTable` - Implementation of TableCreator which generates a table with +borders around the table and between rows. Borders between columns can also be toggled. This class +can be used to create the whole table at once or one row at a time. -`cmd2.table_creator.AlternatingTable` - Implementation of BorderedTable which uses background colors to distinguish between rows instead of row border lines. This class can be used to create the whole table at once or one row at a time. +`cmd2.table_creator.AlternatingTable` - Implementation of BorderedTable which uses background colors +to distinguish between rows instead of row border lines. This class can be used to create the whole +table at once or one row at a time. -See the [table_creation](https://github.com/python-cmd2/cmd2/blob/master/examples/table_creation.py) example to see these classes in use +See the [table_creation](https://github.com/python-cmd2/cmd2/blob/master/examples/table_creation.py) +example to see these classes in use diff --git a/docs/features/transcripts.md b/docs/features/transcripts.md index daa7ab43b..037fc5dda 100644 --- a/docs/features/transcripts.md +++ b/docs/features/transcripts.md @@ -1,10 +1,14 @@ # Transcripts -A transcript is both the input and output of a successful session of a `cmd2`-based app which is saved to a text file. With no extra work on your part, your app can play back these transcripts as a unit test. Transcripts can contain regular expressions, which provide the flexibility to match responses from commands that produce dynamic or variable output. +A transcript is both the input and output of a successful session of a `cmd2`-based app which is +saved to a text file. With no extra work on your part, your app can play back these transcripts as a +unit test. Transcripts can contain regular expressions, which provide the flexibility to match +responses from commands that produce dynamic or variable output. ## Creating From History -A transcript can automatically generated based upon commands previously executed in the _history_ using `history -t`: +A transcript can automatically generated based upon commands previously executed in the _history_ +using `history -t`: ```text (Cmd) help @@ -31,7 +35,8 @@ A transcript can also be automatically generated from a script file using `run_s (Cmd) ``` -This is a particularly attractive option for automatically regenerating transcripts for regression testing as your `cmd2` application changes. +This is a particularly attractive option for automatically regenerating transcripts for regression +testing as your `cmd2` application changes. ## Creating Manually @@ -48,7 +53,8 @@ like maybe we ... could go to hmmm lunch well maybe we could like go to er lunch right? ``` -This transcript has three commands: they are on the lines that begin with the prompt. The first command looks like this: +This transcript has three commands: they are on the lines that begin with the prompt. The first +command looks like this: ```text (Cmd) say -r 3 Goodnight, Gracie @@ -56,7 +62,8 @@ This transcript has three commands: they are on the lines that begin with the pr Following each command is the output generated by that command. -The transcript ignores all lines in the file until it reaches the first line that begins with the prompt. You can take advantage of this by using the first lines of the transcript as comments: +The transcript ignores all lines in the file until it reaches the first line that begins with the +prompt. You can take advantage of this by using the first lines of the transcript as comments: ```text # Lines at the beginning of the transcript that do not @@ -75,7 +82,8 @@ like maybe we ... could go to hmmm lunch maybe we could like go to er lunch right? ``` -In this example I've used several different commenting styles, and even bare text. It doesn't matter what you put on those beginning lines. Everything before: +In this example I've used several different commenting styles, and even bare text. It doesn't matter +what you put on those beginning lines. Everything before: ```text (Cmd) say -r 3 Goodnight, Gracie @@ -85,9 +93,11 @@ will be ignored. ## Regular Expressions -If we used the above transcript as-is, it would likely fail. As you can see, the `mumble` command doesn't always return the same thing: it inserts random words into the input. +If we used the above transcript as-is, it would likely fail. As you can see, the `mumble` command +doesn't always return the same thing: it inserts random words into the input. -Regular expressions can be included in the response portion of a transcript, and are surrounded by slashes: +Regular expressions can be included in the response portion of a transcript, and are surrounded by +slashes: ```text (Cmd) mumble maybe we could go to lunch @@ -96,18 +106,28 @@ Regular expressions can be included in the response portion of a transcript, and /.*\bmaybe\b.*\bcould\b.*\blunch\b.*/ ``` -Without creating a tutorial on regular expressions, this one matches anything that has the words `maybe`, `could`, and `lunch` in that order. It doesn't ensure that `we` or `go` or `to` appear in the output, but it does work if mumble happens to add words to the beginning or the end of the output. +Without creating a tutorial on regular expressions, this one matches anything that has the words +`maybe`, `could`, and `lunch` in that order. It doesn't ensure that `we` or `go` or `to` appear in +the output, but it does work if mumble happens to add words to the beginning or the end of the +output. -Since the output could be multiple lines long, `cmd2` uses multiline regular expression matching, and also uses the `DOTALL` flag. These two flags subtly change the behavior of commonly used special characters like `.`, `^` and `$`, so you may want to double check the [Python regular expression documentation](https://docs.python.org/3/library/re.html). +Since the output could be multiple lines long, `cmd2` uses multiline regular expression matching, +and also uses the `DOTALL` flag. These two flags subtly change the behavior of commonly used special +characters like `.`, `^` and `$`, so you may want to double check the +[Python regular expression documentation](https://docs.python.org/3/library/re.html). -If your output has slashes in it, you will need to escape those slashes so the stuff between them is not interpred as a regular expression. In this transcript: +If your output has slashes in it, you will need to escape those slashes so the stuff between them is +not interpred as a regular expression. In this transcript: ```text (Cmd) say cd /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages ``` -the output contains slashes. The text between the first slash and the second slash, will be interpreted as a regular expression, and those two slashes will not be included in the comparison. When replayed, this transcript would therefore fail. To fix it, we could either write a regular expression to match the path instead of specifying it verbatim, or we can escape the slashes: +the output contains slashes. The text between the first slash and the second slash, will be +interpreted as a regular expression, and those two slashes will not be included in the comparison. +When replayed, this transcript would therefore fail. To fix it, we could either write a regular +expression to match the path instead of specifying it verbatim, or we can escape the slashes: ```text (Cmd) say cd /usr/local/lib/python3.11/site-packages @@ -131,7 +151,8 @@ the output contains slashes. The text between the first slash and the second sla ## Running A Transcript -Once you have created a transcript, it's easy to have your application play it back and check the output. From within the `examples/` directory: +Once you have created a transcript, it's easy to have your application play it back and check the +output. From within the `examples/` directory: ```text $ python example.py --test transcript_regex.txt @@ -142,7 +163,9 @@ Ran 1 test in 0.013s OK ``` -The output will look familiar if you use `unittest`, because that's exactly what happens. Each command in the transcript is run, and we `assert` the output matches the expected result from the transcript. +The output will look familiar if you use `unittest`, because that's exactly what happens. Each +command in the transcript is run, and we `assert` the output matches the expected result from the +transcript. !!! note diff --git a/docs/index.md b/docs/index.md index 727f0b940..bca8cc526 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,10 +1,12 @@ # cmd2 -A python package for building powerful command-line interpreter (CLI) programs. Extends the Python Standard Library's [cmd](https://docs.python.org/3/library/cmd.html) package. +A python package for building powerful command-line interpreter (CLI) programs. Extends the Python +Standard Library's [cmd](https://docs.python.org/3/library/cmd.html) package. The basic use of `cmd2` is identical to that of [cmd](https://docs.python.org/3/library/cmd.html). -1. Create a subclass of [cmd2.Cmd][]. Define attributes and `do_*` methods to control its behavior. Throughout this documentation, we will assume that you are naming your subclass `App`: +1. Create a subclass of [cmd2.Cmd][]. Define attributes and `do_*` methods to control its behavior. + Throughout this documentation, we will assume that you are naming your subclass `App`: ```py title="Creating a class inherited from cmd2.Cmd" linenums="1" from cmd2 import Cmd diff --git a/docs/javascripts/readthedocs.js b/docs/javascripts/readthedocs.js index 380dad3b6..cfa8491e0 100644 --- a/docs/javascripts/readthedocs.js +++ b/docs/javascripts/readthedocs.js @@ -29,7 +29,5 @@ ${config.versions.active `; - document - .querySelector(".md-header__topic") - .insertAdjacentHTML("beforeend", versioning); + document.querySelector(".md-header__topic").insertAdjacentHTML("beforeend", versioning); }); diff --git a/docs/migrating/incompatibilities.md b/docs/migrating/incompatibilities.md index 2680b35a0..030959d18 100644 --- a/docs/migrating/incompatibilities.md +++ b/docs/migrating/incompatibilities.md @@ -1,21 +1,46 @@ # Incompatibilities -`cmd2` strives to be drop-in compatible with [cmd](https://docs.python.org/3/library/cmd.html), however there are a few incompatibilities. +`cmd2` strives to be drop-in compatible with [cmd](https://docs.python.org/3/library/cmd.html), +however there are a few incompatibilities. ## Cmd.emptyline() -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](https://docs.python.org/3/library/cmd.html) 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. `cmd2` completely ignores empty lines and the base class `cmd.emptyline()` method never gets called and thus the empty line behavior cannot be overridden. +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](https://docs.python.org/3/library/cmd.html) 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. `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 -In [cmd](https://docs.python.org/3/library/cmd.html), the [Cmd.identchars](https://docs.python.org/3/library/cmd.html#cmd.Cmd.identchars) attribute contains the string of characters accepted for command names. [cmd](https://docs.python.org/3/library/cmd.html) 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](https://docs.python.org/3/library/cmd.html) 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 [Tab Completion](../features/completion.md) and [Shortcuts, Aliases, and Macros](../features/shortcuts_aliases_macros.md). - -If you really need this functionality in your app, you can add it back in by writing a [Postparsing Hook](../features/hooks.md#postparsing-hooks). +In [cmd](https://docs.python.org/3/library/cmd.html), the +[Cmd.identchars](https://docs.python.org/3/library/cmd.html#cmd.Cmd.identchars) attribute contains +the string of characters accepted for command names. +[cmd](https://docs.python.org/3/library/cmd.html) 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](https://docs.python.org/3/library/cmd.html) 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 [Tab Completion](../features/completion.md) and +[Shortcuts, Aliases, and Macros](../features/shortcuts_aliases_macros.md). + +If you really need this functionality in your app, you can add it back in by writing a +[Postparsing Hook](../features/hooks.md#postparsing-hooks). ## Cmd.cmdqueue -In [cmd](https://docs.python.org/3/library/cmd.html), the [Cmd.cmdqueue](https://docs.python.org/3/library/cmd.html#cmd.Cmd.cmdqueue) attribute contains a list of queued input lines. The cmdqueue list is checked in `cmdloop()` when new input is needed; if it is nonempty, its elements will be processed in order, as if entered at the prompt. +In [cmd](https://docs.python.org/3/library/cmd.html), the +[Cmd.cmdqueue](https://docs.python.org/3/library/cmd.html#cmd.Cmd.cmdqueue) attribute contains a +list of queued input lines. The cmdqueue list is checked in `cmdloop()` when new input is needed; if +it is nonempty, its elements will be processed in order, as if entered at the prompt. -Since version 0.9.13 `cmd2` has removed support for `Cmd.cmdqueue`. Because `cmd2` supports running commands via the main `cmdloop()`, text 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. +Since version 0.9.13 `cmd2` has removed support for `Cmd.cmdqueue`. Because `cmd2` supports running +commands via the main `cmdloop()`, text 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. diff --git a/docs/migrating/index.md b/docs/migrating/index.md index 86257ff62..1ea567485 100644 --- a/docs/migrating/index.md +++ b/docs/migrating/index.md @@ -1,8 +1,13 @@ # Migrating From cmd -If you're thinking of migrating your [cmd](https://docs.python.org/3/library/cmd.html) app to `cmd2`, this section will help you decide if it's right for your app, and show you how to do it. +If you're thinking of migrating your [cmd](https://docs.python.org/3/library/cmd.html) app to +`cmd2`, this section will help you decide if it's right for your app, and show you how to do it. -- [Why cmd2](why.md) - we try and convince you to use `cmd2` instead of [cmd](https://docs.python.org/3/library/cmd.html) -- [Incompatibilities](incompatibilities.md) - `cmd2` is not quite 100% compatible with [cmd](https://docs.python.org/3/library/cmd.html). -- [Minimum Required Changes](minimum.md) - the minimum changes required to move from [cmd](https://docs.python.org/3/library/cmd.html) to `cmd2`. Start your migration here. -- [Next Steps](next_steps.md) - Once you've migrated, here a list of things you can do next to add even more functionality to your app. +- [Why cmd2](why.md) - we try and convince you to use `cmd2` instead of + [cmd](https://docs.python.org/3/library/cmd.html) +- [Incompatibilities](incompatibilities.md) - `cmd2` is not quite 100% compatible with + [cmd](https://docs.python.org/3/library/cmd.html). +- [Minimum Required Changes](minimum.md) - the minimum changes required to move from + [cmd](https://docs.python.org/3/library/cmd.html) to `cmd2`. Start your migration here. +- [Next Steps](next_steps.md) - 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/minimum.md b/docs/migrating/minimum.md index 91101f37b..6e06379ef 100644 --- a/docs/migrating/minimum.md +++ b/docs/migrating/minimum.md @@ -1,6 +1,7 @@ # Minimum Required Changes -`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. +`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 @@ -30,11 +31,15 @@ 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 [Exiting](../features/misc.md#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 [Exiting](../features/misc.md#exiting). ## Distribution -If you are distributing your application, you'll also need to ensure that `cmd2` is properly installed. You will need to add the following dependency to your `pyproject.toml` or `setup.py`: +If you are distributing your application, you'll also need to ensure that `cmd2` is properly +installed. You will need to add the following dependency to your `pyproject.toml` or `setup.py`: 'cmd2>=2,<3' diff --git a/docs/migrating/next_steps.md b/docs/migrating/next_steps.md index b1c5c3a6f..7d56e2f4b 100644 --- a/docs/migrating/next_steps.md +++ b/docs/migrating/next_steps.md @@ -1,25 +1,45 @@ # 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 [Features](../features/index.md) to see what else `cmd2` can help you do. +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 +[Features](../features/index.md) 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: +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. +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 [Tab Completion](../features/completion.md) 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). +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 [Argument Processing](../features/argument_processing.md) if you want to dig in further. +There's a lot more about [Argument Processing](../features/argument_processing.md) 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 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 [standardize all of your help messages](../features/argument_processing.md#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. +If you were already using `argparse` or decided to switch to it, you can easily +[standardize all of your help messages](../features/argument_processing.md#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 `cmd2.Cmd.poutput`, `cmd2.Cmd.perror`, and `cmd2.Cmd.pfeedback`. These methods work with several of the built in [Settings](../features/settings.md) 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 `cmd2.ansi.style` function. These and other related topics are covered in [Generating Output](../features/generating_output.md). +If your program generates output by printing directly to `sys.stdout`, you should consider switching +to `cmd2.Cmd.poutput`, `cmd2.Cmd.perror`, and `cmd2.Cmd.pfeedback`. These methods work with several +of the built in [Settings](../features/settings.md) 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 +`cmd2.ansi.style` function. These and other related topics are covered in +[Generating Output](../features/generating_output.md). diff --git a/docs/migrating/why.md b/docs/migrating/why.md index d7c1efc9b..060ef0c0e 100644 --- a/docs/migrating/why.md +++ b/docs/migrating/why.md @@ -2,29 +2,54 @@ ## cmd -[cmd](#cmd) is the Python Standard Library's module for creating simple interactive command-line applications. [cmd](#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! +[cmd](#cmd) is the Python Standard Library's module for creating simple interactive command-line +applications. [cmd](#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](#cmd) provides the foundation on which `cmd2` is based, understanding the use of [cmd](#cmd) is the first step in learning the use of `cmd2`. Once you have read the [cmd](#cmd) docs, return here to learn the ways that `cmd2` differs from [cmd](#cmd). +Since the API provided by [cmd](#cmd) provides the foundation on which `cmd2` is based, +understanding the use of [cmd](#cmd) is the first step in learning the use of `cmd2`. Once you have +read the [cmd](#cmd) docs, return here to learn the ways that `cmd2` differs from [cmd](#cmd). ## cmd2 -`cmd2` is a batteries-included extension of [cmd](#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. +`cmd2` is a batteries-included extension of [cmd](#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. -`cmd2` can be used as a drop-in replacement for [cmd](#cmd) with a few minor discrepancies as discussed in the [Incompatibilities](incompatibilities.md) section. Simply importing `cmd2` in place of [cmd](#cmd) will add many features to an application without any 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` can be used as a drop-in replacement for [cmd](#cmd) with a few minor discrepancies as +discussed in the [Incompatibilities](incompatibilities.md) section. Simply importing `cmd2` in place +of [cmd](#cmd) will add many features to an application without any 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. ## Free Features -After switching from [cmd](#cmd) to `cmd2`, your application will have the following new features and capabilities, without you having to do anything: - -- More robust [History](../features/history.md). Both [cmd](#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 [Generatoring Output](../features/generating_output.md). +After switching from [cmd](#cmd) to `cmd2`, your application will have the following new features +and capabilities, without you having to do anything: + +- More robust [History](../features/history.md). Both [cmd](#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 + [Generatoring Output](../features/generating_output.md). - Users can load script files, which contain a series of commands to be executed. -- Users can create [Shortcuts, Aliases, and Macros](../features/shortcuts_aliases_macros.md) to reduce the typing required for repetitive commands. +- Users can create [Shortcuts, Aliases, and Macros](../features/shortcuts_aliases_macros.md) 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. -- [Clipboard Integration](../features/clipboard.md) allows you to save command output to the operating system clipboard. +- [Clipboard Integration](../features/clipboard.md) allows you to save command output to the + operating system clipboard. - A built-in [Timer](../features/misc.md#Timer) can show how long it takes a command to execute -- A [Transcript](../features/transcripts.md) 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. +- A [Transcript](../features/transcripts.md) 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 capabilities which can be easily added to your application. [Next Steps](next_steps.md) has some ideas of where you can start, or you can dig in to all the [Features](../features/index.md). +In addition to the features you get with no additional work, `cmd2` offers a broad range of +additional capabilities which can be easily added to your application. [Next Steps](next_steps.md) +has some ideas of where you can start, or you can dig in to all the +[Features](../features/index.md). diff --git a/docs/overview/alternatives.md b/docs/overview/alternatives.md index e54e8f098..c1bbb7876 100644 --- a/docs/overview/alternatives.md +++ b/docs/overview/alternatives.md @@ -1,16 +1,41 @@ # Alternatives -For programs that do not interact with the user in a continuous loop - programs that simply accept a set of arguments from the command line, return results, and do not keep the user within the program's environment - all you need are [sys](https://docs.python.org/3/library/sys.html).argv (the command-line arguments) and [argparse](https://docs.python.org/3/library/argparse.html) (for parsing UNIX-style options and flags). Though some people may prefer [docopt](https://pypi.org/project/docopt) or [click](https://click.palletsprojects.com) to [argparse](https://docs.python.org/3/library/argparse.html). +For programs that do not interact with the user in a continuous loop - programs that simply accept a +set of arguments from the command line, return results, and do not keep the user within the +program's environment - all you need are [sys](https://docs.python.org/3/library/sys.html).argv (the +command-line arguments) and [argparse](https://docs.python.org/3/library/argparse.html) (for parsing +UNIX-style options and flags). Though some people may prefer +[docopt](https://pypi.org/project/docopt) or [click](https://click.palletsprojects.com) to +[argparse](https://docs.python.org/3/library/argparse.html). -The [textual](https://textual.textualize.io/) module is capable of building sophisticated full-screen terminal user interfaces that are not limited to simple text input and output; they can paint the screen with options that are selected from using the cursor keys and even mouse clicks. However, programming a `textual` application is not as straightforward as using `cmd2`. +The [textual](https://textual.textualize.io/) module is capable of building sophisticated +full-screen terminal user interfaces that are not limited to simple text input and output; they can +paint the screen with options that are selected from using the cursor keys and even mouse clicks. +However, programming a `textual` application is not as straightforward as using `cmd2`. -Several Python packages exist for building interactive command-line applications approximately similar in concept to [cmd](https://docs.python.org/3/library/cmd.html) applications. None of them share `cmd2`'s close ties to [cmd](https://docs.python.org/3/library/cmd.html), but they may be worth investigating nonetheless. Two of the most mature and full featured are: +Several Python packages exist for building interactive command-line applications approximately +similar in concept to [cmd](https://docs.python.org/3/library/cmd.html) applications. None of them +share `cmd2`'s close ties to [cmd](https://docs.python.org/3/library/cmd.html), but they may be +worth investigating nonetheless. Two of the most mature and full featured are: - [Python Prompt Toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) - [Click](https://click.palletsprojects.com) -[Python Prompt Toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) is a library for building powerful interactive command lines and terminal applications in Python. It provides a lot of advanced visual features like syntax highlighting, bottom bars, and the ability to create fullscreen apps. +[Python Prompt Toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) is a library for +building powerful interactive command lines and terminal applications in Python. It provides a lot +of advanced visual features like syntax highlighting, bottom bars, and the ability to create +fullscreen apps. -[Click](https://click.palletsprojects.com) is a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It is more geared towards command line utilities instead of command line interpreters, but it can be used for either. +[Click](https://click.palletsprojects.com) is a Python package for creating beautiful command line +interfaces in a composable way with as little code as necessary. It is more geared towards command +line utilities instead of command line interpreters, but it can be used for either. -Getting a working command-interpreter application based on either [Python Prompt Toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) or [Click](https://click.palletsprojects.com) requires a good deal more effort and boilerplate code than `cmd2`. `cmd2` focuses on providing an excellent out-of-the-box experience with as many useful features as possible built in for free with as little work required on the developer's part as possible. We believe that `cmd2` provides developers the easiest way to write a command-line interpreter, while allowing a good experience for end users. If you are seeking a visually richer end-user experience and don't mind investing more development time, we would recommend checking out [Python Prompt Toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit). +Getting a working command-interpreter application based on either +[Python Prompt Toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) or +[Click](https://click.palletsprojects.com) requires a good deal more effort and boilerplate code +than `cmd2`. `cmd2` focuses on providing an excellent out-of-the-box experience with as many useful +features as possible built in for free with as little work required on the developer's part as +possible. We believe that `cmd2` provides developers the easiest way to write a command-line +interpreter, while allowing a good experience for end users. If you are seeking a visually richer +end-user experience and don't mind investing more development time, we would recommend checking out +[Python Prompt Toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit). diff --git a/docs/overview/index.md b/docs/overview/index.md index 92a01bf4a..8038b9c1a 100644 --- a/docs/overview/index.md +++ b/docs/overview/index.md @@ -1,13 +1,18 @@ # Getting Started -Building a new [REPL](https://en.wikipedia.org/wiki/Read–eval–print_loop) or [Command Line Interface](https://en.wikipedia.org/wiki/Command-line_interface) application? +Building a new [REPL](https://en.wikipedia.org/wiki/Read–eval–print_loop) or +[Command Line Interface](https://en.wikipedia.org/wiki/Command-line_interface) application? -Already built an application that uses [cmd](https://docs.python.org/3/library/cmd.html) from the python standard library and want to add more functionality with very little work? +Already built an application that uses [cmd](https://docs.python.org/3/library/cmd.html) from the +python standard library and want to add more functionality with very little work? -`cmd2` is a powerful python library for building command line applications. Start here to find out if this library is a good fit for your needs. +`cmd2` is a powerful python library for building command line applications. Start here to find out +if this library is a good fit for your needs. -- [Installation Instructions](installation.md) - how to install `cmd2` and associated optional dependencies -- [First Application](../examples/first_app.md) - a sample application showing 8 key features of `cmd2` +- [Installation Instructions](installation.md) - how to install `cmd2` and associated optional + dependencies +- [First Application](../examples/first_app.md) - a sample application showing 8 key features of + `cmd2` - [Integrate cmd2 Into Your Project](integrating.md) - adding `cmd2` to your project - [Alternatives](alternatives.md) - other python packages that might meet your needs - [Resources](resources.md) - related links and other materials diff --git a/docs/overview/installation.md b/docs/overview/installation.md index e1be17587..694f518e2 100644 --- a/docs/overview/installation.md +++ b/docs/overview/installation.md @@ -1,7 +1,8 @@ # Installation Instructions -`cmd2` works on Linux, macOS, and Windows. It requires Python 3.9 or higher, [pip](https://pypi.org/project/pip), -and [setuptools](https://pypi.org/project/setuptools). If you've got all that, then you can just: +`cmd2` works on Linux, macOS, and Windows. It requires Python 3.9 or higher, +[pip](https://pypi.org/project/pip), and [setuptools](https://pypi.org/project/setuptools). If +you've got all that, then you can just: ```shell $ pip install cmd2 @@ -18,8 +19,8 @@ $ pip install cmd2 ## Prerequisites If you have Python 3 >=3.9 installed from [python.org](https://www.python.org), you will already -have [pip](https://pypi.org/project/pip) and [setuptools](https://pypi.org/project/setuptools), but may need to upgrade -to the latest versions: +have [pip](https://pypi.org/project/pip) and [setuptools](https://pypi.org/project/setuptools), but +may need to upgrade to the latest versions: On Linux or OS X: @@ -35,8 +36,8 @@ C:\> python -m pip install -U pip setuptools ## Install from PyPI {: #pip_install } -[pip](https://pypi.org/project/pip) is the recommended installer. Installing packages from [PyPI](https://pypi.org) with -pip is easy: +[pip](https://pypi.org/project/pip) is the recommended installer. Installing packages from +[PyPI](https://pypi.org) with pip is easy: ```shell $ pip install cmd2 @@ -46,8 +47,8 @@ This will install the required 3rd-party dependencies, if necessary. ## Install from GitHub {: #github } -The latest version of `cmd2` can be installed directly from the master branch on GitHub -using [pip](https://pypi.org/project/pip): +The latest version of `cmd2` can be installed directly from the master branch on GitHub using +[pip](https://pypi.org/project/pip): ```shell $ pip install -U git+git://github.com/python-cmd2/cmd2.git @@ -55,8 +56,8 @@ $ pip install -U git+git://github.com/python-cmd2/cmd2.git ## Install from Debian or Ubuntu repos -We recommend installing from [pip](https://pypi.org/project/pip), but if you wish to install from Debian or Ubuntu repos -this can be done with apt-get. +We recommend installing from [pip](https://pypi.org/project/pip), but if you wish to install from +Debian or Ubuntu repos this can be done with apt-get. For Python 3: @@ -74,29 +75,34 @@ Upgrade an already installed `cmd2` to the latest version from [PyPI](https://py pip install -U cmd2 -This will upgrade to the newest stable version of `cmd2` and will also upgrade any dependencies if necessary. +This will upgrade to the newest stable version of `cmd2` and will also upgrade any dependencies if +necessary. ## Uninstalling cmd2 -If you wish to permanently uninstall `cmd2`, this can also easily be done with [pip](https://pypi.org/project/pip): +If you wish to permanently uninstall `cmd2`, this can also easily be done with +[pip](https://pypi.org/project/pip): $ pip uninstall cmd2 ## readline Considerations -Tab completion for `cmd2` applications is only tested against GNU Readline. It does not work properly with -the [libedit](http://thrysoee.dk/editline/) library which is similar, but not identical to GNU Readline. `cmd2` will -disable all tab-completion support if an incompatible version of `readline` is found. +Tab completion for `cmd2` applications is only tested against GNU Readline. It does not work +properly with the [libedit](http://thrysoee.dk/editline/) library which is similar, but not +identical to GNU Readline. `cmd2` will disable all tab-completion support if an incompatible version +of `readline` is found. -When installed using `pip`, `uv`, or similar Python packaging tool on either `macOS` or `Windows`, `cmd2` will -automatically install a compatiable version of readline. +When installed using `pip`, `uv`, or similar Python packaging tool on either `macOS` or `Windows`, +`cmd2` will automatically install a compatiable version of readline. -Most `Linux` OSes come with a compatible version of readline. However, if you are using a tool like `uv` to install -Python on your system and configure a virtual environment, `uv` installed versions of Python come with `libEdit`. +Most `Linux` OSes come with a compatible version of readline. However, if you are using a tool like +`uv` to install Python on your system and configure a virtual environment, `uv` installed versions +of Python come with `libEdit`. -macOS comes with the [libedit](http://thrysoee.dk/editline/) library which is similar, but not identical, to GNU -Readline. Tab completion for `cmd2` applications is only tested against GNU Readline. In this case you just need to -install the `gnureadline` Python package which is statically linked against GNU Readline: +macOS comes with the [libedit](http://thrysoee.dk/editline/) library which is similar, but not +identical, to GNU Readline. Tab completion for `cmd2` applications is only tested against GNU +Readline. In this case you just need to install the `gnureadline` Python package which is statically +linked against GNU Readline: ```shell $ pip install -U gnureadline diff --git a/docs/overview/integrating.md b/docs/overview/integrating.md index e53a89779..fae95ec6a 100644 --- a/docs/overview/integrating.md +++ b/docs/overview/integrating.md @@ -1,15 +1,27 @@ # Integrate cmd2 Into Your Project -Once installed, you will want to ensure that your project's dependencies include `cmd2`. Make sure your `pyproject.toml` or `setup.py` includes the following dependency +Once installed, you will want to ensure that your project's dependencies include `cmd2`. Make sure +your `pyproject.toml` or `setup.py` includes the following dependency 'cmd2>=2.4' -The `cmd2` project uses [Semantic Versioning](https://semver.org), which means that any incompatible API changes will be release with a new major version number. The public API is documented in the [API Reference](../api/index.md). +The `cmd2` project uses [Semantic Versioning](https://semver.org), which means that any incompatible +API changes will be release with a new major version number. The public API is documented in the +[API Reference](../api/index.md). -We recommend that you follow the advice given by the Python Packaging User Guide related to [install_requires](https://packaging.python.org/discussions/install-requires-vs-requirements/). By setting an upper bound on the allowed version, you can ensure that your project does not inadvertently get installed with an incompatible future version of `cmd2`. +We recommend that you follow the advice given by the Python Packaging User Guide related to +[install_requires](https://packaging.python.org/discussions/install-requires-vs-requirements/). By +setting an upper bound on the allowed version, you can ensure that your project does not +inadvertently get installed with an incompatible future version of `cmd2`. ## OS Considerations -If you would like to use [Tab Completion](../features/completion.md), then you need a compatible version of [readline](https://tiswww.case.edu/php/chet/readline/rltop.html) installed on your operating system (OS). `cmd2` forces a sane install of `readline` on both `Windows` and `MacOS`, but does not do so on `Linux`. If for some reason, you have a Linux OS that has the [Editline Library (libedit)](https://www.thrysoee.dk/editline/) installed instead of `readline`, you will need to manually add a dependency on `gnureadline`. Make sure to include the following dependency in your `pyproject.toml` or `setup.py`: +If you would like to use [Tab Completion](../features/completion.md), then you need a compatible +version of [readline](https://tiswww.case.edu/php/chet/readline/rltop.html) installed on your +operating system (OS). `cmd2` forces a sane install of `readline` on both `Windows` and `MacOS`, but +does not do so on `Linux`. If for some reason, you have a Linux OS that has the +[Editline Library (libedit)](https://www.thrysoee.dk/editline/) installed instead of `readline`, you +will need to manually add a dependency on `gnureadline`. Make sure to include the following +dependency in your `pyproject.toml` or `setup.py`: 'gnureadline' diff --git a/docs/overview/resources.md b/docs/overview/resources.md index 35e3ac099..022bad3b7 100644 --- a/docs/overview/resources.md +++ b/docs/overview/resources.md @@ -5,4 +5,7 @@ Project related links and other resources: - [cmd](https://docs.python.org/3/library/cmd.html) - [cmd2 project page](https://github.com/python-cmd2/cmd2) - [project bug tracker](https://github.com/python-cmd2/cmd2/issues) -- PyOhio 2019: [slides](https://github.com/python-cmd2/talks/blob/master/PyOhio_2019/cmd2-PyOhio_2019.pdf), [video](https://www.youtube.com/watch?v=pebeWrTqIIw), [examples](https://github.com/python-cmd2/talks/tree/master/PyOhio_2019/examples) +- PyOhio 2019: + [slides](https://github.com/python-cmd2/talks/blob/master/PyOhio_2019/cmd2-PyOhio_2019.pdf), + [video](https://www.youtube.com/watch?v=pebeWrTqIIw), + [examples](https://github.com/python-cmd2/talks/tree/master/PyOhio_2019/examples) diff --git a/docs/plugins/external_test.md b/docs/plugins/external_test.md index 415fb172c..a10d4c2bd 100644 --- a/docs/plugins/external_test.md +++ b/docs/plugins/external_test.md @@ -2,11 +2,18 @@ ## Overview -The [External Test Plugin](https://github.com/python-cmd2/cmd2/tree/master/plugins/ext_test) supports testing of a cmd2 application by exposing access to cmd2 commands with the same context as from within a cmd2 [Python Script](../features/scripting.md#python-scripts). This interface captures `stdout`, `stderr`, as well as any application-specific data returned by the command. This also allows for verification of an application's support for [Python Scripts](../features/scripting.md#python-scripts) and enables the cmd2 application to be tested as part of a larger system integration test. +The [External Test Plugin](https://github.com/python-cmd2/cmd2/tree/master/plugins/ext_test) +supports testing of a cmd2 application by exposing access to cmd2 commands with the same context as +from within a cmd2 [Python Script](../features/scripting.md#python-scripts). This interface captures +`stdout`, `stderr`, as well as any application-specific data returned by the command. This also +allows for verification of an application's support for +[Python Scripts](../features/scripting.md#python-scripts) and enables the cmd2 application to be +tested as part of a larger system integration test. ## Example cmd2 Application -The following short example shows how to mix in the external test plugin to create a fixture for testing your cmd2 application. +The following short example shows how to mix in the external test plugin to create a fixture for +testing your cmd2 application. Define your cmd2 application @@ -46,7 +53,12 @@ def example_app(): ## Writing Tests -Now write your tests that validate your application using the `cmd2_ext_test.ExternalTestMixin.app_cmd` function to access the cmd2 application's commands. This allows invocation of the application's commands in the same format as a user would type. The results from calling a command matches what is returned from running an python script with cmd2's [run_pyscript](../features/builtin_commands.md#run_pyscript) command, which provides `stdout`, `stderr`, and the command's result data. +Now write your tests that validate your application using the +`cmd2_ext_test.ExternalTestMixin.app_cmd` function to access the cmd2 application's commands. This +allows invocation of the application's commands in the same format as a user would type. The results +from calling a command matches what is returned from running an python script with cmd2's +[run_pyscript](../features/builtin_commands.md#run_pyscript) command, which provides `stdout`, +`stderr`, and the command's result data. ```py from cmd2 import CommandResult diff --git a/docs/stylesheets/cmd2.css b/docs/stylesheets/cmd2.css new file mode 100644 index 000000000..a81b84788 --- /dev/null +++ b/docs/stylesheets/cmd2.css @@ -0,0 +1,4 @@ +/* Allow to consume a bigger portion of the overall display width */ +.md-grid { + max-width: 90%; +} diff --git a/docs/testing.md b/docs/testing.md index 4d3434470..ab449dbba 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -6,13 +6,26 @@ This covers special considerations when writing unit tests for a cmd2 applicatio ## Testing Commands -The [External Test Plugin](plugins/external_test.md) provides a mixin class with an function that allows external calls to application commands. The `cmd2_ext_test.ExternalTestMixin.app_cmd` function captures and returns stdout, stderr, and the command-specific result data. +The [External Test Plugin](plugins/external_test.md) provides a mixin class with an function that +allows external calls to application commands. The `cmd2_ext_test.ExternalTestMixin.app_cmd` +function captures and returns stdout, stderr, and the command-specific result data. ## Mocking -If you need to mock anything in your cmd2 application, and most specifically in sub-classes of `cmd2.Cmd` or `cmd2.command_definition.CommandSet`, you must use [Autospeccing](https://docs.python.org/3/library/unittest.mock.html#autospeccing), [spec=True](https://docs.python.org/3/library/unittest.mock.html#patch), or whatever equivalent is provided in the mocking library you're using. - -In order to automatically load functions as commands cmd2 performs a number of reflection calls to look up attributes of classes defined in your cmd2 application. Many mocking libraries will automatically create mock objects to match any attribute being requested, regardless of whether they're present in the object being mocked. This behavior can incorrectly instruct cmd2 to treat a function or attribute as something it needs to recognize and process. To prevent this, you should always mock with [Autospeccing](https://docs.python.org/3/library/unittest.mock.html#autospeccing) or [spec=True](https://docs.python.org/3/library/unittest.mock.html#patch enabled. If you don't have autospeccing on, your unit tests will fail with an error message like: +If you need to mock anything in your cmd2 application, and most specifically in sub-classes of +`cmd2.Cmd` or `cmd2.command_definition.CommandSet`, you must use +[Autospeccing](https://docs.python.org/3/library/unittest.mock.html#autospeccing), +[spec=True](https://docs.python.org/3/library/unittest.mock.html#patch), or whatever equivalent is +provided in the mocking library you're using. + +In order to automatically load functions as commands cmd2 performs a number of reflection calls to +look up attributes of classes defined in your cmd2 application. Many mocking libraries will +automatically create mock objects to match any attribute being requested, regardless of whether +they're present in the object being mocked. This behavior can incorrectly instruct cmd2 to treat a +function or attribute as something it needs to recognize and process. To prevent this, you should +always mock with [Autospeccing](https://docs.python.org/3/library/unittest.mock.html#autospeccing) +or [spec=True](https://docs.python.org/3/library/unittest.mock.html#patch enabled. If you don't have +autospeccing on, your unit tests will fail with an error message like: ```sh cmd2.exceptions.CommandSetRegistrationError: Subcommand diff --git a/examples/README.md b/examples/README.md index 3db86021f..563eb4234 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,23 +1,33 @@ # cmd2 Examples -The [examples](https://github.com/python-cmd2/cmd2/tree/master/examples) directory within the `cmd2` repository contains a number of simple self-contained examples which each demonstrate a few particular features of `cmd2`. None of them are representative of a full real-world complex `cmd2` application, if you are looking for that then see [Projects using cmd2](https://github.com/python-cmd2/cmd2?tab=readme-ov-file#projects-using-cmd2). +The [examples](https://github.com/python-cmd2/cmd2/tree/master/examples) directory within the `cmd2` +repository contains a number of simple self-contained examples which each demonstrate a few +particular features of `cmd2`. None of them are representative of a full real-world complex `cmd2` +application, if you are looking for that then see +[Projects using cmd2](https://github.com/python-cmd2/cmd2?tab=readme-ov-file#projects-using-cmd2). ## List of cmd2 examples -Here is the list of examples in alphabetical order by filename along with a brief description of each: +Here is the list of examples in alphabetical order by filename along with a brief description of +each: - [alias_startup.py](https://github.com/python-cmd2/cmd2/blob/master/examples/alias_startup.py) - - Demonstrates how to add custom command aliases and how to run an initialization script at startup + - Demonstrates how to add custom command aliases and how to run an initialization script at + startup - [arg_decorators.py](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_decorators.py) - - Demonstrates how to use the `cmd2.with_argparser` decorator to specify command arguments using [argparse](https://docs.python.org/3/library/argparse.html) + - Demonstrates how to use the `cmd2.with_argparser` decorator to specify command arguments using + [argparse](https://docs.python.org/3/library/argparse.html) - [arg_print.py](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py) - - Demonstrates how arguments and options get parsed and passed to commands and shows how shortcuts work + - Demonstrates how arguments and options get parsed and passed to commands and shows how + shortcuts work - [argparse_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_completion.py) - Shows how to integrate tab-completion with argparse-based commands - [async_printing.py](https://github.com/python-cmd2/cmd2/blob/master/examples/async_printing.py) - - Shows how to asynchronously print alerts, update the prompt in realtime, and change the window title + - Shows how to asynchronously print alerts, update the prompt in realtime, and change the window + title - [basic.py](https://github.com/python-cmd2/cmd2/blob/master/examples/basic.py) - - Shows how to add a command, add help for it, and create persistent command history for your application + - Shows how to add a command, add help for it, and create persistent command history for your + application - [basic_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/basic_completion.py) - Show how to enable custom tab completion by assigning a completer function to `do_*` commands - [cmd2_as_argument.py](https://github.com/python-cmd2/cmd2/blob/master/examples/cmd_as_argument.py) @@ -25,27 +35,34 @@ Here is the list of examples in alphabetical order by filename along with a brie - [colors.py](https://github.com/python-cmd2/cmd2/blob/master/examples/colors.py) - Show various ways of using colorized output within a cmd2 application - [custom_parser.py](https://github.com/python-cmd2/cmd2/blob/master/examples/custom_parser.py) - - Demonstrates how to create your own customer `Cmd2ArgumentParser`; used by the `override_parser.py` example + - Demonstrates how to create your own customer `Cmd2ArgumentParser`; used by the + `override_parser.py` example - [decorator_example.py](https://github.com/python-cmd2/cmd2/blob/master/examples/decorator_example.py) - Shows how to use cmd2's various argparse decorators to processes command-line arguments - [default_categories.py](https://github.com/python-cmd2/cmd2/blob/master/examples/default_categories.py) - - Demonstrates usage of `@with_default_category` decorator to group and categorize commands and `CommandSet` use + - Demonstrates usage of `@with_default_category` decorator to group and categorize commands and + `CommandSet` use - [dynamic_commands.py](https://github.com/python-cmd2/cmd2/blob/master/examples/dynamic_commands.py) - Shows how `do_*` commands can be dynamically created programatically at runtime - [environment.py](https://github.com/python-cmd2/cmd2/blob/master/examples/environment.py) - - Shows how to create custom `cmd2.Settable` parameters which serve as internal environment variables + - Shows how to create custom `cmd2.Settable` parameters which serve as internal environment + variables - [event_loops.py](https://github.com/python-cmd2/cmd2/blob/master/examples/event_loops.py) - - Shows how to integrate a `cmd2` application with an external event loop which isn't managed by `cmd2` + - Shows how to integrate a `cmd2` application with an external event loop which isn't managed by + `cmd2` - [example.py](https://github.com/python-cmd2/cmd2/blob/master/examples/example.py) - This example is intended to demonstrate `cmd2's` build-in transcript testing capability - [exit_code.py](https://github.com/python-cmd2/cmd2/blob/master/examples/exit_code.py) - Show how to emit a non-zero exit code from your `cmd2` application when it exits - [first_app.py](https://github.com/python-cmd2/cmd2/blob/master/examples/first_app.py) - - Short application that demonstrates 8 key features: Settings, Commands, Argument Parsing, Generating Output, Help, Shortcuts, Multiple Commands, and History + - Short application that demonstrates 8 key features: Settings, Commands, Argument Parsing, + Generating Output, Help, Shortcuts, Multiple Commands, and History - [hello_cmd2.py](https://github.com/python-cmd2/cmd2/blob/master/examples/hello_cmd2.py) - - Completely bare-bones `cmd2` application suitable for rapid testing and debugging of `cmd2` itself + - Completely bare-bones `cmd2` application suitable for rapid testing and debugging of `cmd2` + itself - [help_categories.py](https://github.com/python-cmd2/cmd2/blob/master/examples/help_categories.py) - - Demonstrates command categorization and its impact on the output of the built-in `help` command + - Demonstrates command categorization and its impact on the output of the built-in `help` + command - [hooks.py](https://github.com/python-cmd2/cmd2/blob/master/examples/hooks.py) - Shows how to use various `cmd2` application lifecycle hooks - [initialization.py](https://github.com/python-cmd2/cmd2/blob/master/examples/initialization.py) @@ -57,7 +74,8 @@ Here is the list of examples in alphabetical order by filename along with a brie - [modular_commands_dynamic.py](https://github.com/python-cmd2/cmd2/blob/master/examples/modular_commands_dynamic.py) - Demonstrates dynamic `CommandSet` loading and unloading - [modular_commands_main.py](https://github.com/python-cmd2/cmd2/blob/master/examples/modular_commands_main.py) - - Complex example demonstrating a variety of methods to load `CommandSets` using a mix of command decorators + - Complex example demonstrating a variety of methods to load `CommandSets` using a mix of + command decorators - [modular_subcommands.py](https://github.com/python-cmd2/cmd2/blob/master/examples/modular_subcommands.py) - Shows how to dynamically add and remove subcommands at runtime using `CommandSets` - [override-parser.py](https://github.com/python-cmd2/cmd2/blob/master/examples/override_parser.py) @@ -67,17 +85,23 @@ Here is the list of examples in alphabetical order by filename along with a brie - [persistent_history.py](https://github.com/python-cmd2/cmd2/blob/master/examples/persistent_history.py) - Shows how to enable persistent history in your `cmd2` application - [pirate.py](https://github.com/python-cmd2/cmd2/blob/master/examples/pirate.py) - - Demonstrates many features including colorized output, multiline commands, shorcuts, defaulting to shell, etc. + - Demonstrates many features including colorized output, multiline commands, shorcuts, + defaulting to shell, etc. - [pretty_print.py](https://github.com/python-cmd2/cmd2/blob/master/examples/pretty_print.py) - - Demonstrates use of cmd2.Cmd.ppretty() for pretty-printing arbitrary Python data structures like dictionaries. + - Demonstrates use of cmd2.Cmd.ppretty() for pretty-printing arbitrary Python data structures + like dictionaries. - [python_scripting.py](https://github.com/python-cmd2/cmd2/blob/master/examples/python_scripting.py) - - Shows how cmd2's built-in `run_pyscript` command can provide advanced Python scripting of cmd2 applications + - Shows how cmd2's built-in `run_pyscript` command can provide advanced Python scripting of cmd2 + applications - [read_input.py](https://github.com/python-cmd2/cmd2/blob/master/examples/read_input.py) - - Demonstrates the various ways to call `cmd2.Cmd.read_input()` for input history and tab completion + - Demonstrates the various ways to call `cmd2.Cmd.read_input()` for input history and tab + completion - [remove_builtin_commands.py](https://github.com/python-cmd2/cmd2/blob/master/examples/remove_builtin_commands.py) - - Shows how to remove any built-in cmd2 commands you do not want to be present in your cmd2 application + - Shows how to remove any built-in cmd2 commands you do not want to be present in your cmd2 + application - [remove_settable.py](https://github.com/python-cmd2/cmd2/blob/master/examples/remove_settable.py) - - Shows how to remove any of the built-in cmd2 `Settables` you do not want in your cmd2 application + - Shows how to remove any of the built-in cmd2 `Settables` you do not want in your cmd2 + application - [subcommands.py](https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py) - Shows how to use `argparse` to easily support sub-commands within your cmd2 commands - [table_creation.py](https://github.com/python-cmd2/cmd2/blob/master/examples/table_creation.py) diff --git a/mkdocs.yml b/mkdocs.yml index 0453dafa6..77a3d3d79 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,6 +1,8 @@ # Project information site_name: cmd2 -site_description: cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python. +site_description: + cmd2 - quickly build feature-rich and user-friendly interactive command line applications in + Python. site_dir: build/html site_url: !ENV [READTHEDOCS_CANONICAL_URL, https://cmd2.readthedocs.io/] @@ -216,6 +218,7 @@ nav: # Include extra CSS to make some style adjustments for ReadTheDocs extra_css: + - stylesheets/cmd2.css - stylesheets/readthedocs.css # Include extra JS to setup Read the Docs addons integrations diff --git a/plugins/ext_test/CHANGELOG.md b/plugins/ext_test/CHANGELOG.md index d35f16d3c..b843b9cdb 100644 --- a/plugins/ext_test/CHANGELOG.md +++ b/plugins/ext_test/CHANGELOG.md @@ -2,8 +2,8 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project +adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## 0.2.0 (2020-09-11) diff --git a/plugins/ext_test/README.md b/plugins/ext_test/README.md index 54c0fcd0a..2ec591414 100644 --- a/plugins/ext_test/README.md +++ b/plugins/ext_test/README.md @@ -10,13 +10,14 @@ ## Overview -This plugin supports testing of a cmd2 application by exposing access cmd2 commands with the same context -as from within a cmd2 pyscript. This allows for verification of an application's support for pyscripts. +This plugin supports testing of a cmd2 application by exposing access cmd2 commands with the same +context as from within a cmd2 pyscript. This allows for verification of an application's support for +pyscripts. ## Example cmd2 Application -The following short example shows how to mix in the external test plugin to create a fixture for testing -your cmd2 application. +The following short example shows how to mix in the external test plugin to create a fixture for +testing your cmd2 application. Define your cmd2 application @@ -57,11 +58,10 @@ def example_app(): ## Writing Tests -Now write your tests that validate your application using the `app_cmd` function to access -the cmd2 application's commands. This allows invocation of the application's commands in the -same format as a user would type. The results from calling a command matches what is returned -from running an python script with cmd2's pyscript command, which provides stdout, stderr, and -the command's result data. +Now write your tests that validate your application using the `app_cmd` function to access the cmd2 +application's commands. This allows invocation of the application's commands in the same format as a +user would type. The results from calling a command matches what is returned from running an python +script with cmd2's pyscript command, which provides stdout, stderr, and the command's result data. ```python from cmd2 import CommandResult diff --git a/plugins/template/CHANGELOG.md b/plugins/template/CHANGELOG.md index c802faefd..74009e6c4 100644 --- a/plugins/template/CHANGELOG.md +++ b/plugins/template/CHANGELOG.md @@ -2,8 +2,8 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project +adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## 1.0.0 (2018-07-24) diff --git a/plugins/template/README.md b/plugins/template/README.md index 7d305ea4e..628150d09 100644 --- a/plugins/template/README.md +++ b/plugins/template/README.md @@ -12,28 +12,27 @@ ## Using this template -This template assumes you are creating a new cmd2 plugin called `myplugin`. Your -plugin will have a different name. You will need to rename some of the files and -directories in this template. Don't forget to modify the imports and `setup.py`. +This template assumes you are creating a new cmd2 plugin called `myplugin`. Your plugin will have a +different name. You will need to rename some of the files and directories in this template. Don't +forget to modify the imports and `setup.py`. You'll probably also want to rewrite the README :) ## Naming -You should prefix the name of your project with `cmd2-`. Within that project, -you should have a package with a prefix of `cmd2_`. +You should prefix the name of your project with `cmd2-`. Within that project, you should have a +package with a prefix of `cmd2_`. ## 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`. +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. +The following short example shows how to mix in a plugin and how the plugin gets initialized. Here's the plugin: @@ -63,20 +62,20 @@ class Example(cmd2_myplugin.MyPlugin, cmd2.Cmd): # all plugins have initialized ``` -Note how the plugin must be inherited (or mixed in) before `cmd2.Cmd`. This is -required for two reasons: +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. +- 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: +Your plugin can add user visible commands. You do it the same way in a plugin that you would in a +`cmd2.Cmd` app: ```python class MyPlugin: @@ -86,14 +85,12 @@ class MyPlugin: 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. +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: +A plugin may add user controllable settings to the application. Here's an example: ```python class MyPlugin: @@ -109,30 +106,27 @@ 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. +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. +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](https://cmd2.readthedocs.io/en/latest/hooks.html) in the cmd2 -documentation. +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](https://cmd2.readthedocs.io/en/latest/hooks.html) in the cmd2 documentation. -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. +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: @@ -152,35 +146,33 @@ class MyPlugin: 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. +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 [cmd2 hook documentation](https://cmd2.readthedocs.io/en/latest/hooks.html) -for full details of the application and command lifecycle, including all -available hooks and the ways hooks can influence the lifecycle. +See the [cmd2 hook documentation](https://cmd2.readthedocs.io/en/latest/hooks.html) 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. +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 -Include an example or two in the `examples` directory which demonstrate how your -plugin works. This will help developers utilize it from within their -application. +Include an example or two in the `examples` directory which demonstrate how your plugin works. This +will help developers utilize it from within their application. ## Development Tasks -This project uses many other python modules for various development tasks, -including testing, linting, building wheels, and distributing releases. These -modules can be configured many different ways, which can make it difficult to -learn the specific incantations required for each project you are familiar with. +This project uses many other python modules for various development tasks, including testing, +linting, building wheels, and distributing releases. These modules can be configured many different +ways, which can make it difficult to learn the specific incantations required for each project you +are familiar with. -This project uses [invoke](http://www.pyinvoke.org) to provide a clean, -high level interface for these development tasks. To see the full list of -functions available: +This project uses [invoke](http://www.pyinvoke.org) to provide a clean, high level interface for +these development tasks. To see the full list of functions available: ``` $ invoke -l @@ -192,35 +184,32 @@ You can run multiple tasks in a single invocation, for example: $ invoke clean docs sdist wheel ``` -That one command will remove all superfluous cache, testing, and build -files, render the documentation, and build a source distribution and a -wheel distribution. +That one command will remove all superfluous cache, testing, and build files, render the +documentation, and build a source distribution and a wheel distribution. For more information, read `tasks.py`. -While developing your plugin, you should make sure you support all versions of -python supported by cmd2, and all supported platforms. cmd2 uses a three -tiered testing strategy to accomplish this objective. +While developing your plugin, you should make sure you support all versions of python supported by +cmd2, and all supported platforms. cmd2 uses a three tiered testing strategy to accomplish this +objective. - [pytest](https://pytest.org) runs the unit tests -- [nox](https://nox.thea.codes/en/stable/) runs the unit tests on multiple versions - of python -- [GitHub Actions](https://github.com/features/actions) runs the tests on the various - supported platforms +- [nox](https://nox.thea.codes/en/stable/) runs the unit tests on multiple versions of python +- [GitHub Actions](https://github.com/features/actions) runs the tests on the various supported + platforms This plugin template is set up to use the same strategy. ### Create python environments -This project uses [nox](https://nox.thea.codes/en/stable/) to run the test -suite against multiple python versions. I recommend -[pyenv](https://github.com/pyenv/pyenv) with the -[pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv>) plugin to manage -these various versions. If you are a Windows user, `pyenv` won't work for you, -but [conda](https://conda.io/) can also be used to solve this problem. +This project uses [nox](https://nox.thea.codes/en/stable/) to run the test suite against multiple +python versions. I recommend [pyenv](https://github.com/pyenv/pyenv) with the +[pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv>) plugin to manage these various +versions. If you are a Windows user, `pyenv` won't work for you, but [conda](https://conda.io/) can +also be used to solve this problem. -This distribution includes a shell script `build-pyenvs.sh` which -automates the creation of these environments. +This distribution includes a shell script `build-pyenvs.sh` which automates the creation of these +environments. If you prefer to create these virtualenvs by hand, do the following: @@ -238,10 +227,9 @@ Now set pyenv to make both of those available at the same time: $ pyenv local cmd2-3.8 cmd2-3.9 ``` -Whether you ran the script, or did it by hand, you now have isolated virtualenvs -for each of the major python versions. This table shows various python commands, -the version of python which will be executed, and the virtualenv it will -utilize. +Whether you ran the script, or did it by hand, you now have isolated virtualenvs for each of the +major python versions. This table shows various python commands, the version of python which will be +executed, and the virtualenv it will utilize. | Command | python | virtualenv | | ----------- | ------ | ---------- | @@ -258,18 +246,16 @@ Install all the development dependencies: $ pip install -e .[dev] ``` -This command also installs `cmd2-myplugin` "in-place", so the package points to -the source code instead of copying files to the python `site-packages` folder. +This command also installs `cmd2-myplugin` "in-place", so the package points to the source code +instead of copying files to the python `site-packages` folder. -All the dependencies now have been installed in the `cmd2-3.9` -virtualenv. If you want to work in other virtualenvs, you'll need to manually -select it, and install again:: +All the dependencies now have been installed in the `cmd2-3.9` virtualenv. If you want to work in +other virtualenvs, you'll need to manually select it, and install again:: -$ pyenv shell cmd2-3.4 -$ pip install -e .[dev] +$ pyenv shell cmd2-3.4 $ pip install -e .[dev] -Now that you have your python environments created, you need to install the -package in place, along with all the other development dependencies: +Now that you have your python environments created, you need to install the package in place, along +with all the other development dependencies: ``` $ pip install -e .[dev] @@ -277,14 +263,13 @@ $ pip install -e .[dev] ### Running unit tests -Run `invoke pytest` from the top level directory of your plugin to run all the -unit tests found in the `tests` directory. +Run `invoke pytest` from the top level directory of your plugin to run all the unit tests found in +the `tests` directory. ### Use nox to run unit tests in multiple versions of python -The included `noxfile.py` is setup to run the unit tests in python 3.8, 3.9 -3.10, 3.11, and 3.12 You can run your unit tests in all of these versions -of python by: +The included `noxfile.py` is setup to run the unit tests in python 3.8, 3.9 3.10, 3.11, and 3.12 You +can run your unit tests in all of these versions of python by: ``` $ nox @@ -300,9 +285,8 @@ When creating your `setup.py` file, keep the following in mind: - use the keywords `cmd2 plugin` to make it easier for people to find your plugin - since cmd2 uses semantic versioning, you should use something like - `install_requires=['cmd2 >= 0.9.4, <=2']` to make sure that your plugin - doesn't try and run with a future version of `cmd2` with which it may not be - compatible + `install_requires=['cmd2 >= 0.9.4, <=2']` to make sure that your plugin doesn't try and run with a + future version of `cmd2` with which it may not be compatible ## License