123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- import typing as t
- from gettext import gettext as _
- from gettext import ngettext
- from ._compat import get_text_stderr
- from .utils import echo
- from .utils import format_filename
- if t.TYPE_CHECKING:
- from .core import Command
- from .core import Context
- from .core import Parameter
- def _join_param_hints(
- param_hint: t.Optional[t.Union[t.Sequence[str], str]]
- ) -> t.Optional[str]:
- if param_hint is not None and not isinstance(param_hint, str):
- return " / ".join(repr(x) for x in param_hint)
- return param_hint
- class ClickException(Exception):
- """An exception that Click can handle and show to the user."""
- #: The exit code for this exception.
- exit_code = 1
- def __init__(self, message: str) -> None:
- super().__init__(message)
- self.message = message
- def format_message(self) -> str:
- return self.message
- def __str__(self) -> str:
- return self.message
- def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None:
- if file is None:
- file = get_text_stderr()
- echo(_("Error: {message}").format(message=self.format_message()), file=file)
- class UsageError(ClickException):
- """An internal exception that signals a usage error. This typically
- aborts any further handling.
- :param message: the error message to display.
- :param ctx: optionally the context that caused this error. Click will
- fill in the context automatically in some situations.
- """
- exit_code = 2
- def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None:
- super().__init__(message)
- self.ctx = ctx
- self.cmd: t.Optional["Command"] = self.ctx.command if self.ctx else None
- def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None:
- if file is None:
- file = get_text_stderr()
- color = None
- hint = ""
- if (
- self.ctx is not None
- and self.ctx.command.get_help_option(self.ctx) is not None
- ):
- hint = _("Try '{command} {option}' for help.").format(
- command=self.ctx.command_path, option=self.ctx.help_option_names[0]
- )
- hint = f"{hint}\n"
- if self.ctx is not None:
- color = self.ctx.color
- echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color)
- echo(
- _("Error: {message}").format(message=self.format_message()),
- file=file,
- color=color,
- )
- class BadParameter(UsageError):
- """An exception that formats out a standardized error message for a
- bad parameter. This is useful when thrown from a callback or type as
- Click will attach contextual information to it (for instance, which
- parameter it is).
- .. versionadded:: 2.0
- :param param: the parameter object that caused this error. This can
- be left out, and Click will attach this info itself
- if possible.
- :param param_hint: a string that shows up as parameter name. This
- can be used as alternative to `param` in cases
- where custom validation should happen. If it is
- a string it's used as such, if it's a list then
- each item is quoted and separated.
- """
- def __init__(
- self,
- message: str,
- ctx: t.Optional["Context"] = None,
- param: t.Optional["Parameter"] = None,
- param_hint: t.Optional[str] = None,
- ) -> None:
- super().__init__(message, ctx)
- self.param = param
- self.param_hint = param_hint
- def format_message(self) -> str:
- if self.param_hint is not None:
- param_hint = self.param_hint
- elif self.param is not None:
- param_hint = self.param.get_error_hint(self.ctx) # type: ignore
- else:
- return _("Invalid value: {message}").format(message=self.message)
- return _("Invalid value for {param_hint}: {message}").format(
- param_hint=_join_param_hints(param_hint), message=self.message
- )
- class MissingParameter(BadParameter):
- """Raised if click required an option or argument but it was not
- provided when invoking the script.
- .. versionadded:: 4.0
- :param param_type: a string that indicates the type of the parameter.
- The default is to inherit the parameter type from
- the given `param`. Valid values are ``'parameter'``,
- ``'option'`` or ``'argument'``.
- """
- def __init__(
- self,
- message: t.Optional[str] = None,
- ctx: t.Optional["Context"] = None,
- param: t.Optional["Parameter"] = None,
- param_hint: t.Optional[str] = None,
- param_type: t.Optional[str] = None,
- ) -> None:
- super().__init__(message or "", ctx, param, param_hint)
- self.param_type = param_type
- def format_message(self) -> str:
- if self.param_hint is not None:
- param_hint: t.Optional[str] = self.param_hint
- elif self.param is not None:
- param_hint = self.param.get_error_hint(self.ctx) # type: ignore
- else:
- param_hint = None
- param_hint = _join_param_hints(param_hint)
- param_hint = f" {param_hint}" if param_hint else ""
- param_type = self.param_type
- if param_type is None and self.param is not None:
- param_type = self.param.param_type_name
- msg = self.message
- if self.param is not None:
- msg_extra = self.param.type.get_missing_message(self.param)
- if msg_extra:
- if msg:
- msg += f". {msg_extra}"
- else:
- msg = msg_extra
- msg = f" {msg}" if msg else ""
- # Translate param_type for known types.
- if param_type == "argument":
- missing = _("Missing argument")
- elif param_type == "option":
- missing = _("Missing option")
- elif param_type == "parameter":
- missing = _("Missing parameter")
- else:
- missing = _("Missing {param_type}").format(param_type=param_type)
- return f"{missing}{param_hint}.{msg}"
- def __str__(self) -> str:
- if not self.message:
- param_name = self.param.name if self.param else None
- return _("Missing parameter: {param_name}").format(param_name=param_name)
- else:
- return self.message
- class NoSuchOption(UsageError):
- """Raised if click attempted to handle an option that does not
- exist.
- .. versionadded:: 4.0
- """
- def __init__(
- self,
- option_name: str,
- message: t.Optional[str] = None,
- possibilities: t.Optional[t.Sequence[str]] = None,
- ctx: t.Optional["Context"] = None,
- ) -> None:
- if message is None:
- message = _("No such option: {name}").format(name=option_name)
- super().__init__(message, ctx)
- self.option_name = option_name
- self.possibilities = possibilities
- def format_message(self) -> str:
- if not self.possibilities:
- return self.message
- possibility_str = ", ".join(sorted(self.possibilities))
- suggest = ngettext(
- "Did you mean {possibility}?",
- "(Possible options: {possibilities})",
- len(self.possibilities),
- ).format(possibility=possibility_str, possibilities=possibility_str)
- return f"{self.message} {suggest}"
- class BadOptionUsage(UsageError):
- """Raised if an option is generally supplied but the use of the option
- was incorrect. This is for instance raised if the number of arguments
- for an option is not correct.
- .. versionadded:: 4.0
- :param option_name: the name of the option being used incorrectly.
- """
- def __init__(
- self, option_name: str, message: str, ctx: t.Optional["Context"] = None
- ) -> None:
- super().__init__(message, ctx)
- self.option_name = option_name
- class BadArgumentUsage(UsageError):
- """Raised if an argument is generally supplied but the use of the argument
- was incorrect. This is for instance raised if the number of values
- for an argument is not correct.
- .. versionadded:: 6.0
- """
- class FileError(ClickException):
- """Raised if a file cannot be opened."""
- def __init__(self, filename: str, hint: t.Optional[str] = None) -> None:
- if hint is None:
- hint = _("unknown error")
- super().__init__(hint)
- self.ui_filename: str = format_filename(filename)
- self.filename = filename
- def format_message(self) -> str:
- return _("Could not open file {filename!r}: {message}").format(
- filename=self.ui_filename, message=self.message
- )
- class Abort(RuntimeError):
- """An internal signalling exception that signals Click to abort."""
- class Exit(RuntimeError):
- """An exception that indicates that the application should exit with some
- status code.
- :param code: the status code to exit with.
- """
- __slots__ = ("exit_code",)
- def __init__(self, code: int = 0) -> None:
- self.exit_code: int = code
|