📝 Add extra docs and tests for param types

This commit is contained in:
Sebastián Ramírez 2020-01-05 22:07:49 +01:00 committed by GitHub
commit ff37cb874f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 536 additions and 0 deletions

View 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)

View 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)

View 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)

View 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)

View 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)

View 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>

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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