Visitar URL original
[ty] Detect invalid attempts to subclass `Protocol[]` and `Generic[]` simultaneously by AlexWaygood · Pull Request #22948 · astral-sh/ruff · GitHub
Skip to content

[ty] Detect invalid attempts to subclass Protocol[] and Generic[] simultaneously - #22948

Merged
AlexWaygood merged 1 commit into
mainfrom
alex/generic-protocol-contexts
Jan 29, 2026
Merged

AlexWaygood merged 1 commit into
mainfrom
alex/generic-protocol-contexts

Conversation

@AlexWaygood

@AlexWaygood AlexWaygood commented Jan 29, 2026 •

Copy link
Copy Markdown
Member

Summary

The typing spec states that a class like this is invalid:

from typing import *

T = TypeVar("T")

class Foo(Protocol[T], Generic[T]): ...

This PR adds the necessary logic so that we detect (and, if possible, offer an unsafe autofix for) this error.

If you want to make a generic protocol, you have three alternative spellings of the above class at your disposal:

from typing import *

T = TypeVar("T")

class Foo[T](Protocol): ...
class Foo(Protocol, Generic[T]): ...
class Foo(Protocol[T]): ...

Test Plan

snapshots and mdtests

@AlexWaygood AlexWaygood added the ty The ty type checker label Jan 29, 2026
@astral-sh-bot

astral-sh-bot Bot commented Jan 29, 2026

Copy link
Copy Markdown

Typing conformance results improved 🎉

The percentage of diagnostics emitted that were expected errors increased from 80.00% to 80.02%. The percentage of expected errors that received a diagnostic increased from 71.42% to 71.51%.

Summary

Metric Old New Diff Outcome
True Positives 772 773 +1 ⏫ (✅)
False Positives 193 193 +0
False Negatives 309 308 -1 ⏬ (✅)
Total Diagnostics 965 966 +1 ⏫
Precision 80.00% 80.02% +0.02% ⏫ (✅)
Recall 71.42% 71.51% +0.09% ⏫ (✅)

True positives added

Details
Location Name Message
protocols_generic.py:44:14 invalid-generic-class Cannot both inherit from subscripted Protocol and subscripted Generic

@astral-sh-bot

astral-sh-bot Bot commented Jan 29, 2026

Copy link
Copy Markdown

mypy_primer results

