Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions typer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
from shutil import get_terminal_size as get_terminal_size

from . import colors as colors
from ._click.exceptions import Abort as Abort
from ._click.exceptions import BadParameter as BadParameter
from ._click.exceptions import Exit as Exit
from ._click.termui import confirm as confirm
from ._click.termui import getchar as getchar
from ._click.termui import progressbar as progressbar
Expand All @@ -19,6 +17,9 @@
from ._click.utils import get_app_dir as get_app_dir
from ._click.utils import get_binary_stream as get_binary_stream
from ._click.utils import get_text_stream as get_text_stream
from .exceptions import Abort as Abort
from .exceptions import Exit as Exit
from .exceptions import TyperException as TyperException
from .main import Typer as Typer
from .main import launch as launch
from .main import run as run
Expand Down
10 changes: 2 additions & 8 deletions typer/_click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,9 @@
overload,
)

from ..exceptions import Abort, Exit
from . import types
from .exceptions import (
Abort,
BadParameter,
Exit,
MissingParameter,
NoArgsIsHelpError,
UsageError,
)
from .exceptions import BadParameter, MissingParameter, NoArgsIsHelpError, UsageError
from .formatting import HelpFormatter
from .globals import pop_context, push_context
from .parser import _OptionParser
Expand Down
27 changes: 2 additions & 25 deletions typer/_click/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from collections.abc import Sequence
from typing import IO, TYPE_CHECKING, Any, Union

from ..exceptions import TyperException
from ._compat import get_text_stderr
from .globals import resolve_color_default
from .utils import echo, format_filename
Expand All @@ -16,23 +17,14 @@ def _join_param_hints(param_hint: Sequence[str] | str | None) -> str | None:
return param_hint


class ClickException(Exception):
class ClickException(TyperException):
"""An exception that Click can handle and show to the user."""

exit_code = 1

def __init__(self, message: str) -> None:
super().__init__(message)
# The context will be removed by the time we print the message, so cache
# the color settings here to be used later on (in `show`)
self.show_color: bool | None = resolve_color_default()
self.message = message

def format_message(self) -> str:
return self.message

def __str__(self) -> str:
return self.message

def show(self, file: IO[Any] | None = None) -> None:
if file is None:
Expand Down Expand Up @@ -243,18 +235,3 @@ def __init__(self, filename: str, hint: str | None = None) -> None:

def format_message(self) -> str:
return f"Could not open file {self.ui_filename!r}: {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.
"""

__slots__ = ("exit_code",)

def __init__(self, code: int = 0) -> None:
self.exit_code: int = code
3 changes: 2 additions & 1 deletion typer/_click/termui.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from contextlib import AbstractContextManager
from typing import IO, TYPE_CHECKING, Any, AnyStr, TextIO, TypeVar, overload

from .exceptions import Abort, UsageError
from ..exceptions import Abort
from .exceptions import UsageError
from .globals import resolve_color_default
from .types import ParamType, convert_type
from .utils import LazyFile, echo
Expand Down
9 changes: 5 additions & 4 deletions typer/_completion_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from . import _click
from ._click.globals import get_current_context
from .exceptions import Exit


class Shells(str, Enum):
Expand Down Expand Up @@ -81,7 +82,7 @@ def get_completion_script(*, prog_name: str, complete_var: str, shell: str) -> s
script = _completion_scripts.get(shell)
if script is None:
_click.echo(f"Shell {shell} not supported.", err=True)
raise _click.exceptions.Exit(1)
raise Exit(1)
return (
script
% {
Expand Down Expand Up @@ -175,7 +176,7 @@ def install_powershell(*, prog_name: str, complete_var: str, shell: str) -> Path
)
if result.returncode != 0: # pragma: no cover
_click.echo("Couldn't get PowerShell user profile", err=True)
raise _click.exceptions.Exit(result.returncode)
raise Exit(result.returncode)
path_str = ""
if isinstance(result.stdout, str): # pragma: no cover
path_str = result.stdout
Expand All @@ -188,7 +189,7 @@ def install_powershell(*, prog_name: str, complete_var: str, shell: str) -> Path
pass
if not path_str: # pragma: no cover
_click.echo("Couldn't decode the path automatically", err=True)
raise _click.exceptions.Exit(1)
raise Exit(1)
path_obj = Path(path_str.strip())
parent_dir: Path = path_obj.parent
parent_dir.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -234,7 +235,7 @@ def install(
return shell, installed_path
else:
_click.echo(f"Shell {shell} is not supported.")
raise _click.exceptions.Exit(1)
raise Exit(1)


def _get_shell_name() -> str | None:
Expand Down
18 changes: 6 additions & 12 deletions typer/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from ._click.parser import _OptionParser
from ._click.shell_completion import CompletionItem
from ._typing import Literal
from .exceptions import Abort, Exit
from .utils import parse_boolean_env_var

MarkupMode = Literal["markdown", "rich", None]
Expand Down Expand Up @@ -165,13 +166,10 @@ def _main(
rich_markup_mode: MarkupMode = DEFAULT_MARKUP_MODE,
**extra: Any,
) -> Any:
# Typer override, duplicated from _click.main() to handle custom rich exceptions
# Verify that the environment is configured correctly, or reject
# further execution to avoid a broken script.
# Originally copied from _click.main(), adopted to handle custom rich exceptions etc
if args is None:
args = sys.argv[1:]

# Covered in Click tests
if os.name == "nt" and windows_expand_args: # pragma: no cover
args = _click.utils._expand_args(args)
else:
Expand Down Expand Up @@ -199,20 +197,18 @@ def _main(
ctx.exit()
except EOFError as e:
_click.echo(file=sys.stderr)
raise _click.exceptions.Abort() from e
raise Abort() from e
except KeyboardInterrupt as e:
raise _click.exceptions.Exit(130) from e
raise Exit(130) from e
except _click.exceptions.ClickException as e:
if not standalone_mode:
raise
# Typer override
if HAS_RICH and rich_markup_mode is not None:
from . import rich_utils

rich_utils.rich_format_error(e)
else:
e.show()
# Typer override end
sys.exit(e.exit_code)
except OSError as e:
if e.errno == errno.EPIPE:
Expand All @@ -221,7 +217,7 @@ def _main(
sys.exit(1)
else:
raise
except _click.exceptions.Exit as e:
except Exit as e:
if standalone_mode:
sys.exit(e.exit_code)
else:
Expand All @@ -234,17 +230,15 @@ def _main(
# `ctx.exit(1)` and to `return 1`, the caller won't be able to
# tell the difference between the two
return e.exit_code
except _click.exceptions.Abort:
except Abort:
if not standalone_mode:
raise
# Typer override
if HAS_RICH and rich_markup_mode is not None:
from . import rich_utils

rich_utils.rich_abort_error()
else:
_click.echo(_("Aborted!"), file=sys.stderr)
# Typer override end
sys.exit(1)


Expand Down
29 changes: 29 additions & 0 deletions typer/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class TyperException(Exception):
"""A Typer-specific exception"""

exit_code = 1

def __init__(self, message: str) -> None:
super().__init__(message)
self.message = message

def __str__(self) -> str:
return self.message

def format_message(self) -> str:
return self.message


class Abort(RuntimeError):
"""An internal signalling exception that signals Typer to abort."""


class Exit(RuntimeError):
"""An exception that indicates that the application should exit with some
status code.
"""

__slots__ = ("exit_code",)

def __init__(self, code: int = 0) -> None:
self.exit_code: int = code
Loading