📝 Add extra docs and tests for param types
This commit is contained in:
commit
ff37cb874f
14 changed files with 536 additions and 0 deletions
0
docs/src/parameter_types/bool/__init__.py
Normal file
0
docs/src/parameter_types/bool/__init__.py
Normal file
12
docs/src/parameter_types/bool/tutorial001.py
Normal file
12
docs/src/parameter_types/bool/tutorial001.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
import typer
|
||||
|
||||
|
||||
def main(force: bool = typer.Option(False, "--force")):
|
||||
if force:
|
||||
typer.echo("Forcing operation")
|
||||
else:
|
||||
typer.echo("Not forcing")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
typer.run(main)
|
14
docs/src/parameter_types/bool/tutorial002.py
Normal file
14
docs/src/parameter_types/bool/tutorial002.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
import typer
|
||||
|
||||
|
||||
def main(accept: bool = typer.Option(None, "--accept/--reject")):
|
||||
if accept is None:
|
||||
typer.echo("I don't know what you want yet")
|
||||
elif accept:
|
||||
typer.echo("Accepting!")
|
||||
else:
|
||||
typer.echo("Rejecting!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
typer.run(main)
|
12
docs/src/parameter_types/bool/tutorial003.py
Normal file
12
docs/src/parameter_types/bool/tutorial003.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
import typer
|
||||
|
||||
|
||||
def main(force: bool = typer.Option(False, "--force/--no-force", "-f/-F")):
|
||||
if force:
|
||||
typer.echo("Forcing operation")
|
||||
else:
|
||||
typer.echo("Not forcing")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
typer.run(main)
|
12
docs/src/parameter_types/bool/tutorial004.py
Normal file
12
docs/src/parameter_types/bool/tutorial004.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
import typer
|
||||
|
||||
|
||||
def main(in_prod: bool = typer.Option(True, " /--demo", " /-d")):
|
||||
if in_prod:
|
||||
typer.echo("Running in production")
|
||||
else:
|
||||
typer.echo("Running demo")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
typer.run(main)
|
9
docs/src/parameter_types/number/tutorial003.py
Normal file
9
docs/src/parameter_types/number/tutorial003.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
import typer
|
||||
|
||||
|
||||
def main(verbose: int = typer.Option(0, "--verbose", "-v", count=True)):
|
||||
typer.echo(f"Verbose level is {verbose}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
typer.run(main)
|
190
docs/tutorial/parameter-types/bool.md
Normal file
190
docs/tutorial/parameter-types/bool.md
Normal file
|
@ -0,0 +1,190 @@
|
|||
We have seen some examples of *CLI options* with `bool`, and how **Typer** creates `--something` and `--no-something` automatically.
|
||||
|
||||
But we can customize those names.
|
||||
|
||||
## Only `--force`
|
||||
|
||||
Let's say that we want a `--force` *CLI option* only, we want to discard `--no-force`.
|
||||
|
||||
We can do that by specifying the exact name we want:
|
||||
|
||||
```Python hl_lines="4"
|
||||
{!./src/parameter_types/bool/tutorial001.py!}
|
||||
```
|
||||
|
||||
Now there's only a `--force` *CLI option*:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Check the help
|
||||
$ python main.py --help
|
||||
|
||||
// Notice there's only --force, we no longer have --no-force
|
||||
Usage: main.py [OPTIONS]
|
||||
|
||||
Options:
|
||||
--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.
|
||||
|
||||
// Try it:
|
||||
$ python main.py
|
||||
|
||||
Not forcing
|
||||
|
||||
// Now add --force
|
||||
$ python main.py --force
|
||||
|
||||
Forcing operation
|
||||
|
||||
// And --no-force no longer exists ⛔️
|
||||
$ python main.py --no-force
|
||||
|
||||
Usage: main.py [OPTIONS]
|
||||
Try "main.py --help" for help.
|
||||
|
||||
Error: no such option: --no-force
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Alternative names
|
||||
|
||||
Now let's imagine we have a *CLI option* `--accept`.
|
||||
|
||||
And we want to allow setting `--accept` or the contrary, but `--no-accept` looks ugly.
|
||||
|
||||
We might want to instead have `--accept` and `--reject`.
|
||||
|
||||
We can do that by passing a single `str` with the 2 names for the `bool` *CLI option* separated by `/`:
|
||||
|
||||
```Python hl_lines="4"
|
||||
{!./src/parameter_types/bool/tutorial002.py!}
|
||||
```
|
||||
|
||||
Check it:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Check the help
|
||||
$ python main.py --help
|
||||
|
||||
// Notice the --accept / --reject
|
||||
Usage: main.py [OPTIONS]
|
||||
|
||||
Options:
|
||||
--accept / --reject
|
||||
--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.
|
||||
|
||||
// Try it
|
||||
$ python main.py
|
||||
|
||||
I don't know what you want yet
|
||||
|
||||
// Now pass --accept
|
||||
$ python main.py --accept
|
||||
|
||||
Accepting!
|
||||
|
||||
// And --reject
|
||||
$ python main.py --reject
|
||||
|
||||
Rejecting!
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Short names
|
||||
|
||||
The same way, you can declare short versions of the names for these *CLI options*.
|
||||
|
||||
For example, let's say we want `-f` for `--force` and `-F` for `--no-force`:
|
||||
|
||||
```Python hl_lines="4"
|
||||
{!./src/parameter_types/bool/tutorial003.py!}
|
||||
```
|
||||
|
||||
Check it:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Check the help
|
||||
$ python main.py --help
|
||||
|
||||
// Notice the -f, --force / -F, --no-force
|
||||
Usage: main.py [OPTIONS]
|
||||
|
||||
Options:
|
||||
-f, --force / -F, --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.
|
||||
|
||||
// Try with the short name -f
|
||||
$ python main.py -f
|
||||
|
||||
Forcing operation
|
||||
|
||||
// Try with the short name -F
|
||||
$ python main.py -F
|
||||
|
||||
Not forcing
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Only names for `False`
|
||||
|
||||
If you want to (although it might not be a good idea), you can declare only *CLI option* names to set the `False` value.
|
||||
|
||||
To do that, use a space and a single `/` and pass the negative name after:
|
||||
|
||||
```Python hl_lines="4"
|
||||
{!./src/parameter_types/bool/tutorial004.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Have in mind that it's a string with a preceding space and then a `/`.
|
||||
|
||||
So, it's `" /-S"` not `"/-S"`.
|
||||
|
||||
Check it:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Check the help
|
||||
$ python main.py --help
|
||||
|
||||
// Notice the / -d, --demo
|
||||
Usage: main.py [OPTIONS]
|
||||
|
||||
Options:
|
||||
/ -d, --demo
|
||||
--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.
|
||||
|
||||
// Try it
|
||||
$ python main.py
|
||||
|
||||
Running in production
|
||||
|
||||
// Now pass --demo
|
||||
$ python main.py --demo
|
||||
|
||||
Running demo
|
||||
|
||||
// And the short version
|
||||
$ python main.py -d
|
||||
|
||||
Running demo
|
||||
```
|
||||
|
||||
</div>
|
|
@ -98,3 +98,51 @@ ID is 5
|
|||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Counter *CLI options*
|
||||
|
||||
You can make a *CLI option* work as a counter with the `counter` parameter:
|
||||
|
||||
```Python hl_lines="4"
|
||||
{!./src/parameter_types/number/tutorial003.py!}
|
||||
```
|
||||
|
||||
It means that the *CLI option* will be like a boolean flag, e.g. `--verbose`.
|
||||
|
||||
And the value you receive in the function will be the amount of times that `--verbose` was added:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Check it
|
||||
$ python main.py
|
||||
|
||||
Verbose level is 0
|
||||
|
||||
// Now use one --verbose
|
||||
$ python main.py --verbose
|
||||
|
||||
Verbose level is 1
|
||||
|
||||
// Now 3 --verbose
|
||||
$ python main.py --verbose --verbose --verbose
|
||||
|
||||
Verbose level is 3
|
||||
|
||||
// And with the short name
|
||||
$ python main.py -v
|
||||
|
||||
Verbose level is 1
|
||||
|
||||
// And with the short name 3 times
|
||||
$ python main.py -v -v -v
|
||||
|
||||
Verbose level is 3
|
||||
|
||||
// As short names can be put together, this also works
|
||||
$ python main.py -vvv
|
||||
|
||||
Verbose level is 3
|
||||
```
|
||||
|
||||
</div>
|
|
@ -0,0 +1,46 @@
|
|||
import subprocess
|
||||
|
||||
import typer
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from parameter_types.bool import tutorial001 as mod
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
app = typer.Typer()
|
||||
app.command()(mod.main)
|
||||
|
||||
|
||||
def test_help():
|
||||
result = runner.invoke(app, ["--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "--force" in result.output
|
||||
assert "--no-force" not in result.output
|
||||
|
||||
|
||||
def test_no_force():
|
||||
result = runner.invoke(app)
|
||||
assert result.exit_code == 0
|
||||
assert "Not forcing" in result.output
|
||||
|
||||
|
||||
def test_force():
|
||||
result = runner.invoke(app, ["--force"])
|
||||
assert result.exit_code == 0
|
||||
assert "Forcing operation" in result.output
|
||||
|
||||
|
||||
def test_invalid_no_force():
|
||||
result = runner.invoke(app, ["--no-force"])
|
||||
assert result.exit_code != 0
|
||||
assert "Error: no such option: --no-force" in result.output
|
||||
|
||||
|
||||
def test_script():
|
||||
result = subprocess.run(
|
||||
["coverage", "run", mod.__file__, "--help"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
encoding="utf-8",
|
||||
)
|
||||
assert "Usage" in result.stdout
|
|
@ -0,0 +1,52 @@
|
|||
import subprocess
|
||||
|
||||
import typer
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from parameter_types.bool import tutorial002 as mod
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
app = typer.Typer()
|
||||
app.command()(mod.main)
|
||||
|
||||
|
||||
def test_help():
|
||||
result = runner.invoke(app, ["--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "--accept / --reject" in result.output
|
||||
assert "--no-accept" not in result.output
|
||||
|
||||
|
||||
def test_main():
|
||||
result = runner.invoke(app)
|
||||
assert result.exit_code == 0
|
||||
assert "I don't know what you want yet" in result.output
|
||||
|
||||
|
||||
def test_accept():
|
||||
result = runner.invoke(app, ["--accept"])
|
||||
assert result.exit_code == 0
|
||||
assert "Accepting!" in result.output
|
||||
|
||||
|
||||
def test_reject():
|
||||
result = runner.invoke(app, ["--reject"])
|
||||
assert result.exit_code == 0
|
||||
assert "Rejecting!" in result.output
|
||||
|
||||
|
||||
def test_invalid_no_accept():
|
||||
result = runner.invoke(app, ["--no-accept"])
|
||||
assert result.exit_code != 0
|
||||
assert "Error: no such option: --no-accept" in result.output
|
||||
|
||||
|
||||
def test_script():
|
||||
result = subprocess.run(
|
||||
["coverage", "run", mod.__file__, "--help"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
encoding="utf-8",
|
||||
)
|
||||
assert "Usage" in result.stdout
|
|
@ -0,0 +1,39 @@
|
|||
import subprocess
|
||||
|
||||
import typer
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from parameter_types.bool import tutorial003 as mod
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
app = typer.Typer()
|
||||
app.command()(mod.main)
|
||||
|
||||
|
||||
def test_help():
|
||||
result = runner.invoke(app, ["--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "-f, --force / -F, --no-force" in result.output
|
||||
|
||||
|
||||
def test_force():
|
||||
result = runner.invoke(app, ["-f"])
|
||||
assert result.exit_code == 0
|
||||
assert "Forcing operation" in result.output
|
||||
|
||||
|
||||
def test_no_force():
|
||||
result = runner.invoke(app, ["-F"])
|
||||
assert result.exit_code == 0
|
||||
assert "Not forcing" in result.output
|
||||
|
||||
|
||||
def test_script():
|
||||
result = subprocess.run(
|
||||
["coverage", "run", mod.__file__, "--help"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
encoding="utf-8",
|
||||
)
|
||||
assert "Usage" in result.stdout
|
|
@ -0,0 +1,45 @@
|
|||
import subprocess
|
||||
|
||||
import typer
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from parameter_types.bool import tutorial004 as mod
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
app = typer.Typer()
|
||||
app.command()(mod.main)
|
||||
|
||||
|
||||
def test_help():
|
||||
result = runner.invoke(app, ["--help"])
|
||||
assert result.exit_code == 0
|
||||
assert "/ -d, --demo" in result.output
|
||||
|
||||
|
||||
def test_main():
|
||||
result = runner.invoke(app)
|
||||
assert result.exit_code == 0
|
||||
assert "Running in production" in result.output
|
||||
|
||||
|
||||
def test_demo():
|
||||
result = runner.invoke(app, ["--demo"])
|
||||
assert result.exit_code == 0
|
||||
assert "Running demo" in result.output
|
||||
|
||||
|
||||
def test_short_demo():
|
||||
result = runner.invoke(app, ["-d"])
|
||||
assert result.exit_code == 0
|
||||
assert "Running demo" in result.output
|
||||
|
||||
|
||||
def test_script():
|
||||
result = subprocess.run(
|
||||
["coverage", "run", mod.__file__, "--help"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
encoding="utf-8",
|
||||
)
|
||||
assert "Usage" in result.stdout
|
|
@ -0,0 +1,57 @@
|
|||
import subprocess
|
||||
|
||||
import typer
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from parameter_types.number import tutorial003 as mod
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
app = typer.Typer()
|
||||
app.command()(mod.main)
|
||||
|
||||
|
||||
def test_main():
|
||||
result = runner.invoke(app)
|
||||
assert result.exit_code == 0
|
||||
assert "Verbose level is 0" in result.output
|
||||
|
||||
|
||||
def test_verbose_1():
|
||||
result = runner.invoke(app, ["--verbose"])
|
||||
assert result.exit_code == 0
|
||||
assert "Verbose level is 1" in result.output
|
||||
|
||||
|
||||
def test_verbose_3():
|
||||
result = runner.invoke(app, ["--verbose", "--verbose", "--verbose"])
|
||||
assert result.exit_code == 0
|
||||
assert "Verbose level is 3" in result.output
|
||||
|
||||
|
||||
def test_verbose_short_1():
|
||||
result = runner.invoke(app, ["-v"])
|
||||
assert result.exit_code == 0
|
||||
assert "Verbose level is 1" in result.output
|
||||
|
||||
|
||||
def test_verbose_short_3():
|
||||
result = runner.invoke(app, ["-v", "-v", "-v"])
|
||||
assert result.exit_code == 0
|
||||
assert "Verbose level is 3" in result.output
|
||||
|
||||
|
||||
def test_verbose_short_3_condensed():
|
||||
result = runner.invoke(app, ["-vvv"])
|
||||
assert result.exit_code == 0
|
||||
assert "Verbose level is 3" in result.output
|
||||
|
||||
|
||||
def test_script():
|
||||
result = subprocess.run(
|
||||
["coverage", "run", mod.__file__, "--help"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
encoding="utf-8",
|
||||
)
|
||||
assert "Usage" in result.stdout
|
Loading…
Reference in a new issue