Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/click/exceptions.py: 33%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

135 statements  

1from __future__ import annotations 

2 

3import collections.abc as cabc 

4import typing as t 

5from gettext import gettext as _ 

6from gettext import ngettext 

7 

8from ._compat import get_text_stderr 

9from .globals import resolve_color_default 

10from .utils import echo 

11from .utils import format_filename 

12 

13if t.TYPE_CHECKING: 

14 from .core import Command 

15 from .core import Context 

16 from .core import Parameter 

17 

18 

19def _join_param_hints(param_hint: cabc.Sequence[str] | str | None) -> str | None: 

20 if param_hint is not None and not isinstance(param_hint, str): 

21 return " / ".join(repr(x) for x in param_hint) 

22 

23 return param_hint 

24 

25 

26class ClickException(Exception): 

27 """An exception that Click can handle and show to the user.""" 

28 

29 #: The exit code for this exception. 

30 exit_code = 1 

31 

32 def __init__(self, message: str) -> None: 

33 super().__init__(message) 

34 # The context will be removed by the time we print the message, so cache 

35 # the color settings here to be used later on (in `show`) 

36 self.show_color: bool | None = resolve_color_default() 

37 self.message = message 

38 

39 def format_message(self) -> str: 

40 return self.message 

41 

42 def __str__(self) -> str: 

43 return self.message 

44 

45 def show(self, file: t.IO[t.Any] | None = None) -> None: 

46 if file is None: 

47 file = get_text_stderr() 

48 

49 echo( 

50 _("Error: {message}").format(message=self.format_message()), 

51 file=file, 

52 color=self.show_color, 

53 ) 

54 

55 

56class UsageError(ClickException): 

57 """An internal exception that signals a usage error. This typically 

58 aborts any further handling. 

59 

60 :param message: the error message to display. 

61 :param ctx: optionally the context that caused this error. Click will 

62 fill in the context automatically in some situations. 

63 """ 

64 

65 exit_code = 2 

66 

67 def __init__(self, message: str, ctx: Context | None = None) -> None: 

68 super().__init__(message) 

69 self.ctx = ctx 

70 self.cmd: Command | None = self.ctx.command if self.ctx else None 

71 

72 def show(self, file: t.IO[t.Any] | None = None) -> None: 

73 if file is None: 

74 file = get_text_stderr() 

75 color = None 

76 hint = "" 

77 if ( 

78 self.ctx is not None 

79 and self.ctx.command.get_help_option(self.ctx) is not None 

80 ): 

81 hint = _("Try '{command} {option}' for help.").format( 

82 command=self.ctx.command_path, option=self.ctx.help_option_names[0] 

83 ) 

84 hint = f"{hint}\n" 

85 if self.ctx is not None: 

86 color = self.ctx.color 

87 echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) 

88 echo( 

89 _("Error: {message}").format(message=self.format_message()), 

90 file=file, 

91 color=color, 

92 ) 

93 

94 

95class BadParameter(UsageError): 

96 """An exception that formats out a standardized error message for a 

97 bad parameter. This is useful when thrown from a callback or type as 

98 Click will attach contextual information to it (for instance, which 

99 parameter it is). 

100 

101 .. versionadded:: 2.0 

102 

103 :param param: the parameter object that caused this error. This can 

104 be left out, and Click will attach this info itself 

105 if possible. 

106 :param param_hint: a string that shows up as parameter name. This 

107 can be used as alternative to `param` in cases 

108 where custom validation should happen. If it is 

109 a string it's used as such, if it's a list then 

110 each item is quoted and separated. 

111 """ 

112 

113 def __init__( 

114 self, 

115 message: str, 

116 ctx: Context | None = None, 

117 param: Parameter | None = None, 

118 param_hint: str | None = None, 

119 ) -> None: 

120 super().__init__(message, ctx) 

121 self.param = param 

122 self.param_hint = param_hint 

123 

124 def format_message(self) -> str: 

125 if self.param_hint is not None: 

126 param_hint = self.param_hint 

127 elif self.param is not None: 

128 param_hint = self.param.get_error_hint(self.ctx) # type: ignore 

129 else: 

130 return _("Invalid value: {message}").format(message=self.message) 

131 

132 return _("Invalid value for {param_hint}: {message}").format( 

133 param_hint=_join_param_hints(param_hint), message=self.message 

134 ) 

135 

136 

137class MissingParameter(BadParameter): 

138 """Raised if click required an option or argument but it was not 

139 provided when invoking the script. 

140 

141 .. versionadded:: 4.0 

142 

143 :param param_type: a string that indicates the type of the parameter. 

144 The default is to inherit the parameter type from 

145 the given `param`. Valid values are ``'parameter'``, 

146 ``'option'`` or ``'argument'``. 

147 """ 

148 

149 def __init__( 

150 self, 

151 message: str | None = None, 

152 ctx: Context | None = None, 

153 param: Parameter | None = None, 

154 param_hint: str | None = None, 

155 param_type: str | None = None, 

156 ) -> None: 

