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

1import os 1habcdefg

2import subprocess 1habcdefg

3import sys 1habcdefg

4import typing 1habcdefg

5from pathlib import Path 1habcdefg

6from unittest import mock 1habcdefg

7 

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

17 

18from .utils import requires_completion_permission 1habcdefg

19 

20runner = CliRunner() 1habcdefg

21 

22 

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

27 

28 

29def test_defaults_from_info(): 1habcdefg

30 # Mainly for coverage/completeness 

31 value = solve_typer_info_defaults(TyperInfo()) 1habcdefg

32 assert value 1habcdefg

33 

34 

35def test_too_many_parsers(): 1habcdefg

36 def custom_parser(value: str) -> int: 1habcdefg

37 return int(value) # pragma: no cover 

38 

39 class CustomClickParser(click.ParamType): 1habcdefg

40 name = "custom_parser" 1habcdefg

41 

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 

49 

50 expected_error = ( 1abcdefg

51 "Multiple custom type parsers provided. " 

52 "`parser` and `click_type` may not both be provided." 

53 ) 

54 

55 with pytest.raises(ValueError, match=expected_error): 1habcdefg

56 ParameterInfo(parser=custom_parser, click_type=CustomClickParser()) 1habcdefg

57 

58 

59def test_valid_parser_permutations(): 1habcdefg

60 def custom_parser(value: str) -> int: 1habcdefg

61 return int(value) # pragma: no cover 

62 

63 class CustomClickParser(click.ParamType): 1habcdefg

64 name = "custom_parser" 1habcdefg

65 

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 

73 

74 ParameterInfo() 1habcdefg

75 ParameterInfo(parser=custom_parser) 1habcdefg

76 ParameterInfo(click_type=CustomClickParser()) 1habcdefg

77 

78 

79@requires_completion_permission 1habcdefg

80def test_install_invalid_shell(): 1abcdefg

81 app = typer.Typer() 1habcdefg

82 

83 @app.command() 1habcdefg

84 def main(): 1abcdefg

85 print("Hello World") 1habcdefg

86 

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

94 

95 

96def test_callback_too_many_parameters(): 1habcdefg

97 app = typer.Typer() 1habcdefg

98 

99 def name_callback(ctx, param, val1, val2): 1habcdefg

100 pass # pragma: no cover 

101 

102 @app.command() 1habcdefg

103 def main(name: str = typer.Option(..., callback=name_callback)): 1habcdefg

104 pass # pragma: no cover 

105 

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 ) 

111 

112 

113def test_callback_2_untyped_parameters(): 1habcdefg

114 app = typer.Typer() 1habcdefg

115 

116 def name_callback(ctx, value): 1habcdefg

117 print(f"info name is: {ctx.info_name}") 1habcdefg

118 print(f"value is: {value}") 1habcdefg

119 

120 @app.command() 1habcdefg

121 def main(name: str = typer.Option(..., callback=name_callback)): 1habcdefg

122 print("Hello World") 1habcdefg

123 

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

127 

128 

129def test_callback_3_untyped_parameters(): 1habcdefg

130 app = typer.Typer() 1habcdefg

131 

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

136 

137 @app.command() 1habcdefg

138 def main(name: str = typer.Option(..., callback=name_callback)): 1habcdefg

139 print("Hello World") 1habcdefg

140 

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

145 

146 

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

164 

165 

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

183 

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

190 

191 

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

209 

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

216 

217 

218def test_autocompletion_too_many_parameters(): 1habcdefg

219 app = typer.Typer() 1habcdefg

220 

221 def name_callback(ctx, args, incomplete, val2): 1habcdefg

222 pass # pragma: no cover 

223 

224 @app.command() 1habcdefg

225 def main(name: str = typer.Option(..., autocompletion=name_callback)): 1habcdefg

226 pass # pragma: no cover 

227 

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

231 

232 

233def test_forward_references(): 1habcdefg

234 app = typer.Typer() 1habcdefg

235 

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

243 

244 result = runner.invoke(app, ["Hello", "2", "invalid"]) 1habcdefg

245 

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 ) 

252 

253 

254def test_context_settings_inheritance_single_command(): 1habcdefg

255 app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]}) 1habcdefg

256 

257 @app.command() 1habcdefg

258 def main(name: str): 1habcdefg

259 pass # pragma: no cover 

260 

261 result = runner.invoke(app, ["main", "-h"]) 1habcdefg

262 assert "Show this message and exit." in result.stdout 1habcdefg

263 

264 

265def test_split_opt(): 1habcdefg

266 prefix, opt = _split_opt("--verbose") 1habcdefg

267 assert prefix == "--" 1habcdefg

268 assert opt == "verbose" 1habcdefg

269 

270 prefix, opt = _split_opt("//verbose") 1habcdefg

271 assert prefix == "//" 1habcdefg

272 assert opt == "verbose" 1habcdefg

273 

274 prefix, opt = _split_opt("-verbose") 1habcdefg

275 assert prefix == "-" 1habcdefg

276 assert opt == "verbose" 1habcdefg

277 

278 prefix, opt = _split_opt("verbose") 1habcdefg

279 assert prefix == "" 1habcdefg

280 assert opt == "verbose" 1habcdefg