Skip to content

♻️ Create exceptions module and TyperException base class - #1942

Merged
tiangolo merged 2 commits into
fastapi:masterfrom
svlandeg:feat/typer_exception
Aug 28, 2026
Merged

tiangolo merged 2 commits into
fastapi:masterfrom
svlandeg:feat/typer_exception

Conversation

@svlandeg

@svlandeg svlandeg commented Aug 28, 2026 •

Copy link
Copy Markdown
Member

Pull Request

Discussion: #1832

Description

Continuing from the original Click vendoring, this PR introduces a new base class TyperException that all other exception classes inherit from. This is to replace a check for ClickException (which some users may want to do, cf discusssion thread) which is currently in the private module _click and shouldn't be used/imported directly. The "old" Click exception hierarchy will be refactored in the near future and shouldn't be used directly either.

Abort and Exit have always been part of the public Typer API and as such they are moved into the new Typer module.

AI Disclaimer

No AI used, just good old fashioned human communication & thinking. Refreshing 😎

Checklist

  • This PR links to a GitHub Discussion for the proposed code change.
  • Coverage stays at 100%.
  • The documentation explains the change if needed.

@tiangolo tiangolo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thank you! 🚀

This will be available in Typer 0.27.2 in the next few hours.

@tiangolo
tiangolo merged commit 41dea8f into fastapi:master Aug 28, 2026
23 checks passed
@svlandeg
svlandeg deleted the feat/typer_exception branch August 28, 2026 19:26
ksparavec added a commit to devitops-com/aiagent that referenced this pull request Sep 14, 2026
Typer 0.27.2 moved Abort out of typer._click.exceptions into the new
typer.exceptions module (fastapi/typer#1942). cli/app.py imported Abort
and UsageError from the vendored module in a single try block, so the
relocation raised ImportError and dropped the vendored UsageError from
_USAGE_ERRORS as collateral damage. Typer raises its own vendored
UsageError, not the stdlib Click one, so every usage error — unknown
command, missing required argument — then escaped main() as an unhandled
traceback, and exited 0 while doing it.

Take Abort from the public typer.Abort instead: it is re-exported at the
Typer top level across the supported range, so it survives the class
moving between internal modules. UsageError is not top-level exported and
stays in the vendored Click module, so it keeps its guarded import — but
in a try of its own, so one class moving can never again take the other
down with it.

No test caught this because every CLI test drives `app` through
CliRunner and so never reaches main()'s handlers. Add one that runs the
module entry point end to end and asserts help + exit 2 with no
traceback; confirmed it fails against the pre-fix code.

Also rewrite the metavar assertion: Typer 0.27.0 changed metavar
rendering (breaking, fastapi/typer#1863), so the usage line reads
"{skill}" rather than "SKILL". Both spellings are live here — the venv
resolves Typer from the floors while the bundle installs the lock — so
match the usage line case-insensitively. Scoping to that line also fixes
a false pass: `run` prints the word SKILL in an unrelated --route
description, so the old whole-output check passed even when the metavar
itself had gone.

Latent for any fresh install; unrelated to the Python version.
make check + make test green (178 passed, 90% coverage).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants