@@ -107,9 +103,7 @@ Now let's say we want to have the name and last name separated.
So, extend that to have 2 arguments, `name` and `lastname`:
-```Python hl_lines="4 5"
-{!../docs_src/first_steps/tutorial003.py!}
-```
+{* docs_src/first_steps/tutorial003.py hl[4,5] *}
@@ -234,9 +228,7 @@ This one doesn't receive any values. But *CLI options* can also receive values l
Now add a `--formal` *CLI option*:
-```Python hl_lines="4 5"
-{!../docs_src/first_steps/tutorial004.py!}
-```
+{* docs_src/first_steps/tutorial004.py hl[4,5] *}
Here `formal` is a `bool` that is `False` by default.
@@ -297,9 +289,7 @@ Good day Ms. Camila Gutiérrez.
To convert the `lastname` from a *CLI argument* to a *CLI option*, give it a default value of `""`:
-```Python hl_lines="4"
-{!../docs_src/first_steps/tutorial005.py!}
-```
+{* docs_src/first_steps/tutorial005.py hl[4] *}
As `lastname` now has a default value of `""` (an empty string) it is no longer required in the function, and **Typer** will now by default make it an optional *CLI option*.
@@ -370,9 +360,7 @@ Hello Camila Gutiérrez
If you add a
docstring to your function it will be used in the help text:
-```Python hl_lines="5 6 7 8 9"
-{!../docs_src/first_steps/tutorial006.py!}
-```
+{* docs_src/first_steps/tutorial006.py hl[5,6,7,8,9] *}
Now see it with the `--help` option:
diff --git a/docs/tutorial/launch.md b/docs/tutorial/launch.md
index 935bd7e632..740d7efae6 100644
--- a/docs/tutorial/launch.md
+++ b/docs/tutorial/launch.md
@@ -4,9 +4,7 @@ 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:
-```Python hl_lines="6"
-{!../docs_src/launch/tutorial001.py!}
-```
+{* docs_src/launch/tutorial001.py hl[6] *}
Check it:
@@ -26,9 +24,7 @@ Opening Typer docs
You can also make the operating system open the file browser indicating where a file is located with `locate=True`:
-```Python hl_lines="17"
-{!../docs_src/launch/tutorial002.py!}
-```
+{* docs_src/launch/tutorial002.py hl[17] *}
/// tip
diff --git a/docs/tutorial/multiple-values/arguments-with-multiple-values.md b/docs/tutorial/multiple-values/arguments-with-multiple-values.md
index b48484c105..97af5e0edf 100644
--- a/docs/tutorial/multiple-values/arguments-with-multiple-values.md
+++ b/docs/tutorial/multiple-values/arguments-with-multiple-values.md
@@ -4,9 +4,7 @@
You can define the type of a *CLI argument* using `typing.List`.
-```Python hl_lines="7"
-{!../docs_src/multiple_values/arguments_with_multiple_values/tutorial001.py!}
-```
+{* docs_src/multiple_values/arguments_with_multiple_values/tutorial001.py hl[7] *}
And then you can pass it as many *CLI arguments* of that type as you want:
@@ -39,27 +37,7 @@ A `List` can only be used in the last command (if there are subcommands), as thi
If you want a specific number of values and types, you can use a tuple, and it can even have default values:
-//// tab | Python 3.7+
-
-```Python hl_lines="8-10"
-{!> ../docs_src/multiple_values/arguments_with_multiple_values/tutorial002_an.py!}
-```
-
-////
-
-//// 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!}
-```
-
-////
+{* docs_src/multiple_values/arguments_with_multiple_values/tutorial002_an.py hl[8:10] *}
Check it:
diff --git a/docs/tutorial/multiple-values/multiple-options.md b/docs/tutorial/multiple-values/multiple-options.md
index 0c876eab52..ef03e13c08 100644
--- a/docs/tutorial/multiple-values/multiple-options.md
+++ b/docs/tutorial/multiple-values/multiple-options.md
@@ -6,27 +6,7 @@ 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`:
-//// tab | Python 3.7+
-
-```Python hl_lines="1 7"
-{!> ../docs_src/multiple_values/multiple_options/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="1 6"
-{!> ../docs_src/multiple_values/multiple_options/tutorial001.py!}
-```
-
-////
+{* docs_src/multiple_values/multiple_options/tutorial001_an.py hl[1,7] *}
You will receive the values as you declared them, as a `list` of `str`.
@@ -60,27 +40,7 @@ Processing user: Morty
The same way, you can use other types and they will be converted by **Typer** to their declared type:
-//// tab | Python 3.7+
-
-```Python hl_lines="7"
-{!> ../docs_src/multiple_values/multiple_options/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="6"
-{!> ../docs_src/multiple_values/multiple_options/tutorial002.py!}
-```
-
-////
+{* docs_src/multiple_values/multiple_options/tutorial002_an.py hl[7] *}
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 1d3f5deff4..8f37d2df51 100644
--- a/docs/tutorial/multiple-values/options-with-multiple-values.md
+++ b/docs/tutorial/multiple-values/options-with-multiple-values.md
@@ -6,27 +6,7 @@ You can set the number of values and types to anything you want, but it has to b
For this, use the standard Python `typing.Tuple`:
-//// tab | Python 3.7+
-
-```Python hl_lines="1 7"
-{!> ../docs_src/multiple_values/options_with_multiple_values/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="1 6"
-{!> ../docs_src/multiple_values/options_with_multiple_values/tutorial001.py!}
-```
-
-////
+{* docs_src/multiple_values/options_with_multiple_values/tutorial001_an.py hl[1,7] *}
Each of the internal types defines the type of each value in the tuple.
diff --git a/docs/tutorial/options-autocompletion.md b/docs/tutorial/options-autocompletion.md
index 43777d04fb..fdfc875f7c 100644
--- a/docs/tutorial/options-autocompletion.md
+++ b/docs/tutorial/options-autocompletion.md
@@ -16,27 +16,7 @@ To check it quickly without creating a new Python package, use the `typer` comma
Then let's create small example program:
-//// tab | Python 3.7+
-
-```Python
-{!> ../docs_src/options_autocompletion/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python
-{!> ../docs_src/options_autocompletion/tutorial001.py!}
-```
-
-////
+{* docs_src/options_autocompletion/tutorial001_an.py *}
And let's try it with the `typer` command to get completion:
@@ -70,27 +50,7 @@ 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}:
-//// tab | Python 3.7+
-
-```Python hl_lines="5-6 15"
-{!> ../docs_src/options_autocompletion/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="4-5 14"
-{!> ../docs_src/options_autocompletion/tutorial002.py!}
-```
-
-////
+{* docs_src/options_autocompletion/tutorial002_an.py hl[5:6,15] *}
We return a `list` of strings from the `complete_name()` function.
@@ -119,27 +79,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="7-12"
-{!> ../docs_src/options_autocompletion/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="6-11"
-{!> ../docs_src/options_autocompletion/tutorial003.py!}
-```
-
-////
+{* docs_src/options_autocompletion/tutorial003_an.py hl[7:12] *}
Now let's try it:
@@ -178,27 +118,7 @@ In the `complete_name()` function, instead of providing one `str` per completion
So, in the end, we return a `list` of `tuples` of `str`:
-//// 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!}
-```
-
-////
+{* docs_src/options_autocompletion/tutorial004_an.py hl[4:8,11:17] *}
/// tip
@@ -239,27 +159,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="11-14"
-{!> ../docs_src/options_autocompletion/tutorial005_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="10-13"
-{!> ../docs_src/options_autocompletion/tutorial005.py!}
-```
-
-////
+{* docs_src/options_autocompletion/tutorial005_an.py hl[11:14] *}
That simplifies our code a bit and works the same.
@@ -295,27 +195,7 @@ So, for now, take this as a sneak peek 😉.
For this we use a `List` of `str`:
-//// tab | Python 3.7+
-
-```Python hl_lines="9-14"
-{!> ../docs_src/options_autocompletion/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="8-11"
-{!> ../docs_src/options_autocompletion/tutorial006.py!}
-```
-
-////
+{* docs_src/options_autocompletion/tutorial006_an.py hl[9:14] *}
And then we can use it like:
@@ -340,27 +220,7 @@ 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.
-//// tab | Python 3.7+
-
-```Python hl_lines="13-14 16"
-{!> ../docs_src/options_autocompletion/tutorial007_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="12-13 15"
-{!> ../docs_src/options_autocompletion/tutorial007.py!}
-```
-
-////
+{* docs_src/options_autocompletion/tutorial007_an.py hl[13:14,16] *}
We are getting the `names` already provided with `--name` in the command line before this completion was triggered.
@@ -436,27 +296,7 @@ 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".
-//// tab | Python 3.7+
-
-```Python hl_lines="13 16-17"
-{!> ../docs_src/options_autocompletion/tutorial008_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="12 15-16"
-{!> ../docs_src/options_autocompletion/tutorial008.py!}
-```
-
-////
+{* docs_src/options_autocompletion/tutorial008_an.py hl[13,16:17] *}
/// info
@@ -504,27 +344,7 @@ But it's probably useful only in very advanced use cases.
Of course, you can declare everything if you need it, the context, the raw *CLI parameters*, and the incomplete `str`:
-//// tab | Python 3.7+
-
-```Python hl_lines="16"
-{!> ../docs_src/options_autocompletion/tutorial009_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="15"
-{!> ../docs_src/options_autocompletion/tutorial009.py!}
-```
-
-////
+{* docs_src/options_autocompletion/tutorial009_an.py hl[16] *}
Check it:
diff --git a/docs/tutorial/options/callback-and-context.md b/docs/tutorial/options/callback-and-context.md
index 249616f072..9a6ebf9dca 100644
--- a/docs/tutorial/options/callback-and-context.md
+++ b/docs/tutorial/options/callback-and-context.md
@@ -8,27 +8,7 @@ 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.
-//// tab | Python 3.7+
-
-```Python hl_lines="7-10 13"
-{!> ../docs_src/options/callback/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="6-9 12"
-{!> ../docs_src/options/callback/tutorial001.py!}
-```
-
-////
+{* docs_src/options/callback/tutorial001_an.py hl[7:10,13] *}
Here you pass a function to `typer.Option()` or `typer.Argument()` with the keyword argument `callback`.
@@ -114,27 +94,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="8"
-{!> ../docs_src/options/callback/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="7"
-{!> ../docs_src/options/callback/tutorial002.py!}
-```
-
-////
+{* docs_src/options/callback/tutorial002_an.py hl[8] *}
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.
@@ -169,27 +129,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="7-9"
-{!> ../docs_src/options/callback/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="6-8"
-{!> ../docs_src/options/callback/tutorial003.py!}
-```
-
-////
+{* docs_src/options/callback/tutorial003_an.py hl[7:9] *}
The `ctx.resilient_parsing` will be `True` when handling completion, so you can just return without printing anything else.
@@ -221,27 +161,7 @@ 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.
-//// tab | Python 3.7+
-
-```Python hl_lines="7 10"
-{!> ../docs_src/options/callback/tutorial004_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="6 9"
-{!> ../docs_src/options/callback/tutorial004.py!}
-```
-
-////
+{* docs_src/options/callback/tutorial004_an.py hl[7,10] *}
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 f2ee34db51..b0d389f875 100644
--- a/docs/tutorial/options/help.md
+++ b/docs/tutorial/options/help.md
@@ -4,27 +4,7 @@ You already saw how to add a help text for *CLI arguments* with the `help` param
Let's now do the same for *CLI options*:
-//// tab | Python 3.7+
-
-```Python hl_lines="7-8"
-{!> ../docs_src/options/help/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="6-7"
-{!> ../docs_src/options/help/tutorial001.py!}
-```
-
-////
+{* docs_src/options/help/tutorial001_an.py hl[7:8] *}
The same way as with `typer.Argument()`, we can put `typer.Option()` inside of `Annotated`.
@@ -76,27 +56,7 @@ 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*:
-//// tab | Python 3.7+
-
-```Python hl_lines="11 17"
-{!> ../docs_src/options/help/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="8 11"
-{!> ../docs_src/options/help/tutorial002.py!}
-```
-
-////
+{* docs_src/options/help/tutorial002_an.py hl[11,17] *}
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`.
@@ -142,27 +102,7 @@ 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`:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/options/help/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="4"
-{!> ../docs_src/options/help/tutorial003.py!}
-```
-
-////
+{* docs_src/options/help/tutorial003_an.py hl[5] *}
And it will no longer show the default value in the help text:
@@ -199,27 +139,7 @@ In **Typer** these default values are shown by default. 👀
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:
-//// tab | Python 3.7+
-
-```Python hl_lines="7"
-{!> ../docs_src/options/help/tutorial004_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="6"
-{!> ../docs_src/options/help/tutorial004.py!}
-```
-
-////
+{* docs_src/options/help/tutorial004_an.py hl[7] *}
And it will be used in the help text:
diff --git a/docs/tutorial/options/name.md b/docs/tutorial/options/name.md
index a724a5b563..40e9f4687f 100644
--- a/docs/tutorial/options/name.md
+++ b/docs/tutorial/options/name.md
@@ -28,31 +28,7 @@ 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()`:
-//// 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()`.
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```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.
-
-////
+{* docs_src/options/name/tutorial001_an.py hl[5] *}
/// info
@@ -209,27 +185,7 @@ You can overwrite the *CLI option* name to use as in the previous example, but y
For example, extending the previous example, let's add a *CLI option* short name `-n`:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/options/name/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="4"
-{!> ../docs_src/options/name/tutorial002.py!}
-```
-
-////
+{* docs_src/options/name/tutorial002_an.py hl[5] *}
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`.
@@ -260,27 +216,7 @@ 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.
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/options/name/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="4"
-{!> ../docs_src/options/name/tutorial003.py!}
-```
-
-////
+{* docs_src/options/name/tutorial003_an.py hl[5] *}
Check it:
@@ -308,27 +244,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/options/name/tutorial004_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="4"
-{!> ../docs_src/options/name/tutorial004.py!}
-```
-
-////
+{* docs_src/options/name/tutorial004_an.py hl[5] *}
Check it:
@@ -362,27 +278,7 @@ 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):
-//// tab | Python 3.7+
-
-```Python hl_lines="6-7"
-{!> ../docs_src/options/name/tutorial005_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="5-6"
-{!> ../docs_src/options/name/tutorial005.py!}
-```
-
-////
+{* docs_src/options/name/tutorial005_an.py hl[6:7] *}
/// tip
diff --git a/docs/tutorial/options/password.md b/docs/tutorial/options/password.md
index 8601d848b6..d213d83cbe 100644
--- a/docs/tutorial/options/password.md
+++ b/docs/tutorial/options/password.md
@@ -2,27 +2,7 @@
Apart from having a prompt, you can make a *CLI option* have a `confirmation_prompt=True`:
-//// tab | Python 3.7+
-
-```Python hl_lines="7"
-{!> ../docs_src/options/password/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="5"
-{!> ../docs_src/options/password/tutorial001.py!}
-```
-
-////
+{* docs_src/options/password/tutorial001_an.py hl[7] *}
And the CLI program will ask for confirmation:
@@ -50,27 +30,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="8"
-{!> ../docs_src/options/password/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="6-8"
-{!> ../docs_src/options/password/tutorial002.py!}
-```
-
-////
+{* docs_src/options/password/tutorial002_an.py hl[8] *}
Check it:
diff --git a/docs/tutorial/options/prompt.md b/docs/tutorial/options/prompt.md
index e55a09551e..158934a2a2 100644
--- a/docs/tutorial/options/prompt.md
+++ b/docs/tutorial/options/prompt.md
@@ -2,27 +2,7 @@
It's also possible to, instead of just showing an error, ask for the missing value with `prompt=True`:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/options/prompt/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="4"
-{!> ../docs_src/options/prompt/tutorial001.py!}
-```
-
-////
+{* docs_src/options/prompt/tutorial001_an.py hl[5] *}
And then your program will ask the user for it in the terminal:
@@ -44,27 +24,7 @@ Hello Camila Gutiérrez
You can also set a custom prompt, passing the string that you want to use instead of just `True`:
-//// tab | Python 3.7+
-
-```Python hl_lines="7"
-{!> ../docs_src/options/prompt/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="5"
-{!> ../docs_src/options/prompt/tutorial002.py!}
-```
-
-////
+{* docs_src/options/prompt/tutorial002_an.py hl[7] *}
And then your program will ask for it using with your custom prompt:
@@ -90,27 +50,7 @@ You can do it passing the parameter `confirmation_prompt=True`.
Let's say it's a CLI app to delete a project:
-//// tab | Python 3.7+
-
-```Python hl_lines="6"
-{!> ../docs_src/options/prompt/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="4"
-{!> ../docs_src/options/prompt/tutorial003.py!}
-```
-
-////
+{* docs_src/options/prompt/tutorial003_an.py hl[6] *}
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 4b2c2226eb..06c12844b1 100644
--- a/docs/tutorial/options/required.md
+++ b/docs/tutorial/options/required.md
@@ -13,33 +13,15 @@ To make a *CLI option* required, you can put `typer.Option()` inside of `Annotat
Let's make `--lastname` a required *CLI option*:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/options/required/tutorial001_an.py!}
-```
-
-////
+{* docs_src/options/required/tutorial001_an.py hl[5] *}
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.
-//// tab | Python 3.7+ non-Annotated
-
-```Python hl_lines="4"
-{!> ../docs_src/options/required/tutorial001.py!}
-```
-
-////
+{* docs_src/options/required/tutorial001.py hl[4] *}
Or you can explictily pass `...` to `typer.Option(default=...)`:
-//// tab | Python 3.7+ non-Annotated
-
-```Python hl_lines="4"
-{!> ../docs_src/options/required/tutorial002.py!}
-```
-
-////
+{* docs_src/options/required/tutorial002.py hl[4] *}
/// info
diff --git a/docs/tutorial/options/version.md b/docs/tutorial/options/version.md
index f76112ce39..23daec284d 100644
--- a/docs/tutorial/options/version.md
+++ b/docs/tutorial/options/version.md
@@ -8,27 +8,7 @@ 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:
-//// 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="8-11 16-18"
-{!> ../docs_src/options/version/tutorial001.py!}
-```
-
-////
+{* docs_src/options/version/tutorial001_an.py hl[9:12,17:19] *}
/// tip
@@ -77,27 +57,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="15-17 22-24"
-{!> ../docs_src/options/version/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="14-16 21-23"
-{!> ../docs_src/options/version/tutorial002.py!}
-```
-
-////
+{* docs_src/options/version/tutorial002_an.py hl[15:17,22:24] *}
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:
@@ -136,27 +96,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="23-26"
-{!> ../docs_src/options/version/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="22-24"
-{!> ../docs_src/options/version/tutorial003.py!}
-```
-
-////
+{* docs_src/options/version/tutorial003_an.py hl[23:26] *}
Check it:
diff --git a/docs/tutorial/parameter-types/bool.md b/docs/tutorial/parameter-types/bool.md
index 14adc6a6dd..3d0d80cc63 100644
--- a/docs/tutorial/parameter-types/bool.md
+++ b/docs/tutorial/parameter-types/bool.md
@@ -10,27 +10,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/parameter_types/bool/tutorial001_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/tutorial001.py!}
-```
-
-////
+{* docs_src/parameter_types/bool/tutorial001_an.py hl[5] *}
Now there's only a `--force` *CLI option*:
@@ -78,27 +58,7 @@ 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 `/`:
-//// tab | Python 3.7+
-
-```Python hl_lines="7"
-{!> ../docs_src/parameter_types/bool/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="6"
-{!> ../docs_src/parameter_types/bool/tutorial002.py!}
-```
-
-////
+{* docs_src/parameter_types/bool/tutorial002_an.py hl[7] *}
Check it:
@@ -139,27 +99,7 @@ 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`:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/parameter_types/bool/tutorial003_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/tutorial003.py!}
-```
-
-////
+{* docs_src/parameter_types/bool/tutorial003_an.py hl[5] *}
Check it:
@@ -195,27 +135,7 @@ 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:
-//// tab | Python 3.7+
-
-```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!}
-```
-
-////
+{* docs_src/parameter_types/bool/tutorial004_an.py hl[5] *}
/// tip
diff --git a/docs/tutorial/parameter-types/custom-types.md b/docs/tutorial/parameter-types/custom-types.md
index b048c85bc9..79da55878d 100644
--- a/docs/tutorial/parameter-types/custom-types.md
+++ b/docs/tutorial/parameter-types/custom-types.md
@@ -13,27 +13,7 @@ There are two ways to achieve this:
`typer.Argument` and `typer.Option` can create custom parameter types with a `parser`
callable.
-//// 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
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="12-13 17-18"
-{!> ../docs_src/parameter_types/custom_types/tutorial001.py!}
-```
-
-////
+{* docs_src/parameter_types/custom_types/tutorial001_an.py hl[13:14,18:19] *}
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.
@@ -41,10 +21,4 @@ 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.
-//// tab | Python 3.7+
-
-```Python hl_lines="14-18 22-25"
-{!> ../docs_src/parameter_types/custom_types/tutorial002_an.py!}
-```
-
-////
+{* docs_src/parameter_types/custom_types/tutorial002_an.py hl[14:18,22:25] *}
diff --git a/docs/tutorial/parameter-types/datetime.md b/docs/tutorial/parameter-types/datetime.md
index 84f3524eee..3df6f0f7e8 100644
--- a/docs/tutorial/parameter-types/datetime.md
+++ b/docs/tutorial/parameter-types/datetime.md
@@ -4,9 +4,7 @@ You can specify a *CLI parameter* as a Python
../docs_src/parameter_types/datetime/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="8"
-{!> ../docs_src/parameter_types/datetime/tutorial002.py!}
-```
-
-////
+{* docs_src/parameter_types/datetime/tutorial002_an.py hl[11] *}
/// tip
diff --git a/docs/tutorial/parameter-types/enum.md b/docs/tutorial/parameter-types/enum.md
index 288eee5a92..60852faf54 100644
--- a/docs/tutorial/parameter-types/enum.md
+++ b/docs/tutorial/parameter-types/enum.md
@@ -2,9 +2,7 @@
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!}
-```
+{* docs_src/parameter_types/enum/tutorial001.py hl[1,6,7,8,9,12,13] *}
/// tip
@@ -56,27 +54,7 @@ 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:
-//// tab | Python 3.7+
-
-```Python hl_lines="15"
-{!> ../docs_src/parameter_types/enum/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="13"
-{!> ../docs_src/parameter_types/enum/tutorial002.py!}
-```
-
-////
+{* docs_src/parameter_types/enum/tutorial002_an.py hl[15] *}
And then the values of the `Enum` will be checked no matter if lower case, upper case, or a mix:
@@ -100,27 +78,7 @@ Training neural network of type: lstm
A *CLI parameter* can also take a list of `Enum` values:
-//// tab | Python 3.7+
-
-```Python hl_lines="14"
-{!> ../docs_src/parameter_types/enum/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="13"
-{!> ../docs_src/parameter_types/enum/tutorial003.py!}
-```
-
-////
+{* docs_src/parameter_types/enum/tutorial003_an.py hl[14] *}
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 274962cf07..391c7f8f09 100644
--- a/docs/tutorial/parameter-types/file.md
+++ b/docs/tutorial/parameter-types/file.md
@@ -47,27 +47,7 @@ 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:`
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/parameter_types/file/tutorial001_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/file/tutorial001.py!}
-```
-
-////
+{* docs_src/parameter_types/file/tutorial001_an.py hl[5] *}
Check it:
@@ -94,27 +74,7 @@ Config line: some more settings
For writing text, you can use `typer.FileTextWrite`:
-//// tab | Python 3.7+
-
-```Python hl_lines="5-6"
-{!> ../docs_src/parameter_types/file/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="4-5"
-{!> ../docs_src/parameter_types/file/tutorial002.py!}
-```
-
-////
+{* docs_src/parameter_types/file/tutorial002_an.py hl[5:6] *}
This would be for writing human text, like:
@@ -158,27 +118,7 @@ You will receive `bytes` from it.
It's useful for reading binary files like images:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/parameter_types/file/tutorial003_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/file/tutorial003.py!}
-```
-
-////
+{* docs_src/parameter_types/file/tutorial003_an.py hl[5] *}
Check it:
@@ -207,27 +147,7 @@ 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`.
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/parameter_types/file/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/file/tutorial004.py!}
-```
-
-////
+{* docs_src/parameter_types/file/tutorial004_an.py hl[5] *}
@@ -277,27 +197,7 @@ You can override the `mode` from the defaults above.
For example, you could use `mode="a"` to write "appending" to the same file:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/parameter_types/file/tutorial005_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/file/tutorial005.py!}
-```
-
-////
+{* docs_src/parameter_types/file/tutorial005_an.py hl[5] *}
/// tip
diff --git a/docs/tutorial/parameter-types/index.md b/docs/tutorial/parameter-types/index.md
index f7889944f0..8de90c62e0 100644
--- a/docs/tutorial/parameter-types/index.md
+++ b/docs/tutorial/parameter-types/index.md
@@ -8,9 +8,7 @@ When you declare a *CLI parameter* with some type **Typer** will convert the dat
For example:
-```Python hl_lines="4"
-{!../docs_src/parameter_types/index/tutorial001.py!}
-```
+{* docs_src/parameter_types/index/tutorial001.py hl[4] *}
In this example, the value received for the *CLI argument* `NAME` will be treated as `str`.
diff --git a/docs/tutorial/parameter-types/number.md b/docs/tutorial/parameter-types/number.md
index 062fa7bce3..914f58a035 100644
--- a/docs/tutorial/parameter-types/number.md
+++ b/docs/tutorial/parameter-types/number.md
@@ -2,27 +2,7 @@
You can define numeric validations with `max` and `min` values for `int` and `float` *CLI parameters*:
-//// tab | Python 3.7+
-
-```Python hl_lines="6-8"
-{!> ../docs_src/parameter_types/number/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="5-7"
-{!> ../docs_src/parameter_types/number/tutorial001.py!}
-```
-
-////
+{* docs_src/parameter_types/number/tutorial001_an.py hl[6:8] *}
*CLI arguments* and *CLI options* can both use these validations.
@@ -93,27 +73,7 @@ You might want to, instead of showing an error, use the closest minimum or maxim
You can do it with the `clamp` parameter:
-//// tab | Python 3.7+
-
-```Python hl_lines="6-8"
-{!> ../docs_src/parameter_types/number/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="5-7"
-{!> ../docs_src/parameter_types/number/tutorial002.py!}
-```
-
-////
+{* docs_src/parameter_types/number/tutorial002_an.py hl[6:8] *}
And then, when you pass data that is out of the valid range, it will be "clamped", the closest valid value will be used:
@@ -142,27 +102,7 @@ ID is 5
You can make a *CLI option* work as a counter with the `counter` parameter:
-//// tab | Python 3.7+
-
-```Python hl_lines="5"
-{!> ../docs_src/parameter_types/number/tutorial003_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/number/tutorial003.py!}
-```
-
-////
+{* docs_src/parameter_types/number/tutorial003_an.py hl[5] *}
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 0268630bcd..4c715b8acd 100644
--- a/docs/tutorial/parameter-types/path.md
+++ b/docs/tutorial/parameter-types/path.md
@@ -4,27 +4,7 @@ You can declare a *CLI parameter* to be a standard Python
../docs_src/parameter_types/path/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="1 7"
-{!> ../docs_src/parameter_types/path/tutorial001.py!}
-```
-
-////
+{* docs_src/parameter_types/path/tutorial001_an.py hl[1,8] *}
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.
@@ -85,27 +65,7 @@ All these parameters come directly from ../docs_src/parameter_types/path/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="9-14"
-{!> ../docs_src/parameter_types/path/tutorial002.py!}
-```
-
-////
+{* docs_src/parameter_types/path/tutorial002_an.py hl[11:16] *}
Check it:
diff --git a/docs/tutorial/parameter-types/uuid.md b/docs/tutorial/parameter-types/uuid.md
index afe5986377..906ca618e3 100644
--- a/docs/tutorial/parameter-types/uuid.md
+++ b/docs/tutorial/parameter-types/uuid.md
@@ -22,9 +22,7 @@ This wouldn't be true if you just used `int`s as identifiers, as most databases
You can declare a *CLI parameter* as a UUID:
-```Python hl_lines="1 6 7 8"
-{!../docs_src/parameter_types/uuid/tutorial001.py!}
-```
+{* docs_src/parameter_types/uuid/tutorial001.py hl[1,6,7,8] *}
Your Python code will receive a standard Python `UUID` object with all its attributes and methods, and as you are annotating your function parameter with that type, you will have type checks, autocompletion in your editor, etc.
diff --git a/docs/tutorial/printing.md b/docs/tutorial/printing.md
index 75150d329d..1a5bd4e176 100644
--- a/docs/tutorial/printing.md
+++ b/docs/tutorial/printing.md
@@ -2,9 +2,7 @@
You can use the normal `print()` to show information on the screen:
-```Python hl_lines="5"
-{!../docs_src/first_steps/tutorial001.py!}
-```
+{* docs_src/first_steps/tutorial001.py hl[5] *}
It will show the output normally:
@@ -26,9 +24,7 @@ You can also display beautiful and more complex information using
custom markup syntax to set colors and styles, for example:
-```Python hl_lines="6"
-{!../docs_src/printing/tutorial002.py!}
-```
+{* docs_src/printing/tutorial002.py hl[6] *}
@@ -82,9 +76,7 @@ When you call Rich's `print`, it automatically creates this object and uses it.
But for advanced use cases, you could create a `Console` yourself.
-```Python hl_lines="2-3 5 9-12"
-{!../docs_src/printing/tutorial003.py!}
-```
+{* docs_src/printing/tutorial003.py hl[2:3,5,9:12] *}
In this example, we create a `Console`, and a `Table`. And then we can add some rows to the table, and print it.
@@ -160,9 +152,7 @@ You can print to "standard error" creating a Rich `Console` with `stderr=True`.
Using `stderr=True` tells **Rich** that the output should be shown in "standard error".
-```Python hl_lines="4 8"
-{!../docs_src/printing/tutorial004.py!}
-```
+{* docs_src/printing/tutorial004.py hl[4,8] *}
When you try it in the terminal, it will probably just look the same:
@@ -238,9 +228,7 @@ Again, you are much better off using
Rich's Progress Display to show a progress bar, for example:
-```Python hl_lines="4 9"
-{!../docs_src/progressbar/tutorial001.py!}
-```
+{* docs_src/progressbar/tutorial001.py hl[4,9] *}
You put the thing that you want to iterate over inside of Rich's `track()`, and then iterate over that.
@@ -48,9 +46,7 @@ Rich allows you to display many things in complex and advanced ways.
For example, this will show two spinners:
-```Python hl_lines="4 8-15"
-{!../docs_src/progressbar/tutorial002.py!}
-```
+{* docs_src/progressbar/tutorial002.py hl[4,8:15] *}
I can't show you the beautiful animation here in the docs. 😅
@@ -104,9 +100,7 @@ with typer.progressbar(something) as progress:
And you pass as function argument to `typer.progressbar()` the thing that you would normally iterate over.
-```Python hl_lines="8"
-{!../docs_src/progressbar/tutorial003.py!}
-```
+{* docs_src/progressbar/tutorial003.py hl[8] *}
So, if you have a list of users, this could be:
@@ -169,9 +163,7 @@ The progress bar is generated from the length of the iterable (e.g. the list of
But if the length is not available (for example, with something that fetches a new user from a web API each time) you can pass an explicit `length` to `typer.progressbar()`.
-```Python hl_lines="14"
-{!../docs_src/progressbar/tutorial004.py!}
-```
+{* docs_src/progressbar/tutorial004.py hl[14] *}
Check it:
@@ -219,9 +211,7 @@ Remember, you are much better off using
@@ -83,9 +77,7 @@ Aborted!
If you installed Rich as described in [Printing and Colors](printing.md){.internal-link target=_blank}, you can use Rich to prompt the user for input:
-```Python hl_lines="2 6"
-{!../docs_src/prompt/tutorial004.py!}
-```
+{* docs_src/prompt/tutorial004.py hl[2,6] *}
And when you run it, it will look like:
diff --git a/docs/tutorial/subcommands/add-typer.md b/docs/tutorial/subcommands/add-typer.md
index 55439acf29..82dbc876e3 100644
--- a/docs/tutorial/subcommands/add-typer.md
+++ b/docs/tutorial/subcommands/add-typer.md
@@ -10,9 +10,7 @@ Let's imagine that you are creating a *CLI program* to manage items in some dist
It could be in an `items.py` file with this:
-```Python
-{!../docs_src/subcommands/tutorial001/items.py!}
-```
+{* docs_src/subcommands/tutorial001/items.py *}
And you would use it like:
@@ -32,9 +30,7 @@ But then you realize that you also have to manage users from your *CLI app*.
It could be a file `users.py` with something like:
-```Python
-{!../docs_src/subcommands/tutorial001/users.py!}
-```
+{* docs_src/subcommands/tutorial001/users.py *}
And you would use it like:
@@ -58,9 +54,7 @@ In this case, as with `git remote`, we can put them together as subcommands in a
Now create a `main.py` with:
-```Python hl_lines="3 4 7 8"
-{!../docs_src/subcommands/tutorial001/main.py!}
-```
+{* docs_src/subcommands/tutorial001/main.py hl[3,4,7,8] *}
Here's what we do in `main.py`:
diff --git a/docs/tutorial/subcommands/callback-override.md b/docs/tutorial/subcommands/callback-override.md
index fa82d4ee3b..b99232c543 100644
--- a/docs/tutorial/subcommands/callback-override.md
+++ b/docs/tutorial/subcommands/callback-override.md
@@ -6,9 +6,7 @@ When adding a Typer app inside of another, the sub-Typer can also have its own c
It can handle any *CLI parameters* that go before its own commands and execute any extra code:
-```Python hl_lines="9 10 11"
-{!../docs_src/subcommands/callback_override/tutorial001.py!}
-```
+{* docs_src/subcommands/callback_override/tutorial001.py hl[9,10,11] *}
In this case it doesn't define any *CLI parameters*, it just writes a message.
@@ -30,9 +28,7 @@ Creating user: Camila
It's also possible to add a callback when creating the `typer.Typer()` app that will be added to another Typer app:
-```Python hl_lines="6 7 10"
-{!../docs_src/subcommands/callback_override/tutorial002.py!}
-```
+{* docs_src/subcommands/callback_override/tutorial002.py hl[6,7,10] *}
This achieves exactly the same as above, it's just another place to add the callback.
@@ -55,9 +51,7 @@ If a callback was added when creating the `typer.Typer()` app, it's possible to
This is the same information you saw on the section about [Commands - Typer Callback](../commands/callback.md){.internal-link target=_blank}, and it applies the same for sub-Typer apps:
-```Python hl_lines="6 7 10 14 15 16"
-{!../docs_src/subcommands/callback_override/tutorial003.py!}
-```
+{* docs_src/subcommands/callback_override/tutorial003.py hl[6,7,10,14,15,16] *}
Here we had defined a callback when creating the `typer.Typer()` sub-app, but then we override it with a new callback with the function `user_callback()`.
@@ -83,9 +77,7 @@ Lastly, you can override the callback defined anywhere else when adding a sub-Ty
This has the highest priority:
-```Python hl_lines="13 14 17"
-{!../docs_src/subcommands/callback_override/tutorial004.py!}
-```
+{* docs_src/subcommands/callback_override/tutorial004.py hl[13,14,17] *}
Notice that the precedence goes to `app.add_typer()` and is not affected by the order of execution. There's another callback defined below, but the one from `app.add_typer()` wins.
diff --git a/docs/tutorial/subcommands/name-and-help.md b/docs/tutorial/subcommands/name-and-help.md
index e6d96caa54..47eced3dd3 100644
--- a/docs/tutorial/subcommands/name-and-help.md
+++ b/docs/tutorial/subcommands/name-and-help.md
@@ -12,9 +12,7 @@ app.add_typer(users.app, name="users")
We can also set the `help` while adding a Typer:
-```Python hl_lines="6"
-{!../docs_src/subcommands/name_help/tutorial001.py!}
-```
+{* docs_src/subcommands/name_help/tutorial001.py hl[6] *}
And then we get that help text for that command in the *CLI program*:
@@ -91,9 +89,7 @@ And if that Typer app is added to another Typer app, the default name of the com
Here's an example:
-```Python hl_lines="6 9 10 11 12 13"
-{!../docs_src/subcommands/name_help/tutorial002.py!}
-```
+{* docs_src/subcommands/name_help/tutorial002.py hl[6,9,10,11,12,13] *}
Notice that now we added the sub-Typer without specifying a `name` nor a `help`.
@@ -147,9 +143,7 @@ This has the lowest priority, we'll see later what has a higher priority and can
Check the code:
-```Python hl_lines="6 7 8 9 12"
-{!../docs_src/subcommands/name_help/tutorial003.py!}
-```
+{* docs_src/subcommands/name_help/tutorial003.py hl[6,7,8,9,12] *}
This achieves exactly the same as the previous example.
@@ -193,9 +187,7 @@ Commands:
The same as with normal **Typer** apps, if you pass a `callback` to `typer.Typer(callback=some_function)` and then override it with `@app.callback()`, the name and help text will be inferred from the new callback:
-```Python hl_lines="16 17 18 19 20"
-{!../docs_src/subcommands/name_help/tutorial004.py!}
-```
+{* docs_src/subcommands/name_help/tutorial004.py hl[16,17,18,19,20] *}
Now the name of the command will be `users` instead of `old-callback`, and the help text will be `Manage users in the app.` instead of `Old callback help.`.
@@ -243,9 +235,7 @@ This takes precedence over inferring the name and help from a callback set in `@
Check the code:
-```Python hl_lines="15 16 17 18 21"
-{!../docs_src/subcommands/name_help/tutorial005.py!}
-```
+{* docs_src/subcommands/name_help/tutorial005.py hl[15,16,17,18,21] *}
Now the command will be `new-users` instead of `users`. And the help text will be `I have the highland! Create some users.` instead of the previous ones.
@@ -315,9 +305,7 @@ If you set it explicitly, that takes precedence over inferring.
You can set it when creating a new `typer.Typer()`:
-```Python hl_lines="12"
-{!../docs_src/subcommands/name_help/tutorial006.py!}
-```
+{* docs_src/subcommands/name_help/tutorial006.py hl[12] *}
/// info
@@ -371,9 +359,7 @@ Any parameter that you use when creating a `typer.Typer()` app can be overridden
Continuing with the previous example, we now override the values in `@user_app.callback()`:
-```Python hl_lines="24"
-{!../docs_src/subcommands/name_help/tutorial007.py!}
-```
+{* docs_src/subcommands/name_help/tutorial007.py hl[24] *}
And now the command name will be `call-users` and the help text will be `Help from callback for users.`.
@@ -417,9 +403,7 @@ Commands:
And finally, with the highest priority, you can override all that by explicitly setting the `name` and `help` in `app.add_typer()`, just like we did on the first example above:
-```Python hl_lines="21"
-{!../docs_src/subcommands/name_help/tutorial008.py!}
-```
+{* docs_src/subcommands/name_help/tutorial008.py hl[21] *}
And now, with the highest priorities of them all, the command name will now be `cake-sith-users` and the help text will be `Unlimited powder! Eh, users.`.
diff --git a/docs/tutorial/subcommands/nested-subcommands.md b/docs/tutorial/subcommands/nested-subcommands.md
index c991faa9da..d56028b3ee 100644
--- a/docs/tutorial/subcommands/nested-subcommands.md
+++ b/docs/tutorial/subcommands/nested-subcommands.md
@@ -12,9 +12,7 @@ And each of those could have their own commands, like `create` and `delete`.
Let's start with a file `reigns.py`:
-```Python
-{!../docs_src/subcommands/tutorial003/reigns.py!}
-```
+{* docs_src/subcommands/tutorial003/reigns.py *}
This is already a simple *CLI program* to manage reigns:
@@ -51,9 +49,7 @@ Destroying reign: Mordor
And now the equivalent for managing towns in `towns.py`:
-```Python
-{!../docs_src/subcommands/tutorial003/towns.py!}
-```
+{* docs_src/subcommands/tutorial003/towns.py *}
With it, you can manage towns:
@@ -90,9 +86,7 @@ Burning town: Vizima
Now let's put the `reigns` and `towns` together in the same *CLI program* in `lands.py`:
-```Python
-{!../docs_src/subcommands/tutorial003/lands.py!}
-```
+{* docs_src/subcommands/tutorial003/lands.py *}
And now we have a single *CLI program* with a command (or command group) `reigns` that has its own commands. And another command `towns` with its own subcommands.
@@ -193,9 +187,7 @@ This already is a quite deeply nested "tree" of commands/command groups.
But to achieve that, we just have to add the `lands` **Typer** app to the same `main.py` file we already had:
-```Python hl_lines="4 10"
-{!../docs_src/subcommands/tutorial003/main.py!}
-```
+{* docs_src/subcommands/tutorial003/main.py hl[4,10] *}
And now we have everything in a single *CLI program*:
@@ -246,39 +238,27 @@ Here are all the files if you want to review/copy them:
`reigns.py`:
-```Python
-{!../docs_src/subcommands/tutorial003/reigns.py!}
-```
+{* docs_src/subcommands/tutorial003/reigns.py *}
`towns.py`:
-```Python
-{!../docs_src/subcommands/tutorial003/towns.py!}
-```
+{* docs_src/subcommands/tutorial003/towns.py *}
`lands.py`:
-```Python
-{!../docs_src/subcommands/tutorial003/lands.py!}
-```
+{* docs_src/subcommands/tutorial003/lands.py *}
`users.py`:
-```Python
-{!../docs_src/subcommands/tutorial003/users.py!}
-```
+{* docs_src/subcommands/tutorial003/users.py *}
`items.py`:
-```Python
-{!../docs_src/subcommands/tutorial003/items.py!}
-```
+{* docs_src/subcommands/tutorial003/items.py *}
`main.py`:
-```Python
-{!../docs_src/subcommands/tutorial003/main.py!}
-```
+{* docs_src/subcommands/tutorial003/main.py *}
/// tip
diff --git a/docs/tutorial/subcommands/single-file.md b/docs/tutorial/subcommands/single-file.md
index 50645267cd..f7e943ecc0 100644
--- a/docs/tutorial/subcommands/single-file.md
+++ b/docs/tutorial/subcommands/single-file.md
@@ -4,9 +4,7 @@ In some cases, it's possible that your application code needs to live on a singl
You can still use the same ideas:
-```Python
-{!../docs_src/subcommands/tutorial002/main.py!}
-```
+{* docs_src/subcommands/tutorial002/main.py *}
There are several things to notice here...
@@ -16,9 +14,7 @@ First, you can create `typer.Typer()` objects and add them to another one at the
It doesn't have to be done after creating the subcommands:
-```Python hl_lines="4 5 6 7"
-{!../docs_src/subcommands/tutorial002/main.py!}
-```
+{* docs_src/subcommands/tutorial002/main.py hl[4,5,6,7] *}
You can add the commands (subcommands) to each `typer.Typer()` app later and it will still work.
@@ -28,9 +24,7 @@ As you now have subcommands like `create` for `users` and for `items`, you can n
So we use longer names:
-```Python hl_lines="11 16 21 26 31"
-{!../docs_src/subcommands/tutorial002/main.py!}
-```
+{* docs_src/subcommands/tutorial002/main.py hl[11,16,21,26,31] *}
## Command name
@@ -62,9 +56,7 @@ $ python main.py items items-create
So we pass the name we want to use for each subcommand as the function argument to the decorator:
-```Python hl_lines="10 15 20 25 30"
-{!../docs_src/subcommands/tutorial002/main.py!}
-```
+{* docs_src/subcommands/tutorial002/main.py hl[10,15,20,25,30] *}
## Check it
diff --git a/docs/tutorial/terminating.md b/docs/tutorial/terminating.md
index a8d0b49fa3..23343a651a 100644
--- a/docs/tutorial/terminating.md
+++ b/docs/tutorial/terminating.md
@@ -12,9 +12,7 @@ This doesn't have to mean that there's an error, just that nothing else needs to
In that case, you can raise a `typer.Exit()` exception:
-```Python hl_lines="9"
-{!../docs_src/terminating/tutorial001.py!}
-```
+{* docs_src/terminating/tutorial001.py hl[9] *}
There are several things to see in this example.
@@ -58,9 +56,7 @@ But then **Typer** (actually Click) catches it and just terminates the program n
You can pass a `code` with a number other than `0` to tell the terminal that there was an error in the execution of the program:
-```Python hl_lines="7"
-{!../docs_src/terminating/tutorial002.py!}
-```
+{* docs_src/terminating/tutorial002.py hl[7] *}
Check it:
@@ -103,9 +99,7 @@ There's a special exception that you can use to "abort" a program.
It works more or less the same as `typer.Exit()` but will print `"Aborted!"` to the screen and can be useful in certain cases later to make it explicit that the execution was aborted:
-```Python hl_lines="7"
-{!../docs_src/terminating/tutorial003.py!}
-```
+{* docs_src/terminating/tutorial003.py hl[7] *}
Check it:
diff --git a/docs/tutorial/testing.md b/docs/tutorial/testing.md
index 2fc7e54f09..8e0f82ad7b 100644
--- a/docs/tutorial/testing.md
+++ b/docs/tutorial/testing.md
@@ -4,9 +4,7 @@ Testing **Typer** applications is very easy with .
If you have a CLI with prompts, like:
-//// tab | Python 3.7+
-
-```Python hl_lines="8"
-{!> ../docs_src/testing/app02_an/main.py!}
-```
-
-////
-
-//// tab | Python 3.7+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="7"
-{!> ../docs_src/testing/app02/main.py!}
-```
-
-////
+{* docs_src/testing/app02_an/main.py hl[8] *}
That you would use like:
@@ -167,23 +139,17 @@ When you hit the ENTER key after typing the email, that is just a "ne
So, if you use `input="camila@example.com\n"` it means: "type `camila@example.com` in the terminal, then hit the ENTER key":
-```Python hl_lines="9"
-{!../docs_src/testing/app02/test_main.py!}
-```
+{* docs_src/testing/app02/test_main.py hl[9] *}
## Test a function
If you have a script and you never created an explicit `typer.Typer` app, like:
-```Python hl_lines="9"
-{!../docs_src/testing/app03/main.py!}
-```
+{* docs_src/testing/app03/main.py hl[9] *}
...you can still test it, by creating an app during testing:
-```Python hl_lines="6 7 13"
-{!../docs_src/testing/app03/test_main.py!}
-```
+{* docs_src/testing/app03/test_main.py hl[6,7,13] *}
Of course, if you are testing that script, it's probably easier/cleaner to just create the explicit `typer.Typer` app in `main.py` instead of creating it just during the test.
diff --git a/docs/tutorial/typer-command.md b/docs/tutorial/typer-command.md
index 004415a6ae..803b44d0f5 100644
--- a/docs/tutorial/typer-command.md
+++ b/docs/tutorial/typer-command.md
@@ -241,9 +241,7 @@ You can also use the `typer` command to generate Markdown documentation for your
For example, you could have a script like:
-```Python
-{!../docs_src/commands/help/tutorial001.py!}
-```
+{* docs_src/commands/help/tutorial001.py *}
### Generate docs with the `typer` command
diff --git a/docs/tutorial/using-click.md b/docs/tutorial/using-click.md
index 950531ff7f..49517ffd73 100644
--- a/docs/tutorial/using-click.md
+++ b/docs/tutorial/using-click.md
@@ -28,9 +28,7 @@ A `Command` can have its own *CLI arguments* and *CLI options*, and it has a fun
For example, in this Click app:
-```Python hl_lines="7 14"
-{!../docs_src/using_click/tutorial001.py!}
-```
+{* docs_src/using_click/tutorial001.py hl[7,14] *}
The original `hello` variable is converted by Click from a function to a `Command` object. And the original `hello` function is used by that `Command` internally, but it is no longer named `hello` (as `hello` is now a Click `Command`).
@@ -46,9 +44,7 @@ And a `Group` can also have a function that it calls, right before calling the f
For example:
-```Python hl_lines="5 19 20"
-{!../docs_src/using_click/tutorial002.py!}
-```
+{* docs_src/using_click/tutorial002.py hl[5,19,20] *}
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.
@@ -90,9 +86,7 @@ You can use it directly, and use the Click object with other Click applications.
For example, you could have a **Typer** app, generate a Click `Group` from it, and then include other Click apps in it:
-```Python hl_lines="15 16 29 31 34"
-{!../docs_src/using_click/tutorial003.py!}
-```
+{* docs_src/using_click/tutorial003.py hl[15,16,29,31,34] *}
Notice that we add a callback that does nothing (only document the CLI program), to make sure **Typer** creates a Click `Group`. That way we can add sub-commands to that Click `Group`.
@@ -136,9 +130,7 @@ Hello Camila!
The same way, you can do the contrary and include a **Typer** sub app in a bigger Click app:
-```Python hl_lines="31 33 36"
-{!../docs_src/using_click/tutorial004.py!}
-```
+{* docs_src/using_click/tutorial004.py hl[31,33,36] *}
Notice that we don't have to add a callback or more commands, we can just create a **Typer** app that generates a single Click `Command`, as we don't need to include anything under the Typer app.
diff --git a/mkdocs.yml b/mkdocs.yml
index ead95508a0..042d7ad116 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -192,7 +192,7 @@ markdown_extensions:
# Other extensions
mdx_include:
- base_path: docs
+ markdown_include_variants:
extra:
analytics:
diff --git a/requirements-docs.txt b/requirements-docs.txt
index 7bc027ac71..4f2c9b2f7b 100644
--- a/requirements-docs.txt
+++ b/requirements-docs.txt
@@ -16,3 +16,4 @@ cairosvg==2.7.1
# For griffe, it formats with black
# black==24.3.0
mkdocs-macros-plugin==1.3.7
+markdown-include-variants==0.0.3
diff --git a/requirements-tests.txt b/requirements-tests.txt
index fbac3312c1..264fe0becc 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -1,12 +1,12 @@
-e .
pytest >=4.4.0,<9.0.0
-pytest-cov >=2.10.0,<6.0.0
+pytest-cov >=2.10.0,<7.0.0
coverage[toml] >=6.2,<8.0
pytest-xdist >=1.32.0,<4.0.0
pytest-sugar >=0.9.4,<1.1.0
mypy ==1.4.1
-ruff ==0.7.2
+ruff ==0.7.4
# Needed explicitly by typer-slim
rich >=10.11.0
shellingham >=1.3.0
diff --git a/tests/assets/cli/rich_formatted_app.py b/tests/assets/cli/rich_formatted_app.py
new file mode 100644
index 0000000000..54d8a52267
--- /dev/null
+++ b/tests/assets/cli/rich_formatted_app.py
@@ -0,0 +1,22 @@
+import typer
+from typing_extensions import Annotated
+
+app = typer.Typer(rich_markup_mode="rich")
+
+
+@app.command(help="Say [bold red]hello[/bold red] to the user.")
+def hello(
+ user_1: Annotated[
+ str,
+ typer.Argument(help="The [bold]cool[/bold] name of the [green]user[/green]"),
+ ],
+ user_2: Annotated[str, typer.Argument(help="The world")] = "The World",
+ force: Annotated[
+ bool, typer.Option(help="Force the welcome [red]message[/red]")
+ ] = False,
+):
+ print(f"Hello {user_1} and {user_2}") # pragma: no cover
+
+
+if __name__ == "__main__":
+ app()
diff --git a/tests/assets/cli/richformattedapp-docs.md b/tests/assets/cli/richformattedapp-docs.md
new file mode 100644
index 0000000000..678a2daf6f
--- /dev/null
+++ b/tests/assets/cli/richformattedapp-docs.md
@@ -0,0 +1,21 @@
+# Awesome CLI
+
+Say hello to the user.
+
+**Usage**:
+
+```console
+$ hello [OPTIONS] USER_1 [USER_2]
+```
+
+**Arguments**:
+
+* `USER_1`: The cool name of the user [required]
+* `[USER_2]`: The world [default: The World]
+
+**Options**:
+
+* `--force / --no-force`: Force the welcome message [default: no-force]
+* `--install-completion`: Install completion for the current shell.
+* `--show-completion`: Show completion for the current shell, to copy it or customize the installation.
+* `--help`: Show this message and exit.
diff --git a/tests/test_cli/test_doc.py b/tests/test_cli/test_doc.py
index 98e30631ba..f0d1d9b850 100644
--- a/tests/test_cli/test_doc.py
+++ b/tests/test_cli/test_doc.py
@@ -1,3 +1,4 @@
+import os
import subprocess
import sys
from pathlib import Path
@@ -140,3 +141,34 @@ def test_doc_file_not_existing():
encoding="utf-8",
)
assert "Not a valid file or Python module:" in result.stderr
+
+
+def test_doc_html_output(tmp_path: Path):
+ out_file: Path = tmp_path / "out.md"
+ result = subprocess.run(
+ [
+ sys.executable,
+ "-m",
+ "coverage",
+ "run",
+ "-m",
+ "typer",
+ "tests.assets.cli.rich_formatted_app",
+ "utils",
+ "docs",
+ "--title",
+ "Awesome CLI",
+ "--output",
+ str(out_file),
+ ],
+ capture_output=True,
+ encoding="utf-8",
+ env={**os.environ, "PYTHONIOENCODING": "utf-8"},
+ )
+ docs_path: Path = (
+ Path(__file__).parent.parent / "assets" / "cli" / "richformattedapp-docs.md"
+ )
+ docs = docs_path.read_text(encoding="utf-8")
+ written_docs = out_file.read_text(encoding="utf-8")
+ assert docs in written_docs
+ assert "Docs saved to:" in result.stdout
diff --git a/tests/test_completion/test_completion_complete.py b/tests/test_completion/test_completion_complete.py
index ea37f68546..e6d18b58a3 100644
--- a/tests/test_completion/test_completion_complete.py
+++ b/tests/test_completion/test_completion_complete.py
@@ -79,7 +79,7 @@ def test_completion_complete_subcommand_fish():
},
)
assert (
- "delete\tDelete a user with USERNAME.\ndelete-all\tDelete ALL users in the database."
+ "delete Delete a user with USERNAME.\ndelete-all Delete ALL users in the database."
in result.stdout
)
diff --git a/typer/__init__.py b/typer/__init__.py
index 0ba5475321..cb24d1c768 100644
--- a/typer/__init__.py
+++ b/typer/__init__.py
@@ -1,6 +1,6 @@
"""Typer, build great CLIs. Easy to code. Based on Python type hints."""
-__version__ = "0.13.0"
+__version__ = "0.13.1"
from shutil import get_terminal_size as get_terminal_size
diff --git a/typer/_completion_shared.py b/typer/_completion_shared.py
index 4f40c143c0..cc0add992c 100644
--- a/typer/_completion_shared.py
+++ b/typer/_completion_shared.py
@@ -183,15 +183,15 @@ def install_powershell(*, prog_name: str, complete_var: str, shell: str) -> Path
if isinstance(result.stdout, str): # pragma: no cover
path_str = result.stdout
if isinstance(result.stdout, bytes):
- try:
- # PowerShell would be predominant in Windows
- path_str = result.stdout.decode("windows-1252")
- except UnicodeDecodeError: # pragma: no cover
+ for encoding in ["windows-1252", "utf8", "cp850"]:
try:
- path_str = result.stdout.decode("utf8")
- except UnicodeDecodeError:
- click.echo("Couldn't decode the path automatically", err=True)
- raise
+ path_str = result.stdout.decode(encoding)
+ break
+ except UnicodeDecodeError: # pragma: no cover
+ pass
+ if not path_str: # pragma: no cover
+ click.echo("Couldn't decode the path automatically", err=True)
+ raise click.exceptions.Exit(1)
path_obj = Path(path_str.strip())
parent_dir: Path = path_obj.parent
parent_dir.mkdir(parents=True, exist_ok=True)
diff --git a/typer/cli.py b/typer/cli.py
index 70b9101f37..3fe3d3ee7f 100644
--- a/typer/cli.py
+++ b/typer/cli.py
@@ -11,6 +11,16 @@
from . import __version__
+try:
+ import rich
+
+ has_rich = True
+ from . import rich_utils
+
+except ImportError: # pragma: no cover
+ has_rich = False
+ rich = None # type: ignore
+
default_app_names = ("app", "cli", "main")
default_func_names = ("main", "cli", "app")
@@ -199,7 +209,7 @@ def get_docs_for_click(
title = f"`{command_name}`" if command_name else "CLI"
docs += f" {title}\n\n"
if obj.help:
- docs += f"{obj.help}\n\n"
+ docs += f"{_parse_html(obj.help)}\n\n"
usage_pieces = obj.collect_usage_pieces(ctx)
if usage_pieces:
docs += "**Usage**:\n\n"
@@ -223,7 +233,7 @@ def get_docs_for_click(
for arg_name, arg_help in args:
docs += f"* `{arg_name}`"
if arg_help:
- docs += f": {arg_help}"
+ docs += f": {_parse_html(arg_help)}"
docs += "\n"
docs += "\n"
if opts:
@@ -231,7 +241,7 @@ def get_docs_for_click(
for opt_name, opt_help in opts:
docs += f"* `{opt_name}`"
if opt_help:
- docs += f": {opt_help}"
+ docs += f": {_parse_html(opt_help)}"
docs += "\n"
docs += "\n"
if obj.epilog:
@@ -247,7 +257,7 @@ def get_docs_for_click(
docs += f"* `{command_obj.name}`"
command_help = command_obj.get_short_help_str()
if command_help:
- docs += f": {command_help}"
+ docs += f": {_parse_html(command_help)}"
docs += "\n"
docs += "\n"
for command in commands:
@@ -262,6 +272,12 @@ def get_docs_for_click(
return docs
+def _parse_html(input_text: str) -> str:
+ if not has_rich: # pragma: no cover
+ return input_text
+ return rich_utils.rich_to_html(input_text)
+
+
@utils_app.command()
def docs(
ctx: typer.Context,
diff --git a/typer/completion.py b/typer/completion.py
index 5b930bc20c..07ce83190c 100644
--- a/typer/completion.py
+++ b/typer/completion.py
@@ -15,6 +15,12 @@
except ImportError: # pragma: no cover
shellingham = None
+try:
+ import rich
+
+except ImportError: # pragma: no cover
+ rich = None # type: ignore
+
_click_patched = False
@@ -139,9 +145,17 @@ def shell_complete(
click.echo(comp.source())
return 0
+ # Typer override to print the completion help msg with Rich
if instruction == "complete":
- click.echo(comp.complete())
+ if not rich: # pragma: no cover
+ click.echo(comp.complete())
+ else:
+ from . import rich_utils
+
+ rich_utils.print_with_rich(comp.complete())
+
return 0
+ # Typer override end
click.echo(f'Completion instruction "{instruction}" not supported.', err=True)
return 1
diff --git a/typer/core.py b/typer/core.py
index d9d651aaf8..8ec8b4b95d 100644
--- a/typer/core.py
+++ b/typer/core.py
@@ -366,8 +366,13 @@ def get_help_record(self, ctx: click.Context) -> Optional[Tuple[str, str]]:
if self.required:
extra.append(_("required"))
if extra:
- extra_str = ";".join(extra)
- help = f"{help} [{extra_str}]" if help else f"[{extra_str}]"
+ extra_str = "; ".join(extra)
+ extra_str = f"[{extra_str}]"
+ if rich is not None:
+ # This is needed for when we want to export to HTML
+ extra_str = rich.markup.escape(extra_str).strip()
+
+ help = f"{help} {extra_str}" if help else f"{extra_str}"
return name, help
def make_metavar(self) -> str:
@@ -554,7 +559,12 @@ def _write_opts(opts: Sequence[str]) -> str:
if extra:
extra_str = "; ".join(extra)
- help = f"{help} [{extra_str}]" if help else f"[{extra_str}]"
+ extra_str = f"[{extra_str}]"
+ if rich is not None:
+ # This is needed for when we want to export to HTML
+ extra_str = rich.markup.escape(extra_str).strip()
+
+ help = f"{help} {extra_str}" if help else f"{extra_str}"
return ("; " if any_prefix_is_slash else " / ").join(rv), help
diff --git a/typer/rich_utils.py b/typer/rich_utils.py
index 9ea5a14384..7d603da2d7 100644
--- a/typer/rich_utils.py
+++ b/typer/rich_utils.py
@@ -1,6 +1,7 @@
# Extracted and modified from https://github.com/ewels/rich-click
import inspect
+import io
import sys
from collections import defaultdict
from gettext import gettext as _
@@ -92,6 +93,7 @@
COMMANDS_PANEL_TITLE = _("Commands")
ERRORS_PANEL_TITLE = _("Error")
ABORTED_TEXT = _("Aborted.")
+RICH_HELP = _("Try [blue]'{command_path} {help_option}'[/] for help.")
MARKUP_MODE_MARKDOWN = "markdown"
MARKUP_MODE_RICH = "rich"
@@ -688,7 +690,9 @@ def rich_format_error(self: click.ClickException) -> None:
if ctx is not None and ctx.command.get_help_option(ctx) is not None:
console.print(
- f"Try [blue]'{ctx.command_path} {ctx.help_option_names[0]}'[/] for help.",
+ RICH_HELP.format(
+ command_path=ctx.command_path, help_option=ctx.help_option_names[0]
+ ),
style=STYLE_ERRORS_SUGGESTION,
)
@@ -706,3 +710,22 @@ def rich_abort_error() -> None:
"""Print richly formatted abort error."""
console = _get_rich_console(stderr=True)
console.print(ABORTED_TEXT, style=STYLE_ABORTED)
+
+
+def print_with_rich(text: str) -> None:
+ """Print richly formatted message."""
+ console = _get_rich_console()
+ console.print(text)
+
+
+def rich_to_html(input_text: str) -> str:
+ """Print the HTML version of a rich-formatted input string.
+
+ This function does not provide a full HTML page, but can be used to insert
+ HTML-formatted text spans into a markdown file.
+ """
+ console = Console(record=True, highlight=False, file=io.StringIO())
+
+ console.print(input_text, overflow="ignore", crop=False)
+
+ return console.export_html(inline_styles=True, code_format="{code}").strip()