Skip to content

Commit df2cb14

Browse files
svlandegpre-commit-ci[bot]tiangolo
authored
📝 Update docs to use Typer() more prominently (#1418)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sebastián Ramírez <[email protected]>
1 parent ae80129 commit df2cb14

File tree

197 files changed

+875
-390
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

197 files changed

+875
-390
lines changed

.github/DISCUSSION_TEMPLATE/questions.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,15 @@ body:
6464
placeholder: |
6565
import typer
6666
67+
app = typer.Typer()
6768
69+
@app.command()
6870
def main(name: str):
6971
typer.echo(f"Hello {name}")
7072
7173
7274
if __name__ == "__main__":
73-
typer.run(main)
75+
app()
7476
render: python
7577
validations:
7678
required: true

docs/tutorial/app-dir.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
You can get the application directory where you can, for example, save configuration files with `typer.get_app_dir()`:
44

5-
{* docs_src/app_dir/tutorial001.py hl[9] *}
5+
{* docs_src/app_dir/tutorial001.py hl[12] *}
66

77
It will give you a directory for storing configurations appropriate for your CLI program for the current user in each operating system.
88

docs/tutorial/arguments/default.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ That way the *CLI argument* will be optional *and also* have a default value.
88

99
We can also use `typer.Argument()` to make a *CLI argument* have a default value other than `None`:
1010

11-
{* docs_src/arguments/default/tutorial001_an.py hl[5] *}
11+
{* docs_src/arguments/default/tutorial001_an.py hl[8] *}
1212

1313
/// tip
1414

@@ -52,7 +52,7 @@ Hello Camila
5252

5353
And we can even make the default value be dynamically generated by passing a function as the `default_factory` argument:
5454

55-
{* docs_src/arguments/default/tutorial002_an.py hl[7:8,11] *}
55+
{* docs_src/arguments/default/tutorial002_an.py hl[10:11,14] *}
5656

5757
In this case, we created the function `get_name` that will just return a random `str` each time.
5858

docs/tutorial/arguments/envvar.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ You can learn more about environment variables in the [Environment Variables](..
1010

1111
To do that, use the `envvar` parameter for `typer.Argument()`:
1212

13-
{* docs_src/arguments/envvar/tutorial001_an.py hl[5] *}
13+
{* docs_src/arguments/envvar/tutorial001_an.py hl[8] *}
1414

1515
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:
1616

@@ -55,7 +55,7 @@ Hello Mr. Czernobog
5555

5656
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:
5757

58-
{* docs_src/arguments/envvar/tutorial002_an.py hl[6] *}
58+
{* docs_src/arguments/envvar/tutorial002_an.py hl[9] *}
5959

6060
Check it:
6161

@@ -90,7 +90,7 @@ Hello Mr. Anubis
9090

9191
By default, environment variables used will be shown in the help text, but you can disable them with `show_envvar=False`:
9292

93-
{* docs_src/arguments/envvar/tutorial003_an.py hl[7] *}
93+
{* docs_src/arguments/envvar/tutorial003_an.py hl[10] *}
9494

9595
Check it:
9696

docs/tutorial/arguments/help.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Now that you also know how to use `typer.Argument()`, let's use it to add docume
1212

1313
You can use the `help` parameter to add a help text for a *CLI argument*:
1414

15-
{* docs_src/arguments/help/tutorial001_an.py hl[5] *}
15+
{* docs_src/arguments/help/tutorial001_an.py hl[8] *}
1616

1717
And it will be used in the automatic `--help` option:
1818

@@ -37,7 +37,7 @@ Options:
3737

3838
And of course, you can also combine that `help` with the <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr>:
3939

40-
{* docs_src/arguments/help/tutorial002_an.py hl[5:8] *}
40+
{* docs_src/arguments/help/tutorial002_an.py hl[8:11] *}
4141

4242
And the `--help` option will combine all the information:
4343

@@ -64,7 +64,7 @@ Options:
6464

6565
If you have a *CLI argument* with a default value, like `"World"`:
6666

67-
{* docs_src/arguments/help/tutorial003_an.py hl[5] *}
67+
{* docs_src/arguments/help/tutorial003_an.py hl[8] *}
6868

6969
It will show that default value in the help text:
7070

@@ -89,7 +89,7 @@ Options:
8989

9090
But you can disable that if you want to, with `show_default=False`:
9191

92-
{* docs_src/arguments/help/tutorial004_an.py hl[7] *}
92+
{* docs_src/arguments/help/tutorial004_an.py hl[10] *}
9393

9494
And then it won't show the default value:
9595

@@ -124,7 +124,7 @@ In **Typer** these default values are shown by default. 👀
124124

125125
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:
126126

127-
{* docs_src/arguments/help/tutorial005_an.py hl[9] *}
127+
{* docs_src/arguments/help/tutorial005_an.py hl[12] *}
128128

129129
And it will be used in the help text:
130130

@@ -169,7 +169,7 @@ But you can customize it with the `metavar` parameter for `typer.Argument()`.
169169

170170
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:
171171

172-
{* docs_src/arguments/help/tutorial006_an.py hl[5] *}
172+
{* docs_src/arguments/help/tutorial006_an.py hl[8] *}
173173

174174
Now the generated help text will have `✨username✨` instead of `NAME`:
175175

@@ -195,7 +195,7 @@ You might want to show the help information for *CLI arguments* in different pan
195195

196196
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:
197197

198-
{* docs_src/arguments/help/tutorial007_an.py hl[8,12] *}
198+
{* docs_src/arguments/help/tutorial007_an.py hl[11,15] *}
199199

200200
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`.
201201

@@ -238,7 +238,7 @@ If you want, you can make a *CLI argument* **not** show up in the `Arguments` se
238238

239239
You will probably not want to do this normally, but it's possible:
240240

241-
{* docs_src/arguments/help/tutorial008_an.py hl[5] *}
241+
{* docs_src/arguments/help/tutorial008_an.py hl[8] *}
242242

243243
Check it:
244244

docs/tutorial/arguments/optional.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ In the [First Steps](../first-steps.md#add-a-cli-argument){.internal-link target
3939

4040
Now let's see an alternative way to create the same *CLI argument*:
4141

42+
{* docs_src/arguments/optional/tutorial000.py hl[4] *}
4243

43-
{* docs_src/arguments/optional/tutorial001_an.py hl[5] *}
44+
Or, using an explicit `Typer()` instance creation:
45+
46+
{* docs_src/arguments/optional/tutorial001_an.py hl[8] *}
4447

4548
/// info
4649

@@ -111,7 +114,7 @@ Now, finally what we came for, an optional *CLI argument*.
111114

112115
To make a *CLI argument* optional, use `typer.Argument()` and make sure to provide a "default" value, for example `"World"`:
113116

114-
{* docs_src/arguments/optional/tutorial002_an.py hl[5] *}
117+
{* docs_src/arguments/optional/tutorial002_an.py hl[8] *}
115118

116119
Now we have:
117120

@@ -178,7 +181,7 @@ Notice that "`Camila`" here is an optional *CLI argument*, not a *CLI option*, b
178181

179182
Instead of using `Annotated`, you can use `typer.Argument()` as the default value:
180183

181-
{* docs_src/arguments/optional/tutorial001.py hl[4] *}
184+
{* docs_src/arguments/optional/tutorial001.py hl[7] *}
182185

183186
/// tip
184187

@@ -212,13 +215,13 @@ If you hadn't seen that `...` before: it is a special single value, it is <a hre
212215

213216
///
214217

215-
{* docs_src/arguments/optional/tutorial003.py hl[4] *}
218+
{* docs_src/arguments/optional/tutorial003.py hl[7] *}
216219

217-
And the same way, you can make it optional by passing a different `default` value, for example `None`:
220+
And the same way, you can make it optional by passing a different `default` value, for example `"World"`:
218221

219-
{* docs_src/arguments/optional/tutorial002.py hl[6] *}
222+
{* docs_src/arguments/optional/tutorial002.py hl[7] *}
220223

221-
Because the first parameter passed to `typer.Argument(default=None)` (the new "default" value) is `None`, **Typer** knows that this is an **optional** *CLI argument*, if no value is provided when calling it in the command line, it will have that default value of `None`.
224+
Because the first parameter passed to `typer.Argument(default="World")` (the new "default" value) is `"World"`, **Typer** knows that this is an **optional** *CLI argument*, if no value is provided when calling it in the command line, it will have that default value of `"World"`.
222225

223226
The `default` argument is the first one, so it's possible that you see code that passes the value without explicitly using `default=`, like:
224227

@@ -229,7 +232,7 @@ name: str = typer.Argument(...)
229232
...or like:
230233

231234
```Python
232-
name: str = typer.Argument(None)
235+
name: str = typer.Argument("World")
233236
```
234237

235238
...but again, try to use `Annotated` if possible, that way your code in terms of Python will mean the same thing as with **Typer** and you won't have to remember any of these details.

docs/tutorial/commands/index.md

Lines changed: 1 addition & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -46,127 +46,9 @@ Have that in mind so you don't get confused.
4646

4747
Here I'll use **CLI application** or **program** to refer to the program you are building in Python with Typer, and **command** to refer to one of these "subcommands" of your program.
4848

49-
## Explicit application
50-
51-
Before creating CLI applications with multiple commands/subcommands we need to understand how to create an explicit `typer.Typer()` application.
52-
53-
In the *CLI options* and *CLI argument* tutorials you have seen how to create a single function and then pass that function to `typer.run()`.
54-
55-
For example:
56-
57-
{* docs_src/first_steps/tutorial002.py hl[9] *}
58-
59-
But that is actually a shortcut. Under the hood, **Typer** converts that to a CLI application with `typer.Typer()` and executes it. All that inside of `typer.run()`.
60-
61-
There's also a more explicit way to achieve the same:
62-
63-
{* docs_src/commands/index/tutorial001.py hl[3,6,12] *}
64-
65-
When you use `typer.run()`, **Typer** is doing more or less the same as above, it will:
66-
67-
* Create a new `typer.Typer()` "application".
68-
* Create a new "`command`" with your function.
69-
* Call the same "application" as if it was a function with "`app()`".
70-
71-
/// info | `@decorator` Info
72-
73-
That `@something` syntax in Python is called a "decorator".
74-
75-
You put it on top of a function. Like a pretty decorative hat (I guess that's where the term came from).
76-
77-
A "decorator" takes the function below and does something with it.
78-
79-
In our case, this decorator tells **Typer** that the function below is a "`command`".
80-
81-
///
82-
83-
Both ways, with `typer.run()` and creating the explicit application, achieve almost the same.
84-
85-
/// tip
86-
87-
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.
88-
89-
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.
90-
91-
///
92-
93-
If you run the second example, with the explicit `app`, it works exactly the same:
94-
95-
<div class="termy">
96-
97-
```console
98-
// Without a CLI argument
99-
$ python main.py
100-
101-
Usage: main.py [OPTIONS] NAME
102-
Try "main.py --help" for help.
103-
104-
Error: Missing argument 'NAME'.
105-
106-
// With the NAME CLI argument
107-
$ python main.py Camila
108-
109-
Hello Camila
110-
111-
// Asking for help
112-
$ python main.py --help
113-
114-
Usage: main.py [OPTIONS] NAME
115-
116-
Options:
117-
--install-completion Install completion for the current shell.
118-
--show-completion Show completion for the current shell, to copy it or customize the installation.
119-
--help Show this message and exit.
120-
```
121-
122-
</div>
123-
124-
## CLI application completion
125-
126-
There's a little detail that is worth noting here.
127-
128-
Now the help shows two new *CLI options*:
129-
130-
* `--install-completion`
131-
* `--show-completion`
132-
133-
To get shell/tab completion, it's necessary to build a package that you and your users can install and **call directly**.
134-
135-
So instead of running a Python script like:
136-
137-
<div class="termy">
138-
139-
```console
140-
$ python main.py
141-
142-
✨ Some magic here ✨
143-
```
144-
145-
</div>
146-
147-
...It would be called like:
148-
149-
<div class="termy">
150-
151-
```console
152-
$ magic-app
153-
154-
✨ Some magic here ✨
155-
```
156-
157-
</div>
158-
159-
Having a standalone program like that allows setting up shell/tab completion.
160-
161-
The first step to be able to create an installable package like that is to use an explicit `typer.Typer()` app.
162-
163-
Later you can learn all the process to create a standalone CLI application and [Build a Package](../package.md){.internal-link target=_blank}.
164-
165-
But for now, it's just good to know that you are on that path. 😎
166-
16749
## A CLI application with multiple commands
16850

169-
Coming back to the CLI applications with multiple commands/subcommands, **Typer** allows creating CLI applications with multiple of them.
51+
**Typer** allows creating CLI applications with multiple commands/subcommands.
17052

17153
Now that you know how to create an explicit `typer.Typer()` application and add one command, let's see how to add multiple commands.
17254

docs/tutorial/commands/one-or-multiple.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# One or Multiple Commands
22

3-
You might have noticed that if you create a single command, as in the first example:
3+
You might have noticed that if you create a single command, as in the following example:
44

5-
{* docs_src/commands/index/tutorial001.py hl[3,6,12] *}
5+
{* docs_src/typer_app/tutorial001.py hl[3,6,12] *}
66

77
**Typer** is smart enough to create a CLI application with that single function as the main CLI application, not as a command/subcommand:
88

docs/tutorial/exceptions.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Typer does some tricks to help you detect those errors quickly.
88

99
Let's take this example broken app:
1010

11-
{* docs_src/exceptions/tutorial001.py hl[5] *}
11+
{* docs_src/exceptions/tutorial001.py hl[8] *}
1212

1313
This code is broken because you can't sum a string and a number (`name + 3`).
1414

@@ -26,15 +26,15 @@ So, the error you see will be **much clearer** and simpler, to help you detect t
2626
$ python main.py
2727

2828
<font color="#F92672">╭──────────────── </font><font color="#F92672"><b>Traceback (most recent call last)</b></font><font color="#F92672"> ────────────────╮</font>
29-
<font color="#F92672">│</font> <font color="#A37F4E">/home/user/code/superapp/</font><font color="#F4BF75"><b>main.py</b></font>:<font color="#66D9EF">5</font> in <font color="#A6E22E">main</font> <font color="#F92672">│</font>
29+
<font color="#F92672">│</font> <font color="#A37F4E">/home/user/code/superapp/</font><font color="#F4BF75"><b>main.py</b></font>:<font color="#66D9EF">8</font> in <font color="#A6E22E">main</font> <font color="#F92672">│</font>
3030
<font color="#F92672">│</font> <font color="#F92672">│</font>
31-
<font color="#F92672">│</font> 2 <font color="#F92672">│</font>
32-
<font color="#F92672">│</font> 3 <font color="#F92672">│</font>
33-
<font color="#F92672">│</font> 4 <font color="#66D9EF">def</font> <font color="#A6E22E">main</font>(name: <font color="#A1EFE4">str</font> = <font color="#F4BF75">&quot;morty&quot;</font>): <font color="#F92672">│</font>
34-
<font color="#F92672">│</font> <font color="#F92672">❱ </font> 5 │ <font color="#A1EFE4">print</font>(name + <font color="#66D9EF">3</font>) <font color="#F92672">│</font>
35-
<font color="#F92672">│</font> 6 <font color="#F92672">│</font>
36-
<font color="#F92672">│</font> 7 <font color="#F92672">│</font>
37-
<font color="#F92672">│</font> 8 <font color="#66D9EF">if</font> <font color="#F92672">__name__</font> == <font color="#F4BF75">&quot;__main__&quot;</font>: <font color="#F92672">│</font>
31+
<font color="#F92672">│</font> 5 <font color="#F92672">│</font>
32+
<font color="#F92672">│</font> 6 <font color="#FF00FF">@app</font>.command() <font color="#F92672">│</font>
33+
<font color="#F92672">│</font> 7 <font color="#66D9EF">def</font> <font color="#A6E22E">main</font>(name: <font color="#A1EFE4">str</font> = <font color="#F4BF75">&quot;morty&quot;</font>): <font color="#F92672">│</font>
34+
<font color="#F92672">│</font> <font color="#F92672">❱ </font> 8 │ <font color="#A1EFE4">print</font>(name + <font color="#66D9EF">3</font>) <font color="#F92672">│</font>
35+
<font color="#F92672">│</font> 9 <font color="#F92672">│</font>
36+
<font color="#F92672">│</font> 10 <font color="#F92672">│</font>
37+
<font color="#F92672">│</font> 11 <font color="#66D9EF">if</font> <font color="#F92672">__name__</font> == <font color="#F4BF75">&quot;__main__&quot;</font>: <font color="#F92672">│</font>
3838
<font color="#F92672">│</font> <font color="#F92672">│</font>
3939
<font color="#F92672">│</font> <font color="#F4BF75">╭──── locals ────╮</font> <font color="#F92672">│</font>
4040
<font color="#F92672">│</font> <font color="#F4BF75">│</font> name = <font color="#F4BF75">&apos;morty&apos;</font> <font color="#F4BF75">│</font> <font color="#F92672">│</font>
@@ -57,7 +57,7 @@ $ python main.py
5757
Traceback (most recent call last):
5858

5959
File "main.py", line 12, in <module>
60-
typer.run(main)
60+
app()
6161

6262
File "main.py", line 8, in main
6363
print(name + 3)
@@ -83,7 +83,7 @@ In this case, `name` is a local variable, it comes from a parameter passed to th
8383

8484
But if it was something like a password, you would have liked to hide it.
8585

86-
In that case, you can create the `typer.Typer()` application explicitly and set the parameter `pretty_exceptions_show_locals=False`:
86+
In that case, you can set the parameter `pretty_exceptions_show_locals=False` when creating the `typer.Typer()` application:
8787

8888
{* docs_src/exceptions/tutorial002.py hl[3] *}
8989

0 commit comments

Comments
 (0)