diff --git a/.github/actions/comment-docs-preview-in-pr/Dockerfile b/.github/actions/comment-docs-preview-in-pr/Dockerfile deleted file mode 100644 index 4f20c5f10b..0000000000 --- a/.github/actions/comment-docs-preview-in-pr/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM python:3.7 - -RUN pip install httpx "pydantic==1.5.1" pygithub - -COPY ./app /app - -CMD ["python", "/app/main.py"] diff --git a/.github/actions/comment-docs-preview-in-pr/action.yml b/.github/actions/comment-docs-preview-in-pr/action.yml deleted file mode 100644 index 0eb64402d2..0000000000 --- a/.github/actions/comment-docs-preview-in-pr/action.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Comment Docs Preview in PR -description: Comment with the docs URL preview in the PR -author: SebastiΓ‘n RamΓ­rez -inputs: - token: - description: Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }} - required: true - deploy_url: - description: The deployment URL to comment in the PR - required: true -runs: - using: docker - image: Dockerfile diff --git a/.github/actions/comment-docs-preview-in-pr/app/main.py b/.github/actions/comment-docs-preview-in-pr/app/main.py deleted file mode 100644 index c9fb7cbbef..0000000000 --- a/.github/actions/comment-docs-preview-in-pr/app/main.py +++ /dev/null @@ -1,68 +0,0 @@ -import logging -import sys -from pathlib import Path -from typing import Optional - -import httpx -from github import Github -from github.PullRequest import PullRequest -from pydantic import BaseModel, BaseSettings, SecretStr, ValidationError - -github_api = "https://api.github.com" - - -class Settings(BaseSettings): - github_repository: str - github_event_path: Path - github_event_name: Optional[str] = None - input_token: SecretStr - input_deploy_url: str - - -class PartialGithubEventHeadCommit(BaseModel): - id: str - - -class PartialGithubEventWorkflowRun(BaseModel): - head_commit: PartialGithubEventHeadCommit - - -class PartialGithubEvent(BaseModel): - workflow_run: PartialGithubEventWorkflowRun - - -if __name__ == "__main__": - logging.basicConfig(level=logging.INFO) - settings = Settings() - logging.info(f"Using config: {settings.json()}") - g = Github(settings.input_token.get_secret_value()) - repo = g.get_repo(settings.github_repository) - try: - event = PartialGithubEvent.parse_file(settings.github_event_path) - except ValidationError as e: - logging.error(f"Error parsing event file: {e.errors()}") - sys.exit(0) - use_pr: Optional[PullRequest] = None - for pr in repo.get_pulls(): - if pr.head.sha == event.workflow_run.head_commit.id: - use_pr = pr - break - if not use_pr: - logging.error(f"No PR found for hash: {event.workflow_run.head_commit.id}") - sys.exit(0) - github_headers = { - "Authorization": f"token {settings.input_token.get_secret_value()}" - } - url = f"{github_api}/repos/{settings.github_repository}/issues/{use_pr.number}/comments" - logging.info(f"Using comments URL: {url}") - response = httpx.post( - url, - headers=github_headers, - json={ - "body": f"πŸ“ Docs preview for commit {use_pr.head.sha} at: {settings.input_deploy_url}" - }, - ) - if not (200 <= response.status_code <= 300): - logging.error(f"Error posting comment: {response.text}") - sys.exit(1) - logging.info("Finished") diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 8291f117f1..a38691714e 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -18,7 +18,7 @@ jobs: docs: ${{ steps.filter.outputs.docs }} steps: - uses: actions/checkout@v4 - # For pull requests it's not necessary to checkout the code but for master it is + # For pull requests it's not necessary to checkout the code but for the main branch it is - uses: dorny/paths-filter@v3 id: filter with: @@ -28,9 +28,12 @@ jobs: - docs/** - docs_src/** - requirements-docs.txt + - requirements-docs-insiders.txt - pyproject.toml - mkdocs.yml - mkdocs.insiders.yml + - mkdocs.maybe-insiders.yml + - mkdocs.no-insiders.yml - .github/workflows/build-docs.yml - .github/workflows/deploy-docs.yml @@ -49,31 +52,27 @@ jobs: uses: actions/setup-python@v5 with: python-version: "3.11" - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v02 + key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt', 'requirements-docs-insiders.txt') }}-v02 - name: Install docs extras if: steps.cache.outputs.cache-hit != 'true' run: pip install -r requirements-docs.txt - name: Install Material for MkDocs Insiders if: ( github.event_name != 'pull_request' || github.secret_source == 'Actions' ) && steps.cache.outputs.cache-hit != 'true' - run: | - pip install git+https://${{ secrets.TYPER_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git - pip install git+https://${{ secrets.TYPER_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/griffe-typing-deprecated.git - pip install git+https://${{ secrets.TYPER_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/mkdocstrings-python.git - - uses: actions/cache@v3 + run: pip install -r requirements-docs-insiders.txt + env: + TOKEN: ${{ secrets.TYPER_MKDOCS_MATERIAL_INSIDERS }} + - uses: actions/cache@v4 with: key: mkdocs-cards-${{ github.ref }}-v1 path: .cache + - name: Verify README + run: python ./scripts/docs.py verify-readme - name: Build Docs - if: github.event_name == 'pull_request' && github.secret_source != 'Actions' - run: python -m mkdocs build - - name: Build Docs with Insiders - if: ( github.event_name != 'pull_request' || github.secret_source == 'Actions' ) - run: python -m mkdocs build --config-file mkdocs.insiders.yml - + run: python ./scripts/docs.py build - uses: actions/upload-artifact@v4 with: name: docs-site diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 206d1199e1..28f54d90db 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -6,6 +6,12 @@ on: types: - completed +permissions: + deployments: write + issues: write + pull-requests: write + statuses: write + jobs: deploy-docs: runs-on: ubuntu-latest @@ -15,6 +21,25 @@ jobs: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - uses: actions/cache@v4 + id: cache + with: + path: ${{ env.pythonLocation }} + key: ${{ runner.os }}-python-github-actions-${{ env.pythonLocation }}-${{ hashFiles('requirements-github-actions.txt') }}-v01 + - name: Install GitHub Actions dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: pip install -r requirements-github-actions.txt + - name: Deploy Docs Status Pending + run: python ./scripts/deploy_docs_status.py + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMMIT_SHA: ${{ github.event.workflow_run.head_sha }} + RUN_ID: ${{ github.run_id }} + - name: Clean site run: | rm -rf ./site @@ -39,8 +64,10 @@ jobs: gitHubToken: ${{ secrets.GITHUB_TOKEN }} branch: ${{ ( github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'master' && 'main' ) || ( github.event.workflow_run.head_sha ) }} - name: Comment Deploy - if: steps.deploy.outputs.url != '' - uses: ./.github/actions/comment-docs-preview-in-pr - with: - token: ${{ secrets.GITHUB_TOKEN }} - deploy_url: "${{ steps.deploy.outputs.url }}" + run: python ./scripts/deploy_docs_status.py + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DEPLOY_URL: ${{ steps.deploy.outputs.url }} + COMMIT_SHA: ${{ github.event.workflow_run.head_sha }} + RUN_ID: ${{ github.run_id }} + IS_DONE: "true" diff --git a/.github/workflows/issue-manager.yml b/.github/workflows/issue-manager.yml index 31bf065b01..f6e912a23b 100644 --- a/.github/workflows/issue-manager.yml +++ b/.github/workflows/issue-manager.yml @@ -14,6 +14,9 @@ on: - labeled workflow_dispatch: +permissions: + issues: write + jobs: issue-manager: if: github.repository_owner == 'tiangolo' diff --git a/.github/workflows/test-redistribute.yml b/.github/workflows/test-redistribute.yml index a2d92c788e..9b7847c1d6 100644 --- a/.github/workflows/test-redistribute.yml +++ b/.github/workflows/test-redistribute.yml @@ -57,3 +57,15 @@ jobs: run: | cd dist pip wheel --no-deps typer*.tar.gz + + # https://github.com/marketplace/actions/alls-green#why + test-redistribute-alls-green: # This job does nothing and is only used for the branch protection + if: always() + needs: + - test-redistribute + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db194b150b..5030d0bfdd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,7 +44,7 @@ jobs: # Issue ref: https://github.com/actions/setup-python/issues/436 # cache: "pip" # cache-dependency-path: pyproject.toml - - uses: actions/cache@v3 + - uses: actions/cache@v4 if: ${{ runner.os != 'macOS' }} id: cache with: diff --git a/.gitignore b/.gitignore index a18be48595..f60aaafb66 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ htmlcov .pytest_cache coverage.xml .coverage* +.cache diff --git a/README.md b/README.md index 6bb4983a9f..1e9077ebe4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@

- Typer + Typer +

Typer, build great CLIs. Easy to code. Based on Python type hints. diff --git a/docs/alternatives.md b/docs/alternatives.md index 1938bb9944..656a4ef660 100644 --- a/docs/alternatives.md +++ b/docs/alternatives.md @@ -1,3 +1,5 @@ +# Alternatives, Inspiration and Comparisons + What inspired **Typer**, how it compares to other alternatives and what it learned from them. ## Intro @@ -14,8 +16,11 @@ There have been many tools created before that have helped inspire its creation. It provides a better alternative than reading the *CLI Parameters* as a `list` of `str` and parsing everything by hand. -!!! check "Inspired **Typer** to" - Provide a better development experience than just reading *CLI Parameters* by hand. +/// check | Inspired **Typer** to + +Provide a better development experience than just reading *CLI Parameters* by hand. + +/// ### Hug @@ -23,15 +28,21 @@ Hug is a library to create APIs and CLIs, it uses parameters in functions to dec It inspired a lot of the ideas in **FastAPI** and **Typer**. -!!! check "Inspired **Typer** to" - Use function parameters to declare *CLI arguments* and *CLI options* as it simplifies a lot the development experience. +/// check | Inspired **Typer** to + +Use function parameters to declare *CLI arguments* and *CLI options* as it simplifies a lot the development experience. + +/// ### Plac Plac is another library to create CLIs using parameters in functions, similar to Hug. -!!! check "Inspired **Typer** to" - Provide a simple way to use a function as a command line app, without having to create a complete app, with `typer.run(some_function)`. +/// check | Inspired **Typer** to + +Provide a simple way to use a function as a command line app, without having to create a complete app, with `typer.run(some_function)`. + +/// ### Pydantic @@ -41,8 +52,11 @@ It powers **FastAPI** underneath. It is not used by **Typer**, but it inspired a lot of the design (through **FastAPI**). -!!! check "Inspired **Typer** to" - Use standard Python type annotations to declare types instead of library-specific types or classes and use them for data validation and documentation. +/// check | Inspired **Typer** to + +Use standard Python type annotations to declare types instead of library-specific types or classes and use them for data validation and documentation. + +/// ### Click @@ -56,12 +70,15 @@ It uses decorators on top of functions to modify the actual value of those funct It was built with some great ideas and design using the features available in the language at the time (Python 2.x). -!!! check "**Typer** uses it for" - Everything. πŸš€ +/// check | **Typer** uses it for + +Everything. πŸš€ - **Typer** mainly adds a layer on top of Click, making the code simpler and easier to use, with autocompletion everywhere, etc, but providing all the powerful features of Click underneath. +**Typer** mainly adds a layer on top of Click, making the code simpler and easier to use, with autocompletion everywhere, etc, but providing all the powerful features of Click underneath. - As someone pointed out: "Nice to see it is built on Click but adds the type stuff. Me gusta!" +As someone pointed out: "Nice to see it is built on Click but adds the type stuff. Me gusta!" + +/// ### `click-completion` @@ -71,8 +88,11 @@ Previous versions of **Typer** had deep integrations with `click-completion` and And now **Typer** improved it to have new features, tests, some bug fixes (for issues in plain `click-completion` and Click), and better support for shells, including modern versions of PowerShell (e.g. the default versions that come with Windows 10). -!!! check "Inspired **Typer** to" - Provide auto completion for all the shells. +/// check | Inspired **Typer** to + +Provide auto completion for all the shells. + +/// ### FastAPI diff --git a/docs/contributing.md b/docs/contributing.md index dd038fc408..a4a158543a 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,3 +1,5 @@ +# Development - Contributing + First, you might want to see the basic ways to [help Typer and get help](help-typer.md){.internal-link target=_blank}. ## Developing @@ -22,70 +24,83 @@ That will create a directory `./env/` with the Python binaries and then you will Activate the new environment with: -=== "Linux, macOS" +//// tab | Linux, macOS + +

+ +```console +$ source ./env/bin/activate +``` + +
-
+//// - ```console - $ source ./env/bin/activate - ``` +//// tab | Windows PowerShell -
+
-=== "Windows PowerShell" +```console +$ .\env\Scripts\Activate.ps1 +``` -
+
- ```console - $ .\env\Scripts\Activate.ps1 - ``` +//// -
+//// tab | Windows Bash -=== "Windows Bash" +Or if you use Bash for Windows (e.g. Git Bash): - Or if you use Bash for Windows (e.g. Git Bash): +
-
+```console +$ source ./env/Scripts/activate +``` - ```console - $ source ./env/Scripts/activate - ``` +
-
+//// To check it worked, use: -=== "Linux, macOS, Windows Bash" +//// tab | Linux, macOS, Windows Bash + +
+ +```console +$ which pip -
+some/directory/typer/env/bin/pip +``` - ```console - $ which pip +
- some/directory/typer/env/bin/pip - ``` +//// -
+//// tab | Windows PowerShell -=== "Windows PowerShell" +
-
+```console +$ Get-Command pip - ```console - $ Get-Command pip +some/directory/typer/env/bin/pip +``` - some/directory/typer/env/bin/pip - ``` +
-
+//// If it shows the `pip` binary at `env/bin/pip` then it worked. πŸŽ‰ -!!! tip - Every time you install a new package with `pip` under that environment, activate the environment again. +/// tip + +Every time you install a new package with `pip` under that environment, activate the environment again. + +This makes sure that if you use a terminal program installed by that package (like `flit`), you use the one from your local environment and not any other that could be installed globally. - This makes sure that if you use a terminal program installed by that package (like `flit`), you use the one from your local environment and not any other that could be installed globally. +/// ### Flit @@ -107,31 +122,35 @@ Now re-activate the environment to make sure you are using the `flit` you just i And now use `flit` to install the development dependencies: -=== "Linux, macOS" +//// tab | Linux, macOS + +
+ +```console +$ flit install --deps develop --symlink -
+---> 100% +``` - ```console - $ flit install --deps develop --symlink +
- ---> 100% - ``` +//// -
+//// tab | Windows -=== "Windows" +If you are on Windows, use `--pth-file` instead of `--symlink`: - If you are on Windows, use `--pth-file` instead of `--symlink`: +
-
+```console +$ flit install --deps develop --pth-file - ```console - $ flit install --deps develop --pth-file +---> 100% +``` - ---> 100% - ``` +
-
+//// It will install all the dependencies and your local Typer in your local environment. diff --git a/docs/css/termynal.css b/docs/css/termynal.css index af2fbe6700..8534f91021 100644 --- a/docs/css/termynal.css +++ b/docs/css/termynal.css @@ -26,6 +26,7 @@ position: relative; -webkit-box-sizing: border-box; box-sizing: border-box; + /* Custom line-height */ line-height: 1.2; } diff --git a/docs/features.md b/docs/features.md index f1fb6adef6..5a8643fa35 100644 --- a/docs/features.md +++ b/docs/features.md @@ -1,3 +1,5 @@ +# Features + ## Design based on **FastAPI** @@ -48,27 +50,33 @@ The resulting CLI apps created with **Typer** have the nice features of many "pr * Automatic command and subcommand structure handling (you will see more about subcommands in the Tutorial - User Guide). * Automatic completion for the CLI app in all operating systems, in all the shells (Bash, Zsh, Fish, PowerShell), so that the final user of your app can just hit TAB and get the available options or subcommands. * -!!! note "* Auto completion" - Auto completion works when you create a package (installable with `pip`). Or when using the `typer` command. +/// note | * Auto completion + +Auto completion works when you create a package (installable with `pip`). Or when using the `typer` command. + +**Typer** uses `shellingham` to auto-detect the current shell when installing completion. If you don't want to include `shellingham`, install `typer-slim`. + +**Typer** will automatically create 2 *CLI options*: + +* `--install-completion`: Install completion for the current shell. +* `--show-completion`: Show completion for the current shell, to copy it or customize the installation. - **Typer** uses `shellingham` to auto-detect the current shell when installing completion. If you don't want to include `shellingham`, install `typer-slim`. +If you didn't add `shellingham` (if you installed `pip install typer-slim`) those *CLI options* take a value with the name of the shell to install completion for, e.g.: - **Typer** will automatically create 2 *CLI options*: +* `--install-completion bash`. +* `--show-completion powershell`. - * `--install-completion`: Install completion for the current shell. - * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. +Then you can tell the user to install completion after installing your CLI program and the rest will just work. - If you didn't add `shellingham` (if you installed `pip install typer-slim`) those *CLI options* take a value with the name of the shell to install completion for, e.g.: +/// - * `--install-completion bash`. - * `--show-completion powershell`. +/// tip - Then you can tell the user to install completion after installing your CLI program and the rest will just work. +**Typer**'s completion is implemented internally, it uses ideas and components from Click and ideas from `click-completion`, but it doesn't use `click-completion` and re-implements some of the relevant parts of Click. -!!! tip - **Typer**'s completion is implemented internally, it uses ideas and components from Click and ideas from `click-completion`, but it doesn't use `click-completion` and re-implements some of the relevant parts of Click. +Then it extends those ideas with features and bug fixes. For example, **Typer** programs also support modern versions of PowerShell (e.g. in Windows 10) among all the other shells. - Then it extends those ideas with features and bug fixes. For example, **Typer** programs also support modern versions of PowerShell (e.g. in Windows 10) among all the other shells. +/// ## The power of Click diff --git a/docs/help-typer.md b/docs/help-typer.md index 221492db38..11596d7024 100644 --- a/docs/help-typer.md +++ b/docs/help-typer.md @@ -1,3 +1,5 @@ +# Help Typer - Get Help + Are you liking **Typer**? Would you like to help Typer, other users, and the author? @@ -155,12 +157,15 @@ And if there's any other style or consistency need, I'll ask directly for that, * Then **comment** saying that you did that, that's how I will know you really checked it. -!!! info - Unfortunately, I can't simply trust PRs that just have several approvals. +/// info + +Unfortunately, I can't simply trust PRs that just have several approvals. + +Several times it has happened that there are PRs with 3, 5 or more approvals, probably because the description is appealing, but when I check the PRs, they are actually broken, have a bug, or don't solve the problem they claim to solve. πŸ˜… - Several times it has happened that there are PRs with 3, 5 or more approvals, probably because the description is appealing, but when I check the PRs, they are actually broken, have a bug, or don't solve the problem they claim to solve. πŸ˜… +So, it's really important that you actually read and run the code, and let me know in the comments that you did. πŸ€“ - So, it's really important that you actually read and run the code, and let me know in the comments that you did. πŸ€“ +/// * If the PR can be simplified in a way, you can ask for that, but there's no need to be too picky, there might be a lot of subjective points of view (and I will have my own as well πŸ™ˆ), so it's better if you can focus on the fundamental things. @@ -207,10 +212,13 @@ If you can help me with that, **you are helping me maintain Typer** and making s Join the πŸ‘₯ FastAPI and Friends Discord chat server πŸ‘₯ and hang out with others in the community. There's a `#typer` channel. -!!! tip - For questions, ask them in GitHub Discussions, there's a much better chance you will receive help there. +/// tip + +For questions, ask them in GitHub Discussions, there's a much better chance you will receive help there. + +Use the chat only for other general conversations. - Use the chat only for other general conversations. +/// ### Don't use the chat for questions diff --git a/docs/img/favicon.png b/docs/img/favicon.png old mode 100755 new mode 100644 index b5ce368d78..05752c5c07 Binary files a/docs/img/favicon.png and b/docs/img/favicon.png differ diff --git a/docs/img/github-social-preview.png b/docs/img/github-social-preview.png index 73674f2e24..12ec338123 100644 Binary files a/docs/img/github-social-preview.png and b/docs/img/github-social-preview.png differ diff --git a/docs/img/github-social-preview.svg b/docs/img/github-social-preview.svg index 3743f3ceff..dd99136570 100644 --- a/docs/img/github-social-preview.svg +++ b/docs/img/github-social-preview.svg @@ -1,22 +1,22 @@ + inkscape:export-ydpi="96" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + inkscape:current-layer="g818" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="mm" /> + id="defs2"> + + + @@ -63,32 +102,71 @@ - + Typer - + style="font-style:normal;font-weight:normal;font-size:127.57px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#1a1a1a;fill-opacity:1;stroke:none;stroke-width:3.18925" + xml:space="preserve">Typer + + + + + + + Build great CLIs. Easy to code. Based on Python type hints. diff --git a/docs/img/icon-black.svg b/docs/img/icon-black.svg deleted file mode 100644 index bc987f38b6..0000000000 --- a/docs/img/icon-black.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/img/icon-square.svg b/docs/img/icon-square.svg new file mode 100644 index 0000000000..8e2b3fcd1b --- /dev/null +++ b/docs/img/icon-square.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/docs/img/icon-white.svg b/docs/img/icon-white.svg deleted file mode 100644 index 1de612ccd4..0000000000 --- a/docs/img/icon-white.svg +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - diff --git a/docs/img/icon.svg b/docs/img/icon.svg new file mode 100644 index 0000000000..6bdf83703d --- /dev/null +++ b/docs/img/icon.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/docs/img/logo-margin/logo-margin-vector.svg b/docs/img/logo-margin/logo-margin-vector.svg index 815a4e77fc..ef28325eb0 100644 --- a/docs/img/logo-margin/logo-margin-vector.svg +++ b/docs/img/logo-margin/logo-margin-vector.svg @@ -1,39 +1,15 @@ - + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> image/svg+xml - @@ -56,33 +31,43 @@ id="rect824" style="opacity:0.98000004;fill:none;fill-opacity:1;stroke-width:0.42965442" /> - - - - + id="g818" + transform="translate(-5.3444232)"> + style="font-weight:bold;font-size:127.57px;line-height:1.25;font-family:'Ubuntu Mono';-inkscape-font-specification:'Ubuntu Mono Bold';letter-spacing:0px;word-spacing:0px;stroke-width:3.18925" + d="m 294.86852,68.451101 v 13.01214 H 274.07461 V 147.41693 H 258.25593 V 81.463241 h -20.79391 v -13.01214 z m 63.40204,19.00793 q -2.42383,8.41962 -4.72009,16.584099 -2.16869,8.03691 -4.59252,15.81868 -2.42383,7.6542 -5.23037,15.05326 -2.67897,7.39906 -5.86822,14.41541 -2.42383,5.1028 -4.84766,8.80233 -2.29626,3.69953 -5.23037,5.99579 -2.80654,2.42383 -6.3785,3.57196 -3.44439,1.14813 -8.16448,1.14813 -3.95467,0 -7.27149,-0.63785 -3.18925,-0.63785 -5.35794,-1.65841 l 2.93411,-13.13971 q 2.5514,1.14813 4.46495,1.53084 2.04112,0.51028 4.33738,0.51028 4.59252,0 7.39906,-3.06168 2.80654,-3.06168 4.46495,-7.27149 -5.61308,-11.22616 -11.22616,-25.64157 -5.61308,-14.54298 -10.2056,-32.020069 h 16.32896 q 1.14813,4.72009 2.5514,10.07803 1.53084,5.357939 3.18925,10.715879 1.65841,5.35794 3.44439,10.58831 1.91355,5.1028 3.8271,9.56775 1.2757,-4.46495 2.67897,-9.56775 1.40327,-5.23037 2.67897,-10.46074 1.2757,-5.35794 2.42383,-10.715879 1.2757,-5.35794 2.29626,-10.2056 z m 47.4558,30.489229 q 0,-8.03691 -3.18925,-13.13971 -3.18925,-5.230369 -9.69532,-5.230369 -1.78598,0 -3.8271,0.25514 -2.04112,0.12757 -3.44439,0.255139 v 32.91306 q 1.53084,1.02056 4.08224,1.65841 2.5514,0.63785 5.1028,0.63785 5.61308,0 8.29205,-4.46495 2.67897,-4.59252 2.67897,-12.88457 z m 15.94625,-0.51028 q 0,6.88878 -1.53084,12.757 -1.53084,5.74065 -4.46495,9.95046 -2.93411,4.08224 -7.39906,6.3785 -4.46495,2.29626 -10.33317,2.29626 -5.99579,0 -12.37429,-2.93411 v 22.57989 H 369.87919 V 89.372581 q 4.33738,-1.40327 10.58831,-2.29626 6.3785,-0.89299 12.50186,-0.89299 13.90513,0 21.30419,8.41962 7.39906,8.419619 7.39906,22.835029 z m 7.90909,0.51028 q 0,-7.90934 2.42383,-13.90513 2.42383,-5.995789 6.3785,-9.950459 3.95467,-4.08224 9.05747,-6.12336 5.1028,-2.04112 10.46074,-2.04112 13.26728,0 20.15606,7.90934 6.88878,7.781769 6.88878,22.835029 0,1.53084 -0.12757,3.18925 0,1.65841 -0.12757,2.67897 h -38.90885 q 0,5.86822 4.84766,9.31261 4.84766,3.31682 12.50186,3.31682 4.72009,0 8.9299,-1.02056 4.33738,-1.02056 7.27149,-2.04112 l 2.16869,13.39485 q -4.08224,1.40327 -8.67476,2.29626 -4.59252,1.02056 -10.33317,1.02056 -7.6542,0 -13.77756,-1.91355 -5.99579,-2.04112 -10.33317,-5.86822 -4.20981,-3.95467 -6.50607,-9.69532 -2.29626,-5.74065 -2.29626,-13.39485 z m 40.18455,-6.25093 q 0,-2.42383 -0.63785,-4.59252 -0.63785,-2.29626 -2.04112,-4.08224 -1.40327,-1.78598 -3.57196,-2.80654 -2.16869,-1.148129 -5.35794,-1.148129 -3.06168,0 -5.35794,1.020559 -2.16869,1.02056 -3.69953,2.80654 -1.40327,1.78598 -2.29626,4.08224 -0.76542,2.29626 -1.02056,4.72009 z m 75.39363,-8.29205 q -1.53084,-0.38271 -3.69953,-0.76542 -2.04112,-0.38271 -4.20981,-0.63785 -2.16869,-0.38271 -4.20981,-0.51028 -2.04112,-0.12757 -3.44439,-0.12757 -3.31682,0 -6.50607,0.38271 -3.18925,0.25514 -6.50607,1.14813 v 44.52193 H 500.76552 V 91.413701 q 6.25093,-2.29626 12.757,-3.69953 6.63364,-1.40327 15.43597,-1.40327 1.2757,0 3.57196,0.12757 2.42383,0.12757 5.1028,0.51028 2.67897,0.25514 5.35794,0.76542 2.80654,0.38271 4.97523,1.14813 z" + id="text861" + aria-label="Typer" /> + + + + + + - diff --git a/docs/img/logo-margin/logo-margin-white-vector.svg b/docs/img/logo-margin/logo-margin-white-vector.svg new file mode 100644 index 0000000000..d4c32dddc4 --- /dev/null +++ b/docs/img/logo-margin/logo-margin-white-vector.svg @@ -0,0 +1,73 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/docs/img/logo-margin/logo-margin-white.svg b/docs/img/logo-margin/logo-margin-white.svg new file mode 100644 index 0000000000..b758dc2481 --- /dev/null +++ b/docs/img/logo-margin/logo-margin-white.svg @@ -0,0 +1,78 @@ + + + + + + + image/svg+xml + + + + + + + Typer + + + + + + + + diff --git a/docs/img/logo-margin/logo-margin.svg b/docs/img/logo-margin/logo-margin.svg index a7cf9b14f5..4501f53abd 100644 --- a/docs/img/logo-margin/logo-margin.svg +++ b/docs/img/logo-margin/logo-margin.svg @@ -1,39 +1,15 @@ - + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> image/svg+xml - @@ -62,17 +37,42 @@ id="text861" y="147.41693" x="234.27277" - style="font-style:normal;font-weight:normal;font-size:127.57019043px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3.189255" + style="font-style:normal;font-weight:normal;font-size:127.57px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3.18925" xml:space="preserve">Typer - + id="tspan859">Typer + + + + + + diff --git a/docs/index.md b/docs/index.md index 6bb4983a9f..d8a6addb5f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,12 @@ + +

