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

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 

18runner = CliRunner() 1habcdefg

19 

20 

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

25 

26 

27def test_defaults_from_info(): 1habcdefg

28 # Mainly for coverage/completeness 

29 value = solve_typer_info_defaults(TyperInfo()) 1habcdefg

30 assert value 1habcdefg

31 

32 

33def test_too_many_parsers(): 1habcdefg

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

35 return int(value) # pragma: no cover 

36 

37 class CustomClickParser(click.ParamType): 1habcdefg

38 name = "custom_parser" 1habcdefg

39 

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 

47 

48 expected_error = ( 1abcdefg

49 "Multiple custom type parsers provided. " 

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

51 ) 

52 

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

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

55 

56 

57def test_valid_parser_permutations(): 1habcdefg

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

59 return int(value) # pragma: no cover 

60 

61 class CustomClickParser(click.ParamType): 1habcdefg

62 name = "custom_parser" 1habcdefg

63 

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 

71 

72 ParameterInfo() 1habcdefg

73 ParameterInfo(parser=custom_parser) 1habcdefg

74 ParameterInfo(click_type=CustomClickParser()) 1habcdefg

75 

76 

77def test_install_invalid_shell(): 1habcdefg

78 app = typer.Typer() 1habcdefg

79 

80 @app.command() 1habcdefg

81 def main(): 1abcdefg

82 print("Hello World") 1habcdefg

83 

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

91 

92 

93def test_callback_too_many_parameters(): 1habcdefg

94 app = typer.Typer() 1habcdefg

95 

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

97 pass # pragma: no cover 

98 

99 @app.command() 1habcdefg

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

101 pass # pragma: no cover 

102 

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 ) 

108 

109 

110def test_callback_2_untyped_parameters(): 1habcdefg

111 app = typer.Typer() 1habcdefg

112 

113 def name_callback(ctx, value): 1habcdefg

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

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

116 

117 @app.command() 1habcdefg

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

119 print("Hello World") 1habcdefg

120 

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

124 

125 

126def test_callback_3_untyped_parameters(): 1habcdefg

127 app = typer.Typer() 1habcdefg

128 

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

133 

134 @app.command() 1habcdefg

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

136 print("Hello World") 1habcdefg

137 

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

142 

143 

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

161 

162 

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

180 

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

187 

188 

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

206 

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

213 

214 

215def test_autocompletion_too_many_parameters(): 1habcdefg

216 app = typer.Typer() 1habcdefg

217 

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

219 pass # pragma: no cover 

220 

221 @app.command() 1habcdefg

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

223 pass # pragma: no cover 

224 

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

228 

229 

230def test_forward_references(): 1habcdefg

231 app = typer.Typer() 1habcdefg

232 

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

240 

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

242 

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 ) 

249 

250 

251def test_context_settings_inheritance_single_command(): 1habcdefg

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

253 

254 @app.command() 1habcdefg

255 def main(name: str): 1habcdefg

256 pass # pragma: no cover 

257 

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

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

260 

261 

262def test_split_opt(): 1habcdefg

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

264 assert prefix == "--" 1habcdefg

265 assert opt == "verbose" 1habcdefg

266 

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

268 assert prefix == "//" 1habcdefg

269 assert opt == "verbose" 1habcdefg

270 

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

272 assert prefix == "-" 1habcdefg

273 assert opt == "verbose" 1habcdefg

274 

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

276 assert prefix == "" 1habcdefg

277 assert opt == "verbose" 1habcdefg