B042: don't count a parameterized generic base as an exception super class - #578
Merged
Merged
Conversation
…class A class named like an exception whose only bases are generics such as ContextManager[T] is not an exception. A generic base named like an exception, such as MyError[int], now counts. Refs PyCQA#538.
cooperlees
approved these changes
Sep 27, 2026
cooperlees
left a comment
Collaborator
There was a problem hiding this comment.
This is muse (muse-spark, posting on behalf of @cooperlees via his coding agent).
Reviewed the diff and verified locally: checked out the PR head (a0859da) and ran the full suite in an isolated venv in /tmp — 83 passed, including the new b042.py eval cases.
What I checked:
FailOnException(typing.ContextManager[int])/FailOnError(typing.Iterator[int]): correctly no longer flagged — the only bases areast.Subscript, soconcrete_basesis empty and the unwrappedAttributebase doesn't match the exception-name heuristic. This fixes the false positive in #538.MyGenericError(typing.Iterator[int], Anything): still flagged via the non-generic base — good, preserves the "base may be an exception under another name" behavior.Anything5(MyError[int]): now flagged by unwrapping theSubscripttoName(MyError)— a genuine improvement over main.- Plain cases (
class FooError(Exception), bare-name bases) are untouched; the change is narrowly scoped toast.Subscriptbases.
One non-blocking observation: an attribute-style generic base like typing.MyError[int] still won't match since only ast.Name is checked after unwrapping — but that's a pre-existing gap (non-subscripted Attribute bases were never matched either), so keeping this PR narrow is the right call.
Changelog entry under UNRELEASED looks good. Approving.
Collaborator
|
Many thanks ! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #538.
B042 treats a class as an exception when its name looks like one and it has any base at all, so
class FailOnException(ContextManager[T])from the issue is checked like an exception class. Resolving real inheritance fromBaseExceptionis out of reach for a single-file check, so this takes the narrow, syntactic part of it: a parameterized generic base, such asContextManager[T]ortyping.Iterator[int], no longer counts as the super class that makes a class named...Exceptionor...Erroran exception. A generic base whose own name looks like an exception, such asMyError[int], is now recognised, which it wasn't before because only plain names were checked.Everything else is unchanged. A class named like an exception with any non-generic base is still checked, since that base may be an exception under another name, and bases named like exceptions are matched as before.
New cases in
tests/eval_files/b042.py:FailOnException(typing.ContextManager[int])andFailOnError(typing.Iterator[int]): no longer reported. Both are reported onmain;MyGenericError(typing.Iterator[int], Anything): still reported, through the non-generic base;Anything5(MyError[int]): now reported.mainmisses it.On
main, the eval test fails on exactly these lines. With the change,pytest tests: 81 passed, 2 skipped. There is a changelog entry under UNRELEASED.