- Typer + Typer + + Typer +

Typer, build great CLIs. Easy to code. Based on Python type hints. diff --git a/docs/js/custom.js b/docs/js/custom.js index 0dda9fdd54..ef64c612a9 100644 --- a/docs/js/custom.js +++ b/docs/js/custom.js @@ -110,4 +110,6 @@ async function main() { setupTermynal() } -main() +document$.subscribe(() => { + main() +}) diff --git a/docs/js/termynal.js b/docs/js/termynal.js index 4ac32708a3..45bb371c83 100644 --- a/docs/js/termynal.js +++ b/docs/js/termynal.js @@ -249,7 +249,6 @@ class Termynal { attrs += `${this.pfx}-${prop}="${line[prop]}" ` } } - return attrs; } } diff --git a/docs/release-notes.md b/docs/release-notes.md index d9c26e247f..c6687d72df 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,3 +1,5 @@ +# Release Notes + ## Latest Changes ### Features @@ -6,6 +8,24 @@ ### Internal +* πŸ‘· Upgrade build docs configs. PR [#914](https://github.com/tiangolo/typer/pull/914) by [@tiangolo](https://github.com/tiangolo). +* πŸ”§ Update MkDocs to have titles in Markdown files instead of config. PR [#913](https://github.com/tiangolo/typer/pull/913) by [@tiangolo](https://github.com/tiangolo). +* πŸ‘· Add alls-green for test-redistribute. PR [#911](https://github.com/tiangolo/typer/pull/911) by [@tiangolo](https://github.com/tiangolo). +* πŸ‘· Update docs-previews to handle no docs changes. PR [#912](https://github.com/tiangolo/typer/pull/912) by [@tiangolo](https://github.com/tiangolo). +* πŸ‘·πŸ» Show docs deployment status and preview URLs in comment. PR [#910](https://github.com/tiangolo/typer/pull/910) by [@tiangolo](https://github.com/tiangolo). +* πŸ”§ Enable auto dark mode from system. PR [#908](https://github.com/tiangolo/typer/pull/908) by [@tiangolo](https://github.com/tiangolo). +* πŸ’„ Add dark mode logo. PR [#907](https://github.com/tiangolo/typer/pull/907) by [@tiangolo](https://github.com/tiangolo). +* πŸ”§ Update tabs and admonitions with new syntax and new MkDocs features. PR [#906](https://github.com/tiangolo/typer/pull/906) by [@tiangolo](https://github.com/tiangolo). +* πŸ”§ Enable MkDocs Material features. PR [#905](https://github.com/tiangolo/typer/pull/905) by [@tiangolo](https://github.com/tiangolo). +* πŸ”§ Enable dark mode for docs. PR [#904](https://github.com/tiangolo/typer/pull/904) by [@tiangolo](https://github.com/tiangolo). +* βž– Do not install jieba for MkDocs Material as there are no chinese translations. PR [#903](https://github.com/tiangolo/typer/pull/903) by [@tiangolo](https://github.com/tiangolo). +* πŸ™ˆ Add MkDocs Material cache to gitignore. PR [#902](https://github.com/tiangolo/typer/pull/902) by [@tiangolo](https://github.com/tiangolo). +* πŸ”¨ Update lint script. PR [#901](https://github.com/tiangolo/typer/pull/901) by [@tiangolo](https://github.com/tiangolo). +* πŸ”§ Update MkDocs configs and docs build setup. PR [#900](https://github.com/tiangolo/typer/pull/900) by [@tiangolo](https://github.com/tiangolo). +* ⬆ Bump actions/cache from 3 to 4. PR [#839](https://github.com/tiangolo/typer/pull/839) by [@dependabot[bot]](https://github.com/apps/dependabot). +* 🍱 Update Typer icon and logo. PR [#899](https://github.com/tiangolo/typer/pull/899) by [@tiangolo](https://github.com/tiangolo). +* πŸ‘· Update issue-manager.yml GitHub Action permissions. PR [#897](https://github.com/tiangolo/typer/pull/897) by [@tiangolo](https://github.com/tiangolo). +* πŸ‘· Refactor GitHub Action to comment docs deployment URLs and update token, preparing for GitHub org. PR [#896](https://github.com/tiangolo/typer/pull/896) by [@tiangolo](https://github.com/tiangolo). * πŸ”¨ Update docs Termynal scripts to not include line nums for local dev. PR [#882](https://github.com/tiangolo/typer/pull/882) by [@tiangolo](https://github.com/tiangolo). * ⬆ Bump black from 23.3.0 to 24.3.0. PR [#837](https://github.com/tiangolo/typer/pull/837) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump pillow from 10.1.0 to 10.3.0. PR [#836](https://github.com/tiangolo/typer/pull/836) by [@dependabot[bot]](https://github.com/apps/dependabot). diff --git a/docs/tutorial/app-dir.md b/docs/tutorial/app-dir.md index 3d09346b22..440d1dc01a 100644 --- a/docs/tutorial/app-dir.md +++ b/docs/tutorial/app-dir.md @@ -1,3 +1,5 @@ +# CLI Application Directory + You can get the application directory where you can, for example, save configuration files with `typer.get_app_dir()`: ```Python hl_lines="9" diff --git a/docs/tutorial/arguments/default.md b/docs/tutorial/arguments/default.md index 8a8f98017f..60a041abb1 100644 --- a/docs/tutorial/arguments/default.md +++ b/docs/tutorial/arguments/default.md @@ -1,3 +1,5 @@ +# CLI Arguments with Default + We can also use the same `typer.Argument()` to set a default value. That way the *CLI argument* will be optional *and also* have a default value. @@ -6,25 +8,35 @@ That way the *CLI argument* will be optional *and also* have a default value. We can also use `typer.Argument()` to make a *CLI argument* have a default value other than `None`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/arguments/default/tutorial001_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="5" - {!> ../docs_src/arguments/default/tutorial001_an.py!} - ``` +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/arguments/default/tutorial001.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="4" - {!> ../docs_src/arguments/default/tutorial001.py!} - ``` +Because now the value will be a `str` passed by the user or the default value of `"Wade Wilson"` which is also a `str`, we know the value will never be `None`, so we don't have to (and shouldn't) use `Optional[str]`. -!!! tip - Because now the value will be a `str` passed by the user or the default value of `"Wade Wilson"` which is also a `str`, we know the value will never be `None`, so we don't have to (and shouldn't) use `Optional[str]`. +Have in mind that the `Optional[something]` tells Python that a value "could be `None`". But the use of `Optional` doesn't affect Typer in any way, e.g. it doesn't tell Typer if a value is required or not. - Have in mind that the `Optional[something]` tells Python that a value "could be `None`". But the use of `Optional` doesn't affect Typer in any way, e.g. it doesn't tell Typer if a value is required or not. +/// Check it: @@ -60,27 +72,37 @@ Hello Camila And we can even make the default value be dynamically generated by passing a function as the `default_factory` argument: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="7-8 11" - {!> ../docs_src/arguments/default/tutorial002_an.py!} - ``` +```Python hl_lines="7-8 11" +{!> ../docs_src/arguments/default/tutorial002_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated + +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="6-7 10" - {!> ../docs_src/arguments/default/tutorial002.py!} - ``` +```Python hl_lines="6-7 10" +{!> ../docs_src/arguments/default/tutorial002.py!} +``` + +//// In this case, we created the function `get_name` that will just return a random `str` each time. And we pass it as the first function argument to `typer.Argument()`. -!!! tip - The word "factory" in `default_factory` is just a fancy way of saying "function that will create the default value". +/// tip + +The word "factory" in `default_factory` is just a fancy way of saying "function that will create the default value". + +/// Check it: diff --git a/docs/tutorial/arguments/envvar.md b/docs/tutorial/arguments/envvar.md index 57d49e84bf..970d1ee92a 100644 --- a/docs/tutorial/arguments/envvar.md +++ b/docs/tutorial/arguments/envvar.md @@ -1,21 +1,30 @@ +# CLI Arguments with Environment Variables + You can also configure a *CLI argument* to read a value from an environment variable if it is not provided in the command line as a *CLI argument*. To do that, use the `envvar` parameter for `typer.Argument()`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/arguments/envvar/tutorial001_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="5" - {!> ../docs_src/arguments/envvar/tutorial001_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="4" - {!> ../docs_src/arguments/envvar/tutorial001.py!} - ``` +```Python hl_lines="4" +{!> ../docs_src/arguments/envvar/tutorial001.py!} +``` + +//// In this case, the *CLI argument* `name` will have a default value of `"World"`, but will also read any value passed to the environment variable `AWESOME_NAME` if no value is provided in the command line: @@ -60,20 +69,27 @@ Hello Mr. Czernobog You are not restricted to a single environment variable, you can declare a list of environment variables that could be used to get a value if it was not passed in the command line: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="6" +{!> ../docs_src/arguments/envvar/tutorial002_an.py!} +``` - ```Python hl_lines="6" - {!> ../docs_src/arguments/envvar/tutorial002_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="4" - {!> ../docs_src/arguments/envvar/tutorial002.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/arguments/envvar/tutorial002.py!} +``` + +//// Check it: @@ -108,20 +124,27 @@ Hello Mr. Anubis By default, environment variables used will be shown in the help text, but you can disable them with `show_envvar=False`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="7" +{!> ../docs_src/arguments/envvar/tutorial003_an.py!} +``` + +//// - ```Python hl_lines="7" - {!> ../docs_src/arguments/envvar/tutorial003_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. - ```Python hl_lines="4" - {!> ../docs_src/arguments/envvar/tutorial003.py!} - ``` +/// + +```Python hl_lines="4" +{!> ../docs_src/arguments/envvar/tutorial003.py!} +``` + +//// Check it: @@ -148,7 +171,10 @@ Hello Mr. Wednesday -!!! note "Technical Details" - In Click applications the env vars are hidden by default. πŸ™ˆ +/// note | Technical Details + +In Click applications the env vars are hidden by default. πŸ™ˆ + +In **Typer** these env vars are shown by default. πŸ‘€ - In **Typer** these env vars are shown by default. πŸ‘€ +/// diff --git a/docs/tutorial/arguments/help.md b/docs/tutorial/arguments/help.md index bbbb5e0eff..6203143871 100644 --- a/docs/tutorial/arguments/help.md +++ b/docs/tutorial/arguments/help.md @@ -1,3 +1,5 @@ +# CLI Arguments with Help + In the *First Steps* section you saw how to add help for a CLI app/command by adding it to a function's docstring. Here's how that last example looked like: @@ -12,20 +14,27 @@ Now that you also know how to use `typer.Argument()`, let's use it to add docume You can use the `help` parameter to add a help text for a *CLI argument*: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/arguments/help/tutorial001_an.py!} +``` + +//// - ```Python hl_lines="5" - {!> ../docs_src/arguments/help/tutorial001_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/arguments/help/tutorial001.py!} +``` - ```Python hl_lines="4" - {!> ../docs_src/arguments/help/tutorial001.py!} - ``` +//// And it will be used in the automatic `--help` option: @@ -50,20 +59,27 @@ Options: And of course, you can also combine that `help` with the docstring: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="5-8" - {!> ../docs_src/arguments/help/tutorial002_an.py!} - ``` +```Python hl_lines="5-8" +{!> ../docs_src/arguments/help/tutorial002_an.py!} +``` + +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="4-7" - {!> ../docs_src/arguments/help/tutorial002.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4-7" +{!> ../docs_src/arguments/help/tutorial002.py!} +``` + +//// And the `--help` option will combine all the information: @@ -90,20 +106,27 @@ Options: If you have a *CLI argument* with a default value, like `"World"`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/arguments/help/tutorial003_an.py!} +``` + +//// - ```Python hl_lines="5" - {!> ../docs_src/arguments/help/tutorial003_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. - ```Python hl_lines="4" - {!> ../docs_src/arguments/help/tutorial003.py!} - ``` +/// + +```Python hl_lines="4" +{!> ../docs_src/arguments/help/tutorial003.py!} +``` + +//// It will show that default value in the help text: @@ -128,20 +151,27 @@ Options: But you can disable that if you want to, with `show_default=False`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="7" +{!> ../docs_src/arguments/help/tutorial004_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="7" - {!> ../docs_src/arguments/help/tutorial004_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// + +```Python hl_lines="4" +{!> ../docs_src/arguments/help/tutorial004.py!} +``` - ```Python hl_lines="4" - {!> ../docs_src/arguments/help/tutorial004.py!} - ``` +//// And then it won't show the default value: @@ -164,29 +194,39 @@ Options: -!!! note "Technical Details" - In Click applications the default values are hidden by default. πŸ™ˆ +/// note | Technical Details - In **Typer** these default values are shown by default. πŸ‘€ +In Click applications the default values are hidden by default. πŸ™ˆ + +In **Typer** these default values are shown by default. πŸ‘€ + +/// ## Custom default string You can use the same `show_default` to pass a custom string (instead of a `bool`) to customize the default value to be shown in the help text: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="9" - {!> ../docs_src/arguments/help/tutorial005_an.py!} - ``` +```Python hl_lines="9" +{!> ../docs_src/arguments/help/tutorial005_an.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="6" - {!> ../docs_src/arguments/help/tutorial005.py!} - ``` +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="6" +{!> ../docs_src/arguments/help/tutorial005.py!} +``` + +//// And it will be used in the help text: @@ -231,20 +271,27 @@ But you can customize it with the `metavar` parameter for `typer.Argument()`. For example, let's say you don't want to have the default of `NAME`, you want to have `username`, in lowercase, and you really want ✨ emojis ✨ everywhere: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/arguments/help/tutorial006_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="5" - {!> ../docs_src/arguments/help/tutorial006_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// + +```Python hl_lines="4" +{!> ../docs_src/arguments/help/tutorial006.py!} +``` - ```Python hl_lines="4" - {!> ../docs_src/arguments/help/tutorial006.py!} - ``` +//// Now the generated help text will have `✨username✨` instead of `NAME`: @@ -270,20 +317,27 @@ You might want to show the help information for *CLI arguments* in different pan If you have installed Rich as described in the docs for [Printing and Colors](../printing.md){.internal-link target=_blank}, you can set the `rich_help_panel` parameter to the name of the panel where you want this *CLI argument* to be shown: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="8 12" +{!> ../docs_src/arguments/help/tutorial007_an.py!} +``` + +//// - ```Python hl_lines="8 12" - {!> ../docs_src/arguments/help/tutorial007_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. - ```Python hl_lines="7 10" - {!> ../docs_src/arguments/help/tutorial007.py!} - ``` +/// + +```Python hl_lines="7 10" +{!> ../docs_src/arguments/help/tutorial007.py!} +``` + +//// Then, if you check the `--help` option, you will see a default panel named "`Arguments`" for the *CLI arguments* that don't have a custom `rich_help_panel`. @@ -326,20 +380,27 @@ If you want, you can make a *CLI argument* **not** show up in the `Arguments` se You will probably not want to do this normally, but it's possible: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="5" - {!> ../docs_src/arguments/help/tutorial008_an.py!} - ``` +```Python hl_lines="5" +{!> ../docs_src/arguments/help/tutorial008_an.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="4" - {!> ../docs_src/arguments/help/tutorial008.py!} - ``` +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/arguments/help/tutorial008.py!} +``` + +//// Check it: @@ -359,10 +420,13 @@ Options: -!!! info - Have in mind that the *CLI argument* will still show up in the first line with `Usage`. +/// info + +Have in mind that the *CLI argument* will still show up in the first line with `Usage`. - But it won't show up in the main help text under the `Arguments` section. +But it won't show up in the main help text under the `Arguments` section. + +/// ### Help text for *CLI arguments* in Click @@ -384,5 +448,8 @@ This is also to help you create CLI programs that are ✨ awesome ✨ *by defaul If you want to keep Click's convention in a **Typer** app, you can do it with the `hidden` parameter as described above. -!!! note "Technical Details" - To support `help` in *CLI arguments* **Typer** does a lot of internal work in its own sub-classes of Click's internal classes. +/// note | Technical Details + +To support `help` in *CLI arguments* **Typer** does a lot of internal work in its own sub-classes of Click's internal classes. + +/// diff --git a/docs/tutorial/arguments/index.md b/docs/tutorial/arguments/index.md index 23c97706ce..a52816e457 100644 --- a/docs/tutorial/arguments/index.md +++ b/docs/tutorial/arguments/index.md @@ -1,3 +1,5 @@ +# CLI Arguments + In the next few sections we'll see some ways to modify how *CLI arguments* work. We'll create optional *CLI arguments*, we'll add integrated help for *CLI arguments*, etc. diff --git a/docs/tutorial/arguments/optional.md b/docs/tutorial/arguments/optional.md index 6bda570843..e33b9cdc46 100644 --- a/docs/tutorial/arguments/optional.md +++ b/docs/tutorial/arguments/optional.md @@ -1,3 +1,5 @@ +# Optional CLI Arguments + We said before that *by default*: * *CLI options* are **optional** @@ -44,12 +46,15 @@ Now let's see an alternative way to create the same *CLI argument*: {!> ../docs_src/arguments/optional/tutorial001_an.py!} ``` -!!! info - Typer added support for `Annotated` (and started recommending it) in version 0.9.0. +/// info + +Typer added support for `Annotated` (and started recommending it) in version 0.9.0. - If you have an older version, you would get errors when trying to use `Annotated`. +If you have an older version, you would get errors when trying to use `Annotated`. - Make sure you upgrade the Typer version to at least 0.9.0 before using `Annotated`. +Make sure you upgrade the Typer version to at least 0.9.0 before using `Annotated`. + +/// Before, you had this function parameter: @@ -122,8 +127,11 @@ name: Annotated[Optional[str], typer.Argument()] = None Because we are using `typer.Argument()` **Typer** will know that this is a *CLI argument* (no matter if *required* or *optional*). -!!! tip - By using `Optional` your editor will be able to know that the value *could* be `None`, and will be able to warn you if you do something assuming it is a `str` that would break if it was `None`. +/// tip + +By using `Optional` your editor will be able to know that the value *could* be `None`, and will be able to warn you if you do something assuming it is a `str` that would break if it was `None`. + +/// Check the help: @@ -144,10 +152,13 @@ Options: -!!! tip - Notice that `NAME` is still a *CLI argument*, it's shown up there in the "`Usage: main.py` ...". +/// tip + +Notice that `NAME` is still a *CLI argument*, it's shown up there in the "`Usage: main.py` ...". + +Also notice that now `[NAME]` has brackets ("`[`" and "`]`") around (before it was just `NAME`) to denote that it's **optional**, not **required**. - Also notice that now `[NAME]` has brackets ("`[`" and "`]`") around (before it was just `NAME`) to denote that it's **optional**, not **required**. +/// Now run it and test it: @@ -167,8 +178,11 @@ Hello Camila -!!! tip - Notice that "`Camila`" here is an optional *CLI argument*, not a *CLI option*, because we didn't use something like "`--name Camila`", we just passed "`Camila`" directly to the program. +/// tip + +Notice that "`Camila`" here is an optional *CLI argument*, not a *CLI option*, because we didn't use something like "`--name Camila`", we just passed "`Camila`" directly to the program. + +/// ## Alternative (old) `typer.Argument()` as the default value @@ -180,8 +194,11 @@ Instead of using `Annotated`, you can use `typer.Argument()` as the default valu {!> ../docs_src/arguments/optional/tutorial001.py!} ``` -!!! tip - Prefer to use the `Annotated` version if possible. +/// tip + +Prefer to use the `Annotated` version if possible. + +/// Before, because `name` didn't have any default value it would be a **required parameter** for the Python function, in Python terms. @@ -203,8 +220,11 @@ Not passing any value to the `default` argument is the same as marking it as req name: str = typer.Argument(default=...) ``` -!!! info - If you hadn't seen that `...` before: it is a special single value, it is part of Python and is called "Ellipsis". +/// info + +If you hadn't seen that `...` before: it is a special single value, it is part of Python and is called "Ellipsis". + +/// ```Python hl_lines="4" {!> ../docs_src/arguments/optional/tutorial003.py!} diff --git a/docs/tutorial/arguments/other-uses.md b/docs/tutorial/arguments/other-uses.md index f7f398f341..1870e9c6c3 100644 --- a/docs/tutorial/arguments/other-uses.md +++ b/docs/tutorial/arguments/other-uses.md @@ -1,3 +1,5 @@ +# Other uses + `typer.Argument()` has several other use cases. Such as for data validation, to enable other features, etc. You will see about these use cases later in the docs. diff --git a/docs/tutorial/commands/arguments.md b/docs/tutorial/commands/arguments.md index 9829082c39..43bc423245 100644 --- a/docs/tutorial/commands/arguments.md +++ b/docs/tutorial/commands/arguments.md @@ -1,3 +1,5 @@ +# Command CLI Arguments + The same way as with a CLI application with a single command, subcommands (or just "commands") can also have their own *CLI arguments*: ```Python hl_lines="7 12" @@ -28,12 +30,18 @@ Deleting user: Camila -!!! tip - Everything to the *right* of the *command* are *CLI parameters* (*CLI arguments* and *CLI options*) for that command. +/// tip + +Everything to the *right* of the *command* are *CLI parameters* (*CLI arguments* and *CLI options*) for that command. + +/// + +/// note | Technical Details + +Actually, it's everything to the right of that command, *before any subcommand*. -!!! note "Technical Details" - Actually, it's everything to the right of that command, *before any subcommand*. +It's possible to have groups of *subcommands*, it's like if one *command* also had *subcommands*. And then those *subcommands* could have their own *CLI parameters*, taking their own *CLI parameters*. - It's possible to have groups of *subcommands*, it's like if one *command* also had *subcommands*. And then those *subcommands* could have their own *CLI parameters*, taking their own *CLI parameters*. +You will see about them later in another section. - You will see about them later in another section. +/// diff --git a/docs/tutorial/commands/callback.md b/docs/tutorial/commands/callback.md index db8d18f2fd..ca10243c75 100644 --- a/docs/tutorial/commands/callback.md +++ b/docs/tutorial/commands/callback.md @@ -1,3 +1,5 @@ +# Typer Callback + When you create an `app = typer.Typer()` it works as a group of commands. And you can create multiple commands with it. @@ -16,10 +18,13 @@ It's very similar to `@app.command()`, but it declares the *CLI parameters* for Here we create a `callback` with a `--verbose` *CLI option*. -!!! tip - After getting the `--verbose` flag, we modify a global `state`, and we use it in the other commands. +/// tip + +After getting the `--verbose` flag, we modify a global `state`, and we use it in the other commands. + +There are other ways to achieve the same, but this will suffice for this example. - There are other ways to achieve the same, but this will suffice for this example. +/// And as we added a docstring to the callback function, by default it will be extracted and used as the help text. @@ -179,7 +184,10 @@ def cli(): The original function `cli` would be the equivalent of a Typer callback. -!!! note "Technical Details" - When using Click, it converts that `cli` variable to a Click `Group` object. And then the original function no longer exists in that variable. +/// note | Technical Details + +When using Click, it converts that `cli` variable to a Click `Group` object. And then the original function no longer exists in that variable. + +**Typer** doesn't do that, the callback function is not modified, only registered in the `typer.Typer` app. This is intentional, it's part of **Typer**'s design, to allow having editor auto completion and type checks. - **Typer** doesn't do that, the callback function is not modified, only registered in the `typer.Typer` app. This is intentional, it's part of **Typer**'s design, to allow having editor auto completion and type checks. +/// diff --git a/docs/tutorial/commands/context.md b/docs/tutorial/commands/context.md index 51e0a8912e..2600225507 100644 --- a/docs/tutorial/commands/context.md +++ b/docs/tutorial/commands/context.md @@ -1,3 +1,5 @@ +# Using the Context + When you create a **Typer** application it uses Click underneath. And every Click application has a special object called a "Context" that is normally hidden. But you can access the context by declaring a function parameter of type `typer.Context`. @@ -126,5 +128,8 @@ Got extra arg: Berlin -!!! tip - Notice that it saves all the extra *CLI parameters* as a raw `list` of `str`, including the *CLI option* names and values, everything together. +/// tip + +Notice that it saves all the extra *CLI parameters* as a raw `list` of `str`, including the *CLI option* names and values, everything together. + +/// diff --git a/docs/tutorial/commands/help.md b/docs/tutorial/commands/help.md index 0310b36d41..b9501b72ee 100644 --- a/docs/tutorial/commands/help.md +++ b/docs/tutorial/commands/help.md @@ -1,21 +1,30 @@ +# Command Help + The same as before, you can add help for the commands in the docstrings and the *CLI options*. And the `typer.Typer()` application receives a parameter `help` that you can pass with the main help text for your CLI program: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="4 9-11 22 26-30 43 47-51 60-62" +{!> ../docs_src/commands/help/tutorial001_an.py!} +``` - ```Python hl_lines="4 9-11 22 26-30 43 47-51 60-62" - {!> ../docs_src/commands/help/tutorial001_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="3 8-10 20 23-27 39 42-46 55-57" - {!> ../docs_src/commands/help/tutorial001.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="3 8-10 20 23-27 39 42-46 55-57" +{!> ../docs_src/commands/help/tutorial001.py!} +``` + +//// Check it: @@ -91,10 +100,13 @@ Options: -!!! tip - `typer.Typer()` receives several other parameters for other things, we'll see that later. +/// tip + +`typer.Typer()` receives several other parameters for other things, we'll see that later. + +You will also see how to use "Callbacks" later, and those include a way to add this same help message in a function docstring. - You will also see how to use "Callbacks" later, and those include a way to add this same help message in a function docstring. +/// ## Overwrite command help @@ -194,27 +206,37 @@ If you have **Rich** installed as described in [Printing and Colors](../printing Then you can use more formatting in the docstrings and the `help` parameter for *CLI arguments* and *CLI options*. You will see more about it below. πŸ‘‡ -!!! info - By default, `rich_markup_mode` is `None`, which disables any rich text formatting. +/// info + +By default, `rich_markup_mode` is `None`, which disables any rich text formatting. + +/// ### Rich Markup If you set `rich_markup_mode="rich"` when creating the `typer.Typer()` app, you will be able to use Rich Console Markup in the docstring, and even in the help for the *CLI arguments* and options: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="4 10 14-16 21 24 27" +{!> ../docs_src/commands/help/tutorial004_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="4 10 14-16 21 24 27" - {!> ../docs_src/commands/help/tutorial004_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// + +```Python hl_lines="3 9 13-15 20 22 24" +{!> ../docs_src/commands/help/tutorial004.py!} +``` - ```Python hl_lines="3 9 13-15 20 22 24" - {!> ../docs_src/commands/help/tutorial004.py!} - ``` +//// With that, you can use Rich Console Markup to format the text in the docstring for the command `create`, make the word "`create`" bold and green, and even use an emoji. @@ -277,20 +299,27 @@ $ python main.py delete --help If you set `rich_markup_mode="markdown"` when creating the `typer.Typer()` app, you will be able to use Markdown in the docstring: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="4 9 12-20 25 27-28" - {!> ../docs_src/commands/help/tutorial005_an.py!} - ``` +```Python hl_lines="4 9 12-20 25 27-28" +{!> ../docs_src/commands/help/tutorial005_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated + +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="3 7 9-17 22 24-25" - {!> ../docs_src/commands/help/tutorial005.py!} - ``` +```Python hl_lines="3 7 9-17 22 24-25" +{!> ../docs_src/commands/help/tutorial005.py!} +``` + +//// With that, you can use Markdown to format the text in the docstring for the command `create`, make the word "`create`" bold, show a list of items, and even use an emoji. @@ -350,8 +379,11 @@ $ python main.py delete --help -!!! info - Notice that in Markdown you cannot define colors. For colors you might prefer to use Rich markup. +/// info + +Notice that in Markdown you cannot define colors. For colors you might prefer to use Rich markup. + +/// ## Help Panels @@ -363,11 +395,13 @@ If you installed ../docs_src/commands/help/tutorial006.py!} - ``` +```Python hl_lines="22 30 38 46" +{!> ../docs_src/commands/help/tutorial006.py!} +``` + +//// Commands without a panel will be shown in the default panel `Commands`, and the rest will be shown in the next panels: @@ -408,20 +442,27 @@ The same way, you can configure the panels for *CLI arguments* and *CLI options* And of course, in the same application you can also set the `rich_help_panel` for commands. -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="15 21 27 37" +{!> ../docs_src/commands/help/tutorial007_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="15 21 27 37" - {!> ../docs_src/commands/help/tutorial007_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// + +```Python hl_lines="12 16 21 30" +{!> ../docs_src/commands/help/tutorial007.py!} +``` - ```Python hl_lines="12 16 21 30" - {!> ../docs_src/commands/help/tutorial007.py!} - ``` +//// Then if you run the application you will see all the *CLI parameters* in their respective panels. diff --git a/docs/tutorial/commands/index.md b/docs/tutorial/commands/index.md index 1afc7dd1ee..d2693849d7 100644 --- a/docs/tutorial/commands/index.md +++ b/docs/tutorial/commands/index.md @@ -1,3 +1,5 @@ +# Commands + We have seen how to create a CLI program with possibly several *CLI options* and *CLI arguments*. But **Typer** allows you to create CLI programs with several commands (also known as subcommands). @@ -28,8 +30,11 @@ Another command of `git` is `git pull`, it also has some *CLI parameters*. It's like if the same big program `git` had several small programs inside. -!!! tip - A command looks the same as a *CLI argument*, it's just some name without a preceding `--`. But commands have a predefined name, and are used to group different sets of functionalities into the same CLI application. +/// tip + +A command looks the same as a *CLI argument*, it's just some name without a preceding `--`. But commands have a predefined name, and are used to group different sets of functionalities into the same CLI application. + +/// ## Command or subcommand @@ -67,21 +72,27 @@ When you use `typer.run()`, **Typer** is doing more or less the same as above, i * Create a new "`command`" with your function. * Call the same "application" as if it was a function with "`app()`". -!!! info "`@decorator` Info" - That `@something` syntax in Python is called a "decorator". +/// info | `@decorator` Info + +That `@something` syntax in Python is called a "decorator". - You put it on top of a function. Like a pretty decorative hat (I guess that's where the term came from). +You put it on top of a function. Like a pretty decorative hat (I guess that's where the term came from). - A "decorator" takes the function below and does something with it. +A "decorator" takes the function below and does something with it. - In our case, this decorator tells **Typer** that the function below is a "`command`". +In our case, this decorator tells **Typer** that the function below is a "`command`". + +/// Both ways, with `typer.run()` and creating the explicit application, achieve almost the same. -!!! tip - If your use case is solved with just `typer.run()`, that's fine, you don't have to create the explicit `app` and use `@app.command()`, etc. +/// tip + +If your use case is solved with just `typer.run()`, that's fine, you don't have to create the explicit `app` and use `@app.command()`, etc. + +You might want to do that later when your app needs the extra features, but if it doesn't need them yet, that's fine. - You might want to do that later when your app needs the extra features, but if it doesn't need them yet, that's fine. +/// If you run the second example, with the explicit `app`, it works exactly the same: @@ -208,8 +219,11 @@ Deleting user: Hiro Hamada Notice that the help text now shows the 2 commands: `create` and `delete`. -!!! tip - By default, the names of the commands are generated from the function name. +/// tip + +By default, the names of the commands are generated from the function name. + +/// ## Show the help message if no command is given @@ -247,10 +261,13 @@ Commands: If you come from Click, a `typer.Typer` app with subcommands is more or less the equivalent of a Click Group. -!!! note "Technical Details" - A `typer.Typer` app is *not* a Click Group, but it provides the equivalent functionality. And it creates a Click Group when calling it. +/// note | Technical Details + +A `typer.Typer` app is *not* a Click Group, but it provides the equivalent functionality. And it creates a Click Group when calling it. - It is not directly a Group because **Typer** doesn't modify the functions in your code to convert them to another type of object, it only registers them. +It is not directly a Group because **Typer** doesn't modify the functions in your code to convert them to another type of object, it only registers them. + +/// ## Decorator Technical Details @@ -260,7 +277,10 @@ But Typer doesn't modify that function itself, the function is left as is. That means that if your function is simple enough that you could create it without using `typer.Option()` or `typer.Argument()`, you could use the same function for a **Typer** application and a **FastAPI** application putting both decorators on top, or similar tricks. -!!! note "Click Technical Details" - This behavior is a design difference with Click. +/// note | Click Technical Details + +This behavior is a design difference with Click. + +In Click, when you add a `@click.command()` decorator it actually modifies the function underneath and replaces it with an object. - In Click, when you add a `@click.command()` decorator it actually modifies the function underneath and replaces it with an object. +/// diff --git a/docs/tutorial/commands/name.md b/docs/tutorial/commands/name.md index 7d3ddc1a5c..4f0faa047b 100644 --- a/docs/tutorial/commands/name.md +++ b/docs/tutorial/commands/name.md @@ -1,3 +1,5 @@ +# Custom Command Name + By default, the command names are generated from the function name. So, if your function is something like: diff --git a/docs/tutorial/commands/one-or-multiple.md b/docs/tutorial/commands/one-or-multiple.md index cc72a6ba45..5f744c5a2b 100644 --- a/docs/tutorial/commands/one-or-multiple.md +++ b/docs/tutorial/commands/one-or-multiple.md @@ -1,3 +1,5 @@ +# One or Multiple Commands + You might have noticed that if you create a single command, as in the first example: ```Python hl_lines="3 6 12" @@ -35,8 +37,11 @@ Options: -!!! tip - Notice that it doesn't show a command `main`, even though the function name is `main`. +/// tip + +Notice that it doesn't show a command `main`, even though the function name is `main`. + +/// But if you add multiple commands, **Typer** will create one *CLI command* for each one of them: diff --git a/docs/tutorial/commands/options.md b/docs/tutorial/commands/options.md index 1bb3921ef8..a9c21b66b9 100644 --- a/docs/tutorial/commands/options.md +++ b/docs/tutorial/commands/options.md @@ -1,21 +1,30 @@ +# Command CLI Options + Commands can also have their own *CLI options*. In fact, each command can have different *CLI arguments* and *CLI options*: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="8 14-17 27-29 38" +{!> ../docs_src/commands/options/tutorial001_an.py!} +``` - ```Python hl_lines="8 14-17 27-29 38" - {!> ../docs_src/commands/options/tutorial001_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="7 13-14 24 33" - {!> ../docs_src/commands/options/tutorial001.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="7 13-14 24 33" +{!> ../docs_src/commands/options/tutorial001.py!} +``` + +//// Here we have multiple commands, with different *CLI parameters*: @@ -51,8 +60,11 @@ Commands: -!!! tip - Check the command `delete-all`, by default command names are generated from the function name, replacing `_` with `-`. +/// tip + +Check the command `delete-all`, by default command names are generated from the function name, replacing `_` with `-`. + +/// Test it: diff --git a/docs/tutorial/first-steps.md b/docs/tutorial/first-steps.md index 6ef4212dde..53dc5eab4d 100644 --- a/docs/tutorial/first-steps.md +++ b/docs/tutorial/first-steps.md @@ -1,3 +1,5 @@ +# First Steps + ## The simplest example The simplest **Typer** file could look like this: @@ -93,8 +95,11 @@ Hello Camila GutiΓ©rrez -!!! tip - If you need to pass a single value that contains spaces to a *CLI argument*, use quotes (`"`) around it. +/// tip + +If you need to pass a single value that contains spaces to a *CLI argument*, use quotes (`"`) around it. + +/// ## Two CLI arguments @@ -145,16 +150,19 @@ Hello Camila GutiΓ©rrez -!!! tip - Notice that the order is important. The last name has to go after the first name. +/// tip + +Notice that the order is important. The last name has to go after the first name. - If you called it with: +If you called it with: + +``` +$ python main.py GutiΓ©rrez Camila +``` - ``` - $ python main.py GutiΓ©rrez Camila - ``` +your app wouldn't have a way to know which is the `name` and which the `lastname`. It expects the first *CLI argument* to be the `name` and the second *CLI argument* to be the `lastname`. - your app wouldn't have a way to know which is the `name` and which the `lastname`. It expects the first *CLI argument* to be the `name` and the second *CLI argument* to be the `lastname`. +/// ## What is a **CLI option** @@ -214,10 +222,13 @@ So, the main and **most important** difference is that: * *CLI options* **start with `--`** and don't depend on the order * *CLI arguments* depend on the **sequence order** -!!! tip - In this example above the *CLI option* `--size` is just a "flag" or "switch" that will contain a boolean value, `True` or `False`, depending on if it was added to the command or not. +/// tip - This one doesn't receive any values. But *CLI options* can also receive values like *CLI arguments*. You'll see how later. +In this example above the *CLI option* `--size` is just a "flag" or "switch" that will contain a boolean value, `True` or `False`, depending on if it was added to the command or not. + +This one doesn't receive any values. But *CLI options* can also receive values like *CLI arguments*. You'll see how later. + +/// ## Add one *CLI option* @@ -250,8 +261,11 @@ $ python main.py --help -!!! tip - Notice that it automatically creates a `--formal` and a `--no-formal` because it detected that `formal` is a `bool`. +/// tip + +Notice that it automatically creates a `--formal` and a `--no-formal` because it detected that `formal` is a `bool`. + +/// Now call it normally: @@ -309,10 +323,13 @@ $ python main.py --help -!!! tip - Notice the `--lastname`, and notice that it takes a textual value. +/// tip + +Notice the `--lastname`, and notice that it takes a textual value. + +A *CLI option* with a value like `--lastname` (contrary to a *CLI option* without a value, a `bool` flag, like `--formal` or `--size`) takes as its value whatever is at the *right side* of the *CLI option*. - A *CLI option* with a value like `--lastname` (contrary to a *CLI option* without a value, a `bool` flag, like `--formal` or `--size`) takes as its value whatever is at the *right side* of the *CLI option*. +///

