Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ca532f6
Add tests for `docs_src/app_dir/tutorial001_py39.py`
YuriiMotov Dec 25, 2025
63fb62b
Add tests for `docs_src/arguments/optional/tutorial000_py39.py`
YuriiMotov Dec 25, 2025
bc5c388
Add tests for `docs_src/launch/tutorial001_py39.py`
YuriiMotov Dec 25, 2025
099e706
Add tests for `docs_src/launch/tutorial002_py39.py`
YuriiMotov Dec 25, 2025
05d4dc1
Add tests for `docs_src/options/callback/tutorial002_*.py`
YuriiMotov Dec 25, 2025
7f66abf
Add tests for `docs_src/options/help/tutorial004_*.py`
YuriiMotov Dec 25, 2025
c805695
Add `strip_double_spaces` function to `utils`
YuriiMotov Dec 25, 2025
7b2a61a
Add tests for `docs_src/options/password/tutorial001_*.py`
YuriiMotov Dec 25, 2025
b2dba5d
Add tests for `docs_src/options/password/tutorial002_*.py`
YuriiMotov Dec 25, 2025
1f65c4e
Add tests for `docs_src/options/version/tutorial001_*.py`
YuriiMotov Dec 25, 2025
b322b10
Add tests for `docs_src/options/version/tutorial002_*.py`
YuriiMotov Dec 25, 2025
11aa2f5
Add tests for `docs_src/options_autocompletion/tutorial001_*.py`
YuriiMotov Dec 25, 2025
53df1a9
Add tests for `docs_src/options_autocompletion/tutorial005_*.py`
YuriiMotov Dec 25, 2025
c3983eb
Add tests for `docs_src/options_autocompletion/tutorial006_*.py`
YuriiMotov Dec 25, 2025
6a0091c
Add `normalize_rich_output` function to `utils
YuriiMotov Dec 25, 2025
e0f7f9a
Add tests for `docs_src/printing/tutorial001_py39.py`
YuriiMotov Dec 25, 2025
4d4788d
Add tests for `docs_src/printing/tutorial002_py39.py`
YuriiMotov Dec 25, 2025
f0bd9da
Add tests for `docs_src/printing/tutorial003_py39.py`
YuriiMotov Dec 25, 2025
9b5c428
Add tests for `docs_src/printing/tutorial004_py39.py`
YuriiMotov Dec 26, 2025
1e0278e
Add tests for `docs_src/printing/tutorial005_py39.py`
YuriiMotov Dec 26, 2025
a0f97bf
Add tests for `docs_src/printing/tutorial006_py39.py`
YuriiMotov Dec 26, 2025
eb15c2e
Add tests for `docs_src/progressbar/tutorial001_py39.py`
YuriiMotov Dec 26, 2025
d66a631
Add tests for `docs_src/progressbar/tutorial002_py39.py`
YuriiMotov Dec 26, 2025
c850ddb
Add tests for `docs_src/progressbar/tutorial003_py39.py`
YuriiMotov Dec 26, 2025
65554ba
Add tests for `docs_src/progressbar/tutorial004_py39.py`
YuriiMotov Dec 26, 2025
f32c543
Add tests for `docs_src/progressbar/tutorial005_py39.py`
YuriiMotov Dec 26, 2025
aa8ca0a
Add tests for `docs_src/progressbar/tutorial006_py39.py`
YuriiMotov Dec 26, 2025
e1192d8
Add tests for `docs_src/prompt/tutorial004_py39.py`
YuriiMotov Dec 26, 2025
1a94ffd
Add tests for `docs_src/using_click/tutorial002_py39.py`
YuriiMotov Dec 26, 2025
8add382
Add tests for `docs_src/using_click/tutorial001_py39.py`
YuriiMotov Dec 26, 2025
3188c54
Merge branch 'master' into add-missing-tests-for-code-examples
YuriiMotov Dec 29, 2025
393f99f
📝 Update docs examples
tiangolo Dec 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/tutorial/arguments/optional.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ 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_py39.py hl[4] *}
{* docs_src/arguments/optional/tutorial000_an_py39.py hl[6] *}

Or, using an explicit `Typer()` instance creation:

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorial/options/version.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Awesome CLI Version: 0.1.0

But now let's say that the `--name` *CLI option* that we declared before `--version` is required, and it has a callback that could exit the program:

{* docs_src/options/version/tutorial002_an_py310.py hl[16:18,24:26] *}
{* docs_src/options/version/tutorial002_an_py310.py hl[16:19,25:27] *}

Then our CLI program could not work as expected in some cases as it is *right now*, because if we use `--version` after `--name` then the callback for `--name` will be processed before and we can get its error:

Expand Down
11 changes: 11 additions & 0 deletions docs_src/arguments/optional/tutorial000_an_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from typing import Annotated

import typer


def main(name: Annotated[str, typer.Argument()]):
print(f"Hello {name}")


if __name__ == "__main__":
typer.run(main)
1 change: 1 addition & 0 deletions docs_src/options/version/tutorial002_an_py310.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def version_callback(value: bool):
def name_callback(name: str):
if name != "Camila":
raise typer.BadParameter("Only Camila is allowed")
return name


@app.command()
Expand Down
1 change: 1 addition & 0 deletions docs_src/options/version/tutorial002_an_py39.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def version_callback(value: bool):
def name_callback(name: str):
if name != "Camila":
raise typer.BadParameter("Only Camila is allowed")
return name


@app.command()
Expand Down
1 change: 1 addition & 0 deletions docs_src/options/version/tutorial002_py310.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def version_callback(value: bool):
def name_callback(name: str):
if name != "Camila":
raise typer.BadParameter("Only Camila is allowed")
return name


@app.command()
Expand Down
1 change: 1 addition & 0 deletions docs_src/options/version/tutorial002_py39.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def version_callback(value: bool):
def name_callback(name: str):
if name != "Camila":
raise typer.BadParameter("Only Camila is allowed")
return name


@app.command()
Expand Down
28 changes: 0 additions & 28 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,34 +130,6 @@ source = [
]
omit = [
"typer/_typing.py",
"docs_src/app_dir/tutorial001_py39.py", # ToDo: add test
"docs_src/arguments/optional/tutorial000_py39.py", # ToDo: add test
"docs_src/launch/tutorial001_py39.py", # ToDo: add test
"docs_src/launch/tutorial002_py39.py", # ToDo: add test
"docs_src/options/callback/tutorial002_*.py", # ToDo: add test
"docs_src/options/help/tutorial004_*.py", # ToDo: add test
"docs_src/options/password/tutorial001_*.py", # ToDo: add test
"docs_src/options/password/tutorial002_*.py", # ToDo: add test
"docs_src/options/version/tutorial001_*.py", # ToDo: add test
"docs_src/options/version/tutorial002_*.py", # ToDo: add test
"docs_src/options_autocompletion/tutorial001_*.py", # ToDo: add test
"docs_src/options_autocompletion/tutorial005_*.py", # ToDo: add test
"docs_src/options_autocompletion/tutorial006_*.py", # ToDo: add test
"docs_src/printing/tutorial001_py39.py", # ToDo: add test
"docs_src/printing/tutorial002_py39.py", # ToDo: add test
"docs_src/printing/tutorial003_py39.py", # ToDo: add test
"docs_src/printing/tutorial004_py39.py", # ToDo: add test
"docs_src/printing/tutorial005_py39.py", # ToDo: add test
"docs_src/printing/tutorial006_py39.py", # ToDo: add test
"docs_src/progressbar/tutorial001_py39.py", # ToDo: add test
"docs_src/progressbar/tutorial002_py39.py", # ToDo: add test
"docs_src/progressbar/tutorial003_py39.py", # ToDo: add test
"docs_src/progressbar/tutorial004_py39.py", # ToDo: add test
"docs_src/progressbar/tutorial005_py39.py", # ToDo: add test
"docs_src/progressbar/tutorial006_py39.py", # ToDo: add test
"docs_src/prompt/tutorial004_py39.py", # ToDo: add test
"docs_src/using_click/tutorial001_py39.py", # ToDo: add test
"docs_src/using_click/tutorial002_py39.py", # ToDo: add test
]
context = '${CONTEXT}'
relative_files = true
Expand Down
Empty file.
45 changes: 45 additions & 0 deletions tests/test_tutorial/test_app_dir/test_tutorial001.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import subprocess
import sys
from pathlib import Path

import pytest
import typer
from typer.testing import CliRunner

from docs_src.app_dir import tutorial001_py39 as mod

runner = CliRunner()


@pytest.fixture(name="config_file")
def create_config_file():
app_dir = Path(typer.get_app_dir("my-super-cli-app"))
app_dir.mkdir(parents=True, exist_ok=True)
config_path = app_dir / "config.json"
config_path.touch(exist_ok=True)

yield config_path

config_path.unlink()
app_dir.rmdir()


def test_cli_config_doesnt_exist():
result = runner.invoke(mod.app)
assert result.exit_code == 0
assert "Config file doesn't exist yet" in result.output


def test_cli_config_exists(config_file: Path):
result = runner.invoke(mod.app)
assert result.exit_code == 0
assert "Config file doesn't exist yet" not in result.output


def test_script():
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
capture_output=True,
encoding="utf-8",
)
assert "Usage" in result.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import importlib
import subprocess
import sys
from types import ModuleType

import pytest
import typer
from typer.testing import CliRunner

runner = CliRunner()


@pytest.fixture(
name="mod",
params=[
pytest.param("tutorial000_py39"),
pytest.param("tutorial000_an_py39"),
],
)
def get_mod(request: pytest.FixtureRequest) -> ModuleType:
module_name = f"docs_src.arguments.optional.{request.param}"
mod = importlib.import_module(module_name)
return mod


@pytest.fixture(name="app")
def get_app(mod: ModuleType) -> typer.Typer:
app = typer.Typer()
app.command()(mod.main)
return app


def test_cli(app: typer.Typer):
result = runner.invoke(app, ["World"])
assert result.exit_code == 0
assert "Hello World" in result.output


def test_cli_missing_argument(app: typer.Typer):
result = runner.invoke(app)
assert result.exit_code == 2
assert "Missing argument 'NAME'" in result.output


def test_script(mod: ModuleType):
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
capture_output=True,
encoding="utf-8",
)
assert "Usage" in result.stdout
27 changes: 27 additions & 0 deletions tests/test_tutorial/test_launch/test_tutorial001.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import subprocess
import sys
from unittest.mock import patch

from typer.testing import CliRunner

from docs_src.launch import tutorial001_py39 as mod

runner = CliRunner()


def test_cli():
with patch("typer.launch") as launch_mock:
result = runner.invoke(mod.app)

assert result.exit_code == 0
assert result.output.strip() == "Opening Typer's docs"
launch_mock.assert_called_once_with("https://typer.tiangolo.com")


def test_script():
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
capture_output=True,
encoding="utf-8",
)
assert "Usage" in result.stdout
47 changes: 47 additions & 0 deletions tests/test_tutorial/test_launch/test_tutorial002.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import subprocess
import sys
from pathlib import Path
from unittest.mock import patch

import pytest
import typer
from typer.testing import CliRunner

from docs_src.launch import tutorial002_py39 as mod

runner = CliRunner()


@pytest.fixture(name="app_dir")
def app_dir():
app_dir = Path(typer.get_app_dir("my-super-cli-app"))
if app_dir.exists(): # pragma: no cover
for item in app_dir.iterdir():
if item.is_file():
item.unlink()

yield app_dir

if app_dir.exists():
for item in app_dir.iterdir():
if item.is_file():
item.unlink()
app_dir.rmdir()


def test_cli(app_dir: Path):
with patch("typer.launch") as launch_mock:
result = runner.invoke(mod.app)

assert result.exit_code == 0
assert "Opening config directory" in result.output
launch_mock.assert_called_with(str(app_dir / "config.json"), locate=True)


def test_script():
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
capture_output=True,
encoding="utf-8",
)
assert "Usage" in result.stdout
50 changes: 50 additions & 0 deletions tests/test_tutorial/test_options/test_callback/test_tutorial002.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import importlib
import subprocess
import sys
from types import ModuleType

import pytest
from typer.testing import CliRunner

from ....utils import needs_py310

runner = CliRunner()


@pytest.fixture(
name="mod",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
def get_mod(request: pytest.FixtureRequest) -> ModuleType:
module_name = f"docs_src.options.callback.{request.param}"
mod = importlib.import_module(module_name)
return mod


def test_1(mod: ModuleType):
result = runner.invoke(mod.app, ["--name", "Camila"])
assert result.exit_code == 0
assert "Validating name" in result.output
assert "Hello Camila" in result.output


def test_2(mod: ModuleType):
result = runner.invoke(mod.app, ["--name", "rick"])
assert result.exit_code != 0
assert "Validating name" in result.output
assert "Invalid value for '--name'" in result.output
assert "Only Camila is allowed" in result.output


def test_script(mod: ModuleType):
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
capture_output=True,
encoding="utf-8",
)
assert "Usage" in result.stdout
45 changes: 45 additions & 0 deletions tests/test_tutorial/test_options/test_help/test_tutorial004.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import importlib
import subprocess
import sys
from types import ModuleType

import pytest
from typer.testing import CliRunner

runner = CliRunner()


@pytest.fixture(
name="mod",
params=[
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_an_py39"),
],
)
def get_mod(request: pytest.FixtureRequest) -> ModuleType:
module_name = f"docs_src.options.help.{request.param}"
mod = importlib.import_module(module_name)
return mod


def test_call(mod: ModuleType):
result = runner.invoke(mod.app)
assert result.exit_code == 0
assert "Hello Wade Wilson" in result.output


def test_help(mod: ModuleType):
result = runner.invoke(mod.app, ["--help"])
assert result.exit_code == 0
assert "--fullname" in result.output
assert "TEXT" in result.output
assert "[default: (Deadpoolio the amazing's name)]" in result.output


def test_script(mod: ModuleType):
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
capture_output=True,
encoding="utf-8",
)
assert "Usage" in result.stdout
Empty file.
Loading