Coverage for tests / test_annotated.py: 100%
64 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-26 21:46 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-26 21:46 +0000
1import sys 1acdefbg
2from pathlib import Path 1acdefbg
3from typing import Annotated 1acdefbg
5import typer 1acdefbg
6from typer.testing import CliRunner 1acdefbg
8runner = CliRunner() 1acdefbg
11def test_annotated_argument_with_default(): 1acdefbg
12 app = typer.Typer() 1acdefbg
14 @app.command() 1acdefbg
15 def cmd(val: Annotated[int, typer.Argument()] = 0): 1acdefbg
16 print(f"hello {val}") 1acdefbg
18 result = runner.invoke(app) 1acdefbg
19 assert result.exit_code == 0, result.output 1acdefbg
20 assert "hello 0" in result.output 1acdefbg
22 result = runner.invoke(app, ["42"]) 1acdefbg
23 assert result.exit_code == 0, result.output 1acdefbg
24 assert "hello 42" in result.output 1acdefbg
27def test_annotated_argument_in_string_type_with_default(): 1acdefbg
28 app = typer.Typer() 1acdefbg
30 @app.command() 1acdefbg
31 def cmd(val: "Annotated[int, typer.Argument()]" = 0): 1acdefbg
32 print(f"hello {val}") 1acdefbg
34 result = runner.invoke(app) 1acdefbg
35 assert result.exit_code == 0, result.output 1acdefbg
36 assert "hello 0" in result.output 1acdefbg
38 result = runner.invoke(app, ["42"]) 1acdefbg
39 assert result.exit_code == 0, result.output 1acdefbg
40 assert "hello 42" in result.output 1acdefbg
43def test_annotated_argument_with_default_factory(): 1acdefbg
44 app = typer.Typer() 1acdefbg
46 def make_string(): 1acdefbg
47 return "I made it" 1acdefbg
49 @app.command() 1acdefbg
50 def cmd(val: Annotated[str, typer.Argument(default_factory=make_string)]): 1acdefbg
51 print(val) 1acdefbg
53 result = runner.invoke(app) 1acdefbg
54 assert result.exit_code == 0, result.output 1acdefbg
55 assert "I made it" in result.output 1acdefbg
57 result = runner.invoke(app, ["overridden"]) 1acdefbg
58 assert result.exit_code == 0, result.output 1acdefbg
59 assert "overridden" in result.output 1acdefbg
62def test_annotated_option_with_argname_doesnt_mutate_multiple_calls(): 1acdefbg
63 app = typer.Typer() 1acdefbg
65 @app.command() 1acdefbg
66 def cmd(force: Annotated[bool, typer.Option("--force")] = False): 1acdefbg
67 if force: 1acdefbg
68 print("Forcing operation") 1acdefbg
69 else:
70 print("Not forcing") 1acdefbg
72 result = runner.invoke(app) 1acdefbg
73 assert result.exit_code == 0, result.output 1acdefbg
74 assert "Not forcing" in result.output 1acdefbg
76 result = runner.invoke(app, ["--force"]) 1acdefbg
77 assert result.exit_code == 0, result.output 1acdefbg
78 assert "Forcing operation" in result.output 1acdefbg
81def test_annotated_custom_path(): 1acdefbg
82 app = typer.Typer() 1acdefbg
84 class CustomPath(Path): 1acdefbg
85 # Subclassing Path was not fully supported before 3.12
86 # https://docs.python.org/3.12/whatsnew/3.12.html
87 if sys.version_info < (3, 12): 1acdefbg
88 _flavour = type(Path())._flavour 1ab
90 @app.command() 1acdefbg
91 def custom_parser( 1acdefbg
92 my_path: Annotated[CustomPath, typer.Argument(parser=CustomPath)],
93 ):
94 assert isinstance(my_path, CustomPath) 1acdefbg
96 result = runner.invoke(app, "/some/quirky/path/implementation") 1acdefbg
97 assert result.exit_code == 0 1acdefbg