157 super().__init__(message or "", ctx, param, param_hint) 

158 self.param_type = param_type 

159 

160 def format_message(self) -> str: 

161 if self.param_hint is not None: 

162 param_hint: str | None = self.param_hint 

163 elif self.param is not None: 

164 param_hint = self.param.get_error_hint(self.ctx) # type: ignore 

165 else: 

166 param_hint = None 

167 

168 param_hint = _join_param_hints(param_hint) 

169 param_hint = f" {param_hint}" if param_hint else "" 

170 

171 param_type = self.param_type 

172 if param_type is None and self.param is not None: 

173 param_type = self.param.param_type_name 

174 

175 msg = self.message 

176 if self.param is not None: 

177 msg_extra = self.param.type.get_missing_message( 

178 param=self.param, ctx=self.ctx 

179 ) 

180 if msg_extra: 

181 if msg: 

182 msg += f". {msg_extra}" 

183 else: 

184 msg = msg_extra 

185 

186 msg = f" {msg}" if msg else "" 

187 

188 # Translate param_type for known types. 

189 if param_type == "argument": 

190 missing = _("Missing argument") 

191 elif param_type == "option": 

192 missing = _("Missing option") 

193 elif param_type == "parameter": 

194 missing = _("Missing parameter") 

195 else: 

196 missing = _("Missing {param_type}").format(param_type=param_type) 

197 

198 return f"{missing}{param_hint}.{msg}" 

199 

200 def __str__(self) -> str: 

201 if not self.message: 

202 param_name = self.param.name if self.param else None 

203 return _("Missing parameter: {param_name}").format(param_name=param_name) 

204 else: 

205 return self.message 

206 

207 

208class NoSuchOption(UsageError): 

209 """Raised if click attempted to handle an option that does not 

210 exist. 

211 

212 .. versionadded:: 4.0 

213 """ 

214 

215 def __init__( 

216 self, 

217 option_name: str, 

218 message: str | None = None, 

219 possibilities: cabc.Sequence[str] | None = None, 

220 ctx: Context | None = None, 

221 ) -> None: 

222 if message is None: 

223 message = _("No such option: {name}").format(name=option_name) 

224 

225 super().__init__(message, ctx) 

226 self.option_name = option_name 

227 self.possibilities = possibilities 

228 

229 def format_message(self) -> str: 

230 if not self.possibilities: 

231 return self.message 

232 

233 possibility_str = ", ".join(sorted(self.possibilities)) 

234 suggest = ngettext( 

235 "Did you mean {possibility}?", 

236 "(Possible options: {possibilities})", 

237 len(self.possibilities), 

238 ).format(possibility=possibility_str, possibilities=possibility_str) 

239 return f"{self.message} {suggest}" 

240 

241 

242class BadOptionUsage(UsageError): 

243 """Raised if an option is generally supplied but the use of the option 

244 was incorrect. This is for instance raised if the number of arguments 

245 for an option is not correct. 

246 

247 .. versionadded:: 4.0 

248 

249 :param option_name: the name of the option being used incorrectly. 

250 """ 

251 

252 def __init__( 

253 self, option_name: str, message: str, ctx: Context | None = None 

254 ) -> None: 

255 super().__init__(message, ctx) 

256 self.option_name = option_name 

257 

258 

259class BadArgumentUsage(UsageError): 

260 """Raised if an argument is generally supplied but the use of the argument 

261 was incorrect. This is for instance raised if the number of values 

262 for an argument is not correct. 

263 

264 .. versionadded:: 6.0 

265 """ 

266 

267 

268class NoArgsIsHelpError(UsageError): 

269 def __init__(self, ctx: Context) -> None: 

270 self.ctx: Context 

271 super().__init__(ctx.get_help(), ctx=ctx) 

272 

273 def show(self, file: t.IO[t.Any] | None = None) -> None: 

274 echo(self.format_message(), file=file, err=True, color=self.ctx.color) 

275 

276 

277class FileError(ClickException): 

278 """Raised if a file cannot be opened.""" 

279 

280 def __init__(self, filename: str, hint: str | None = None) -> None: 

281 if hint is None: 

282 hint = _("unknown error") 

283 

284 super().__init__(hint) 

285 self.ui_filename: str = format_filename(filename) 

286 self.filename = filename 

287 

288 def format_message(self) -> str: 

289 return _("Could not open file {filename!r}: {message}").format( 

290 filename=self.ui_filename, message=self.message 

291 ) 

292 

293 

294class Abort(RuntimeError): 

295 """An internal signalling exception that signals Click to abort.""" 

296 

297 

298class Exit(RuntimeError): 

299 """An exception that indicates that the application should exit with some 

300 status code. 

301 

302 :param code: the status code to exit with. 

303 """ 

304 

305 __slots__ = ("exit_code",) 

306 

307 def __init__(self, code: int = 0) -> None: 

308 self.exit_code: int = code