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

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

125 statements  

1import typing as t 

2from gettext import gettext as _ 

3from gettext import ngettext 

4 

5from ._compat import get_text_stderr 

6from .utils import echo 

7from .utils import format_filename 

8 

9if t.TYPE_CHECKING: 

10 from .core import Command 

11 from .core import Context 

12 from .core import Parameter 

13 

14 

15def _join_param_hints( 

16 param_hint: t.Optional[t.Union[t.Sequence[str], str]] 

17) -> t.Optional[str]: 

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

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

20 

21 return param_hint 

22 

23 

24class ClickException(Exception): 

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

26 

27 #: The exit code for this exception. 

28 exit_code = 1 

29 

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

31 super().__init__(message) 

32 self.message = message 

33 

34 def format_message(self) -> str: 

35 return self.message 

36 

37 def __str__(self) -> str: 

38 return self.message 

39 

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

41 if file is None: 

42 file = get_text_stderr() 

43 

44 echo(_("Error: {message}").format(message=self.format_message()), file=file) 

45 

46 

47class UsageError(ClickException): 

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

49 aborts any further handling. 

50 

51 :param message: the error message to display. 

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

53 fill in the context automatically in some situations. 

54 """ 

55 

56 exit_code = 2 

57 

58 def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None: 

59 super().__init__(message) 

60 self.ctx = ctx 

61 self.cmd: t.Optional["Command"] = self.ctx.command if self.ctx else None 

62 

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

64 if file is None: 

65 file = get_text_stderr() 

66 color = None 

67 hint = "" 

68 if ( 

69 self.ctx is not None 

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

71 ): 

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

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

74 ) 

75 hint = f"{hint}\n" 

76 if self.ctx is not None: 

77 color = self.ctx.color 

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

79 echo( 

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

81 file=file, 

82 color=color, 

83 ) 

84 

85 

86class BadParameter(UsageError): 

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

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

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

90 parameter it is). 

91 

92 .. versionadded:: 2.0 

93 

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

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

96 if possible. 

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

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

99 where custom validation should happen. If it is 

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

101 each item is quoted and separated. 

102 """ 

103 

104 def __init__( 

105 self, 

106 message: str, 

107 ctx: t.Optional["Context"] = None, 

108 param: t.Optional["Parameter"] = None, 

109 param_hint: t.Optional[str] = None, 

110 ) -> None: 

111 super().__init__(message, ctx) 

112 self.param = param 

113 self.param_hint = param_hint 

114 

115 def format_message(self) -> str: 

116 if self.param_hint is not None: 

117 param_hint = self.param_hint 

118 elif self.param is not None: 

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

120 else: 

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

122 

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

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

125 ) 

126 

127 

128class MissingParameter(BadParameter): 

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

130 provided when invoking the script. 

131 

132 .. versionadded:: 4.0 

133 

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

135 The default is to inherit the parameter type from 

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

137 ``'option'`` or ``'argument'``. 

138 """ 

139 

140 def __init__( 

141 self, 

142 message: t.Optional[str] = None, 

143 ctx: t.Optional["Context"] = None, 

144 param: t.Optional["Parameter"] = None, 

145 param_hint: t.Optional[str] = None, 

146 param_type: t.Optional[str] = None, 

147 ) -> None: 

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

149 self.param_type = param_type 

150 

151 def format_message(self) -> str: 

152 if self.param_hint is not None: 

153 param_hint: t.Optional[str] = self.param_hint 

154 elif self.param is not None: 

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

156 else: 

157 param_hint = None 

158 

159 param_hint = _join_param_hints(param_hint) 

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

161 

162 param_type = self.param_type 

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

164 param_type = self.param.param_type_name 

165 

166 msg = self.message 

167 if self.param is not None: 

168 msg_extra = self.param.type.get_missing_message(self.param) 

169 if msg_extra: 

170 if msg: 

171 msg += f". {msg_extra}" 

172 else: 

173 msg = msg_extra 

174 

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

176 

177 # Translate param_type for known types. 

178 if param_type == "argument": 

179 missing = _("Missing argument") 

180 elif param_type == "option": 

181 missing = _("Missing option") 

182 elif param_type == "parameter": 

183 missing = _("Missing parameter") 

184 else: 

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

186 

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

188 

189 def __str__(self) -> str: 

190 if not self.message: 

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

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

193 else: 

194 return self.message 

195 

196 

197class NoSuchOption(UsageError): 

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

199 exist. 

200 

201 .. versionadded:: 4.0 

202 """ 

203 

204 def __init__( 

205 self, 

206 option_name: str, 

207 message: t.Optional[str] = None, 

208 possibilities: t.Optional[t.Sequence[str]] = None, 

209 ctx: t.Optional["Context"] = None, 

210 ) -> None: 

211 if message is None: 

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

213 

214 super().__init__(message, ctx) 

215 self.option_name = option_name 

216 self.possibilities = possibilities 

217 

218 def format_message(self) -> str: 

219 if not self.possibilities: 

220 return self.message 

221 

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

223 suggest = ngettext( 

224 "Did you mean {possibility}?", 

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

226 len(self.possibilities), 

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

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

229 

230 

231class BadOptionUsage(UsageError): 

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

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

234 for an option is not correct. 

235 

236 .. versionadded:: 4.0 

237 

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

239 """ 

240 

241 def __init__( 

242 self, option_name: str, message: str, ctx: t.Optional["Context"] = None 

243 ) -> None: 

244 super().__init__(message, ctx) 

245 self.option_name = option_name 

246 

247 

248class BadArgumentUsage(UsageError): 

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

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

251 for an argument is not correct. 

252 

253 .. versionadded:: 6.0 

254 """ 

255 

256 

257class FileError(ClickException): 

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

259 

260 def __init__(self, filename: str, hint: t.Optional[str] = None) -> None: 

261 if hint is None: 

262 hint = _("unknown error") 

263 

264 super().__init__(hint) 

265 self.ui_filename: str = format_filename(filename) 

266 self.filename = filename 

267 

268 def format_message(self) -> str: 

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

270 filename=self.ui_filename, message=self.message 

271 ) 

272 

273 

274class Abort(RuntimeError): 

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

276 

277 

278class Exit(RuntimeError): 

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

280 status code. 

281 

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

283 """ 

284 

285 __slots__ = ("exit_code",) 

286 

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

288 self.exit_code: int = code