Coverage for tests/test_others.py: 100%
147 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 os 1habcdefg
2import subprocess 1habcdefg
3import sys 1habcdefg
4import typing 1habcdefg
5from pathlib import Path 1habcdefg
6from unittest import mock 1habcdefg
8import click 1habcdefg
9import pytest 1habcdefg
10import shellingham 1habcdefg
11import typer 1habcdefg
12import typer.completion 1habcdefg
13from typer.core import _split_opt 1habcdefg
14from typer.main import solve_typer_info_defaults, solve_typer_info_help 1habcdefg
15from typer.models import ParameterInfo, TyperInfo 1habcdefg
16from typer.testing import CliRunner 1habcdefg
18runner = CliRunner() 1habcdefg
21def test_help_from_info(): 1habcdefg
22 # Mainly for coverage/completeness
23 value = solve_typer_info_help(TyperInfo()) 1habcdefg
24 assert value is None 1habcdefg
27def test_defaults_from_info(): 1habcdefg
28 # Mainly for coverage/completeness
29 value = solve_typer_info_defaults(TyperInfo()) 1habcdefg
30 assert value 1habcdefg
33def test_too_many_parsers(): 1habcdefg
34 def custom_parser(value: str) -> int: 1habcdefg
35 return int(value) # pragma: no cover
37 class CustomClickParser(click.ParamType): 1habcdefg
38 name = "custom_parser" 1habcdefg
40 def convert( 1abcdefg
41 self,
42 value: str,
43 param: typing.Optional[click.Parameter],
44 ctx: typing.Optional[click.Context],
45 ) -> typing.Any:
46 return int(value) # pragma: no cover
48 expected_error = ( 1abcdefg
49 "Multiple custom type parsers provided. "
50 "`parser` and `click_type` may not both be provided."
51 )
53 with pytest.raises(ValueError, match=expected_error): 1habcdefg
54 ParameterInfo(parser=custom_parser, click_type=CustomClickParser()) 1habcdefg
57def test_valid_parser_permutations(): 1habcdefg
58 def custom_parser(value: str) -> int: 1habcdefg
59 return int(value) # pragma: no cover
61 class CustomClickParser(click.ParamType): 1habcdefg
62 name = "custom_parser" 1habcdefg
64 def convert( 1abcdefg
65 self,
66 value: str,
67 param: typing.Optional[click.Parameter],
68 ctx: typing.Optional[click.Context],
69 ) -> typing.Any:
70 return int(value) # pragma: no cover
72 ParameterInfo() 1habcdefg
73 ParameterInfo(parser=custom_parser) 1habcdefg
74 ParameterInfo(click_type=CustomClickParser()) 1habcdefg
77def test_install_invalid_shell(): 1habcdefg
78 app = typer.Typer() 1habcdefg
80 @app.command() 1habcdefg
81 def main(): 1abcdefg
82 print("Hello World") 1habcdefg
84 with mock.patch.object( 1habcdefg
85 shellingham, "detect_shell", return_value=("xshell", "/usr/bin/xshell")
86 ):
87 result = runner.invoke(app, ["--install-completion"]) 1habcdefg
88 assert "Shell xshell is not supported." in result.stdout 1habcdefg
89 result = runner.invoke(app) 1habcdefg
90 assert "Hello World" in result.stdout 1habcdefg
93def test_callback_too_many_parameters(): 1habcdefg
94 app = typer.Typer() 1habcdefg
96 def name_callback(ctx, param, val1, val2): 1habcdefg
97 pass # pragma: no cover
99 @app.command() 1habcdefg
100 def main(name: str = typer.Option(..., callback=name_callback)): 1habcdefg
101 pass # pragma: no cover
103 with pytest.raises(click.ClickException) as exc_info: 1habcdefg
104 runner.invoke(app, ["--name", "Camila"]) 1habcdefg
105 assert ( 1habcdefg
106 exc_info.value.message == "Too many CLI parameter callback function parameters"
107 )
110def test_callback_2_untyped_parameters(): 1habcdefg
111 app = typer.Typer() 1habcdefg
113 def name_callback(ctx, value): 1habcdefg
114 print(f"info name is: {ctx.info_name}") 1habcdefg
115 print(f"value is: {value}") 1habcdefg
117 @app.command() 1habcdefg
118 def main(name: str = typer.Option(..., callback=name_callback)): 1habcdefg
119 print("Hello World") 1habcdefg
121 result = runner.invoke(app, ["--name", "Camila"]) 1habcdefg
122 assert "info name is: main" in result.stdout 1habcdefg
123 assert "value is: Camila" in result.stdout 1habcdefg
126def test_callback_3_untyped_parameters(): 1habcdefg
127 app = typer.Typer() 1habcdefg
129 def name_callback(ctx, param, value): 1habcdefg
130 print(f"info name is: {ctx.info_name}") 1habcdefg
131 print(f"param name is: {param.name}") 1habcdefg
132 print(f"value is: {value}") 1habcdefg
134 @app.command() 1habcdefg
135 def main(name: str = typer.Option(..., callback=name_callback)): 1habcdefg
136 print("Hello World") 1habcdefg
138 result = runner.invoke(app, ["--name", "Camila"]) 1habcdefg
139 assert "info name is: main" in result.stdout 1habcdefg
140 assert "param name is: name" in result.stdout 1habcdefg
141 assert "value is: Camila" in result.stdout 1habcdefg
144def test_completion_argument(): 1habcdefg
145 file_path = Path(__file__).parent / "assets/completion_argument.py" 1habcdefg
146 result = subprocess.run( 1habcdefg
147 [sys.executable, "-m", "coverage", "run", str(file_path), "E"],
148 capture_output=True,
149 encoding="utf-8",
150 env={
151 **os.environ,
152 "_COMPLETION_ARGUMENT.PY_COMPLETE": "complete_zsh",
153 "_TYPER_COMPLETE_ARGS": "completion_argument.py E",
154 "_TYPER_COMPLETE_TESTING": "True",
155 },
156 )
157 assert "Emma" in result.stdout or "_files" in result.stdout 1habcdefg
158 assert "ctx: completion_argument" in result.stderr 1habcdefg
159 assert "arg is: name" in result.stderr 1habcdefg
160 assert "incomplete is: E" in result.stderr 1habcdefg
163def test_completion_untyped_parameters(): 1habcdefg
164 file_path = Path(__file__).parent / "assets/completion_no_types.py" 1habcdefg
165 result = subprocess.run( 1habcdefg
166 [sys.executable, "-m", "coverage", "run", str(file_path)],
167 capture_output=True,
168 encoding="utf-8",
169 env={
170 **os.environ,
171 "_COMPLETION_NO_TYPES.PY_COMPLETE": "complete_zsh",
172 "_TYPER_COMPLETE_ARGS": "completion_no_types.py --name Sebastian --name Ca",
173 },
174 )
175 assert "info name is: completion_no_types.py" in result.stderr 1habcdefg
176 assert "args is: []" in result.stderr 1habcdefg
177 assert "incomplete is: Ca" in result.stderr 1habcdefg
178 assert '"Camila":"The reader of books."' in result.stdout 1habcdefg
179 assert '"Carlos":"The writer of scripts."' in result.stdout 1habcdefg
181 result = subprocess.run( 1habcdefg
182 [sys.executable, "-m", "coverage", "run", str(file_path)],
183 capture_output=True,
184 encoding="utf-8",
185 )
186 assert "Hello World" in result.stdout 1habcdefg
189def test_completion_untyped_parameters_different_order_correct_names(): 1habcdefg
190 file_path = Path(__file__).parent / "assets/completion_no_types_order.py" 1habcdefg
191 result = subprocess.run( 1habcdefg
192 [sys.executable, "-m", "coverage", "run", str(file_path)],
193 capture_output=True,
194 encoding="utf-8",
195 env={
196 **os.environ,
197 "_COMPLETION_NO_TYPES_ORDER.PY_COMPLETE": "complete_zsh",
198 "_TYPER_COMPLETE_ARGS": "completion_no_types_order.py --name Sebastian --name Ca",
199 },
200 )
201 assert "info name is: completion_no_types_order.py" in result.stderr 1habcdefg
202 assert "args is: []" in result.stderr 1habcdefg
203 assert "incomplete is: Ca" in result.stderr 1habcdefg
204 assert '"Camila":"The reader of books."' in result.stdout 1habcdefg
205 assert '"Carlos":"The writer of scripts."' in result.stdout 1habcdefg
207 result = subprocess.run( 1habcdefg
208 [sys.executable, "-m", "coverage", "run", str(file_path)],
209 capture_output=True,
210 encoding="utf-8",
211 )
212 assert "Hello World" in result.stdout 1habcdefg
215def test_autocompletion_too_many_parameters(): 1habcdefg
216 app = typer.Typer() 1habcdefg
218 def name_callback(ctx, args, incomplete, val2): 1habcdefg
219 pass # pragma: no cover
221 @app.command() 1habcdefg
222 def main(name: str = typer.Option(..., autocompletion=name_callback)): 1habcdefg
223 pass # pragma: no cover
225 with pytest.raises(click.ClickException) as exc_info: 1habcdefg
226 runner.invoke(app, ["--name", "Camila"]) 1habcdefg
227 assert exc_info.value.message == "Invalid autocompletion callback parameters: val2" 1habcdefg
230def test_forward_references(): 1habcdefg
231 app = typer.Typer() 1habcdefg
233 @app.command() 1habcdefg
234 def main(arg1, arg2: int, arg3: "int", arg4: bool = False, arg5: "bool" = False): 1habcdefg
235 print(f"arg1: {type(arg1)} {arg1}") 1habcdefg
236 print(f"arg2: {type(arg2)} {arg2}") 1habcdefg
237 print(f"arg3: {type(arg3)} {arg3}") 1habcdefg
238 print(f"arg4: {type(arg4)} {arg4}") 1habcdefg
239 print(f"arg5: {type(arg5)} {arg5}") 1habcdefg
241 result = runner.invoke(app, ["Hello", "2", "invalid"]) 1habcdefg
243 assert "Invalid value for 'ARG3': 'invalid' is not a valid integer" in result.stdout 1habcdefg
244 result = runner.invoke(app, ["Hello", "2", "3", "--arg4", "--arg5"]) 1habcdefg
245 assert ( 1habcdefg
246 "arg1: <class 'str'> Hello\narg2: <class 'int'> 2\narg3: <class 'int'> 3\narg4: <class 'bool'> True\narg5: <class 'bool'> True\n"
247 in result.stdout
248 )
251def test_context_settings_inheritance_single_command(): 1habcdefg
252 app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]}) 1habcdefg
254 @app.command() 1habcdefg
255 def main(name: str): 1habcdefg
256 pass # pragma: no cover
258 result = runner.invoke(app, ["main", "-h"]) 1habcdefg
259 assert "Show this message and exit." in result.stdout 1habcdefg
262def test_split_opt(): 1habcdefg
263 prefix, opt = _split_opt("--verbose") 1habcdefg
264 assert prefix == "--" 1habcdefg
265 assert opt == "verbose" 1habcdefg
267 prefix, opt = _split_opt("//verbose") 1habcdefg
268 assert prefix == "//" 1habcdefg
269 assert opt == "verbose" 1habcdefg
271 prefix, opt = _split_opt("-verbose") 1habcdefg
272 assert prefix == "-" 1habcdefg
273 assert opt == "verbose" 1habcdefg
275 prefix, opt = _split_opt("verbose") 1habcdefg
276 assert prefix == "" 1habcdefg
277 assert opt == "verbose" 1habcdefg