📝 Add docs and examples for CLI parameters with multiple values

This commit is contained in:
Sebastián Ramírez 2020-01-05 22:09:41 +01:00
parent ff37cb874f
commit fb8622b8bb
8 changed files with 247 additions and 0 deletions

View file

@ -0,0 +1,15 @@
from pathlib import Path
from typing import List
import typer
def main(files: List[Path], celebration: str):
for path in files:
if path.is_file():
typer.echo(f"This file exists: {path.name}")
typer.echo(celebration)
if __name__ == "__main__":
typer.run(main)

View file

@ -0,0 +1,15 @@
from typing import List
import typer
def main(user: List[str] = typer.Option(None)):
if not user:
typer.echo("No provided users")
raise typer.Abort()
for u in user:
typer.echo(f"Processing user: {u}")
if __name__ == "__main__":
typer.run(main)

View file

@ -0,0 +1,11 @@
from typing import List
import typer
def main(number: List[float] = typer.Option([])):
typer.echo(f"The sum is {sum(number)}")
if __name__ == "__main__":
typer.run(main)

View file

@ -0,0 +1,17 @@
from typing import Tuple
import typer
def main(user: Tuple[str, int, bool] = typer.Option((None, None, None))):
username, coins, is_wizard = user
if not username:
typer.echo("No user provided")
raise typer.Abort()
typer.echo(f"The username {username} has {coins} coins")
if is_wizard:
typer.echo("And this user is a wizard!")
if __name__ == "__main__":
typer.run(main)

View file

@ -0,0 +1,28 @@
*CLI arguments* can also receive multiple values.
You can define the type of a *CLI argument* using `typing.List`.
```Python hl_lines="7"
{!./src/multiple_values/arguments_with_multiple_values/tutorial001.py!}
```
And then you can pass it as many *CLI arguments* of that type as you want:
<div class="termy">
```console
$ python main.py ./index.md ./first-steps.md woohoo!
This file exists: index.md
woohoo!
This file exists: first-steps.md
woohoo!
```
</div>
!!! tip
We also declared a final *CLI argument* `celebration`, and it's correctly used even if we pass an arbitrary number of `files` first.
!!! info
A `List` can only be used in the last command (if there are subcommands), as this will take anything to the right and assume it's part of the expected *CLI arguments*.

View file

@ -0,0 +1,3 @@
There are several ways to declare multiple values for *CLI options* and *CLI arguments*.
We'll see them in the next short sections.

View file

@ -0,0 +1,66 @@
You can declare a *CLI option* that can be used multiple times, and then get all the values.
For example, let's say you want to accept several users in a single execution.
For this, use the standard Python `typing.List` to declare it as a `list` of `str`:
```Python hl_lines="1 6"
{!./src/multiple_values/multiple_options/tutorial001.py!}
```
You will receive the values as you declared them, as a `list` of `str`.
Check it:
<div class="termy">
```console
$ python main.py
No provided users
Aborted!
// Now pass a user
$ python main.py --user Camila
Processing user: Camila
// And now try with several users
$ python main.py --user Camila --user Rick --user Morty
Processing user: Camila
Processing user: Rick
Processing user: Morty
```
</div>
## Multiple `float`
The same way, you can use other types and they will be converted by **Typer** to their declared type:
```Python hl_lines="6"
{!./src/multiple_values/multiple_options/tutorial002.py!}
```
Check it:
<div class="termy">
```console
$ python main.py
The sum is 0
// Try with some numbers
$ python main.py --number 2
The sum is 2.0
// Try with some numbers
$ python main.py --number 2 --number 3 --number 4.5
The sum is 9.5
```
</div>

View file

@ -0,0 +1,92 @@
You can also declare a *CLI option* that takes several values of different types.
You can set the number of values and types to anything you want, but it has to be a fixed number of values.
For this, use the standard Python `typing.Tuple`:
```Python hl_lines="1 6"
{!./src/multiple_values/options_with_multiple_values/tutorial001.py!}
```
Each of the internal types defines the type of each value in the tuple.
So:
```Python
user: Tuple[str, int, bool]
```
means that the parameter `user` is a tuple of 3 values.
* The first value is a `str`.
* The second value is an `int`.
* The third value is a `bool`.
Later we do:
```Python
username, coins, is_wizard = user
```
If you hadn't seen that, it means that `user` is a tuple with 3 values, and we are assigning each of the values to a new variable:
* The first value in the tuple `user` (a `str`) goes to the variable `username`.
* The second value in the tuple `user` (an `int`) goes to the variable `coins`.
* The third value in the tuple `user` (a `bool`) goes to the variable `is_wizard`.
So, this:
```Python
username, coins, is_wizard = user
```
is equivalent to this:
```Python
username = user[0]
coins = user[1]
is_wizard = user[2]
```
!!! tip
Notice that the default is a tuple with `(None, None, None)`.
You cannot simply use `None` here as the default because <a href="https://github.com/pallets/click/issues/472" target="_blank">Click doesn't support it</a>.
## Check it
Now let's see how this works in the terminal:
<div class="termy">
```console
// check the help
$ python main.py --help
// Notice the &lt;TEXT INTEGER BOOLEAN&gt;
Usage: main.py [OPTIONS]
Options:
--user &lt;TEXT INTEGER BOOLEAN&gt;...
--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.
// Now try it
$ python main.py --user Camila 50 yes
The username Camila has 50 coins
And this user is a wizard!
// With other values
$ python main.py --user Morty 3 no
The username Morty has 3 coins
// Try with invalid values (not enough)
$ python main.py --user Camila 50
Error: --user option requires 3 arguments
```
</div>