Changes were detected when running on open source projects
prefect (https://github.com/PrefectHQ/prefect)
- src/integrations/prefect-dbt/prefect_dbt/core/settings.py:94:28: error[invalid-assignment] Object of type `dict[Any, Any] | int | dict[str, Any] | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
- src/integrations/prefect-dbt/prefect_dbt/core/settings.py:99:28: error[invalid-assignment] Object of type `int | dict[Any, Any] | float | ... omitted 3 union elements` is not assignable to `dict[str, Any]`
- src/prefect/cli/deploy/_core.py:86:21: error[invalid-assignment] Object of type `dict[Any, Any] | int | dict[str, Any] | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
- src/prefect/cli/deploy/_core.py:87:21: error[invalid-assignment] Object of type `int | dict[Any, Any] | float | ... omitted 3 union elements` is not assignable to `dict[str, Any]`
- src/prefect/deployments/runner.py:997:70: warning[possibly-missing-attribute] Attribute `__name__` may be missing on object of type `Unknown | (((...) -> Any) & ((*args: object, **kwargs: object) -> object))`
+ src/prefect/deployments/runner.py:997:70: warning[possibly-missing-attribute] Attribute `__name__` may be missing on object of type `Unknown | ((...) -> Any)`
- src/prefect/deployments/steps/core.py:137:38: error[invalid-argument-type] Argument is incorrect: Argument type `dict[Any, Any] | int | dict[str, Any] | ... omitted 4 union elements` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
+ src/prefect/flow_engine.py:989:32: error[invalid-await] `Unknown | R@FlowRunEngine | Coroutine[Any, Any, R@FlowRunEngine]` is not awaitable
+ src/prefect/flow_engine.py:1580:24: error[invalid-await] `Unknown | R@AsyncFlowRunEngine | Coroutine[Any, Any, R@AsyncFlowRunEngine]` is not awaitable
+ src/prefect/flow_engine.py:1661:43: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Unknown | R@run_generator_flow_sync`
+ src/prefect/flow_engine.py:1669:21: warning[possibly-missing-attribute] Attribute `throw` may be missing on object of type `Unknown | R@run_generator_flow_sync`
+ src/prefect/flow_engine.py:1703:44: warning[possibly-missing-attribute] Attribute `__anext__` may be missing on object of type `Unknown | R@run_generator_flow_async`
+ src/prefect/flow_engine.py:1710:25: warning[possibly-missing-attribute] Attribute `throw` may be missing on object of type `Unknown | R@run_generator_flow_async`
- src/prefect/flows.py:285:34: error[unresolved-attribute] Object of type `((**P@Flow) -> R@Flow) & ((*args: object, **kwargs: object) -> object)` has no attribute `__name__`
+ src/prefect/flows.py:285:34: error[unresolved-attribute] Object of type `(**P@Flow) -> R@Flow` has no attribute `__name__`
- src/prefect/flows.py:403:68: error[unresolved-attribute] Object of type `((**P@Flow) -> R@Flow) & ((*args: object, **kwargs: object) -> object)` has no attribute `__name__`
+ src/prefect/flows.py:403:68: error[unresolved-attribute] Object of type `(**P@Flow) -> R@Flow` has no attribute `__name__`
- src/prefect/flows.py:1877:53: warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ src/prefect/flows.py:1937:21: error[no-matching-overload] No overload of function `run_coro_as_sync` matches arguments
- src/prefect/utilities/templating.py:320:13: error[invalid-assignment] Invalid subscript assignment with key of type `object` and value of type `Unknown | int | dict[str, Any] | ... omitted 4 union elements` on object of type `dict[str, Any]`
+ src/prefect/utilities/templating.py:320:13: error[invalid-assignment] Invalid subscript assignment with key of type `object` and value of type `Unknown | dict[str, Any]` on object of type `dict[str, Any]`
- src/prefect/utilities/templating.py:323:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_block_document_references | dict[str, Any]`, found `list[Unknown | int | dict[str, Any] | ... omitted 4 union elements]`
+ src/prefect/utilities/templating.py:323:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_block_document_references | dict[str, Any]`, found `list[Unknown | dict[str, Any]]`
- src/prefect/utilities/templating.py:437:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `dict[object, Unknown | int | float | ... omitted 4 union elements]`
+ src/prefect/utilities/templating.py:437:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `dict[object, Unknown]`
- src/prefect/utilities/templating.py:442:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `list[Unknown | int | float | ... omitted 4 union elements]`
+ src/prefect/utilities/templating.py:442:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `list[Unknown]`
+ src/prefect/workers/base.py:232:13: error[invalid-argument-type] Argument is incorrect: Argument type `str | dict[str, Any]` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
- src/prefect/workers/base.py:232:13: error[invalid-argument-type] Argument is incorrect: Argument type `str | int | dict[str, Any] | ... omitted 3 union elements` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
- src/prefect/workers/base.py:234:20: error[invalid-argument-type] Argument expression after ** must be a mapping type: Found `int | Unknown | float | ... omitted 4 union elements`

scikit-build-core (https://github.com/scikit-build/scikit-build-core)
- src/scikit_build_core/build/wheel.py:99:20: error[no-matching-overload] No overload of bound method `__init__` matches arguments
- Found 47 diagnostics
+ Found 46 diagnostics

core (https://github.com/home-assistant/core)
+ homeassistant/util/variance.py:47:12: error[invalid-return-type] Return type does not match returned value: expected `(**_P@ignore_variance) -> _R@ignore_variance`, found `_Wrapped[_P@ignore_variance, int | _R@ignore_variance | float | datetime, _P@ignore_variance, _R@ignore_variance | int | float | datetime]`
- Found 14512 diagnostics
+ Found 14513 diagnostics

No memory usage changes detected ✅

@AlexWaygood
AlexWaygood marked this pull request as ready for review January 29, 2026 17:31
@AlexWaygood
AlexWaygood merged commit 340aae9 into main Jan 29, 2026
50 checks passed
@AlexWaygood
AlexWaygood deleted the alex/generic-protocol-contexts branch January 29, 2026 22:27
carljm added a commit that referenced this pull request Jan 30, 2026
* main: (76 commits)
  [ty] Improve the check for `NewType`s with generic bases (#22961)
  [ty] Ban legacy `TypeVar` bounds or constraints from containing type variables (#22949)
  Bump the typing conformance suite pin (#22960)
  [ty] Emit an error if a TypeVarTuple is used to subscript `Generic` or `Protocol` without being unpacked (#22952)
  [ty] Reduce false positives when subscripting classes generic over `TypeVarTuple`s (#22950)
  [ty] Detect invalid attempts to subclass `Protocol[]` and `Generic[]` simultaneously (#22948)
  Fix suppression indentation matching (#22903)
  Remove hidden `--output-format` warning (#22944)
  [ty] Validate signatures of dataclass `__post_init__` methods (#22730)
  [ty] extend special-cased `numbers` diagnostic to `invalid-argument-type` errors (#22938)
  [ty] Avoid false positive for `not-iterable` with no-positive intersection types (#22089)
  [ty] Preserve pure negation types in descriptor protocol (#22907)
  [ty] add special-case diagnostic for `numbers` module (#22931)
  [ty] Move the location of more `invalid-overload` diagnostics (#22933)
  [ty] Fix unary and comparison operators for TypeVars with union bounds (#22925)
  [ty] Rule Selection: ignore/warn/select all rules (unless subsequently overriden) (#22832)
  [ty] Fix TypedDict construction from existing TypedDict values (#22904)
  [ty] fix bug in string annotations and clean up diagnostics (#22913)
  [ty] Improve support for goto-type, goto-declaration, hover, and highlighting of string annotations (#22878)
  [ty] Rename old typing imports to new on `unresolved-reference`. (#22827)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty The ty type checker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants