-
-
Notifications
You must be signed in to change notification settings - Fork 805
📝 Update docs to use Typer() more prominently
#1418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
29fc205
1c57854
0377ad4
f654dbc
e34df56
ab5e5c9
024cd31
877612a
b3562ba
1440f34
da39182
ff40c66
2c2266a
c2949d5
07dc0f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,8 +39,11 @@ In the [First Steps](../first-steps.md#add-a-cli-argument){.internal-link target | |
|
|
||
| Now let's see an alternative way to create the same *CLI argument*: | ||
|
|
||
| {* docs_src/arguments/optional/tutorial000.py hl[4] *} | ||
|
|
||
| {* docs_src/arguments/optional/tutorial001_an.py hl[5] *} | ||
| Or, using an explicit `Typer()` instance creation: | ||
|
|
||
| {* docs_src/arguments/optional/tutorial001_an.py hl[8] *} | ||
|
|
||
| /// info | ||
|
|
||
|
|
@@ -111,7 +114,7 @@ Now, finally what we came for, an optional *CLI argument*. | |
|
|
||
| To make a *CLI argument* optional, use `typer.Argument()` and make sure to provide a "default" value, for example `"World"`: | ||
|
|
||
| {* docs_src/arguments/optional/tutorial002_an.py hl[5] *} | ||
| {* docs_src/arguments/optional/tutorial002_an.py hl[8] *} | ||
|
|
||
| Now we have: | ||
|
|
||
|
|
@@ -178,7 +181,7 @@ Notice that "`Camila`" here is an optional *CLI argument*, not a *CLI option*, b | |
|
|
||
| Instead of using `Annotated`, you can use `typer.Argument()` as the default value: | ||
|
|
||
| {* docs_src/arguments/optional/tutorial001.py hl[4] *} | ||
| {* docs_src/arguments/optional/tutorial001.py hl[7] *} | ||
|
|
||
| /// tip | ||
|
|
||
|
|
@@ -212,13 +215,13 @@ If you hadn't seen that `...` before: it is a special single value, it is <a hre | |
|
|
||
| /// | ||
|
|
||
| {* docs_src/arguments/optional/tutorial003.py hl[4] *} | ||
| {* docs_src/arguments/optional/tutorial003.py hl[7] *} | ||
|
|
||
| And the same way, you can make it optional by passing a different `default` value, for example `None`: | ||
| And the same way, you can make it optional by passing a different `default` value, for example `"World"`: | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, and in the lines below, I've had to make extra edits, because this section had become out-of-date on |
||
|
|
||
| {* docs_src/arguments/optional/tutorial002.py hl[6] *} | ||
| {* docs_src/arguments/optional/tutorial002.py hl[7] *} | ||
|
|
||
| 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`. | ||
| 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"`. | ||
|
|
||
| The `default` argument is the first one, so it's possible that you see code that passes the value without explicitly using `default=`, like: | ||
|
|
||
|
|
@@ -229,7 +232,7 @@ name: str = typer.Argument(...) | |
| ...or like: | ||
|
|
||
| ```Python | ||
| name: str = typer.Argument(None) | ||
| name: str = typer.Argument("World") | ||
| ``` | ||
|
|
||
| ...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. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,127 +46,10 @@ Have that in mind so you don't get confused. | |
|
|
||
| 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. | ||
|
|
||
| ## Explicit application | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This bit is moved almost verbatim to |
||
|
|
||
| Before creating CLI applications with multiple commands/subcommands we need to understand how to create an explicit `typer.Typer()` application. | ||
|
|
||
| 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()`. | ||
|
|
||
| For example: | ||
|
|
||
| {* docs_src/first_steps/tutorial002.py hl[9] *} | ||
|
|
||
| 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()`. | ||
|
|
||
| There's also a more explicit way to achieve the same: | ||
|
|
||
| {* docs_src/commands/index/tutorial001.py hl[3,6,12] *} | ||
|
|
||
| When you use `typer.run()`, **Typer** is doing more or less the same as above, it will: | ||
|
|
||
| * Create a new `typer.Typer()` "application". | ||
| * 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". | ||
|
|
||
| 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. | ||
|
|
||
| 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. | ||
|
|
||
| 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: | ||
|
|
||
| <div class="termy"> | ||
|
|
||
| ```console | ||
| // Without a CLI argument | ||
| $ python main.py | ||
|
|
||
| Usage: main.py [OPTIONS] NAME | ||
| Try "main.py --help" for help. | ||
|
|
||
| Error: Missing argument 'NAME'. | ||
|
|
||
| // With the NAME CLI argument | ||
| $ python main.py Camila | ||
|
|
||
| Hello Camila | ||
|
|
||
| // Asking for help | ||
| $ python main.py --help | ||
|
|
||
| Usage: main.py [OPTIONS] NAME | ||
|
|
||
| Options: | ||
| --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. | ||
| ``` | ||
|
|
||
| </div> | ||
|
|
||
| ## CLI application completion | ||
|
|
||
| There's a little detail that is worth noting here. | ||
|
|
||
| Now the help shows two new *CLI options*: | ||
|
|
||
| * `--install-completion` | ||
| * `--show-completion` | ||
|
|
||
| To get shell/tab completion, it's necessary to build a package that you and your users can install and **call directly**. | ||
|
|
||
| So instead of running a Python script like: | ||
|
|
||
| <div class="termy"> | ||
|
|
||
| ```console | ||
| $ python main.py | ||
|
|
||
| ✨ Some magic here ✨ | ||
| ``` | ||
|
|
||
| </div> | ||
|
|
||
| ...It would be called like: | ||
|
|
||
| <div class="termy"> | ||
|
|
||
| ```console | ||
| $ magic-app | ||
|
|
||
| ✨ Some magic here ✨ | ||
| ``` | ||
|
|
||
| </div> | ||
|
|
||
| Having a standalone program like that allows setting up shell/tab completion. | ||
|
|
||
| The first step to be able to create an installable package like that is to use an explicit `typer.Typer()` app. | ||
|
|
||
| Later you can learn all the process to create a standalone CLI application and [Build a Package](../package.md){.internal-link target=_blank}. | ||
|
|
||
| But for now, it's just good to know that you are on that path. 😎 | ||
|
|
||
| ## A CLI application with multiple commands | ||
|
|
||
| Coming back to the CLI applications with multiple commands/subcommands, **Typer** allows creating CLI applications with multiple of them. | ||
|
|
||
| **Typer** allows creating CLI applications with multiple commands/subcommands. | ||
|
|
||
| Now that you know how to create an explicit `typer.Typer()` application and add one command, let's see how to add multiple commands. | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, I've created a new tutorial file (
docs_src/arguments/optional/tutorial000.py) to better show the difference with the more simplisticdocs_src/first_steps/tutorial002.py. The next version then (docs_src/arguments/optional/tutorial001_an.py) introduces bothAnnotatedas well asTyper().