Coverage for tests/test_others.py: 100%
149 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-11-13 11:07 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-11-13 11:07 +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
18from .utils import requires_completion_permission 1habcdefg
20runner = CliRunner() 1habcdefg
23def test_help_from_info(): 1habcdefg
24 # Mainly for coverage/completeness
25 value = solve_typer_info_help(TyperInfo()) 1habcdefg
26 assert value is None 1habcdefg
29def test_defaults_from_info(): 1habcdefg
30 # Mainly for coverage/completeness
31 value = solve_typer_info_defaults(TyperInfo()) 1habcdefg
32 assert value 1habcdefg
35def test_too_many_parsers(): 1habcdefg
36 def custom_parser(value: str) -> int: 1habcdefg
37 return int(value) # pragma: no cover
39 class CustomClickParser(click.ParamType): 1habcdefg
40 name = "custom_parser" 1habcdefg
42 def convert( 1abcdefg
43 self,
44 value: str,
45 param: typing.Optional[click.Parameter],
46 ctx: typing.Optional[click.Context],
47 ) -> typing.Any:
48 return int(value) # pragma: no cover
50 expected_error = ( 1abcdefg
51 "Multiple custom type parsers provided. "
52 "`parser` and `click_type` may not both be provided."
53 )
55 with pytest.raises(ValueError, match=expected_error): 1habcdefg
56 ParameterInfo(parser=custom_parser, click_type=CustomClickParser()) 1habcdefg
59def test_valid_parser_permutations(): 1habcdefg
60 def custom_parser(value: str) -> int: 1habcdefg
61 return int(value) # pragma: no cover
63 class CustomClickParser(click.ParamType): 1habcdefg
64 name = "custom_parser" 1habcdefg
66 def convert( 1abcdefg
67 self,
68 value: str,
69 param: typing.Optional[click.Parameter],
70 ctx: typing.Optional[click.Context],
71 ) -> typing.Any:
72 return int(value) # pragma: no cover
74 ParameterInfo() 1habcdefg
75 ParameterInfo(parser=custom_parser) 1habcdefg
76 ParameterInfo(click_type=CustomClickParser()) 1habcdefg
79@requires_completion_permission 1habcdefg
80def test_install_invalid_shell(): 1abcdefg
81 app = typer.Typer() 1habcdefg
83 @app.command() 1habcdefg
84 def main(): 1abcdefg
85 print("Hello World") 1habcdefg
87 with mock.patch.object( 1habcdefg
88 shellingham, "detect_shell", return_value=("xshell", "/usr/bin/xshell")
89 ):
90 result = runner.invoke(app, ["--install-completion"]) 1habcdefg
91 assert "Shell xshell is not supported." in result.stdout 1habcdefg
92 result = runner.invoke(app) 1habcdefg
93 assert "Hello World" in result.stdout 1habcdefg
96def test_callback_too_many_parameters(): 1habcdefg
97 app = typer.Typer() 1habcdefg
99 def name_callback(ctx, param, val1, val2): 1habcdefg
100 pass # pragma: no cover
102 @app.command() 1habcdefg
103 def main(name: str = typer.Option(..., callback=name_callback)): 1habcdefg
104 pass # pragma: no cover
106 with pytest.raises(click.ClickException) as exc_info: 1habcdefg
107 runner.invoke(app, ["--name", "Camila"]) 1habcdefg
108 assert ( 1habcdefg
109 exc_info.value.message == "Too many CLI parameter callback function parameters"
110 )
113def test_callback_2_untyped_parameters(): 1habcdefg
114 app = typer.Typer() 1habcdefg
116 def name_callback(ctx, value): 1habcdefg
117 print(f"info name is: {ctx.info_name}") 1habcdefg
118 print(f"value is: {value}") 1habcdefg
120 @app.command() 1habcdefg
121 def main(name: str = typer.Option(..., callback=name_callback)): 1habcdefg
122 print("Hello World") 1habcdefg
124 result = runner.invoke(app, ["--name", "Camila"]) 1habcdefg
125 assert "info name is: main" in result.stdout 1habcdefg
126 assert "value is: Camila" in result.stdout 1habcdefg
129def test_callback_3_untyped_parameters(): 1habcdefg
130 app = typer.Typer() 1habcdefg
132 def name_callback(ctx, param, value): 1habcdefg
133 print(f"info name is: {ctx.info_name}") 1habcdefg
134 print(f"param name is: {param.name}") 1habcdefg
135 print(f"value is: {value}") 1habcdefg
137 @app.command() 1habcdefg
138 def main(name: str = typer.Option(..., callback=name_callback)): 1habcdefg
139 print("Hello World") 1habcdefg
141 result = runner.invoke(app, ["--name", "Camila"]) 1habcdefg
142 assert "info name is: main" in result.stdout 1habcdefg
143 assert "param name is: name" in result.stdout 1habcdefg
144 assert "value is: Camila" in result.stdout 1habcdefg
147def test_completion_argument(): 1habcdefg
148 file_path = Path(__file__).parent / "assets/completion_argument.py" 1habcdefg
149 result = subprocess.run( 1habcdefg
150 [sys.executable, "-m", "coverage", "run", str(file_path), "E"],
151 capture_output=True,
152 encoding="utf-8",
153 env={
154 **os.environ,
155 "_COMPLETION_ARGUMENT.PY_COMPLETE": "complete_zsh",
156 "_TYPER_COMPLETE_ARGS": "completion_argument.py E",
157 "_TYPER_COMPLETE_TESTING": "True",
158 },
159 )
160 assert "Emma" in result.stdout or "_files" in result.stdout 1habcdefg
161 assert "ctx: completion_argument" in result.stderr 1habcdefg
162 assert "arg is: name" in result.stderr 1habcdefg
163 assert "incomplete is: E" in result.stderr 1habcdefg
166def test_completion_untyped_parameters(): 1habcdefg
167 file_path = Path(__file__).parent / "assets/completion_no_types.py" 1habcdefg
168 result = subprocess.run( 1habcdefg
169 [sys.executable, "-m", "coverage", "run", str(file_path)],
170 capture_output=True,
171 encoding="utf-8",
172 env={
173 **os.environ,
174 "_COMPLETION_NO_TYPES.PY_COMPLETE": "complete_zsh",
175 "_TYPER_COMPLETE_ARGS": "completion_no_types.py --name Sebastian --name Ca",
176 },
177 )
178 assert "info name is: completion_no_types.py" in result.stderr 1habcdefg
179 assert "args is: []" in result.stderr 1habcdefg
180 assert "incomplete is: Ca" in result.stderr 1habcdefg
181 assert '"Camila":"The reader of books."' in result.stdout 1habcdefg
182 assert '"Carlos":"The writer of scripts."' in result.stdout 1habcdefg
184 result = subprocess.run( 1habcdefg
185 [sys.executable, "-m", "coverage", "run", str(file_path)],
186 capture_output=True,
187 encoding="utf-8",
188 )
189 assert "Hello World" in result.stdout 1habcdefg
192def test_completion_untyped_parameters_different_order_correct_names(): 1habcdefg
193 file_path = Path(__file__).parent / "assets/completion_no_types_order.py" 1habcdefg
194 result = subprocess.run( 1habcdefg
195 [sys.executable, "-m", "coverage", "run", str(file_path)],
196 capture_output=True,
197 encoding="utf-8",
198 env={
199 **os.environ,
200 "_COMPLETION_NO_TYPES_ORDER.PY_COMPLETE": "complete_zsh",
201 "_TYPER_COMPLETE_ARGS": "completion_no_types_order.py --name Sebastian --name Ca",
202 },
203 )
204 assert "info name is: completion_no_types_order.py" in result.stderr 1habcdefg
205 assert "args is: []" in result.stderr 1habcdefg
206 assert "incomplete is: Ca" in result.stderr 1habcdefg
207 assert '"Camila":"The reader of books."' in result.stdout 1habcdefg
208 assert '"Carlos":"The writer of scripts."' in result.stdout 1habcdefg
210 result = subprocess.run( 1habcdefg
211 [sys.executable, "-m", "coverage", "run", str(file_path)],
212 capture_output=True,
213 encoding="utf-8",
214 )
215 assert "Hello World" in result.stdout 1habcdefg
218def test_autocompletion_too_many_parameters(): 1habcdefg
219 app = typer.Typer() 1habcdefg
221 def name_callback(ctx, args, incomplete, val2): 1habcdefg
222 pass # pragma: no cover
224 @app.command() 1habcdefg
225 def main(name: str = typer.Option(..., autocompletion=name_callback)): 1habcdefg
226 pass # pragma: no cover
228 with pytest.raises(click.ClickException) as exc_info: 1habcdefg
229 runner.invoke(app, ["--name", "Camila"]) 1habcdefg
230 assert exc_info.value.message == "Invalid autocompletion callback parameters: val2" 1habcdefg
233def test_forward_references(): 1habcdefg
234 app = typer.Typer() 1habcdefg
236 @app.command() 1habcdefg
237 def main(arg1, arg2: int, arg3: "int", arg4: bool = False, arg5: "bool" = False): 1habcdefg
238 print(f"arg1: {type(arg1)} {arg1}") 1habcdefg
239 print(f"arg2: {type(arg2)} {arg2}") 1habcdefg
240 print(f"arg3: {type(arg3)} {arg3}") 1habcdefg
241 print(f"arg4: {type(arg4)} {arg4}") 1habcdefg
242 print(f"arg5: {type(arg5)} {arg5}") 1habcdefg
244 result = runner.invoke(app, ["Hello", "2", "invalid"]) 1habcdefg
246 assert "Invalid value for 'ARG3': 'invalid' is not a valid integer" in result.stdout 1habcdefg
247 result = runner.invoke(app, ["Hello", "2", "3", "--arg4", "--arg5"]) 1habcdefg
248 assert ( 1habcdefg
249 "arg1: <class 'str'> Hello\narg2: <class 'int'> 2\narg3: <class 'int'> 3\narg4: <class 'bool'> True\narg5: <class 'bool'> True\n"
250 in result.stdout
251 )
254def test_context_settings_inheritance_single_command(): 1habcdefg
255 app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]}) 1habcdefg
257 @app.command() 1habcdefg
258 def main(name: str): 1habcdefg
259 pass # pragma: no cover
261 result = runner.invoke(app, ["main", "-h"]) 1habcdefg
262 assert "Show this message and exit." in result.stdout 1habcdefg
265def test_split_opt(): 1habcdefg
266 prefix, opt = _split_opt("--verbose") 1habcdefg
267 assert prefix == "--" 1habcdefg
268 assert opt == "verbose" 1habcdefg
270 prefix, opt = _split_opt("//verbose") 1habcdefg
271 assert prefix == "//" 1habcdefg
272 assert opt == "verbose" 1habcdefg
274 prefix, opt = _split_opt("-verbose") 1habcdefg
275 assert prefix == "-" 1habcdefg
276 assert opt == "verbose" 1habcdefg
278 prefix, opt = _split_opt("verbose") 1habcdefg
279 assert prefix == "" 1habcdefg
280 assert opt == "verbose" 1habcdefg