@@ -330,8 +347,11 @@ Hello Camila GutiΓ©rrez
-!!! tip - Notice that "`GutiΓ©rrez`" is at the right side of `--lastname`. A *CLI option* with a value takes as its value whatever is at the *right side*. +/// tip + +Notice that "`GutiΓ©rrez`" is at the right side of `--lastname`. A *CLI option* with a value takes as its value whatever is at the *right side*. + +/// And as `--lastname` is now a *CLI option* that doesn't depend on the order, you can pass it before the name: @@ -379,8 +399,11 @@ $ python main.py --help -!!! tip - There is another place to document the specific *CLI options* and *CLI arguments* that will show up next to them in the help text as with `--install-completion` or `--help`, you will learn that later in the tutorial. +/// tip + +There is another place to document the specific *CLI options* and *CLI arguments* that will show up next to them in the help text as with `--install-completion` or `--help`, you will learn that later in the tutorial. + +/// ## Arguments, options, parameters, optional, required @@ -397,25 +420,28 @@ def main(name: str, lastname: str = ""): are called "Python function parameters" or "Python function arguments". -!!! note "Technical Details" - There's actually a very small distinction in Python between "parameter" and "argument". +/// note | Technical Details - It's quite technical... and somewhat pedantic. +There's actually a very small distinction in Python between "parameter" and "argument". - *Parameter* refers to the variable name in a function *declaration*. Like: +It's quite technical... and somewhat pedantic. - ``` - def bring_person(name: str, lastname: str = ""): - pass - ``` +*Parameter* refers to the variable name in a function *declaration*. Like: - *Argument* refers to the value passed when *calling* a function. Like: +``` +def bring_person(name: str, lastname: str = ""): + pass +``` - ``` - person = bring_person("Camila", lastname="GutiΓ©rrez") - ``` +*Argument* refers to the value passed when *calling* a function. Like: - ...but you will probably see them used interchangeably in most of the places (including here). +``` +person = bring_person("Camila", lastname="GutiΓ©rrez") +``` + +...but you will probably see them used interchangeably in most of the places (including here). + +/// #### Python default values @@ -486,7 +512,10 @@ Hello World So you can use it to have auto completion for your own scripts as you continue with the tutorial. -!!! tip - Your CLI application built with **Typer** won't need the `typer` command to have auto completion once you create a Python package. +/// tip + +Your CLI application built with **Typer** won't need the `typer` command to have auto completion once you create a Python package. + +But for short scripts and for learning, before creating a Python package, it might be useful. - But for short scripts and for learning, before creating a Python package, it might be useful. +/// diff --git a/docs/tutorial/index.md b/docs/tutorial/index.md index 6cec65fe23..8051465b10 100644 --- a/docs/tutorial/index.md +++ b/docs/tutorial/index.md @@ -1,3 +1,5 @@ +# Tutorial - User Guide + ## Python types If you need a refresher about how to use Python type hints, check the first part of FastAPI's Python types intro. @@ -75,15 +77,18 @@ Successfully installed typer click shellingham rich By default, `typer` comes with `rich` and `shellingham`. -!!! note - If you are an advanced user and want to opt out of these default extra dependencies, you can instead install `typer-slim`. +/// note + +If you are an advanced user and want to opt out of these default extra dependencies, you can instead install `typer-slim`. - ```bash - pip install typer - ``` +```bash +pip install typer +``` - ...includes the same optional dependencies as: +...includes the same optional dependencies as: + +```bash +pip install "typer-slim[standard]" +``` - ```bash - pip install "typer-slim[standard]" - ``` +/// diff --git a/docs/tutorial/launch.md b/docs/tutorial/launch.md index 90b3767b25..935bd7e632 100644 --- a/docs/tutorial/launch.md +++ b/docs/tutorial/launch.md @@ -1,3 +1,5 @@ +# Launching Applications + You can launch applications from your CLI program with `typer.launch()`. It will launch the appropriate application depending on the URL or file type you pass it: @@ -28,10 +30,13 @@ You can also make the operating system open the file browser indicating where a {!../docs_src/launch/tutorial002.py!} ``` -!!! tip - The rest of the code in this example is just making sure the app directory exists and creating the config file. +/// tip + +The rest of the code in this example is just making sure the app directory exists and creating the config file. + +But the most important part is the `typer.launch(config_file_str, locate=True)` with the argument `locate=True`. - But the most important part is the `typer.launch(config_file_str, locate=True)` with the argument `locate=True`. +/// Check it: diff --git a/docs/tutorial/multiple-values/arguments-with-multiple-values.md b/docs/tutorial/multiple-values/arguments-with-multiple-values.md index 07e6cd888a..b48484c105 100644 --- a/docs/tutorial/multiple-values/arguments-with-multiple-values.md +++ b/docs/tutorial/multiple-values/arguments-with-multiple-values.md @@ -1,3 +1,5 @@ +# CLI Arguments with Multiple Values + *CLI arguments* can also receive multiple values. You can define the type of a *CLI argument* using `typing.List`. @@ -21,30 +23,43 @@ woohoo! -!!! tip - We also declared a final *CLI argument* `celebration`, and it's correctly used even if we pass an arbitrary number of `files` first. +/// tip + +We also declared a final *CLI argument* `celebration`, and it's correctly used even if we pass an arbitrary number of `files` first. + +/// -!!! info - A `List` can only be used in the last command (if there are subcommands), as this will take anything to the right and assume it's part of the expected *CLI arguments*. +/// info + +A `List` can only be used in the last command (if there are subcommands), as this will take anything to the right and assume it's part of the expected *CLI arguments*. + +/// ## *CLI arguments* with tuples If you want a specific number of values and types, you can use a tuple, and it can even have default values: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="8-10" - {!> ../docs_src/multiple_values/arguments_with_multiple_values/tutorial002_an.py!} - ``` +```Python hl_lines="8-10" +{!> ../docs_src/multiple_values/arguments_with_multiple_values/tutorial002_an.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +//// tab | Python 3.7+ non-Annotated + +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="7-8" +{!> ../docs_src/multiple_values/arguments_with_multiple_values/tutorial002.py!} +``` - ```Python hl_lines="7-8" - {!> ../docs_src/multiple_values/arguments_with_multiple_values/tutorial002.py!} - ``` +//// Check it: diff --git a/docs/tutorial/multiple-values/index.md b/docs/tutorial/multiple-values/index.md index ee1bfa4da7..b511eef10a 100644 --- a/docs/tutorial/multiple-values/index.md +++ b/docs/tutorial/multiple-values/index.md @@ -1,3 +1,5 @@ +# Multiple Values + There are several ways to declare multiple values for *CLI options* and *CLI arguments*. We'll see them in the next short sections. diff --git a/docs/tutorial/multiple-values/multiple-options.md b/docs/tutorial/multiple-values/multiple-options.md index a7c5c88fb6..0c876eab52 100644 --- a/docs/tutorial/multiple-values/multiple-options.md +++ b/docs/tutorial/multiple-values/multiple-options.md @@ -1,23 +1,32 @@ +# Multiple CLI Options + You can declare a *CLI option* that can be used multiple times, and then get all the values. For example, let's say you want to accept several users in a single execution. For this, use the standard Python `typing.List` to declare it as a `list` of `str`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="1 7" +{!> ../docs_src/multiple_values/multiple_options/tutorial001_an.py!} +``` + +//// - ```Python hl_lines="1 7" - {!> ../docs_src/multiple_values/multiple_options/tutorial001_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="1 6" +{!> ../docs_src/multiple_values/multiple_options/tutorial001.py!} +``` - ```Python hl_lines="1 6" - {!> ../docs_src/multiple_values/multiple_options/tutorial001.py!} - ``` +//// You will receive the values as you declared them, as a `list` of `str`. @@ -51,20 +60,27 @@ Processing user: Morty The same way, you can use other types and they will be converted by **Typer** to their declared type: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="7" - {!> ../docs_src/multiple_values/multiple_options/tutorial002_an.py!} - ``` +```Python hl_lines="7" +{!> ../docs_src/multiple_values/multiple_options/tutorial002_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="6" +{!> ../docs_src/multiple_values/multiple_options/tutorial002.py!} +``` - ```Python hl_lines="6" - {!> ../docs_src/multiple_values/multiple_options/tutorial002.py!} - ``` +//// Check it: diff --git a/docs/tutorial/multiple-values/options-with-multiple-values.md b/docs/tutorial/multiple-values/options-with-multiple-values.md index feeb45eea9..1d3f5deff4 100644 --- a/docs/tutorial/multiple-values/options-with-multiple-values.md +++ b/docs/tutorial/multiple-values/options-with-multiple-values.md @@ -1,23 +1,32 @@ +# CLI Options with Multiple Values + You can also declare a *CLI option* that takes several values of different types. You can set the number of values and types to anything you want, but it has to be a fixed number of values. For this, use the standard Python `typing.Tuple`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="1 7" +{!> ../docs_src/multiple_values/options_with_multiple_values/tutorial001_an.py!} +``` - ```Python hl_lines="1 7" - {!> ../docs_src/multiple_values/options_with_multiple_values/tutorial001_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="1 6" - {!> ../docs_src/multiple_values/options_with_multiple_values/tutorial001.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="1 6" +{!> ../docs_src/multiple_values/options_with_multiple_values/tutorial001.py!} +``` + +//// Each of the internal types defines the type of each value in the tuple. @@ -59,10 +68,13 @@ coins = user[1] is_wizard = user[2] ``` -!!! tip - Notice that the default is a tuple with `(None, None, None)`. +/// tip + +Notice that the default is a tuple with `(None, None, None)`. + +You cannot simply use `None` here as the default because Click doesn't support it. - You cannot simply use `None` here as the default because Click doesn't support it. +/// ## Check it diff --git a/docs/tutorial/options-autocompletion.md b/docs/tutorial/options-autocompletion.md index 7ac42dff8d..43777d04fb 100644 --- a/docs/tutorial/options-autocompletion.md +++ b/docs/tutorial/options-autocompletion.md @@ -1,3 +1,5 @@ +# CLI Option autocompletion + As you have seen, apps built with **Typer** have completion in your shell that works when you create a Python package or using the `typer` command. It normally completes *CLI options*, *CLI arguments*, and subcommands (that you will learn about later). @@ -14,20 +16,27 @@ To check it quickly without creating a new Python package, use the `typer` comma Then let's create small example program: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python +{!> ../docs_src/options_autocompletion/tutorial001_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python - {!> ../docs_src/options_autocompletion/tutorial001_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python - {!> ../docs_src/options_autocompletion/tutorial001.py!} - ``` +```Python +{!> ../docs_src/options_autocompletion/tutorial001.py!} +``` + +//// And let's try it with the `typer` command to get completion: @@ -61,20 +70,27 @@ Right now we get completion for the *CLI option* names, but not for the values. We can provide completion for the values creating an `autocompletion` function, similar to the `callback` functions from [CLI Option Callback and Context](./options/callback-and-context.md){.internal-link target=_blank}: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5-6 15" +{!> ../docs_src/options_autocompletion/tutorial002_an.py!} +``` + +//// - ```Python hl_lines="5-6 15" - {!> ../docs_src/options_autocompletion/tutorial002_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. - ```Python hl_lines="4-5 14" - {!> ../docs_src/options_autocompletion/tutorial002.py!} - ``` +/// + +```Python hl_lines="4-5 14" +{!> ../docs_src/options_autocompletion/tutorial002.py!} +``` + +//// We return a `list` of strings from the `complete_name()` function. @@ -103,20 +119,27 @@ Modify the `complete_name()` function to receive a parameter of type `str`, it w Then we can check and return only the values that start with the incomplete value from the command line: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="7-12" +{!> ../docs_src/options_autocompletion/tutorial003_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="7-12" - {!> ../docs_src/options_autocompletion/tutorial003_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="6-11" - {!> ../docs_src/options_autocompletion/tutorial003.py!} - ``` +```Python hl_lines="6-11" +{!> ../docs_src/options_autocompletion/tutorial003.py!} +``` + +//// Now let's try it: @@ -133,12 +156,15 @@ Camila Carlos Now we are only returning the valid values, that start with `Ca`, we are no longer returning `Sebastian` as a completion option. -!!! tip - You have to declare the incomplete value of type `str` and that's what you will receive in the function. +/// tip + +You have to declare the incomplete value of type `str` and that's what you will receive in the function. - No matter if the actual value will be an `int`, or something else, when doing completion, you will only get a `str` as the incomplete value. +No matter if the actual value will be an `int`, or something else, when doing completion, you will only get a `str` as the incomplete value. - And the same way, you can only return `str`, not `int`, etc. +And the same way, you can only return `str`, not `int`, etc. + +/// ## Add help to completions @@ -152,32 +178,45 @@ In the `complete_name()` function, instead of providing one `str` per completion So, in the end, we return a `list` of `tuples` of `str`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="4-8 11-17" +{!> ../docs_src/options_autocompletion/tutorial004_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated + +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="3-7 10-16" +{!> ../docs_src/options_autocompletion/tutorial004.py!} +``` + +//// - ```Python hl_lines="4-8 11-17" - {!> ../docs_src/options_autocompletion/tutorial004_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +If you want to have help text for each item, make sure each item in the list is a `tuple`. Not a `list`. - !!! tip - Prefer to use the `Annotated` version if possible. +Click checks specifically for a `tuple` when extracting the help text. - ```Python hl_lines="3-7 10-16" - {!> ../docs_src/options_autocompletion/tutorial004.py!} - ``` +So in the end, the return will be a `list` (or other iterable) of `tuples` of 2 `str`. -!!! tip - If you want to have help text for each item, make sure each item in the list is a `tuple`. Not a `list`. +/// - Click checks specifically for a `tuple` when extracting the help text. +/// info - So in the end, the return will be a `list` (or other iterable) of `tuples` of 2 `str`. +The help text will be visible in Zsh, Fish, and PowerShell. -!!! info - The help text will be visible in Zsh, Fish, and PowerShell. +Bash doesn't support showing the help text, but completion will still work the same. - Bash doesn't support showing the help text, but completion will still work the same. +/// If you have a shell like Zsh, it would look like: @@ -200,32 +239,45 @@ Instead of creating and returning a list with values (`str` or `tuple`), we can That way our function will be a generator that **Typer** (actually Click) can iterate: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="11-14" +{!> ../docs_src/options_autocompletion/tutorial005_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="11-14" - {!> ../docs_src/options_autocompletion/tutorial005_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="10-13" - {!> ../docs_src/options_autocompletion/tutorial005.py!} - ``` +```Python hl_lines="10-13" +{!> ../docs_src/options_autocompletion/tutorial005.py!} +``` + +//// That simplifies our code a bit and works the same. -!!! tip - If all the `yield` part seems complex for you, don't worry, you can just use the version with the `list` above. +/// tip + +If all the `yield` part seems complex for you, don't worry, you can just use the version with the `list` above. + +In the end, that's just to save us a couple of lines of code. + +/// - In the end, that's just to save us a couple of lines of code. +/// info -!!! info - The function can use `yield`, so it doesn't have to return strictly a `list`, it just has to be iterable. +The function can use `yield`, so it doesn't have to return strictly a `list`, it just has to be iterable. - But each of the elements for completion has to be a `str` or a `tuple` (when containing a help text). +But each of the elements for completion has to be a `str` or a `tuple` (when containing a help text). + +/// ## Access other *CLI parameters* with the Context @@ -233,27 +285,37 @@ Let's say that now we want to modify the program to be able to "say hi" to multi So, we will allow multiple `--name` *CLI options*. -!!! tip - You will learn more about *CLI parameters* with multiple values later in the tutorial. +/// tip + +You will learn more about *CLI parameters* with multiple values later in the tutorial. + +So, for now, take this as a sneak peek πŸ˜‰. - So, for now, take this as a sneak peek πŸ˜‰. +/// For this we use a `List` of `str`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="9-14" +{!> ../docs_src/options_autocompletion/tutorial006_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="9-14" - {!> ../docs_src/options_autocompletion/tutorial006_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="8-11" - {!> ../docs_src/options_autocompletion/tutorial006.py!} - ``` +```Python hl_lines="8-11" +{!> ../docs_src/options_autocompletion/tutorial006.py!} +``` + +//// And then we can use it like: @@ -278,20 +340,27 @@ But you can access the context by declaring a function parameter of type `typer. And from that context you can get the current values for each parameter. -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="13-14 16" +{!> ../docs_src/options_autocompletion/tutorial007_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="13-14 16" - {!> ../docs_src/options_autocompletion/tutorial007_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// + +```Python hl_lines="12-13 15" +{!> ../docs_src/options_autocompletion/tutorial007.py!} +``` - ```Python hl_lines="12-13 15" - {!> ../docs_src/options_autocompletion/tutorial007.py!} - ``` +//// We are getting the `names` already provided with `--name` in the command line before this completion was triggered. @@ -329,8 +398,11 @@ Carlos -- The writer of scripts. -!!! tip - It's quite possible that if there's only one option left, your shell will complete it right away instead of showing the option with the help text, to save you more typing. +/// tip + +It's quite possible that if there's only one option left, your shell will complete it right away instead of showing the option with the help text, to save you more typing. + +/// ## Getting the raw *CLI parameters* @@ -338,10 +410,13 @@ You can also get the raw *CLI parameters*, just a `list` of `str` with everythin For example, something like `["typer", "main.py", "run", "--name"]`. -!!! tip - This would be for advanced scenarios, in most use cases you would be better off using the context. +/// tip + +This would be for advanced scenarios, in most use cases you would be better off using the context. - But it's still possible if you need it. +But it's still possible if you need it. + +/// As a simple example, let's show it on the screen before completion. @@ -349,8 +424,11 @@ Because completion is based on the output printed by your program (handled inter ### Printing to "standard error" -!!! tip - If you need a refresher about what is "standard output" and "standard error" check the section in [Printing and Colors: "Standard Output" and "Standard Error"](./printing.md#standard-output-and-standard-error){.internal-link target=_blank}. +/// tip + +If you need a refresher about what is "standard output" and "standard error" check the section in [Printing and Colors: "Standard Output" and "Standard Error"](./printing.md#standard-output-and-standard-error){.internal-link target=_blank}. + +/// The completion system only reads from "standard output", so, printing to "standard error" won't break completion. πŸš€ @@ -358,30 +436,43 @@ You can print to "standard error" with a **Rich** `Console(stderr=True)`. Using `stderr=True` tells **Rich** that the output should be shown in "standard error". -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="13 16-17" +{!> ../docs_src/options_autocompletion/tutorial008_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="13 16-17" - {!> ../docs_src/options_autocompletion/tutorial008_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="12 15-16" - {!> ../docs_src/options_autocompletion/tutorial008.py!} - ``` +```Python hl_lines="12 15-16" +{!> ../docs_src/options_autocompletion/tutorial008.py!} +``` + +//// + +/// info -!!! info - If you can't install and use Rich, you can also use `print(lastname, file=sys.stderr)` or `typer.echo("some text", err=True)` instead. +If you can't install and use Rich, you can also use `print(lastname, file=sys.stderr)` or `typer.echo("some text", err=True)` instead. + +/// We get all the *CLI parameters* as a raw `list` of `str` by declaring a parameter with type `List[str]`, here it's named `args`. -!!! tip - Here we name the list of all the raw *CLI parameters* `args` because that's the convention with Click. +/// tip + +Here we name the list of all the raw *CLI parameters* `args` because that's the convention with Click. - But it doesn't contain only *CLI arguments*, it has everything, including *CLI options* and values, as a raw `list` of `str`. +But it doesn't contain only *CLI arguments*, it has everything, including *CLI options* and values, as a raw `list` of `str`. + +/// And then we just print it to "standard error". @@ -401,29 +492,39 @@ Sebastian -- The type hints guy. -!!! tip - This is a very simple (and quite useless) example, just so you know how it works and that you can use it. +/// tip + +This is a very simple (and quite useless) example, just so you know how it works and that you can use it. + +But it's probably useful only in very advanced use cases. - But it's probably useful only in very advanced use cases. +/// ## Getting the Context and the raw *CLI parameters* Of course, you can declare everything if you need it, the context, the raw *CLI parameters*, and the incomplete `str`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="16" +{!> ../docs_src/options_autocompletion/tutorial009_an.py!} +``` - ```Python hl_lines="16" - {!> ../docs_src/options_autocompletion/tutorial009_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="15" +{!> ../docs_src/options_autocompletion/tutorial009.py!} +``` - ```Python hl_lines="15" - {!> ../docs_src/options_autocompletion/tutorial009.py!} - ``` +//// Check it: diff --git a/docs/tutorial/options/callback-and-context.md b/docs/tutorial/options/callback-and-context.md index 4179eeff94..249616f072 100644 --- a/docs/tutorial/options/callback-and-context.md +++ b/docs/tutorial/options/callback-and-context.md @@ -1,3 +1,5 @@ +# CLI Option Callback and Context + In some occasions you might want to have some custom logic for a specific *CLI parameter* (for a *CLI option* or *CLI argument*) that is executed with the value received from the terminal. In those cases you can use a *CLI parameter* callback function. @@ -6,20 +8,27 @@ In those cases you can use a *CLI parameter* callback function. For example, you could do some validation before the rest of the code is executed. -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="7-10 13" +{!> ../docs_src/options/callback/tutorial001_an.py!} +``` + +//// - ```Python hl_lines="7-10 13" - {!> ../docs_src/options/callback/tutorial001_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="6-9 12" +{!> ../docs_src/options/callback/tutorial001.py!} +``` - ```Python hl_lines="6-9 12" - {!> ../docs_src/options/callback/tutorial001.py!} - ``` +//// Here you pass a function to `typer.Option()` or `typer.Argument()` with the keyword argument `callback`. @@ -105,20 +114,27 @@ But the main **important point** is that it is all based on values printed by yo Let's say that when the callback is running, we want to show a message saying that it's validating the name: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="8" - {!> ../docs_src/options/callback/tutorial002_an.py!} - ``` +```Python hl_lines="8" +{!> ../docs_src/options/callback/tutorial002_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="7" +{!> ../docs_src/options/callback/tutorial002.py!} +``` - ```Python hl_lines="7" - {!> ../docs_src/options/callback/tutorial002.py!} - ``` +//// And because the callback will be called when the shell calls your program asking for completion, that message `"Validating name"` will be printed and it will break completion. @@ -153,20 +169,27 @@ But you can access the context by declaring a function parameter of type `typer. The "context" has some additional data about the current execution of your program: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="7-9" - {!> ../docs_src/options/callback/tutorial003_an.py!} - ``` +```Python hl_lines="7-9" +{!> ../docs_src/options/callback/tutorial003_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="6-8" +{!> ../docs_src/options/callback/tutorial003.py!} +``` - ```Python hl_lines="6-8" - {!> ../docs_src/options/callback/tutorial003.py!} - ``` +//// The `ctx.resilient_parsing` will be `True` when handling completion, so you can just return without printing anything else. @@ -198,20 +221,27 @@ Hello Camila The same way you can access the `typer.Context` by declaring a function parameter with its value, you can declare another function parameter with type `typer.CallbackParam` to get the specific Click `Parameter` object. -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="7 10" - {!> ../docs_src/options/callback/tutorial004_an.py!} - ``` +```Python hl_lines="7 10" +{!> ../docs_src/options/callback/tutorial004_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="6 9" +{!> ../docs_src/options/callback/tutorial004.py!} +``` - ```Python hl_lines="6 9" - {!> ../docs_src/options/callback/tutorial004.py!} - ``` +//// It's probably not very common, but you could do it if you need it. diff --git a/docs/tutorial/options/help.md b/docs/tutorial/options/help.md index 772daaf1bb..f2ee34db51 100644 --- a/docs/tutorial/options/help.md +++ b/docs/tutorial/options/help.md @@ -1,21 +1,30 @@ +# CLI Options with Help + You already saw how to add a help text for *CLI arguments* with the `help` parameter. Let's now do the same for *CLI options*: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="7-8" +{!> ../docs_src/options/help/tutorial001_an.py!} +``` + +//// - ```Python hl_lines="7-8" - {!> ../docs_src/options/help/tutorial001_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="6-7" +{!> ../docs_src/options/help/tutorial001.py!} +``` - ```Python hl_lines="6-7" - {!> ../docs_src/options/help/tutorial001.py!} - ``` +//// The same way as with `typer.Argument()`, we can put `typer.Option()` inside of `Annotated`. @@ -67,20 +76,27 @@ The same as with *CLI arguments*, you can put the help for some *CLI options* in If you have installed Rich as described in the docs for [Printing and Colors](../printing.md){.internal-link target=_blank}, you can set the `rich_help_panel` parameter to the name of the panel you want for each *CLI option*: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="11 17" - {!> ../docs_src/options/help/tutorial002_an.py!} - ``` +```Python hl_lines="11 17" +{!> ../docs_src/options/help/tutorial002_an.py!} +``` + +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="8 11" - {!> ../docs_src/options/help/tutorial002.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="8 11" +{!> ../docs_src/options/help/tutorial002.py!} +``` + +//// Now, when you check the `--help` option, you will see a default panel named "`Options`" for the *CLI options* that don't have a custom `rich_help_panel`. @@ -126,20 +142,27 @@ If you are in a hurry you can jump there, but otherwise, it would be better to c You can tell Typer to not show the default value in the help text with `show_default=False`: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="5" - {!> ../docs_src/options/help/tutorial003_an.py!} - ``` +```Python hl_lines="5" +{!> ../docs_src/options/help/tutorial003_an.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="4" - {!> ../docs_src/options/help/tutorial003.py!} - ``` +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/options/help/tutorial003.py!} +``` + +//// And it will no longer show the default value in the help text: @@ -164,29 +187,39 @@ Options: -!!! note "Technical Details" - In Click applications the default values are hidden by default. πŸ™ˆ +/// note | Technical Details + +In Click applications the default values are hidden by default. πŸ™ˆ + +In **Typer** these default values are shown by default. πŸ‘€ - In **Typer** these default values are shown by default. πŸ‘€ +/// ## Custom default string You can use the same `show_default` to pass a custom string (instead of a `bool`) to customize the default value to be shown in the help text: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="7" - {!> ../docs_src/options/help/tutorial004_an.py!} - ``` +```Python hl_lines="7" +{!> ../docs_src/options/help/tutorial004_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="6" +{!> ../docs_src/options/help/tutorial004.py!} +``` - ```Python hl_lines="6" - {!> ../docs_src/options/help/tutorial004.py!} - ``` +//// And it will be used in the help text: diff --git a/docs/tutorial/options/index.md b/docs/tutorial/options/index.md index 13c4505eb3..f71c2167e7 100644 --- a/docs/tutorial/options/index.md +++ b/docs/tutorial/options/index.md @@ -1,3 +1,5 @@ +# CLI Options + In the next short sections we will see how to modify *CLI options* using `typer.Option()`. `typer.Option()` works very similarly to `typer.Argument()`, but has some extra features that we'll see next. diff --git a/docs/tutorial/options/name.md b/docs/tutorial/options/name.md index 2392edcaa5..7ece83f8b5 100644 --- a/docs/tutorial/options/name.md +++ b/docs/tutorial/options/name.md @@ -1,3 +1,5 @@ +# CLI Option Name + By default **Typer** will create a *CLI option* name from the function parameter. So, if you have a function with: @@ -26,33 +28,43 @@ Let's say the function parameter name is `user_name` as above, but you want the You can pass the *CLI option* name that you want to have in the following positional argument passed to `typer.Option()`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/options/name/tutorial001_an.py!} +``` + +Here you are passing the string `"--name"` as the first positional argument to `typer.Option()`. + +//// - ```Python hl_lines="5" - {!> ../docs_src/options/name/tutorial001_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated - Here you are passing the string `"--name"` as the first positional argument to `typer.Option()`. +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="4" - {!> ../docs_src/options/name/tutorial001.py!} - ``` +```Python hl_lines="4" +{!> ../docs_src/options/name/tutorial001.py!} +``` + +Here you are passing the string `"--name"` as the second positional argument to `typer.Option()`, as the first argument is `...` to mark it as required. + +//// - Here you are passing the string `"--name"` as the second positional argument to `typer.Option()`, as the first argument is `...` to mark it as required. +/// info -!!! info - "Positional" means that it's not a function argument with a keyword name. +"Positional" means that it's not a function argument with a keyword name. - For example `show_default=True` is a keyword argument. "`show_default`" is the keyword. +For example `show_default=True` is a keyword argument. "`show_default`" is the keyword. - But in `"--name"` there's no `option_name="--name"` or something similar, it's just the string value `"--name"` that goes in `typer.Option()`. +But in `"--name"` there's no `option_name="--name"` or something similar, it's just the string value `"--name"` that goes in `typer.Option()`. - That's a "positional argument" in a function. +That's a "positional argument" in a function. + +/// Check it: @@ -185,29 +197,39 @@ In **Typer** you can also define *CLI option* short names the same way you can c You can pass *positional* arguments to `typer.Option()` to define the *CLI option* name(s). -!!! tip - Remember the *positional* function arguments are those that don't have a keyword. +/// tip + +Remember the *positional* function arguments are those that don't have a keyword. - All the other function arguments/parameters you pass to `typer.Option()` like `prompt=True` and `help="This option blah, blah"` require the keyword. +All the other function arguments/parameters you pass to `typer.Option()` like `prompt=True` and `help="This option blah, blah"` require the keyword. + +/// You can overwrite the *CLI option* name to use as in the previous example, but you can also declare extra alternatives, including short names. For example, extending the previous example, let's add a *CLI option* short name `-n`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/options/name/tutorial002_an.py!} +``` - ```Python hl_lines="5" - {!> ../docs_src/options/name/tutorial002_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="4" - {!> ../docs_src/options/name/tutorial002.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/options/name/tutorial002.py!} +``` + +//// Here we are overwriting the *CLI option* name that by default would be `--user-name`, and we are defining it to be `--name`. And we are also declaring a *CLI option* short name of `-n`. @@ -238,20 +260,27 @@ Hello Camila If you only declare a short name like `-n` then that will be the only *CLI option* name. And neither `--name` nor `--user-name` will be available. -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/options/name/tutorial003_an.py!} +``` - ```Python hl_lines="5" - {!> ../docs_src/options/name/tutorial003_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="4" - {!> ../docs_src/options/name/tutorial003.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/options/name/tutorial003.py!} +``` + +//// Check it: @@ -279,20 +308,27 @@ Hello Camila Continuing with the example above, as **Typer** allows you to declare a *CLI option* as having only a short name, if you want to have the default long name plus a short name, you have to declare both explicitly: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/options/name/tutorial004_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated + +/// tip - ```Python hl_lines="5" - {!> ../docs_src/options/name/tutorial004_an.py!} - ``` +Prefer to use the `Annotated` version if possible. -=== "Python 3.7+ non-Annotated" +/// - !!! tip - Prefer to use the `Annotated` version if possible. +```Python hl_lines="4" +{!> ../docs_src/options/name/tutorial004.py!} +``` - ```Python hl_lines="4" - {!> ../docs_src/options/name/tutorial004.py!} - ``` +//// Check it: @@ -326,23 +362,33 @@ You can create multiple short names and use them together. You don't have to do anything special for it to work (apart from declaring those short versions): -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="6-7" +{!> ../docs_src/options/name/tutorial005_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="6-7" - {!> ../docs_src/options/name/tutorial005_an.py!} - ``` +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="5-6" +{!> ../docs_src/options/name/tutorial005.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="5-6" - {!> ../docs_src/options/name/tutorial005.py!} - ``` +Notice that, again, we are declaring the long and short version of the *CLI option* names. -!!! tip - Notice that, again, we are declaring the long and short version of the *CLI option* names. +/// Check it: diff --git a/docs/tutorial/options/password.md b/docs/tutorial/options/password.md index abe33e5411..8601d848b6 100644 --- a/docs/tutorial/options/password.md +++ b/docs/tutorial/options/password.md @@ -1,19 +1,28 @@ +# Password CLI Option and Confirmation Prompt + Apart from having a prompt, you can make a *CLI option* have a `confirmation_prompt=True`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="7" +{!> ../docs_src/options/password/tutorial001_an.py!} +``` + +//// - ```Python hl_lines="7" - {!> ../docs_src/options/password/tutorial001_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="5" +{!> ../docs_src/options/password/tutorial001.py!} +``` - ```Python hl_lines="5" - {!> ../docs_src/options/password/tutorial001.py!} - ``` +//// And the CLI program will ask for confirmation: @@ -41,20 +50,27 @@ You can achieve the same using `hide_input=True`. And if you combine it with `confirmation_prompt=True` you can easily receive a password with double confirmation: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="8" - {!> ../docs_src/options/password/tutorial002_an.py!} - ``` +```Python hl_lines="8" +{!> ../docs_src/options/password/tutorial002_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="6-8" +{!> ../docs_src/options/password/tutorial002.py!} +``` - ```Python hl_lines="6-8" - {!> ../docs_src/options/password/tutorial002.py!} - ``` +//// Check it: diff --git a/docs/tutorial/options/prompt.md b/docs/tutorial/options/prompt.md index 9f7472eac4..e55a09551e 100644 --- a/docs/tutorial/options/prompt.md +++ b/docs/tutorial/options/prompt.md @@ -1,19 +1,28 @@ +# CLI Option Prompt + It's also possible to, instead of just showing an error, ask for the missing value with `prompt=True`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/options/prompt/tutorial001_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="5" - {!> ../docs_src/options/prompt/tutorial001_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="4" - {!> ../docs_src/options/prompt/tutorial001.py!} - ``` +```Python hl_lines="4" +{!> ../docs_src/options/prompt/tutorial001.py!} +``` + +//// And then your program will ask the user for it in the terminal: @@ -35,20 +44,27 @@ Hello Camila GutiΓ©rrez You can also set a custom prompt, passing the string that you want to use instead of just `True`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="7" +{!> ../docs_src/options/prompt/tutorial002_an.py!} +``` + +//// - ```Python hl_lines="7" - {!> ../docs_src/options/prompt/tutorial002_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. - ```Python hl_lines="5" - {!> ../docs_src/options/prompt/tutorial002.py!} - ``` +/// + +```Python hl_lines="5" +{!> ../docs_src/options/prompt/tutorial002.py!} +``` + +//// And then your program will ask for it using with your custom prompt: @@ -74,20 +90,27 @@ You can do it passing the parameter `confirmation_prompt=True`. Let's say it's a CLI app to delete a project: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="6" +{!> ../docs_src/options/prompt/tutorial003_an.py!} +``` - ```Python hl_lines="6" - {!> ../docs_src/options/prompt/tutorial003_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/options/prompt/tutorial003.py!} +``` - ```Python hl_lines="4" - {!> ../docs_src/options/prompt/tutorial003.py!} - ``` +//// And it will prompt the user for a value and then for the confirmation: diff --git a/docs/tutorial/options/required.md b/docs/tutorial/options/required.md index 311fbd93ae..4b2c2226eb 100644 --- a/docs/tutorial/options/required.md +++ b/docs/tutorial/options/required.md @@ -1,3 +1,5 @@ +# Required CLI Options + We said before that *by default*: * *CLI options* are **optional** @@ -11,35 +13,47 @@ To make a *CLI option* required, you can put `typer.Option()` inside of `Annotat Let's make `--lastname` a required *CLI option*: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/options/required/tutorial001_an.py!} +``` - ```Python hl_lines="5" - {!> ../docs_src/options/required/tutorial001_an.py!} - ``` +//// The same way as with `typer.Argument()`, the old style of using the function parameter default value is also supported, in that case you would just not pass anything to the `default` parameter. -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="4" - {!> ../docs_src/options/required/tutorial001.py!} - ``` +```Python hl_lines="4" +{!> ../docs_src/options/required/tutorial001.py!} +``` + +//// Or you can explictily pass `...` to `typer.Option(default=...)`: -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="4" - {!> ../docs_src/options/required/tutorial002.py!} - ``` +```Python hl_lines="4" +{!> ../docs_src/options/required/tutorial002.py!} +``` -!!! info - If you hadn't seen that `...` before: it is a special single value, it is part of Python and is called "Ellipsis". +//// + +/// info + +If you hadn't seen that `...` before: it is a special single value, it is part of Python and is called "Ellipsis". + +/// That will tell **Typer** that it's still a *CLI option*, but it doesn't have a default value, and it's required. -!!! tip - Again, prefer to use the `Annotated` version if possible. That way your code will mean the same in standard Python and in **Typer**. +/// tip + +Again, prefer to use the `Annotated` version if possible. That way your code will mean the same in standard Python and in **Typer**. + +/// And test it: diff --git a/docs/tutorial/options/version.md b/docs/tutorial/options/version.md index 497a30262c..f76112ce39 100644 --- a/docs/tutorial/options/version.md +++ b/docs/tutorial/options/version.md @@ -1,3 +1,5 @@ +# Version CLI Option, `is_eager` + You could use a callback to implement a `--version` *CLI option*. It would show the version of your CLI program and then it would terminate it. Even before any other *CLI parameter* is processed. @@ -6,23 +8,33 @@ It would show the version of your CLI program and then it would terminate it. Ev Let's see a first version of how it could look like: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="9-12 17-19" +{!> ../docs_src/options/version/tutorial001_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated + +/// tip + +Prefer to use the `Annotated` version if possible. - ```Python hl_lines="9-12 17-19" - {!> ../docs_src/options/version/tutorial001_an.py!} - ``` +/// -=== "Python 3.7+ non-Annotated" +```Python hl_lines="8-11 16-18" +{!> ../docs_src/options/version/tutorial001.py!} +``` + +//// - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="8-11 16-18" - {!> ../docs_src/options/version/tutorial001.py!} - ``` +Notice that we don't have to get the `typer.Context` and check for `ctx.resilient_parsing` for completion to work, because we only print and modify the program when `--version` is passed, otherwise, nothing is printed or changed from the callback. -!!! tip - Notice that we don't have to get the `typer.Context` and check for `ctx.resilient_parsing` for completion to work, because we only print and modify the program when `--version` is passed, otherwise, nothing is printed or changed from the callback. +/// If the `--version` *CLI option* is passed, we get a value `True` in the callback. @@ -65,20 +77,27 @@ Awesome CLI Version: 0.1.0 But now let's say that the `--name` *CLI option* that we declared before `--version` is required, and it has a callback that could exit the program: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="15-17 22-24" +{!> ../docs_src/options/version/tutorial002_an.py!} +``` - ```Python hl_lines="15-17 22-24" - {!> ../docs_src/options/version/tutorial002_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="14-16 21-23" - {!> ../docs_src/options/version/tutorial002.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="14-16 21-23" +{!> ../docs_src/options/version/tutorial002.py!} +``` + +//// Then our CLI program could not work as expected in some cases as it is *right now*, because if we use `--version` after `--name` then the callback for `--name` will be processed before and we can get its error: @@ -93,14 +112,23 @@ Aborted! -!!! tip - We don't have to check for `ctx.resilient_parsing` in the `name_callback()` for completion to work, because we are not using `typer.echo()`, instead we are raising a `typer.BadParameter`. +/// tip + +We don't have to check for `ctx.resilient_parsing` in the `name_callback()` for completion to work, because we are not using `typer.echo()`, instead we are raising a `typer.BadParameter`. + +/// + +/// note | Technical Details + +`typer.BadParameter` prints the error to "standard error", not to "standard output", and because the completion system only reads from "standard output", it won't break completion. + +/// + +/// info -!!! note "Technical Details" - `typer.BadParameter` prints the error to "standard error", not to "standard output", and because the completion system only reads from "standard output", it won't break completion. +If you need a refresher about what is "standard output" and "standard error" check the section in [Printing and Colors: "Standard Output" and "Standard Error"](../printing.md#standard-output-and-standard-error){.internal-link target=_blank}. -!!! info - If you need a refresher about what is "standard output" and "standard error" check the section in [Printing and Colors: "Standard Output" and "Standard Error"](../printing.md#standard-output-and-standard-error){.internal-link target=_blank}. +/// ### Fix with `is_eager` @@ -108,20 +136,27 @@ For those cases, we can mark a *CLI parameter* (a *CLI option* or *CLI argument* That will tell **Typer** (actually Click) that it should process this *CLI parameter* before the others: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="23-26" - {!> ../docs_src/options/version/tutorial003_an.py!} - ``` +```Python hl_lines="23-26" +{!> ../docs_src/options/version/tutorial003_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="22-24" +{!> ../docs_src/options/version/tutorial003.py!} +``` - ```Python hl_lines="22-24" - {!> ../docs_src/options/version/tutorial003.py!} - ``` +//// Check it: diff --git a/docs/tutorial/package.md b/docs/tutorial/package.md index 17fe5a4149..cb04fd6d2c 100644 --- a/docs/tutorial/package.md +++ b/docs/tutorial/package.md @@ -1,3 +1,5 @@ +# Building a Package + When you create a CLI program with **Typer** you probably want to create your own Python package. That's what allows your users to install it and have it as an independent program that they can use in their terminal. @@ -10,8 +12,11 @@ You might even have your favorite already. Here's a very opinionated, short guide, showing one of the alternative ways of creating a Python package with a **Typer** app, from scratch. -!!! tip - If you already have a favorite way of creating Python packages, feel free to skip this. +/// tip + +If you already have a favorite way of creating Python packages, feel free to skip this. + +/// ## Prerequisites @@ -141,8 +146,11 @@ def load(): typer.echo("Loading portal gun") ``` -!!! tip - As we are creating an installable Python package, there's no need to add a section with `if __name__ == "__main__":`. +/// tip + +As we are creating an installable Python package, there's no need to add a section with `if __name__ == "__main__":`. + +/// ## Modify the README @@ -319,13 +327,19 @@ $ pip install --user /home/rock/code/rick-portal-gun/dist/rick_portal_gun-0.1.0- -!!! warning - The `--user` is important, that ensures you install it in your user's directory and not in the global system. +/// warning - If you installed it in the global system (e.g. with `sudo`) you could install a version of a library (e.g. a sub-dependency) that is incompatible with your system. +The `--user` is important, that ensures you install it in your user's directory and not in the global system. -!!! tip - Bonus points if you use `pipx` to install it while keeping an isolated environment for your Python CLI programs πŸš€ +If you installed it in the global system (e.g. with `sudo`) you could install a version of a library (e.g. a sub-dependency) that is incompatible with your system. + +/// + +/// tip + +Bonus points if you use `pipx` to install it while keeping an isolated environment for your Python CLI programs πŸš€ + +/// Now you have your CLI program installed. And you can use it freely: @@ -353,8 +367,11 @@ Completion will take effect once you restart the terminal. -!!! tip - If you want to remove completion you can just delete the added line in that file. +/// tip + +If you want to remove completion you can just delete the added line in that file. + +/// And after you restart the terminal you will get completion for your new CLI program: @@ -398,8 +415,11 @@ Here we pass `pip` as the value for `-m`, so, Python will execute the module `pi These two are more or less equivalent, the `install fastapi` will be passed to `pip`. -!!! tip - In the case of `pip`, in many occasions it's actually recommended that you run it with `python -m`, because if you create a virtual environment with its own `python`, that will ensure that you use the `pip` from *that* environment. +/// tip + +In the case of `pip`, in many occasions it's actually recommended that you run it with `python -m`, because if you create a virtual environment with its own `python`, that will ensure that you use the `pip` from *that* environment. + +/// ### Add a `__main__.py` @@ -456,8 +476,11 @@ Commands: -!!! tip - Notice that you have to pass the importable version of the package name, so `rick_portal_gun` instead of `rick-portal-gun`. +/// tip + +Notice that you have to pass the importable version of the package name, so `rick_portal_gun` instead of `rick-portal-gun`. + +/// That works! πŸš€ Sort of... πŸ€” @@ -481,8 +504,11 @@ from .main import app app(prog_name="rick-portal-gun") ``` -!!! tip - You can pass all the arguments and keyword arguments you could pass to a Click application, including `prog_name`. +/// tip + +You can pass all the arguments and keyword arguments you could pass to a Click application, including `prog_name`. + +///
@@ -664,8 +690,11 @@ You just have to pass it the module to import (`rick_portal_gun.main`) and it wi By specifying the `--name` of the program it will be able to use it while generating the docs. -!!! tip - If you installed `typer-slim` and don't have the `typer` command, you can use `python -m typer` instead. +/// tip + +If you installed `typer-slim` and don't have the `typer` command, you can use `python -m typer` instead. + +/// ### Publish a new version with the docs diff --git a/docs/tutorial/parameter-types/bool.md b/docs/tutorial/parameter-types/bool.md index 68ef638062..14adc6a6dd 100644 --- a/docs/tutorial/parameter-types/bool.md +++ b/docs/tutorial/parameter-types/bool.md @@ -1,3 +1,5 @@ +# Boolean CLI Options + We have seen some examples of *CLI options* with `bool`, and how **Typer** creates `--something` and `--no-something` automatically. But we can customize those names. @@ -8,20 +10,27 @@ Let's say that we want a `--force` *CLI option* only, we want to discard `--no-f We can do that by specifying the exact name we want: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/parameter_types/bool/tutorial001_an.py!} +``` + +//// - ```Python hl_lines="5" - {!> ../docs_src/parameter_types/bool/tutorial001_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/parameter_types/bool/tutorial001.py!} +``` - ```Python hl_lines="4" - {!> ../docs_src/parameter_types/bool/tutorial001.py!} - ``` +//// Now there's only a `--force` *CLI option*: @@ -69,20 +78,27 @@ We might want to instead have `--accept` and `--reject`. We can do that by passing a single `str` with the 2 names for the `bool` *CLI option* separated by `/`: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="7" - {!> ../docs_src/parameter_types/bool/tutorial002_an.py!} - ``` +```Python hl_lines="7" +{!> ../docs_src/parameter_types/bool/tutorial002_an.py!} +``` + +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="6" - {!> ../docs_src/parameter_types/bool/tutorial002.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="6" +{!> ../docs_src/parameter_types/bool/tutorial002.py!} +``` + +//// Check it: @@ -123,20 +139,27 @@ The same way, you can declare short versions of the names for these *CLI options For example, let's say we want `-f` for `--force` and `-F` for `--no-force`: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="5" - {!> ../docs_src/parameter_types/bool/tutorial003_an.py!} - ``` +```Python hl_lines="5" +{!> ../docs_src/parameter_types/bool/tutorial003_an.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="4" - {!> ../docs_src/parameter_types/bool/tutorial003.py!} - ``` +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/parameter_types/bool/tutorial003.py!} +``` + +//// Check it: @@ -172,25 +195,35 @@ If you want to (although it might not be a good idea), you can declare only *CLI To do that, use a space and a single `/` and pass the negative name after: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/parameter_types/bool/tutorial004_an.py!} +``` - ```Python hl_lines="5" - {!> ../docs_src/parameter_types/bool/tutorial004_an.py!} - ``` +//// + +//// tab | Python 3.7+ non-Annotated + +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/parameter_types/bool/tutorial004.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="4" - {!> ../docs_src/parameter_types/bool/tutorial004.py!} - ``` +Have in mind that it's a string with a preceding space and then a `/`. -!!! tip - Have in mind that it's a string with a preceding space and then a `/`. +So, it's `" /-S"` not `"/-S"`. - So, it's `" /-S"` not `"/-S"`. +/// Check it: diff --git a/docs/tutorial/parameter-types/custom-types.md b/docs/tutorial/parameter-types/custom-types.md index fd0d395832..b048c85bc9 100644 --- a/docs/tutorial/parameter-types/custom-types.md +++ b/docs/tutorial/parameter-types/custom-types.md @@ -1,3 +1,5 @@ +# Custom Types + You can easily use your own custom types in your **Typer** applications. The way to do it is by providing a way to parse input into your own types. @@ -11,20 +13,27 @@ There are two ways to achieve this: `typer.Argument` and `typer.Option` can create custom parameter types with a `parser` callable. -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="13-14 18-19" +{!> ../docs_src/parameter_types/custom_types/tutorial001_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="13-14 18-19" - {!> ../docs_src/parameter_types/custom_types/tutorial001_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="12-13 17-18" - {!> ../docs_src/parameter_types/custom_types/tutorial001.py!} - ``` +```Python hl_lines="12-13 17-18" +{!> ../docs_src/parameter_types/custom_types/tutorial001.py!} +``` + +//// The function (or callable) that you pass to the parameter `parser` will receive the input value as a string and should return the parsed value with your own custom type. @@ -32,17 +41,10 @@ The function (or callable) that you pass to the parameter `parser` will receive If you already have a Click Custom Type, you can use it in `typer.Argument()` and `typer.Option()` with the `click_type` parameter. -=== "Python 3.7+" - - ```Python hl_lines="14-18 22-25" - {!> ../docs_src/parameter_types/custom_types/tutorial002_an.py!} - ``` - -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ - !!! tip - Prefer to use the `Annotated` version if possible. +```Python hl_lines="14-18 22-25" +{!> ../docs_src/parameter_types/custom_types/tutorial002_an.py!} +``` - ```Python hl_lines="13-17 21-22" - {!> ../docs_src/parameter_types/custom_types/tutorial002.py!} - ``` +//// diff --git a/docs/tutorial/parameter-types/datetime.md b/docs/tutorial/parameter-types/datetime.md index 04a3eb71a8..84f3524eee 100644 --- a/docs/tutorial/parameter-types/datetime.md +++ b/docs/tutorial/parameter-types/datetime.md @@ -1,3 +1,5 @@ +# DateTime + You can specify a *CLI parameter* as a Python `datetime`. Your function will receive a standard Python `datetime` object, and again, your editor will give you completion, etc. @@ -58,23 +60,33 @@ For example, let's imagine that you want to accept an ISO formatted datetime, bu ...It's a crazy example, but let's say you also needed that strange format: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="11" +{!> ../docs_src/parameter_types/datetime/tutorial002_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="11" - {!> ../docs_src/parameter_types/datetime/tutorial002_an.py!} - ``` +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="8" +{!> ../docs_src/parameter_types/datetime/tutorial002.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="8" - {!> ../docs_src/parameter_types/datetime/tutorial002.py!} - ``` +Notice the last string in `formats`: `"%m/%d/%Y"`. -!!! tip - Notice the last string in `formats`: `"%m/%d/%Y"`. +/// Check it: diff --git a/docs/tutorial/parameter-types/enum.md b/docs/tutorial/parameter-types/enum.md index b3b2c149f0..288eee5a92 100644 --- a/docs/tutorial/parameter-types/enum.md +++ b/docs/tutorial/parameter-types/enum.md @@ -1,13 +1,18 @@ +# Enum - Choices + To define a *CLI parameter* that can take a value from a predefined set of values you can use a standard Python `enum.Enum`: ```Python hl_lines="1 6 7 8 9 12 13" {!../docs_src/parameter_types/enum/tutorial001.py!} ``` -!!! tip - Notice that the function parameter `network` will be an `Enum`, not a `str`. +/// tip + +Notice that the function parameter `network` will be an `Enum`, not a `str`. - To get the `str` value in your function's code use `network.value`. +To get the `str` value in your function's code use `network.value`. + +/// Check it: @@ -51,20 +56,27 @@ Error: Invalid value for '--network': 'CONV' is not one of 'simple', 'conv', 'ls You can make an `Enum` (choice) *CLI parameter* be case-insensitive with the `case_sensitive` parameter: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="15" +{!> ../docs_src/parameter_types/enum/tutorial002_an.py!} +``` + +//// - ```Python hl_lines="15" - {!> ../docs_src/parameter_types/enum/tutorial002_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. - ```Python hl_lines="13" - {!> ../docs_src/parameter_types/enum/tutorial002.py!} - ``` +/// + +```Python hl_lines="13" +{!> ../docs_src/parameter_types/enum/tutorial002.py!} +``` + +//// And then the values of the `Enum` will be checked no matter if lower case, upper case, or a mix: @@ -88,20 +100,27 @@ Training neural network of type: lstm A *CLI parameter* can also take a list of `Enum` values: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="14" +{!> ../docs_src/parameter_types/enum/tutorial003_an.py!} +``` + +//// - ```Python hl_lines="14" - {!> ../docs_src/parameter_types/enum/tutorial003_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="13" +{!> ../docs_src/parameter_types/enum/tutorial003.py!} +``` - ```Python hl_lines="13" - {!> ../docs_src/parameter_types/enum/tutorial003.py!} - ``` +//// This works just like any other parameter value taking a list of things: diff --git a/docs/tutorial/parameter-types/file.md b/docs/tutorial/parameter-types/file.md index 3bb1cf51ce..274962cf07 100644 --- a/docs/tutorial/parameter-types/file.md +++ b/docs/tutorial/parameter-types/file.md @@ -1,9 +1,14 @@ +# File + Apart from `Path` *CLI parameters* you can also declare some types of "files". -!!! tip - In most of the cases you are probably fine just using `Path`. +/// tip + +In most of the cases you are probably fine just using `Path`. + +You can read and write data with `Path` the same way. - You can read and write data with `Path` the same way. +/// The difference is that these types will give you a Python file-like object instead of a Python Path. @@ -42,20 +47,27 @@ content = b"la cig\xc3\xbce\xc3\xb1a trae al ni\xc3\xb1o" You will get all the correct editor support, attributes, methods, etc for the file-like object:` -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/parameter_types/file/tutorial001_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="5" - {!> ../docs_src/parameter_types/file/tutorial001_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="4" - {!> ../docs_src/parameter_types/file/tutorial001.py!} - ``` +```Python hl_lines="4" +{!> ../docs_src/parameter_types/file/tutorial001.py!} +``` + +//// Check it: @@ -82,20 +94,27 @@ Config line: some more settings For writing text, you can use `typer.FileTextWrite`: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5-6" +{!> ../docs_src/parameter_types/file/tutorial002_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="5-6" - {!> ../docs_src/parameter_types/file/tutorial002_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// + +```Python hl_lines="4-5" +{!> ../docs_src/parameter_types/file/tutorial002.py!} +``` - ```Python hl_lines="4-5" - {!> ../docs_src/parameter_types/file/tutorial002.py!} - ``` +//// This would be for writing human text, like: @@ -123,10 +142,13 @@ Some config written by the app
-!!! info "Technical Details" - `typer.FileTextWrite` is a just a convenience class. +/// info | Technical Details - It's the same as using `typer.FileText` and setting `mode="w"`. You will learn about `mode` later below. +`typer.FileTextWrite` is a just a convenience class. + +It's the same as using `typer.FileText` and setting `mode="w"`. You will learn about `mode` later below. + +/// ## `FileBinaryRead` @@ -136,20 +158,27 @@ You will receive `bytes` from it. It's useful for reading binary files like images: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/parameter_types/file/tutorial003_an.py!} +``` + +//// - ```Python hl_lines="5" - {!> ../docs_src/parameter_types/file/tutorial003_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. - ```Python hl_lines="4" - {!> ../docs_src/parameter_types/file/tutorial003.py!} - ``` +/// + +```Python hl_lines="4" +{!> ../docs_src/parameter_types/file/tutorial003.py!} +``` + +//// Check it: @@ -178,20 +207,27 @@ Have in mind that you have to pass `bytes` to its `.write()` method, not `str`. If you have a `str`, you have to encode it first to get `bytes`. -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/parameter_types/file/tutorial004_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="5" - {!> ../docs_src/parameter_types/file/tutorial004_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="4" - {!> ../docs_src/parameter_types/file/tutorial004.py!} - ``` +```Python hl_lines="4" +{!> ../docs_src/parameter_types/file/tutorial004.py!} +``` + +////
@@ -241,23 +277,33 @@ You can override the `mode` from the defaults above. For example, you could use `mode="a"` to write "appending" to the same file: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="5" - {!> ../docs_src/parameter_types/file/tutorial005_an.py!} - ``` +```Python hl_lines="5" +{!> ../docs_src/parameter_types/file/tutorial005_an.py!} +``` -=== "Python 3.7+ non-Annotated" +//// - !!! tip - Prefer to use the `Annotated` version if possible. +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="4" - {!> ../docs_src/parameter_types/file/tutorial005.py!} - ``` +/// tip -!!! tip - As you are manually setting `mode="a"`, you can use `typer.FileText` or `typer.FileTextWrite`, both will work. +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/parameter_types/file/tutorial005.py!} +``` + +//// + +/// tip + +As you are manually setting `mode="a"`, you can use `typer.FileText` or `typer.FileTextWrite`, both will work. + +/// Check it: @@ -289,10 +335,13 @@ This is a single line ## About the different types -!!! info - These are technical details about why the different types/classes provided by **Typer**. +/// info + +These are technical details about why the different types/classes provided by **Typer**. + +But you don't need this information to be able to use them. You can skip it. - But you don't need this information to be able to use them. You can skip it. +/// **Typer** provides you these different types (classes) because they inherit directly from the actual Python implementation that will be provided underneath for each case. diff --git a/docs/tutorial/parameter-types/index.md b/docs/tutorial/parameter-types/index.md index ed3b7ad186..f7889944f0 100644 --- a/docs/tutorial/parameter-types/index.md +++ b/docs/tutorial/parameter-types/index.md @@ -1,3 +1,5 @@ +# CLI Parameter Types + You can use several data types for the *CLI options* and *CLI arguments*, and you can add data validation requirements too. ## Data conversion @@ -62,5 +64,8 @@ Error: Invalid value for '--age': '15.3' is not a valid integer See more about specific types and validations in the next sections... -!!! info "Technical Details" - All the types you will see in the next sections are handled underneath by Click's Parameter Types. +/// info | Technical Details + +All the types you will see in the next sections are handled underneath by Click's Parameter Types. + +/// diff --git a/docs/tutorial/parameter-types/number.md b/docs/tutorial/parameter-types/number.md index 001e4fccbb..062fa7bce3 100644 --- a/docs/tutorial/parameter-types/number.md +++ b/docs/tutorial/parameter-types/number.md @@ -1,19 +1,28 @@ +# Number + You can define numeric validations with `max` and `min` values for `int` and `float` *CLI parameters*: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="6-8" +{!> ../docs_src/parameter_types/number/tutorial001_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="6-8" - {!> ../docs_src/parameter_types/number/tutorial001_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="5-7" - {!> ../docs_src/parameter_types/number/tutorial001.py!} - ``` +```Python hl_lines="5-7" +{!> ../docs_src/parameter_types/number/tutorial001.py!} +``` + +//// *CLI arguments* and *CLI options* can both use these validations. @@ -84,20 +93,27 @@ You might want to, instead of showing an error, use the closest minimum or maxim You can do it with the `clamp` parameter: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="6-8" +{!> ../docs_src/parameter_types/number/tutorial002_an.py!} +``` + +//// - ```Python hl_lines="6-8" - {!> ../docs_src/parameter_types/number/tutorial002_an.py!} - ``` +//// tab | Python 3.7+ non-Annotated -=== "Python 3.7+ non-Annotated" +/// tip - !!! tip - Prefer to use the `Annotated` version if possible. +Prefer to use the `Annotated` version if possible. - ```Python hl_lines="5-7" - {!> ../docs_src/parameter_types/number/tutorial002.py!} - ``` +/// + +```Python hl_lines="5-7" +{!> ../docs_src/parameter_types/number/tutorial002.py!} +``` + +//// And then, when you pass data that is out of the valid range, it will be "clamped", the closest valid value will be used: @@ -126,20 +142,27 @@ ID is 5 You can make a *CLI option* work as a counter with the `counter` parameter: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="5" +{!> ../docs_src/parameter_types/number/tutorial003_an.py!} +``` - ```Python hl_lines="5" - {!> ../docs_src/parameter_types/number/tutorial003_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip + +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="4" +{!> ../docs_src/parameter_types/number/tutorial003.py!} +``` - ```Python hl_lines="4" - {!> ../docs_src/parameter_types/number/tutorial003.py!} - ``` +//// It means that the *CLI option* will be like a boolean flag, e.g. `--verbose`. diff --git a/docs/tutorial/parameter-types/path.md b/docs/tutorial/parameter-types/path.md index f6617db4d8..0268630bcd 100644 --- a/docs/tutorial/parameter-types/path.md +++ b/docs/tutorial/parameter-types/path.md @@ -1,21 +1,30 @@ +# Path + You can declare a *CLI parameter* to be a standard Python `pathlib.Path`. This is what you would do for directory paths, file paths, etc: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="1 8" +{!> ../docs_src/parameter_types/path/tutorial001_an.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated - ```Python hl_lines="1 8" - {!> ../docs_src/parameter_types/path/tutorial001_an.py!} - ``` +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="1 7" - {!> ../docs_src/parameter_types/path/tutorial001.py!} - ``` +```Python hl_lines="1 7" +{!> ../docs_src/parameter_types/path/tutorial001.py!} +``` + +//// And again, as you receive a standard Python `Path` object the same as the type annotation, your editor will give you autocompletion for all its attributes and methods. @@ -62,28 +71,41 @@ You can perform several validations for `Path` *CLI parameters*: * `readable`: if true, a readable check is performed. * `resolve_path`: if this is true, then the path is fully resolved before the value is passed onwards. This means that it’s absolute and symlinks are resolved. -!!! note "Technical Details" - It will not expand a tilde-prefix (something with `~`, like `~/Documents/`), as this is supposed to be done by the shell only. +/// note | Technical Details + +It will not expand a tilde-prefix (something with `~`, like `~/Documents/`), as this is supposed to be done by the shell only. + +/// + +/// tip -!!! tip - All these parameters come directly from Click. +All these parameters come directly from Click. + +/// For example: -=== "Python 3.7+" +//// tab | Python 3.7+ + +```Python hl_lines="11-16" +{!> ../docs_src/parameter_types/path/tutorial002_an.py!} +``` - ```Python hl_lines="11-16" - {!> ../docs_src/parameter_types/path/tutorial002_an.py!} - ``` +//// -=== "Python 3.7+ non-Annotated" +//// tab | Python 3.7+ non-Annotated - !!! tip - Prefer to use the `Annotated` version if possible. +/// tip - ```Python hl_lines="9-14" - {!> ../docs_src/parameter_types/path/tutorial002.py!} - ``` +Prefer to use the `Annotated` version if possible. + +/// + +```Python hl_lines="9-14" +{!> ../docs_src/parameter_types/path/tutorial002.py!} +``` + +//// Check it: @@ -118,10 +140,13 @@ Error: Invalid value for '--config': File './' is a directory. ### Advanced `Path` configurations -!!! warning "Advanced Details" - You probably won't need these configurations at first, you may want to skip it. +/// warning | Advanced Details + +You probably won't need these configurations at first, you may want to skip it. + +They are used for more advanced use cases. - They are used for more advanced use cases. +/// * `allow_dash`: If this is set to True, a single dash to indicate standard streams is permitted. * `path_type`: optionally a string type that should be used to represent the path. The default is None which means the return value will be either bytes or unicode depending on what makes most sense given the input data Click deals with. diff --git a/docs/tutorial/parameter-types/uuid.md b/docs/tutorial/parameter-types/uuid.md index 8b96f6ad45..afe5986377 100644 --- a/docs/tutorial/parameter-types/uuid.md +++ b/docs/tutorial/parameter-types/uuid.md @@ -1,21 +1,24 @@ -!!! info - A UUID is a "Universally Unique Identifier". +# UUID - It's a standard format for identifiers, like passport numbers, but for anything, not just people in countries. +/// info - They look like this: +A UUID is a "Universally Unique Identifier". - ``` - d48edaa6-871a-4082-a196-4daab372d4a1 - ``` +It's a standard format for identifiers, like passport numbers, but for anything, not just people in countries. - The way they are generated makes them sufficiently long and random that you could assume that every UUID generated is unique. Even if it was generated by a different application, database, or system. +They look like this: - So, if your system uses UUIDs to identify your data, you could mix it with the data from some other system that also uses UUIDs with some confidence that their IDs (UUIDs) won't clash with yours. +``` +d48edaa6-871a-4082-a196-4daab372d4a1 +``` + +The way they are generated makes them sufficiently long and random that you could assume that every UUID generated is unique. Even if it was generated by a different application, database, or system. - This wouldn't be true if you just used `int`s as identifiers, as most databases do. +So, if your system uses UUIDs to identify your data, you could mix it with the data from some other system that also uses UUIDs with some confidence that their IDs (UUIDs) won't clash with yours. +This wouldn't be true if you just used `int`s as identifiers, as most databases do. +/// You can declare a *CLI parameter* as a UUID: diff --git a/docs/tutorial/printing.md b/docs/tutorial/printing.md index 058998473e..75150d329d 100644 --- a/docs/tutorial/printing.md +++ b/docs/tutorial/printing.md @@ -1,3 +1,5 @@ +# Printing and Colors + You can use the normal `print()` to show information on the screen: ```Python hl_lines="5" @@ -136,19 +138,25 @@ And there's another "**virtual file**" called "**standard error**" that is norma But we can also "print" to "standard error". And both are shown on the terminal to the users. -!!! info - If you use PowerShell it's quite possible that what you print to "standard error" won't be shown in the terminal. +/// info + +If you use PowerShell it's quite possible that what you print to "standard error" won't be shown in the terminal. + +In PowerShell, to see "standard error" you would have to check the variable `$Error`. - In PowerShell, to see "standard error" you would have to check the variable `$Error`. +But it will work normally in Bash, Zsh, and Fish. - But it will work normally in Bash, Zsh, and Fish. +/// ### Printing to "standard error" You can print to "standard error" creating a Rich `Console` with `stderr=True`. -!!! tip - `stderr` is short for "standard error". +/// tip + +`stderr` is short for "standard error". + +/// Using `stderr=True` tells **Rich** that the output should be shown in "standard error". @@ -182,10 +190,13 @@ But understanding that will come handy in the future, for example for autocomple ## Typer Echo -!!! warning - In most of the cases, for displaying advanced information, it is recommended to use Rich. +/// warning - You can probably skip the rest of this section. πŸŽ‰πŸ˜Ž +In most of the cases, for displaying advanced information, it is recommended to use Rich. + +You can probably skip the rest of this section. πŸŽ‰πŸ˜Ž + +/// **Typer** also has a small utility `typer.echo()` to print information on the screen, it comes directly from Click. But normally you shouldn't need it. @@ -203,18 +214,27 @@ If you have some `bytes` objects, you would probably want to decode them intenti And if you want to print data with colors and other features, you are much better off with the more advanced tools in **Rich**. -!!! info - `typer.echo()` comes directly from Click, you can read more about it in Click's docs. +/// info + +`typer.echo()` comes directly from Click, you can read more about it in Click's docs. + +/// ### Color -!!! note "Technical Details" - The way color works in terminals is by using some codes (ANSI escape sequences) as part of the text. +/// note | Technical Details + +The way color works in terminals is by using some codes (ANSI escape sequences) as part of the text. - So, a colored text is still just a `str`. +So, a colored text is still just a `str`. -!!! tip - Again, you are much better off using Rich for this. 😎 +/// + +/// tip + +Again, you are much better off using Rich for this. 😎 + +/// You can create colored strings to output to the terminal with `typer.style()`, that gives you `str`s that you can then pass to `typer.echo()`: @@ -222,10 +242,13 @@ You can create colored strings to output to the terminal with `typer.style()`, t {!../docs_src/printing/tutorial005.py!} ``` -!!! tip - The parameters `fg` and `bg` receive strings with the color names for the "**f**ore**g**round" and "**b**ack**g**round" colors. You could simply pass `fg="green"` and `bg="red"`. +/// tip + +The parameters `fg` and `bg` receive strings with the color names for the "**f**ore**g**round" and "**b**ack**g**round" colors. You could simply pass `fg="green"` and `bg="red"`. + +But **Typer** provides them all as variables like `typer.colors.GREEN` just so you can use autocompletion while selecting them. - But **Typer** provides them all as variables like `typer.colors.GREEN` just so you can use autocompletion while selecting them. +/// Check it: @@ -247,13 +270,19 @@ You can pass these function arguments to `typer.style()`: * `reverse`: enable or disable inverse rendering (foreground becomes background and the other way round). * `reset`: by default a reset-all code is added at the end of the string which means that styles do not carry over. This can be disabled to compose styles. -!!! info - You can read more about it in Click's docs about `style()` +/// info + +You can read more about it in Click's docs about `style()` + +/// ### `typer.secho()` - style and print -!!! tip - In case you didn't see above, you are much better off using Rich for this. 😎 +/// tip + +In case you didn't see above, you are much better off using Rich for this. 😎 + +/// There's a shorter form to style and print at the same time with `typer.secho()` it's like `typer.echo()` but also adds style like `typer.style()`: diff --git a/docs/tutorial/progressbar.md b/docs/tutorial/progressbar.md index 7b7bc166ab..250ea49382 100644 --- a/docs/tutorial/progressbar.md +++ b/docs/tutorial/progressbar.md @@ -1,3 +1,5 @@ +# Progress Bar + If you are executing an operation that can take some time, you can inform it to the user. πŸ€“ ## Progress Bar @@ -71,19 +73,27 @@ You can learn more about it in the Click's docs. +/// info + +`typer.progressbar()` comes directly from Click, you can read more about it in Click's docs. +/// ### Use `typer.progressbar` -!!! tip - Remember, you are much better off using Rich for this. 😎 +/// tip + +Remember, you are much better off using Rich for this. 😎 + +/// You can use `typer.progressbar()` with a `with` statement, as in: @@ -119,13 +129,19 @@ with typer.progressbar(users) as progress: typer.echo(user) ``` -!!! tip - Notice that there are 2 levels of code blocks. One for the `with` statement and one for the `for` statement. +/// tip + +Notice that there are 2 levels of code blocks. One for the `with` statement and one for the `for` statement. -!!! info - This is mostly useful for operations that take some time. +/// - In the example above we are faking it with `time.sleep()`. +/// info + +This is mostly useful for operations that take some time. + +In the example above we are faking it with `time.sleep()`. + +/// Check it: @@ -143,8 +159,11 @@ Processed 100 things. ### Setting a Progress Bar `length` -!!! tip - Remember, you are much better off using Rich for this. 😎 +/// tip + +Remember, you are much better off using Rich for this. 😎 + +/// The progress bar is generated from the length of the iterable (e.g. the list of users). @@ -192,8 +211,11 @@ would print each of the "user IDs" (here it's just the numbers from `0` to `99`) ### Add a `label` -!!! tip - Remember, you are much better off using Rich for this. 😎 +/// tip + +Remember, you are much better off using Rich for this. 😎 + +/// You can also set a `label`: diff --git a/docs/tutorial/prompt.md b/docs/tutorial/prompt.md index ef3c3e0a12..3203edbfa1 100644 --- a/docs/tutorial/prompt.md +++ b/docs/tutorial/prompt.md @@ -1,3 +1,5 @@ +# Ask with Prompt + When you need to ask the user for info interactively you should normally use [*CLI Option*s with Prompt](options/prompt.md){.internal-link target=_blank}, because they allow using the CLI program in a non-interactive way (for example, a Bash script could use it). But if you absolutely need to ask for interactive information without using a *CLI option*, you can use `typer.prompt()`: diff --git a/docs/tutorial/subcommands/add-typer.md b/docs/tutorial/subcommands/add-typer.md index 0e867558cc..55439acf29 100644 --- a/docs/tutorial/subcommands/add-typer.md +++ b/docs/tutorial/subcommands/add-typer.md @@ -1,3 +1,5 @@ +# Add Typer + We'll start with the core idea. To add a `typer.Typer()` app inside of another. @@ -127,8 +129,11 @@ Selling item: Vase
-!!! tip - Notice that we are still calling `$ python main.py` but now we are using the command `items`. +/// tip + +Notice that we are still calling `$ python main.py` but now we are using the command `items`. + +/// And now check the command `users`, with all its subcommands: diff --git a/docs/tutorial/subcommands/callback-override.md b/docs/tutorial/subcommands/callback-override.md index 6a2683e9e3..fa82d4ee3b 100644 --- a/docs/tutorial/subcommands/callback-override.md +++ b/docs/tutorial/subcommands/callback-override.md @@ -1,3 +1,5 @@ +# Sub-Typer Callback Override + When creating a **Typer** app you can define a callback function, it always executes and defines the *CLI arguments* and *CLI options* that go before a command. When adding a Typer app inside of another, the sub-Typer can also have its own callback. diff --git a/docs/tutorial/subcommands/index.md b/docs/tutorial/subcommands/index.md index 5a8df35958..86df1af904 100644 --- a/docs/tutorial/subcommands/index.md +++ b/docs/tutorial/subcommands/index.md @@ -1,3 +1,5 @@ +# SubCommands - Command Groups + You read before how to create a program with [Commands](../commands/index.md){.internal-link target=_blank}. Now we'll see how to create a *CLI program* with commands that have their own subcommands. Also known as command groups. diff --git a/docs/tutorial/subcommands/name-and-help.md b/docs/tutorial/subcommands/name-and-help.md index 474dc91ae9..e6d96caa54 100644 --- a/docs/tutorial/subcommands/name-and-help.md +++ b/docs/tutorial/subcommands/name-and-help.md @@ -1,3 +1,5 @@ +# SubCommand Name and Help + When adding a Typer app to another we have seen how to set the `name` to use for the command. For example to set the command to `users`: @@ -52,10 +54,13 @@ We can set the `name` and `help` in several places, each one taking precedence o Let's see those locations. -!!! tip - There are other attributes that can be set in that same way in the same places we'll see next. +/// tip + +There are other attributes that can be set in that same way in the same places we'll see next. - But those are documented later in another section. +But those are documented later in another section. + +/// ## Inferring name and help from callback @@ -296,8 +301,11 @@ But if you set the name and help text explicitly, that has a higher priority tha Let's now see the places where you can set the command name and help text, from lowest priority to highest. -!!! tip - Setting the name and help text explicitly always has a higher precedence than inferring from a callback function. +/// tip + +Setting the name and help text explicitly always has a higher precedence than inferring from a callback function. + +/// ### Name and help in `typer.Typer()` @@ -311,8 +319,11 @@ You can set it when creating a new `typer.Typer()`: {!../docs_src/subcommands/name_help/tutorial006.py!} ``` -!!! info - The rest of the callbacks and overrides are there only to show you that they don't affect the name and help text when you set it explicitly. +/// info + +The rest of the callbacks and overrides are there only to show you that they don't affect the name and help text when you set it explicitly. + +/// We set an explicit name `exp-users`, and an explicit help `Explicit help.`. diff --git a/docs/tutorial/subcommands/nested-subcommands.md b/docs/tutorial/subcommands/nested-subcommands.md index a3fbe6c827..c991faa9da 100644 --- a/docs/tutorial/subcommands/nested-subcommands.md +++ b/docs/tutorial/subcommands/nested-subcommands.md @@ -1,3 +1,5 @@ +# Nested SubCommands + We'll now see how these same ideas can be extended for deeply nested commands. Let's imagine that the same *CLI program* from the previous examples now needs to handle `lands`. @@ -278,10 +280,13 @@ Here are all the files if you want to review/copy them: {!../docs_src/subcommands/tutorial003/main.py!} ``` -!!! tip - All these files have an `if __name__ == "__main__"` block just to demonstrate how each of them can also be an independent *CLI app*. +/// tip + +All these files have an `if __name__ == "__main__"` block just to demonstrate how each of them can also be an independent *CLI app*. + +But for your final application, only `main.py` would need it. - But for your final application, only `main.py` would need it. +/// ## Recap @@ -289,7 +294,10 @@ That's it, you can just add **Typer** applications one inside another as much as You can probably achieve a simpler *CLI program* design that's easier to use than the example here. But if your requirements are complex, **Typer** helps you build your *CLI app* easily. -!!! tip - Auto completion helps a lot, specially with complex programs. +/// tip + +Auto completion helps a lot, specially with complex programs. + +Check the docs about adding auto completion to your *CLI apps*. - Check the docs about adding auto completion to your *CLI apps*. +/// diff --git a/docs/tutorial/subcommands/single-file.md b/docs/tutorial/subcommands/single-file.md index 88abd9578c..50645267cd 100644 --- a/docs/tutorial/subcommands/single-file.md +++ b/docs/tutorial/subcommands/single-file.md @@ -1,3 +1,5 @@ +# SubCommands in a Single File + In some cases, it's possible that your application code needs to live on a single file. You can still use the same ideas: diff --git a/docs/tutorial/terminating.md b/docs/tutorial/terminating.md index 94f6d239e0..a8d0b49fa3 100644 --- a/docs/tutorial/terminating.md +++ b/docs/tutorial/terminating.md @@ -1,3 +1,5 @@ +# Terminating + There are some cases where you might want to terminate a command at some point, and stop all subsequent execution. It could be that your code determined that the program completed successfully, or it could be an operation aborted. @@ -40,12 +42,15 @@ The user already exists -!!! tip - Even though you are raising an exception, it doesn't necessarily mean there's an error. +/// tip + +Even though you are raising an exception, it doesn't necessarily mean there's an error. + +This is done with an exception because it works as an "error" and stops all execution. - This is done with an exception because it works as an "error" and stops all execution. +But then **Typer** (actually Click) catches it and just terminates the program normally. - But then **Typer** (actually Click) catches it and just terminates the program normally. +/// ## Exit with an error @@ -86,8 +91,11 @@ $ echo $? -!!! tip - The error code might be used by other programs (for example a Bash script) that execute your CLI program. +/// tip + +The error code might be used by other programs (for example a Bash script) that execute your CLI program. + +/// ## Abort diff --git a/docs/tutorial/testing.md b/docs/tutorial/testing.md index 2df3460ba4..2fc7e54f09 100644 --- a/docs/tutorial/testing.md +++ b/docs/tutorial/testing.md @@ -1,3 +1,5 @@ +# Testing + Testing **Typer** applications is very easy with pytest. Let's say you have an application `app/main.py` with: @@ -37,8 +39,11 @@ This runner is what will "invoke" or "call" your command line application. {!../docs_src/testing/app01/test_main.py!} ``` -!!! tip - It's important that the name of the file starts with `test_`, that way pytest will be able to detect it and use it automatically. +/// tip + +It's important that the name of the file starts with `test_`, that way pytest will be able to detect it and use it automatically. + +/// ### Call the app @@ -54,8 +59,11 @@ The second parameter is a `list` of `str`, with all the text you would pass in t {!../docs_src/testing/app01/test_main.py!} ``` -!!! tip - The name of the function has to start with `test_`, that way pytest can detect it and use it automatically. +/// tip + +The name of the function has to start with `test_`, that way pytest can detect it and use it automatically. + +/// ### Check the result @@ -69,11 +77,17 @@ Here we are checking that the exit code is 0, as it is for programs that exit wi Then we check that the text printed to "standard output" contains the text that our CLI program prints. -!!! tip - You could also check `result.stderr` for "standard error" independently from "standard output" if your `CliRunner` instance is created with the `mix_stderr=False` argument. +/// tip + +You could also check `result.stderr` for "standard error" independently from "standard output" if your `CliRunner` instance is created with the `mix_stderr=False` argument. + +/// + +/// info + +If you need a refresher about what is "standard output" and "standard error" check the section in [Printing and Colors: "Standard Output" and "Standard Error"](printing.md#standard-output-and-standard-error){.internal-link target=_blank}. -!!! info - If you need a refresher about what is "standard output" and "standard error" check the section in [Printing and Colors: "Standard Output" and "Standard Error"](printing.md#standard-output-and-standard-error){.internal-link target=_blank}. +/// ### Call `pytest` @@ -103,20 +117,27 @@ test_main.py . If you have a CLI with prompts, like: -=== "Python 3.7+" +//// tab | Python 3.7+ - ```Python hl_lines="8" - {!> ../docs_src/testing/app02_an/main.py!} - ``` +```Python hl_lines="8" +{!> ../docs_src/testing/app02_an/main.py!} +``` + +//// + +//// tab | Python 3.7+ non-Annotated + +/// tip -=== "Python 3.7+ non-Annotated" +Prefer to use the `Annotated` version if possible. - !!! tip - Prefer to use the `Annotated` version if possible. +/// - ```Python hl_lines="7" - {!> ../docs_src/testing/app02/main.py!} - ``` +```Python hl_lines="7" +{!> ../docs_src/testing/app02/main.py!} +``` + +//// That you would use like: @@ -136,8 +157,11 @@ You can test the input typed in the terminal using `input="camila@example.com\n" This is because what you type in the terminal goes to "**standard input**" and is handled by the operating system as if it was a "virtual file". -!!! info - If you need a refresher about what is "standard output", "standard error", and "standard input" check the section in [Printing and Colors: "Standard Output" and "Standard Error"](printing.md#standard-output-and-standard-error){.internal-link target=_blank}. +/// info + +If you need a refresher about what is "standard output", "standard error", and "standard input" check the section in [Printing and Colors: "Standard Output" and "Standard Error"](printing.md#standard-output-and-standard-error){.internal-link target=_blank}. + +/// When you hit the ENTER key after typing the email, that is just a "new line character". And in Python that is represented with `"\n"`. diff --git a/docs/tutorial/typer-command.md b/docs/tutorial/typer-command.md index 021dee002d..004415a6ae 100644 --- a/docs/tutorial/typer-command.md +++ b/docs/tutorial/typer-command.md @@ -261,12 +261,15 @@ $ typer some_script.py utils docs -!!! tip - If you installed only `typer-slim` and you don't have the `typer` command, you can still generate docs with: +/// tip - ```console - $ python -m typer some_script.py utils docs - ``` +If you installed only `typer-slim` and you don't have the `typer` command, you can still generate docs with: + +```console +$ python -m typer some_script.py utils docs +``` + +/// **Options**: diff --git a/docs/tutorial/using-click.md b/docs/tutorial/using-click.md index d4d32057e6..950531ff7f 100644 --- a/docs/tutorial/using-click.md +++ b/docs/tutorial/using-click.md @@ -1,7 +1,12 @@ -!!! warning - This is a more advanced topic, if you are starting with **Typer**, feel free to skip it. +# Using Click - It will be mostly useful for people that already work with Click and have questions around it. +/// warning + +This is a more advanced topic, if you are starting with **Typer**, feel free to skip it. + +It will be mostly useful for people that already work with Click and have questions around it. + +/// **Typer** is powered by Click. It does all the work underneath. @@ -47,8 +52,11 @@ For example: The `cli` variable is converted by Click from a function to a `Group` object. And the original `cli` function is used by that `Group` internally. -!!! tip - The original `cli` function would be the equivalent of a [Typer Callback](./commands/callback.md){.internal-link target=_blank}. +/// tip + +The original `cli` function would be the equivalent of a [Typer Callback](./commands/callback.md){.internal-link target=_blank}. + +/// Then the `cli` variable, that now is a `Group` object, is used to add sub-commands. @@ -66,8 +74,11 @@ But **Typer** creates a Click `Group` object if your app has any of: * A callback. * Sub-Typer apps (sub commands). -!!! tip - If you want to learn more about this check the section [One or Multiple Commands](./commands/one-or-multiple.md){.internal-link target=_blank}. +/// tip + +If you want to learn more about this check the section [One or Multiple Commands](./commands/one-or-multiple.md){.internal-link target=_blank}. + +/// ### Combine Click and **Typer** @@ -181,7 +192,10 @@ Most of the functionality provided by decorators in Click has an alternative way For example, to access the context, you can just declare a function parameter of type `typer.Context`. -!!! tip - You can read more about using the context in the docs: [Commands: Using the Context](commands/context.md){.internal-link target=_blank} +/// tip + +You can read more about using the context in the docs: [Commands: Using the Context](commands/context.md){.internal-link target=_blank} + +/// But if you need to use something based on Click decorators, you can always generate a Click object using the methods described above, and use it as you would normally use Click. diff --git a/mkdocs.insiders.yml b/mkdocs.insiders.yml index bb475642cd..c1568000e2 100644 --- a/mkdocs.insiders.yml +++ b/mkdocs.insiders.yml @@ -1,4 +1,7 @@ -INHERIT: mkdocs.yml plugins: - social: typeset: +markdown_extensions: + material.extensions.preview: + targets: + include: + - ./* diff --git a/mkdocs.maybe-insiders.yml b/mkdocs.maybe-insiders.yml new file mode 100644 index 0000000000..07aefaaa99 --- /dev/null +++ b/mkdocs.maybe-insiders.yml @@ -0,0 +1,6 @@ +# Define this here and not in the main mkdocs.yml file because that one could be auto +# updated and written, and the script would remove the env var +INHERIT: !ENV [INSIDERS_FILE, './mkdocs.no-insiders.yml'] +markdown_extensions: + pymdownx.highlight: + linenums: !ENV [LINENUMS, false] diff --git a/mkdocs.no-insiders.yml b/mkdocs.no-insiders.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mkdocs.yml b/mkdocs.yml index 77024d83bb..707c9a52f7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,3 +1,4 @@ +INHERIT: ./mkdocs.maybe-insiders.yml site_name: Typer site_description: Typer, build great CLIs. Easy to code. Based on Python type hints. site_url: https://typer.tiangolo.com/ @@ -6,117 +7,197 @@ theme: name: material custom_dir: docs/overrides palette: + - media: "(prefers-color-scheme)" + toggle: + icon: material/lightbulb-auto + name: Switch to light mode + - media: '(prefers-color-scheme: light)' + scheme: default primary: black accent: teal + toggle: + icon: material/lightbulb + name: Switch to dark mode + - media: '(prefers-color-scheme: dark)' + scheme: slate + primary: black + accent: teal + toggle: + icon: material/lightbulb-outline + name: Switch to system preference + features: + - content.code.annotate + - content.code.copy + # - content.code.select + - content.footnote.tooltips + - content.tabs.link + - content.tooltips + - navigation.footer + - navigation.indexes + - navigation.instant + - navigation.instant.prefetch + - navigation.instant.preview + - navigation.instant.progress + - navigation.path + # - navigation.tabs + # - navigation.tabs.sticky + - navigation.top + - navigation.tracking + - search.highlight + - search.share + - search.suggest + - toc.follow + icon: repo: fontawesome/brands/github-alt - logo: img/icon-white.svg + logo: img/icon.svg favicon: img/favicon.png - + language: en repo_name: tiangolo/typer repo_url: https://github.com/tiangolo/typer -edit_uri: "" plugins: - search: null + # Material for MkDocs + search: + social: + # Other plugins redirects: redirect_maps: typer-cli.md: tutorial/typer-command.md nav: - Typer: index.md - - Features: features.md + - features.md - Tutorial - User Guide: - - Tutorial - User Guide - Intro: tutorial/index.md - - First Steps: tutorial/first-steps.md - - Printing and Colors: tutorial/printing.md - - Terminating: tutorial/terminating.md + - tutorial/index.md + - tutorial/first-steps.md + - tutorial/printing.md + - tutorial/terminating.md - CLI Arguments: - - CLI Arguments Intro: tutorial/arguments/index.md - - Optional CLI Arguments: tutorial/arguments/optional.md - - CLI Arguments with Default: tutorial/arguments/default.md - - CLI Arguments with Help: tutorial/arguments/help.md - - CLI Arguments with Environment Variables: tutorial/arguments/envvar.md - - Other uses: tutorial/arguments/other-uses.md + - tutorial/arguments/index.md + - tutorial/arguments/optional.md + - tutorial/arguments/default.md + - tutorial/arguments/help.md + - tutorial/arguments/envvar.md + - tutorial/arguments/other-uses.md - CLI Options: - - CLI Options Intro: tutorial/options/index.md - - CLI Options with Help: tutorial/options/help.md - - Required CLI Options: tutorial/options/required.md - - CLI Option Prompt: tutorial/options/prompt.md - - Password CLI Option and Confirmation Prompt: tutorial/options/password.md - - CLI Option Name: tutorial/options/name.md - - CLI Option Callback and Context: tutorial/options/callback-and-context.md - - Version CLI Option, is_eager: tutorial/options/version.md + - tutorial/options/index.md + - tutorial/options/help.md + - tutorial/options/required.md + - tutorial/options/prompt.md + - tutorial/options/password.md + - tutorial/options/name.md + - tutorial/options/callback-and-context.md + - tutorial/options/version.md - Commands: - - Commands Intro: tutorial/commands/index.md - - Command CLI Arguments: tutorial/commands/arguments.md - - Command CLI Options: tutorial/commands/options.md - - Command Help: tutorial/commands/help.md - - Custom Command Name: tutorial/commands/name.md - - Typer Callback: tutorial/commands/callback.md - - One or Multiple Commands: tutorial/commands/one-or-multiple.md - - Using the Context: tutorial/commands/context.md - - CLI Option autocompletion: tutorial/options-autocompletion.md + - tutorial/commands/index.md + - tutorial/commands/arguments.md + - tutorial/commands/options.md + - tutorial/commands/help.md + - tutorial/commands/name.md + - tutorial/commands/callback.md + - tutorial/commands/one-or-multiple.md + - tutorial/commands/context.md + - tutorial/options-autocompletion.md - CLI Parameter Types: - - CLI Parameter Types Intro: tutorial/parameter-types/index.md - - Number: tutorial/parameter-types/number.md - - Boolean CLI Options: tutorial/parameter-types/bool.md - - UUID: tutorial/parameter-types/uuid.md - - DateTime: tutorial/parameter-types/datetime.md - - Enum - Choices: tutorial/parameter-types/enum.md - - Path: tutorial/parameter-types/path.md - - File: tutorial/parameter-types/file.md - - Custom Types: tutorial/parameter-types/custom-types.md + - tutorial/parameter-types/index.md + - tutorial/parameter-types/number.md + - tutorial/parameter-types/bool.md + - tutorial/parameter-types/uuid.md + - tutorial/parameter-types/datetime.md + - tutorial/parameter-types/enum.md + - tutorial/parameter-types/path.md + - tutorial/parameter-types/file.md + - tutorial/parameter-types/custom-types.md - SubCommands - Command Groups: - - SubCommands - Command Groups - Intro: tutorial/subcommands/index.md - - Add Typer: tutorial/subcommands/add-typer.md - - SubCommands in a Single File: tutorial/subcommands/single-file.md - - Nested SubCommands: tutorial/subcommands/nested-subcommands.md - - Sub-Typer Callback Override: tutorial/subcommands/callback-override.md - - SubCommand Name and Help: tutorial/subcommands/name-and-help.md + - tutorial/subcommands/index.md + - tutorial/subcommands/add-typer.md + - tutorial/subcommands/single-file.md + - tutorial/subcommands/nested-subcommands.md + - tutorial/subcommands/callback-override.md + - tutorial/subcommands/name-and-help.md - Multiple Values: - - Multiple Values Intro: tutorial/multiple-values/index.md - - Multiple CLI Options: tutorial/multiple-values/multiple-options.md - - CLI Options with Multiple Values: tutorial/multiple-values/options-with-multiple-values.md - - CLI Arguments with Multiple Values: tutorial/multiple-values/arguments-with-multiple-values.md - - Ask with Prompt: tutorial/prompt.md - - Progress Bar: tutorial/progressbar.md - - CLI Application Directory: tutorial/app-dir.md - - Launching Applications: tutorial/launch.md - - Testing: tutorial/testing.md - - Using Click: tutorial/using-click.md - - Building a Package: tutorial/package.md + - tutorial/multiple-values/index.md + - tutorial/multiple-values/multiple-options.md + - tutorial/multiple-values/options-with-multiple-values.md + - tutorial/multiple-values/arguments-with-multiple-values.md + - tutorial/prompt.md + - tutorial/progressbar.md + - tutorial/app-dir.md + - tutorial/launch.md + - tutorial/testing.md + - tutorial/using-click.md + - tutorial/package.md - tutorial/exceptions.md - tutorial/typer-command.md - - Alternatives, Inspiration and Comparisons: alternatives.md - - Help Typer - Get Help: help-typer.md - - Development - Contributing: contributing.md - - Release Notes: release-notes.md + - alternatives.md + - help-typer.md + - contributing.md + - release-notes.md markdown_extensions: - - toc: - permalink: true - - markdown.extensions.codehilite: - guess_lang: false - - admonition - - codehilite - - extra - - pymdownx.superfences: - custom_fences: - - name: mermaid - class: mermaid - format: !!python/name:pymdownx.superfences.fence_code_format '' - - pymdownx.tabbed: - alternate_style: true - - mdx_include: - base_path: docs - # Enable while writing docs to simplify highlighting - # - pymdownx.highlight: - # linenums: true + # Python Markdown + abbr: + attr_list: + footnotes: + md_in_html: + tables: + toc: + permalink: true + + # Python Markdown Extensions + pymdownx.betterem: + smart_enable: all + pymdownx.caret: + pymdownx.highlight: + line_spans: __span + pymdownx.inlinehilite: + pymdownx.keys: + pymdownx.mark: + pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + pymdownx.tilde: + + # pymdownx blocks + pymdownx.blocks.admonition: + types: + - note + - attention + - caution + - danger + - error + - tip + - hint + - warning + # Custom types + - info + pymdownx.blocks.details: + pymdownx.blocks.tab: + alternate_style: True + + # Other extensions + mdx_include: + base_path: docs extra: analytics: provider: google property: G-T78C5GNRXK + feedback: + title: Was this page helpful? + ratings: + - icon: material/emoticon-happy-outline + name: This page was helpful + data: 1 + note: >- + Thanks for your feedback! + - icon: material/emoticon-sad-outline + name: This page could be improved + data: 0 + note: >- + Thanks for your feedback! social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/typer @@ -136,6 +217,8 @@ extra_css: - css/custom.css extra_javascript: - - https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - js/termynal.js - js/custom.js + +hooks: + - scripts/mkdocs_hooks.py diff --git a/requirements-docs-insiders.txt b/requirements-docs-insiders.txt new file mode 100644 index 0000000000..d8d3c37a9f --- /dev/null +++ b/requirements-docs-insiders.txt @@ -0,0 +1,3 @@ +git+https://${TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git@9.5.30-insiders-4.53.11 +git+https://${TOKEN}@github.com/pawamoy-insiders/griffe-typing-deprecated.git +git+https://${TOKEN}@github.com/pawamoy-insiders/mkdocstrings-python.git diff --git a/requirements-docs.txt b/requirements-docs.txt index a85c03c87d..4ad8149417 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,17 +1,18 @@ -e . -mkdocs-material==9.4.7 +mkdocs-material==9.5.18 mdx-include >=1.4.1,<2.0.0 -mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0 mkdocs-redirects>=1.2.1,<1.3.0 pyyaml >=5.3.1,<7.0.0 # For Material for MkDocs, Chinese search -jieba==0.42.1 +# jieba==0.42.1 # For image processing by Material for MkDocs pillow==10.3.0 # For image processing by Material for MkDocs -cairosvg==2.7.0 -mkdocstrings[python]==0.23.0 -griffe-typingdoc==0.2.2 +cairosvg==2.7.1 +# mkdocstrings[python]==0.25.1 +# Enable griffe-typingdoc once dropping Python 3.7 and upgrading typing-extensions +# griffe-typingdoc==0.2.5 # For griffe, it formats with black -black==24.3.0 +# black==24.3.0 +mkdocs-macros-plugin==1.0.5 diff --git a/requirements-github-actions.txt b/requirements-github-actions.txt new file mode 100644 index 0000000000..559dc06fb2 --- /dev/null +++ b/requirements-github-actions.txt @@ -0,0 +1,4 @@ +PyGithub>=2.3.0,<3.0.0 +pydantic>=2.5.3,<3.0.0 +pydantic-settings>=2.1.0,<3.0.0 +httpx>=0.27.0,<0.28.0 diff --git a/scripts/build-docs.sh b/scripts/build-docs.sh deleted file mode 100755 index 4f4ae2f74e..0000000000 --- a/scripts/build-docs.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -python -m mkdocs build - -cp ./docs/index.md ./README.md diff --git a/scripts/clean.sh b/scripts/clean.sh deleted file mode 100755 index d5a4b790ae..0000000000 --- a/scripts/clean.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -e - -if [ -d 'dist' ] ; then - rm -r dist -fi -if [ -d 'site' ] ; then - rm -r site -fi diff --git a/scripts/deploy_docs_status.py b/scripts/deploy_docs_status.py new file mode 100644 index 0000000000..8cef2f7581 --- /dev/null +++ b/scripts/deploy_docs_status.py @@ -0,0 +1,89 @@ +import logging +import re + +from github import Github +from pydantic import SecretStr +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + github_repository: str + github_token: SecretStr + deploy_url: str | None = None + commit_sha: str + run_id: int + is_done: bool = False + + +def main(): + logging.basicConfig(level=logging.INFO) + settings = Settings() + + logging.info(f"Using config: {settings.model_dump_json()}") + g = Github(settings.github_token.get_secret_value()) + repo = g.get_repo(settings.github_repository) + use_pr = next( + (pr for pr in repo.get_pulls() if pr.head.sha == settings.commit_sha), None + ) + if not use_pr: + logging.error(f"No PR found for hash: {settings.commit_sha}") + return + commits = list(use_pr.get_commits()) + current_commit = [c for c in commits if c.sha == settings.commit_sha][0] + run_url = f"https://github.com/{settings.github_repository}/actions/runs/{settings.run_id}" + if settings.is_done and not settings.deploy_url: + current_commit.create_status( + state="success", + description="No Docs Changes", + context="deploy-docs", + target_url=run_url, + ) + logging.info("No docs changes found") + return + if not settings.deploy_url: + current_commit.create_status( + state="pending", + description="Deploying Docs", + context="deploy-docs", + target_url=run_url, + ) + logging.info("No deploy URL available yet") + return + current_commit.create_status( + state="success", + description="Docs Deployed", + context="deploy-docs", + target_url=run_url, + ) + + files = list(use_pr.get_files()) + docs_files = [f for f in files if f.filename.startswith("docs/")] + + deploy_url = settings.deploy_url.rstrip("/") + links: list[str] = [] + for f in docs_files: + match = re.match(r"docs/(.*)", f.filename) + assert match + path = match.group(1) + if path.endswith("index.md"): + path = path.replace("index.md", "") + else: + path = path.replace(".md", "/") + link = f"{deploy_url}/{path}" + links.append(link) + links.sort() + + message = f"πŸ“ Docs preview for commit {settings.commit_sha} at: {deploy_url}" + + if links: + message += "\n\n### Modified Pages\n\n" + message += "\n".join([f"* {link}" for link in links]) + + print(message) + use_pr.as_issue().create_comment(message) + + logging.info("Finished") + + +if __name__ == "__main__": + main() diff --git a/scripts/docs-live.sh b/scripts/docs-live.sh deleted file mode 100755 index 5342a9e59f..0000000000 --- a/scripts/docs-live.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -set -e - -mkdocs serve --dev-addr 127.0.0.1:8008 diff --git a/scripts/docs.py b/scripts/docs.py new file mode 100644 index 0000000000..3a3ef7f062 --- /dev/null +++ b/scripts/docs.py @@ -0,0 +1,136 @@ +import logging +import os +import re +import subprocess +from functools import lru_cache +from http.server import HTTPServer, SimpleHTTPRequestHandler +from importlib import metadata +from pathlib import Path + +import typer + +logging.basicConfig(level=logging.INFO) + +mkdocs_name = "mkdocs.yml" +en_docs_path = Path("") + +app = typer.Typer() + + +@lru_cache +def is_mkdocs_insiders() -> bool: + version = metadata.version("mkdocs-material") + return "insiders" in version + + +@app.callback() +def callback() -> None: + if is_mkdocs_insiders(): + os.environ["INSIDERS_FILE"] = "./mkdocs.insiders.yml" + # For MacOS with insiders and Cairo + os.environ["DYLD_FALLBACK_LIBRARY_PATH"] = "/opt/homebrew/lib" + + +def generate_readme_content() -> str: + en_index = en_docs_path / "docs" / "index.md" + content = en_index.read_text("utf-8") + match_pre = re.search(r"\n\n", content) + if not match_pre: + raise RuntimeError("Couldn't find pre section (