Coverage for tests/test_ambiguous_params.py: 100%
81 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-06-24 00:17 +0000
« prev ^ index » next coverage.py v7.5.4, created at 2024-06-24 00:17 +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")]): 1habcdefg
33 ... # pragma: no cover
35 with pytest.raises(AnnotatedParamWithDefaultValueError) as excinfo: 1habcdefg
36 runner.invoke(app) 1habcdefg
38 assert vars(excinfo.value) == { 1habcdefg
39 "param_type": typer.models.ArgumentInfo,
40 "argument_name": "my_param",
41 }
44def test_allow_options_to_have_names(): 1habcdefg
45 app = typer.Typer() 1habcdefg
47 @app.command() 1habcdefg
48 def cmd(my_param: Annotated[str, typer.Option("--some-opt")]): 1habcdefg
49 print(my_param) 1habcdefg
51 result = runner.invoke(app, ["--some-opt", "hello"]) 1habcdefg
52 assert result.exit_code == 0, result.output 1habcdefg
53 assert "hello" in result.output 1habcdefg
56@pytest.mark.parametrize( 1habcdefg
57 ["param", "param_info_type"],
58 [
59 (typer.Argument, typer.models.ArgumentInfo),
60 (typer.Option, typer.models.OptionInfo),
61 ],
62)
63def test_forbid_annotated_param_and_default_param(param, param_info_type): 1abcdefg
64 app = typer.Typer() 1habcdefg
66 @app.command() 1habcdefg
67 def cmd(my_param: Annotated[str, param()] = param("foo")): 1habcdefg
68 ... # pragma: no cover
70 with pytest.raises(MixedAnnotatedAndDefaultStyleError) as excinfo: 1habcdefg
71 runner.invoke(app) 1habcdefg
73 assert vars(excinfo.value) == { 1habcdefg
74 "argument_name": "my_param",
75 "annotated_param_type": param_info_type,
76 "default_param_type": param_info_type,
77 }
80def test_forbid_multiple_typer_params_in_annotated(): 1habcdefg
81 app = typer.Typer() 1habcdefg
83 @app.command() 1habcdefg
84 def cmd( 1abcdefg
85 my_param: Annotated[str, typer.Argument(), typer.Argument()],
86 ):
87 ... # pragma: no cover
89 with pytest.raises(MultipleTyperAnnotationsError) as excinfo: 1habcdefg
90 runner.invoke(app) 1habcdefg
92 assert vars(excinfo.value) == {"argument_name": "my_param"} 1habcdefg
95def test_allow_multiple_non_typer_params_in_annotated(): 1habcdefg
96 app = typer.Typer() 1habcdefg
98 @app.command() 1habcdefg
99 def cmd(my_param: Annotated[str, "someval", typer.Argument(), 4] = "hello"): 1habcdefg
100 print(my_param) 1habcdefg
102 result = runner.invoke(app) 1habcdefg
103 # Should behave like normal
104 assert result.exit_code == 0, result.output 1habcdefg
105 assert "hello" in result.output 1habcdefg
108@pytest.mark.parametrize( 1habcdefg
109 ["param", "param_info_type"],
110 [
111 (typer.Argument, typer.models.ArgumentInfo),
112 (typer.Option, typer.models.OptionInfo),
113 ],
114)
115def test_forbid_default_factory_and_default_value_in_annotated(param, param_info_type): 1abcdefg
116 def make_string(): 1habcdefg
117 return "foo" # pragma: no cover
119 app = typer.Typer() 1habcdefg
121 @app.command() 1habcdefg
122 def cmd( 1abcdefg
123 my_param: Annotated[str, param(default_factory=make_string)] = "hello",
124 ):
125 ... # pragma: no cover
127 with pytest.raises(DefaultFactoryAndDefaultValueError) as excinfo: 1habcdefg
128 runner.invoke(app) 1habcdefg
130 assert vars(excinfo.value) == { 1habcdefg
131 "argument_name": "my_param",
132 "param_type": param_info_type,
133 }
136@pytest.mark.parametrize( 1habcdefg
137 "param",
138 [
139 typer.Argument,
140 typer.Option,
141 ],
142)
143def test_allow_default_factory_with_default_param(param): 1abcdefg
144 def make_string(): 1habcdefg
145 return "foo" 1habcdefg
147 app = typer.Typer() 1habcdefg
149 @app.command() 1habcdefg
150 def cmd(my_param: str = param(default_factory=make_string)): 1habcdefg
151 print(my_param) 1habcdefg
153 result = runner.invoke(app) 1habcdefg
154 assert result.exit_code == 0, result.output 1habcdefg
155 assert "foo" in result.output 1habcdefg
158@pytest.mark.parametrize( 1habcdefg
159 ["param", "param_info_type"],
160 [
161 (typer.Argument, typer.models.ArgumentInfo),
162 (typer.Option, typer.models.OptionInfo),
163 ],
164)
165def test_forbid_default_and_default_factory_with_default_param(param, param_info_type): 1abcdefg
166 def make_string(): 1habcdefg
167 return "foo" # pragma: no cover
169 app = typer.Typer() 1habcdefg
171 @app.command() 1habcdefg
172 def cmd( 1abcdefg
173 my_param: str = param("hi", default_factory=make_string),
174 ):
175 ... # pragma: no cover
177 with pytest.raises(DefaultFactoryAndDefaultValueError) as excinfo: 1habcdefg
178 runner.invoke(app) 1habcdefg
180 assert vars(excinfo.value) == { 1habcdefg
181 "argument_name": "my_param",
182 "param_type": param_info_type,
183 }
186@pytest.mark.parametrize( 1habcdefg
187 ["error", "message"],
188 [
189 (
190 AnnotatedParamWithDefaultValueError(
191 argument_name="my_argument",
192 param_type=typer.models.ArgumentInfo,
193 ),
194 "`Argument` default value cannot be set in `Annotated` for 'my_argument'. Set the default value with `=` instead.",
195 ),
196 (
197 MixedAnnotatedAndDefaultStyleError(
198 argument_name="my_argument",
199 annotated_param_type=typer.models.OptionInfo,
200 default_param_type=typer.models.ArgumentInfo,
201 ),
202 "Cannot specify `Option` in `Annotated` and `Argument` as a default value together for 'my_argument'",
203 ),
204 (
205 MixedAnnotatedAndDefaultStyleError(
206 argument_name="my_argument",
207 annotated_param_type=typer.models.OptionInfo,
208 default_param_type=typer.models.OptionInfo,
209 ),
210 "Cannot specify `Option` in `Annotated` and default value together for 'my_argument'",
211 ),
212 (
213 MixedAnnotatedAndDefaultStyleError(
214 argument_name="my_argument",
215 annotated_param_type=typer.models.ArgumentInfo,
216 default_param_type=typer.models.ArgumentInfo,
217 ),
218 "Cannot specify `Argument` in `Annotated` and default value together for 'my_argument'",
219 ),
220 (
221 MultipleTyperAnnotationsError(
222 argument_name="my_argument",
223 ),
224 "Cannot specify multiple `Annotated` Typer arguments for 'my_argument'",
225 ),
226 (
227 DefaultFactoryAndDefaultValueError(
228 argument_name="my_argument",
229 param_type=typer.models.OptionInfo,
230 ),
231 "Cannot specify `default_factory` and a default value together for `Option`",
232 ),
233 ],
234)
235def test_error_rendering(error, message): 1abcdefg
236 assert str(error) == message 1habcdefg