Coverage for tests/test_ambiguous_params.py: 100%
71 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-09 18:26 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-09 18:26 +0000
1import pytest 1habcdefg
2import typer 1habcdefg
3from typer.testing import CliRunner 1habcdefg
4from typer.utils import ( 1habcdefg
5 AnnotatedParamWithDefaultValueError,
6 DefaultFactoryAndDefaultValueError,
7 MixedAnnotatedAndDefaultStyleError,
8 MultipleTyperAnnotationsError,
9 _split_annotation_from_typer_annotations,
10)
11from typing_extensions import Annotated 1habcdefg
13runner = CliRunner() 1habcdefg
16def test_split_annotations_from_typer_annotations_simple(): 1habcdefg
17 # Simple sanity check that this utility works. If this isn't working on a given
18 # python version, then no other tests for Annotated will work.
19 given = Annotated[str, typer.Argument()] 1habcdefg
20 base, typer_annotations = _split_annotation_from_typer_annotations(given) 1habcdefg
21 assert base is str 1habcdefg
22 # No equality check on the param types. Checking the length is sufficient.
23 assert len(typer_annotations) == 1 1habcdefg
26def test_forbid_default_value_in_annotated_argument(): 1habcdefg
27 app = typer.Typer() 1habcdefg
29 # This test case only works with `typer.Argument`. `typer.Option` uses positionals
30 # for param_decls too.
31 @app.command() 1habcdefg
32 def cmd(my_param: Annotated[str, typer.Argument("foo")]): ... # pragma: no cover 1habcdefg
34 with pytest.raises(AnnotatedParamWithDefaultValueError) as excinfo: 1habcdefg
35 runner.invoke(app) 1habcdefg
37 assert vars(excinfo.value) == { 1habcdefg
38 "param_type": typer.models.ArgumentInfo,
39 "argument_name": "my_param",
40 }
43def test_allow_options_to_have_names(): 1habcdefg
44 app = typer.Typer() 1habcdefg
46 @app.command() 1habcdefg
47 def cmd(my_param: Annotated[str, typer.Option("--some-opt")]): 1habcdefg
48 print(my_param) 1habcdefg
50 result = runner.invoke(app, ["--some-opt", "hello"]) 1habcdefg
51 assert result.exit_code == 0, result.output 1habcdefg
52 assert "hello" in result.output 1habcdefg
55@pytest.mark.parametrize( 1habcdefg
56 ["param", "param_info_type"],
57 [
58 (typer.Argument, typer.models.ArgumentInfo),
59 (typer.Option, typer.models.OptionInfo),
60 ],
61)
62def test_forbid_annotated_param_and_default_param(param, param_info_type): 1abcdefg
63 app = typer.Typer() 1habcdefg
65 @app.command() 1habcdefg
66 def cmd(my_param: Annotated[str, param()] = param("foo")): ... # pragma: no cover 1habcdefg
68 with pytest.raises(MixedAnnotatedAndDefaultStyleError) as excinfo: 1habcdefg
69 runner.invoke(app) 1habcdefg
71 assert vars(excinfo.value) == { 1habcdefg
72 "argument_name": "my_param",
73 "annotated_param_type": param_info_type,
74 "default_param_type": param_info_type,
75 }
78def test_forbid_multiple_typer_params_in_annotated(): 1habcdefg
79 app = typer.Typer() 1habcdefg
81 @app.command() 1habcdefg
82 def cmd( 1abcdefg
83 my_param: Annotated[str, typer.Argument(), typer.Argument()], 1habcdefg
84 ): ... # pragma: no cover
86 with pytest.raises(MultipleTyperAnnotationsError) as excinfo: 1habcdefg
87 runner.invoke(app) 1habcdefg
89 assert vars(excinfo.value) == {"argument_name": "my_param"} 1habcdefg
92def test_allow_multiple_non_typer_params_in_annotated(): 1habcdefg
93 app = typer.Typer() 1habcdefg
95 @app.command() 1habcdefg
96 def cmd(my_param: Annotated[str, "someval", typer.Argument(), 4] = "hello"): 1habcdefg
97 print(my_param) 1habcdefg
99 result = runner.invoke(app) 1habcdefg
100 # Should behave like normal
101 assert result.exit_code == 0, result.output 1habcdefg
102 assert "hello" in result.output 1habcdefg
105@pytest.mark.parametrize( 1habcdefg
106 ["param", "param_info_type"],
107 [
108 (typer.Argument, typer.models.ArgumentInfo),
109 (typer.Option, typer.models.OptionInfo),
110 ],
111)
112def test_forbid_default_factory_and_default_value_in_annotated(param, param_info_type): 1abcdefg
113 def make_string(): 1habcdefg
114 return "foo" # pragma: no cover
116 app = typer.Typer() 1habcdefg
118 @app.command() 1habcdefg
119 def cmd( 1abcdefg
120 my_param: Annotated[str, param(default_factory=make_string)] = "hello", 1habcdefg
121 ): ... # pragma: no cover
123 with pytest.raises(DefaultFactoryAndDefaultValueError) as excinfo: 1habcdefg
124 runner.invoke(app) 1habcdefg
126 assert vars(excinfo.value) == { 1habcdefg
127 "argument_name": "my_param",
128 "param_type": param_info_type,
129 }
132@pytest.mark.parametrize( 1habcdefg
133 "param",
134 [
135 typer.Argument,
136 typer.Option,
137 ],
138)
139def test_allow_default_factory_with_default_param(param): 1abcdefg
140 def make_string(): 1habcdefg
141 return "foo" 1habcdefg
143 app = typer.Typer() 1habcdefg
145 @app.command() 1habcdefg
146 def cmd(my_param: str = param(default_factory=make_string)): 1habcdefg
147 print(my_param) 1habcdefg
149 result = runner.invoke(app) 1habcdefg
150 assert result.exit_code == 0, result.output 1habcdefg
151 assert "foo" in result.output 1habcdefg
154@pytest.mark.parametrize( 1habcdefg
155 ["param", "param_info_type"],
156 [
157 (typer.Argument, typer.models.ArgumentInfo),
158 (typer.Option, typer.models.OptionInfo),
159 ],
160)
161def test_forbid_default_and_default_factory_with_default_param(param, param_info_type): 1abcdefg
162 def make_string(): 1habcdefg
163 return "foo" # pragma: no cover
165 app = typer.Typer() 1habcdefg
167 @app.command() 1habcdefg
168 def cmd( 1abcdefg
169 my_param: str = param("hi", default_factory=make_string), 1habcdefg
170 ): ... # pragma: no cover
172 with pytest.raises(DefaultFactoryAndDefaultValueError) as excinfo: 1habcdefg
173 runner.invoke(app) 1habcdefg
175 assert vars(excinfo.value) == { 1habcdefg
176 "argument_name": "my_param",
177 "param_type": param_info_type,
178 }
181@pytest.mark.parametrize( 1habcdefg
182 ["error", "message"],
183 [
184 (
185 AnnotatedParamWithDefaultValueError(
186 argument_name="my_argument",
187 param_type=typer.models.ArgumentInfo,
188 ),
189 "`Argument` default value cannot be set in `Annotated` for 'my_argument'. Set the default value with `=` instead.",
190 ),
191 (
192 MixedAnnotatedAndDefaultStyleError(
193 argument_name="my_argument",
194 annotated_param_type=typer.models.OptionInfo,
195 default_param_type=typer.models.ArgumentInfo,
196 ),
197 "Cannot specify `Option` in `Annotated` and `Argument` as a default value together for 'my_argument'",
198 ),
199 (
200 MixedAnnotatedAndDefaultStyleError(
201 argument_name="my_argument",
202 annotated_param_type=typer.models.OptionInfo,
203 default_param_type=typer.models.OptionInfo,
204 ),
205 "Cannot specify `Option` in `Annotated` and default value together for 'my_argument'",
206 ),
207 (
208 MixedAnnotatedAndDefaultStyleError(
209 argument_name="my_argument",
210 annotated_param_type=typer.models.ArgumentInfo,
211 default_param_type=typer.models.ArgumentInfo,
212 ),
213 "Cannot specify `Argument` in `Annotated` and default value together for 'my_argument'",
214 ),
215 (
216 MultipleTyperAnnotationsError(
217 argument_name="my_argument",
218 ),
219 "Cannot specify multiple `Annotated` Typer arguments for 'my_argument'",
220 ),
221 (
222 DefaultFactoryAndDefaultValueError(
223 argument_name="my_argument",
224 param_type=typer.models.OptionInfo,
225 ),
226 "Cannot specify `default_factory` and a default value together for `Option`",
227 ),
228 ],
229)
230def test_error_rendering(error, message): 1abcdefg
231 assert str(error) == message 1habcdefg