Skip to content

[ty] Support class decorators#25091

Merged
charliermarsh merged 17 commits into
mainfrom
charlie/class-decorators
May 19, 2026
Merged

[ty] Support class decorators#25091
charliermarsh merged 17 commits into
mainfrom
charlie/class-decorators

Conversation

@charliermarsh
Copy link
Copy Markdown
Member

@charliermarsh charliermarsh commented May 10, 2026

Summary

This PR adds support for class decorator return types, following Carl's comment in astral-sh/ty#2604 (comment): assume unannotated decorators preserve the class binding when their result is otherwise Unknown, but support explicit spelling of an annotated decorator return type.

In more detail, the rule is roughly:

  • If applying the decorator gives a non-Unknown result...
    • And that result still retains the original class object, we preserve the class.
    • Otherwise, we replace the public binding with that result.
  • If applying the decorator gives an Unknown result:
    • We fall back to the decorator’s own shape.
    • Unannotated function/method decorators are treated as "identity-preserving", so we keep the current class binding.
    • Decorators with an explicit return annotation are not, so we do not preserve the binding.

As a concrete example, an unannotated decorator like the personify example from #2604 is still treated as preserving the original class (since we don't have a static replacement type):

def personify(cls):
    class Wrapped(cls):
        full_name: str

        def set_full_name(self, full_name: str) -> None:
            self.full_name = full_name

    return Wrapped

@personify
class Animal: ...

reveal_type(Animal)  # <class 'Animal'>
Animal().set_full_name("John")  # error: unresolved attribute

But if the decorator has an explicit return type, we use it for the public class binding:

class WrapBackend:
    def __init__(self, cls: type[object]) -> None: ...

    def get(self, key: str) -> bytes | None: ...

@WrapBackend
class CacheClient: ...

reveal_type(CacheClient)  # WrapBackend
reveal_type(CacheClient.get("x"))  # bytes | None

This gives us stable behavior for common untyped identity decorators while leaving the advanced and unsound returned-class inference path out of scope...

Closes astral-sh/ty#143.

@astral-sh-bot astral-sh-bot Bot added the ty Multi-file analysis & type inference label May 10, 2026
@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented May 10, 2026

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 89.36%. The percentage of expected errors that received a diagnostic held steady at 85.49%. The number of fully passing files held steady at 88/134.

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented May 10, 2026

Memory usage report

Summary

Project Old New Diff Outcome
flake8 47.42MB 47.42MB -
sphinx 256.15MB 256.15MB -0.00% (128.00B) ⬇️
prefect 687.24MB 687.21MB -0.00% (33.71kB) ⬇️
trio 115.44MB 114.28MB -1.01% (1.16MB) ⬇️

Significant changes

Click to expand detailed breakdown

sphinx

Name Old New Diff Outcome
infer_definition_types 21.98MB 21.98MB +0.01% (1.18kB) ⬇️
StaticClassLiteral<'db>::decorators_ 121.11kB 121.89kB +0.64% (792.00B) ⬇️
all_negative_narrowing_constraints_for_expression 2.34MB 2.34MB -0.03% (696.00B) ⬇️
IntersectionType 486.07kB 485.70kB -0.08% (384.00B) ⬇️
is_redundant_with_impl 923.46kB 923.16kB -0.03% (312.00B) ⬇️
is_redundant_with_impl::interned_arguments 1.07MB 1.07MB -0.02% (264.00B) ⬇️
infer_expression_types_impl 18.50MB 18.50MB -0.00% (204.00B) ⬇️
IntersectionType<'db>::from_two_elements_ 31.64kB 31.47kB -0.54% (176.00B) ⬇️
IntersectionType<'db>::from_two_elements_::interned_arguments 33.43kB 33.34kB -0.26% (88.00B) ⬇️

prefect

Name Old New Diff Outcome
StaticClassLiteral<'db>::decorators_ 476.58kB 513.04kB +7.65% (36.46kB) ⬇️
infer_definition_types 81.72MB 81.75MB +0.03% (29.23kB) ⬇️
Type<'db>::class_member_with_policy_ 17.77MB 17.75MB -0.13% (24.09kB) ⬇️
Type<'db>::member_lookup_with_policy_ 16.47MB 16.45MB -0.13% (22.00kB) ⬇️
StaticClassLiteral<'db>::explicit_bases_ 610.06kB 630.30kB +3.32% (20.24kB) ⬇️
StaticClassLiteral<'db>::inherited_legacy_generic_context_ 476.08kB 495.67kB +4.11% (19.59kB) ⬇️
StaticClassLiteral<'db>::try_metaclass_ 1.41MB 1.42MB +1.12% (16.20kB) ⬇️
StaticClassLiteral<'db>::try_mro_ 4.46MB 4.48MB +0.32% (14.81kB) ⬇️
Type<'db>::try_call_dunder_get_ 11.13MB 11.12MB -0.13% (14.26kB) ⬇️
enum_metadata 2.93MB 2.94MB +0.37% (11.11kB) ⬇️
Type<'db>::class_member_with_policy_::interned_arguments 10.33MB 10.32MB -0.10% (11.07kB) ⬇️
StaticClassLiteral<'db>::implicit_attribute_inner_ 6.88MB 6.87MB -0.14% (9.58kB) ⬇️
FunctionType<'db>::signature_ 4.27MB 4.26MB -0.22% (9.43kB) ⬇️
StaticClassLiteral<'db>::implicit_attribute_inner_::interned_arguments 5.62MB 5.61MB -0.14% (8.25kB) ⬇️
Type<'db>::member_lookup_with_policy_::interned_arguments 6.24MB 6.23MB -0.12% (7.72kB) ⬇️
... 52 more

trio

Name Old New Diff Outcome
check_file_impl 1.69MB 1.55MB -8.26% (143.27kB) ⬇️
Type<'db>::class_member_with_policy_ 2.05MB 1.94MB -5.61% (117.79kB) ⬇️
infer_expression_types_impl 6.21MB 6.10MB -1.81% (115.29kB) ⬇️
Type<'db>::member_lookup_with_policy_ 1.95MB 1.87MB -4.07% (81.22kB) ⬇️
Type<'db>::try_call_dunder_get_ 1.34MB 1.27MB -5.67% (77.97kB) ⬇️
Type<'db>::class_member_with_policy_::interned_arguments 1.13MB 1.07MB -5.33% (61.65kB) ⬇️
Type<'db>::apply_specialization_::interned_arguments 630.62kB 581.72kB -7.76% (48.91kB) ⬇️
Type<'db>::apply_specialization_ 620.42kB 574.20kB -7.45% (46.22kB) ⬇️
FunctionType<'db>::signature_ 1.11MB 1.07MB -3.31% (37.62kB) ⬇️
infer_scope_types_impl 4.02MB 3.99MB -0.86% (35.27kB) ⬇️
FunctionType 1.53MB 1.49MB -2.22% (34.73kB) ⬇️
StaticClassLiteral<'db>::decorators_ 44.79kB 77.19kB +72.35% (32.40kB) ⬇️
is_redundant_with_impl 214.88kB 183.38kB -14.66% (31.50kB) ⬇️
is_redundant_with_impl::interned_arguments 237.53kB 206.25kB -13.17% (31.28kB) ⬇️
Specialization 457.05kB 426.80kB -6.62% (30.25kB) ⬇️
... 74 more

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented May 10, 2026

ecosystem-analyzer results

Lint rule Added Removed Changed
unknown-argument 0 350 142
invalid-type-form 115 140 3
invalid-argument-type 11 222 14
unresolved-attribute 30 61 54
unsupported-operator 0 96 8
no-matching-overload 0 71 0
unused-type-ignore-comment 31 10 0
missing-argument 0 38 0
invalid-assignment 3 13 12
invalid-base 0 26 0
too-many-positional-arguments 0 10 0
unsupported-base 8 2 0
invalid-method-override 0 9 0
invalid-return-type 1 5 2
unbound-type-variable 3 0 0
not-iterable 0 2 0
not-subscriptable 2 0 0
redundant-cast 0 2 0
invalid-yield 0 1 0
Total 204 1,058 235

Showing a random sample of 368 of 1497 changes. See the HTML report for the full diff.

Raw diff sample (368 of 1497 changes)
attrs (https://github.com/python-attrs/attrs)
- tests/test_make.py:1178:15 error[too-many-positional-arguments] Too many positional arguments: expected 0, got 1
- tests/test_make.py:1178:18 error[unknown-argument] Argument `y` does not match any known parameter

core (https://github.com/home-assistant/core)
+ homeassistant/components/stream/hls.py:416:16 error[invalid-type-form] Variable of type `type[StreamOutput]` is not allowed in a type expression
+ homeassistant/auth/providers/homeassistant.py:37:48 error[invalid-type-form] Variable of type `type[AuthProvider]` is not allowed in a return type annotation
+ homeassistant/auth/providers/homeassistant.py:41:25 error[invalid-type-form] Variable of type `type[AuthProvider]` is not allowed in a type expression
+ homeassistant/auth/providers/homeassistant.py:410:31 error[invalid-type-form] Variable of type `type[AuthProvider]` is not allowed in a type expression
+ homeassistant/components/homekit/type_air_purifiers.py:73:19 warning[unsupported-base] Unsupported class base with type `type[HomeAccessory]`
+ homeassistant/components/homekit/type_sensors.py:260:29 warning[unsupported-base] Unsupported class base with type `type[HomeAccessory]`
+ homeassistant/scripts/auth.py:87:36 error[invalid-type-form] Variable of type `type[AuthProvider]` is not allowed in a parameter annotation
+ homeassistant/scripts/auth.py:104:36 error[invalid-type-form] Variable of type `type[AuthProvider]` is not allowed in a parameter annotation
+ homeassistant/scripts/auth.py:117:36 error[invalid-type-form] Variable of type `type[AuthProvider]` is not allowed in a parameter annotation

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- tests/contrib/ray/jobs/actor_without_init.py:18:15 error[unresolved-attribute] Class `Counter` has no attribute `remote`
- tests/contrib/ray/test_ray.py:116:25 error[unresolved-attribute] Class `Counter` has no attribute `remote`

discord.py (https://github.com/Rapptz/discord.py)
- discord/app_commands/tree.py:1011:27 error[unresolved-attribute] Object of type `((Interaction[Any], Member, /) -> Coroutine[Any, Any, Any]) | ((Interaction[Any], User, /) -> Coroutine[Any, Any, Any]) | ((Interaction[Any], Message, /) -> Coroutine[Any, Any, Any])` has no attribute `__name__`
+ discord/app_commands/tree.py:1011:27 error[unresolved-attribute] Object of type `((Interaction[Any], Member, /) -> Coroutine[Any, Any, Any]) | ((Interaction[Any], User, /) -> Coroutine[Any, Any, Any]) | ((Interaction[Any], @Todo, /) -> Coroutine[Any, Any, Any])` has no attribute `__name__`
+ discord/ext/commands/converter.py:328:28 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ discord/interactions.py:508:80 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ discord/interactions.py:616:85 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/message.py:713:16 error[invalid-return-type] Return type does not match returned value: expected `Message | None`, found `(ConnectionState[Client] & ~AlwaysTruthy) | None | Message`
+ discord/message.py:1042:65 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive

graphql-core (https://github.com/graphql-python/graphql-core)
- tests/language/test_predicates.py:29:30 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
- tests/language/test_predicates.py:66:42 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
- tests/utilities/test_type_info.py:344:25 error[unknown-argument] Argument `alias` does not match any known parameter of `object.__init__`
- tests/utilities/test_type_info.py:345:25 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:430:13 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:431:13 error[unknown-argument] Argument `arguments` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:435:13 error[unknown-argument] Argument `directives` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:436:13 error[unknown-argument] Argument `selection_set` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:514:13 error[unknown-argument] Argument `type_condition` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:530:17 error[unknown-argument] Argument `type_condition` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:739:13 error[unknown-argument] Argument `description` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:740:13 error[unknown-argument] Argument `directives` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:812:13 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:815:13 error[unknown-argument] Argument `directives` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:839:13 error[unknown-argument] Argument `description` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:842:13 error[unknown-argument] Argument `default_value` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:918:13 error[unknown-argument] Argument `description` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:998:13 error[unknown-argument] Argument `interfaces` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:270:25 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:270:57 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:349:17 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:349:17 error[unknown-argument] Argument `name` does not match any known parameter
- src/graphql/language/parser.py:352:17 error[unknown-argument] Argument `selection_set` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:352:17 error[unknown-argument] Argument `selection_set` does not match any known parameter
- src/graphql/language/parser.py:359:13 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:359:13 error[unknown-argument] Argument `name` does not match any known parameter
- src/graphql/language/parser.py:361:13 error[unknown-argument] Argument `directives` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:361:13 error[unknown-argument] Argument `directives` does not match any known parameter
- src/graphql/language/parser.py:362:13 error[unknown-argument] Argument `selection_set` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:362:13 error[unknown-argument] Argument `selection_set` does not match any known parameter
- src/graphql/language/parser.py:400:29 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:400:53 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:458:17 error[unknown-argument] Argument `nullability_assertion` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:458:55 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:463:17 error[unknown-argument] Argument `nullability_assertion` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:463:57 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:467:17 error[unknown-argument] Argument `nullability_assertion` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:467:57 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:488:66 error[unknown-argument] Argument `loc` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:532:17 error[unknown-argument] Argument `selection_set` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:532:17 error[unknown-argument] Argument `selection_set` does not match any known parameter
- src/graphql/language/parser.py:615:29 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:615:54 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:621:56 error[unknown-argument] Argument `loc` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:629:37 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:629:49 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:673:13 error[unknown-argument] Argument `loc` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:673:13 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:685:34 error[unknown-argument] Argument `type` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:685:51 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:685:51 error[unknown-argument] Argument `loc` does not match any known parameter of `object.__init__`
- src/graphql/language/parser.py:689:36 error[unknown-argument] Argument `type` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:689:48 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:695:30 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:695:54 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:763:13 error[unknown-argument] Argument `description` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:763:13 error[unknown-argument] Argument `description` does not match any known parameter
- src/graphql/language/parser.py:766:13 error[unknown-argument] Argument `loc` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:766:13 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:782:13 error[unknown-argument] Argument `directives` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:782:13 error[unknown-argument] Argument `directives` does not match any known parameter
- src/graphql/language/parser.py:874:13 error[unknown-argument] Argument `description` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:874:13 error[unknown-argument] Argument `description` does not match any known parameter
- src/graphql/language/parser.py:900:13 error[unknown-argument] Argument `directives` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:900:13 error[unknown-argument] Argument `directives` does not match any known parameter
- src/graphql/language/parser.py:982:13 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:982:13 error[unknown-argument] Argument `name` does not match any known parameter
- src/graphql/language/parser.py:982:47 error[unknown-argument] Argument `loc` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:982:47 error[unknown-argument] Argument `loc` does not match any known parameter
- src/graphql/language/parser.py:1062:47 error[unknown-argument] Argument `fields` does not match any known parameter of `object.__init__`
+ src/graphql/language/parser.py:1062:62 error[unknown-argument] Argument `loc` does not match any known parameter
+ src/graphql/language/visitor.py:238:24 error[not-subscriptable] Cannot subscript object of type `_T@list` with no `__getitem__` method
+ src/graphql/language/visitor.py:238:24 error[not-subscriptable] Cannot subscript object of type `_T@list` with no `__getitem__` method
- src/graphql/type/definition.py:435:27 error[invalid-argument-type] Invalid argument to key "parse_literal" with declared type `((ValueNode, dict[str, Any] | None, /) -> Any) | None` on TypedDict `GraphQLScalarTypeKwargs`: value of type `None | (bound method Self@to_kwargs.parse_literal(node: ValueNode, variables: dict[str, Any] | None = None) -> Any) | (def parse_literal(self, node: ValueNode, variables: dict[str, Any] | None = None) -> Any)`
- src/graphql/utilities/ast_from_value.py:113:37 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- src/graphql/utilities/value_from_ast.py:137:46 error[invalid-argument-type] Argument to function `GraphQLScalarType.parse_literal` is incorrect: Expected `GraphQLScalarType`, found `ValueNode & ~AlwaysFalsy & ~VariableNode & ~NullValueNode`
- src/graphql/utilities/value_from_ast.py:139:46 error[invalid-argument-type] Argument to function `GraphQLScalarType.parse_literal` is incorrect: Expected `GraphQLScalarType`, found `ValueNode & ~AlwaysFalsy & ~VariableNode & ~NullValueNode`
- src/graphql/validation/rules/values_of_correct_type.py:165:48 error[invalid-argument-type] Argument to function `GraphQLScalarType.parse_literal` is incorrect: Expected `GraphQLScalarType`, found `ValueNode`
- tests/language/test_ast.py:169:31 error[unknown-argument] Argument `alpha` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:197:33 error[unknown-argument] Argument `selections` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:201:31 error[unknown-argument] Argument `alpha` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:216:32 error[unknown-argument] Argument `foo` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:216:43 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:223:25 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:234:41 error[unknown-argument] Argument `beta` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:243:32 error[unknown-argument] Argument `alpha` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:248:31 error[unknown-argument] Argument `alpha` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:260:40 error[unknown-argument] Argument `beta` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:266:40 error[unknown-argument] Argument `beta` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:267:44 error[unknown-argument] Argument `beta` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:275:32 error[unknown-argument] Argument `alpha` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:276:31 error[unknown-argument] Argument `alpha` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:176:40 error[unknown-argument] Argument `beta` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:182:40 error[unknown-argument] Argument `beta` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:204:31 error[unknown-argument] Argument `alpha` does not match any known parameter of `object.__init__`
+ tests/language/test_ast.py:204:48 error[unknown-argument] Argument `loc` does not match any known parameter
- tests/language/test_ast.py:204:40 error[unknown-argument] Argument `beta` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:212:43 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
- tests/language/test_ast.py:315:31 error[unknown-argument] Argument `alpha` does not match any known parameter of `object.__init__`
+ tests/language/test_ast.py:315:48 error[unknown-argument] Argument `loc` does not match any known parameter
- tests/language/test_ast.py:315:48 error[unknown-argument] Argument `loc` does not match any known parameter of `object.__init__`
+ tests/language/test_parser.py:655:51 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- tests/language/test_schema_parser.py:95:9 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
- tests/language/test_schema_parser.py:98:9 error[unknown-argument] Argument `directives` does not match any known parameter of `object.__init__`
- tests/language/test_schema_parser.py:124:9 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
- tests/language/test_schema_parser.py:126:9 error[unknown-argument] Argument `default_value` does not match any known parameter of `object.__init__`
- tests/language/test_schema_parser.py:129:9 error[unknown-argument] Argument `description` does not match any known parameter of `object.__init__`
- tests/language/test_schema_parser.py:112:9 error[unknown-argument] Argument `loc` does not match any known parameter of `object.__init__`
+ tests/language/test_schema_parser.py:112:9 error[unknown-argument] Argument `loc` does not match any known parameter
- tests/language/test_schema_parser.py:142:25 error[unknown-argument] Argument `type` does not match any known parameter of `object.__init__`
+ tests/language/test_schema_parser.py:142:37 error[unknown-argument] Argument `loc` does not match any known parameter
- tests/language/test_schema_parser.py:151:9 error[unknown-argument] Argument `directives` does not match any known parameter of `object.__init__`
+ tests/language/test_schema_parser.py:151:65 error[unknown-argument] Argument `loc` does not match any known parameter
- tests/language/test_schema_parser.py:166:37 error[unknown-argument] Argument `arguments` does not match any known parameter of `object.__init__`
- tests/language/test_schema_printer.py:13:55 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/language/test_visitor.py:321:21 error[unknown-argument] Argument `operation` does not match any known parameter of `object.__init__`
- tests/language/test_visitor.py:402:47 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/language/test_visitor.py:612:27 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/language/test_visitor.py:615:51 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/language/test_visitor.py:622:13 error[unknown-argument] Argument `selections` does not match any known parameter of `object.__init__`
- tests/language/test_visitor.py:631:35 error[unknown-argument] Argument `definitions` does not match any known parameter of `object.__init__`
- tests/language/test_visitor.py:324:21 error[unknown-argument] Argument `directives` does not match any known parameter of `object.__init__`
+ tests/language/test_visitor.py:324:21 error[unknown-argument] Argument `directives` does not match any known parameter
- tests/language/test_visitor.py:341:21 error[unknown-argument] Argument `selection_set` does not match any known parameter of `object.__init__`
+ tests/language/test_visitor.py:341:21 error[unknown-argument] Argument `selection_set` does not match any known parameter
- tests/type/test_definition.py:445:56 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
+ tests/type/test_definition.py:445:56 error[unknown-argument] Argument `name` does not match any known parameter
- tests/type/test_definition.py:676:44 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
+ tests/type/test_definition.py:676:44 error[unknown-argument] Argument `name` does not match any known parameter
- tests/type/test_directives.py:14:13 error[unknown-argument] Argument `locations` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:37:73 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:50:72 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:83:70 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:85:68 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:101:13 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:113:70 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:188:72 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:207:67 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:225:34 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:226:34 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:233:13 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:254:13 error[unknown-argument] Argument `fields` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:256:21 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
+ tests/utilities/test_ast_from_value.py:256:21 error[unknown-argument] Argument `name` does not match any known parameter
- tests/utilities/test_ast_from_value.py:259:49 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_from_value.py:267:38 error[unknown-argument] Argument `name` does not match any known parameter of `object.__init__`
+ tests/utilities/test_ast_from_value.py:267:38 error[unknown-argument] Argument `name` does not match any known parameter
- tests/utilities/test_ast_to_dict.py:7:25 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_to_dict.py:37:33 error[unknown-argument] Argument `value` does not match any known parameter of `object.__init__`
- tests/utilities/test_ast_to_dict.py:37:47 error[unknown-argument] Argument `arguments` does not match any known parameter of `object.__init__`
+ tests/utilities/test_ast_to_dict.py:28:43 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ tests/utilities/test_ast_to_dict.py:30:45 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ tests/utilities/test_ast_to_dict.py:32:41 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive

ibis (https://github.com/ibis-project/ibis)
- ibis/backends/athena/__init__.py:287:27 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, DataType]`
- ibis/backends/athena/__init__.py:583:13 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, DataType]`
- ibis/backends/bigquery/__init__.py:979:18 error[unsupported-operator] Operator `-` is not supported between two objects of type `Schema`
- ibis/backends/databricks/tests/test_datatypes.py:19:9 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, str | Struct]`
- ibis/backends/datafusion/__init__.py:544:13 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, DataType]`
- ibis/backends/duckdb/__init__.py:1726:13 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, DataType]`
- ibis/backends/exasol/__init__.py:274:13 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, DataType]`
- ibis/backends/flink/tests/test_ddl.py:262:9 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, Unknown]`
- ibis/backends/flink/tests/test_ddl.py:486:24 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, String | Int64 | Float64]`
- ibis/backends/impala/__init__.py:1202:27 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, Unknown]`
- ibis/backends/oracle/__init__.py:600:27 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, Unknown]`
- ibis/backends/polars/rewrites.py:33:13 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, DataType]`
- ibis/backends/polars/rewrites.py:51:16 error[unsupported-operator] Operator `|` is not supported between two objects of type `Schema`
- ibis/backends/singlestoredb/__init__.py:949:27 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, Unknown]`
- ibis/backends/snowflake/__init__.py:591:13 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, DataType]`
- ibis/backends/sql/rewrites.py:172:29 error[invalid-argument-type] Argument is incorrect: Expected `FrozenDict[str, Value[Unknown, Any]]`, found `dict[Unknown, Unknown]`
- ibis/backends/tests/test_join.py:214:57 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, str]`
- ibis/backends/trino/__init__.py:184:13 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, DataType]`
- ibis/backends/trino/__init__.py:345:13 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, DataType]`
- ibis/common/tests/test_collections.py:309:12 error[unsupported-operator] Operator `<` is not supported between two objects of type `MySchema`
- ibis/common/tests/test_collections.py:311:12 error[unsupported-operator] Operator `<=` is not supported between two objects of type `MySchema`
- ibis/common/tests/test_collections.py:317:16 error[unsupported-operator] Operator `<` is not supported between two objects of type `MySchema`
- ibis/common/tests/test_collections.py:327:9 error[unsupported-operator] Operator `<=` is not supported between objects of type `MySchema` and `Literal[1]`
- ibis/common/tests/test_collections.py:332:12 error[unsupported-operator] Operator `>=` is not supported between two objects of type `MySchema`
- ibis/common/tests/test_collections.py:340:16 error[unsupported-operator] Operator `>` is not supported between two objects of type `MySchema`
- ibis/common/tests/test_collections.py:362:13 error[unsupported-operator] Operator `&` is not supported between two objects of type `MySchema`
- ibis/common/tests/test_grounds.py:116:35 error[invalid-argument-type] Argument is incorrect: Expected `List[Unknown]`, found `list[Unknown]`
+ ibis/common/tests/test_grounds.py:168:17 error[unbound-type-variable] Type variable `K` is not bound to any outer generic context
- ibis/expr/api.py:546:29 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, DataType]`
- ibis/expr/datatypes/tests/test_core.py:422:9 error[invalid-assignment] Cannot assign to a subscript on an object of type `Struct`
- ibis/expr/datatypes/tests/test_core.py:440:25 error[invalid-argument-type] Argument to bound method `MapSet.isdisjoint` is incorrect: Expected `Mapping[Unknown, Unknown]`, found `Struct`
- ibis/expr/datatypes/tests/test_core.py:443:12 error[unsupported-operator] Operator `>=` is not supported between two objects of type `Struct`
- ibis/expr/operations/relations.py:466:23 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, Unknown]`
- ibis/expr/schema.py:257:24 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, Unknown]`
- ibis/expr/tests/test_schema.py:141:12 error[unsupported-operator] Operator `>=` is not supported between two objects of type `Schema`
- ibis/expr/tests/test_schema.py:142:12 error[unsupported-operator] Operator `<=` is not supported between two objects of type `Schema`
- ibis/expr/tests/test_schema.py:146:21 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[Unknown, Unknown]`
- ibis/expr/tests/test_schema.py:181:9 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, str]`
- ibis/expr/tests/test_schema.py:334:20 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, String | Int64 | Float64]`
- ibis/expr/tests/test_schema.py:336:20 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, Int64 | Float64 | String]`
- ibis/expr/tests/test_schema.py:337:20 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, Int64 | Float64 | String | Boolean]`
- ibis/expr/tests/test_schema.py:339:32 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, String | Float64]`
- ibis/expr/tests/test_schema.py:343:12 error[unsupported-operator] Operator `-` is not supported between two objects of type `Schema`
- ibis/expr/tests/test_schema.py:343:32 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, Int64]`
- ibis/expr/tests/test_schema.py:347:29 error[invalid-argument-type] Argument to bound method `MapSet.isdisjoint` is incorrect: Expected `Mapping[Unknown, Unknown]`, found `Schema`
- ibis/expr/tests/test_schema.py:348:25 error[invalid-argument-type] Argument to bound method `MapSet.isdisjoint` is incorrect: Expected `Mapping[Unknown, Unknown]`, found `Schema`
- ibis/expr/tests/test_schema.py:352:16 error[unsupported-operator] Operator `<` is not supported between two objects of type `Schema`
- ibis/expr/tests/test_schema.py:358:12 error[unsupported-operator] Operator `<=` is not supported between two objects of type `Schema`
- ibis/expr/tests/test_schema.py:359:12 error[unsupported-operator] Operator `<` is not supported between two objects of type `Schema`
- ibis/expr/tests/test_schema.py:402:38 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, Int64 | String | Boolean]`
- ibis/expr/types/generic.py:1554:35 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, Value[Unknown, Any]]`, found `dict[Unknown, Value[Unknown, Any]]`
- ibis/expr/types/relations.py:3242:35 error[invalid-argument-type] Argument is incorrect: Expected `Value[Numeric | String, Any] | FrozenDict[str, Any]`, found `Scalar | Mapping[str, Scalar]`
- ibis/expr/types/temporal_windows.py:83:13 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, Value[Unknown, ibis.expr.datashape.Scalar]]`, found `Sequence[ibis.expr.types.generic.Scalar] | None`
- ibis/formats/numpy.py:107:27 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, DataType]`
- ibis/formats/pandas.py:85:27 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str | Any, Unknown]`
- ibis/tests/expr/test_table.py:1161:28 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, str]`
- ibis/tests/expr/test_table.py:1224:29 error[invalid-argument-type] Argument is incorrect: Expected `FrozenOrderedDict[str, DataType]`, found `dict[str, str]`

jax (https://github.com/google/jax)
- jax/_src/pallas/pipelining/schedulers.py:430:12 error[invalid-return-type] Return type does not match returned value: expected `Sequence[int] | None`, found `list[Array | int]`

jinja (https://github.com/pallets/jinja)
+ src/jinja2/environment.py:93:28 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive

mypy (https://github.com/python/mypy)
- mypy/typeshed/stdlib/typing.pyi:289:19 error[invalid-type-form] Invalid subscript of object of type `_SpecialForm` in a type expression
- mypy/typeshed/stdlib/typing.pyi:301:19 error[invalid-type-form] Invalid subscript of object of type `_SpecialForm` in a type expression
- mypy/typeshed/stdlib/typing.pyi:399:28 error[invalid-argument-type] Method `__getitem__` of type `bound method _SpecialForm.__getitem__(parameters: Any) -> object` cannot be called with key of type `tuple[EllipsisType, <class 'Any'>]` on object of type `_SpecialForm`
- mypy/typeshed/stdlib/typing.pyi:411:24 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:444:28 error[invalid-argument-type] Argument to `TypeVar.__init__` is incorrect: Expected `Any`, found `<class 'str'>`
- mypy/typeshed/stdlib/typing.pyi:466:28 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:474:21 error[invalid-base] Invalid class base with type `_SpecialForm`
- mypy/typeshed/stdlib/typing.pyi:486:21 error[invalid-base] Invalid class base with type `_SpecialForm`
- mypy/typeshed/stdlib/typing.pyi:504:21 error[invalid-argument-type] Method `__getitem__` of type `bound method _SpecialForm.__getitem__(parameters: Any) -> object` cannot be called with key of type `TypeVar` on object of type `_SpecialForm`
- mypy/typeshed/stdlib/typing.pyi:527:16 error[invalid-base] Invalid class base with type `object`
- mypy/typeshed/stdlib/typing.pyi:532:33 error[invalid-base] Invalid class base with type `object`
- mypy/typeshed/stdlib/typing.pyi:534:27 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:544:54 error[unknown-argument] Argument `default` does not match any known parameter of `TypeVar.__init__`
- mypy/typeshed/stdlib/typing.pyi:547:39 error[invalid-base] Invalid class base with type `object`
- mypy/typeshed/stdlib/typing.pyi:592:27 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:600:98 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:627:49 error[invalid-base] Invalid class base with type `object`
- mypy/typeshed/stdlib/typing.pyi:650:53 error[invalid-argument-type] Method `__getitem__` of type `bound method _SpecialForm.__getitem__(parameters: Any) -> object` cannot be called with key of type `TypeVar` on object of type `_SpecialForm`
- mypy/typeshed/stdlib/typing.pyi:713:65 error[unsupported-operator] Operator `|` is not supported between two objects of type `TypeVar`
- mypy/typeshed/stdlib/typing.pyi:740:61 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:743:50 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:745:78 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:748:68 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:749:61 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:749:69 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:749:79 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:754:57 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:756:55 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:759:53 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:760:54 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:762:55 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:764:64 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:780:32 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:787:48 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:796:44 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:798:32 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:801:35 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:803:24 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:803:38 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:805:38 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:814:96 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a return type annotation
- mypy/typeshed/stdlib/typing.pyi:816:45 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:844:43 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/typeshed/stdlib/typing.pyi:844:92 error[invalid-type-form] Variable of type `TypeVar` is not allowed in a parameter annotation
- mypy/checker.py:6676:20 error[invalid-return-type] Return type does not match returned value: expected `tuple[dict[Expression, Type], dict[Expression, Type]]`, found `tuple[dict[Expression, ProperType], dict[Expression, ProperType]]`
+ mypy/checker.py:6676:20 error[invalid-return-type] Return type does not match returned value: expected `tuple[dict[Unknown, Type], dict[Unknown, Type]]`, found `tuple[dict[Unknown, ProperType], dict[Unknown, ProperType]]`
- mypy/checker.py:6689:16 error[invalid-return-type] Return type does not match returned value: expected `tuple[dict[Expression, Type], dict[Expression, Type]]`, found `tuple[dict[Expression, ProperType], dict[Expression, ProperType]]`
+ mypy/checker.py:6689:16 error[invalid-return-type] Return type does not match returned value: expected `tuple[dict[Unknown, Type], dict[Unknown, Type]]`, found `tuple[dict[Unknown, ProperType], dict[Unknown, ProperType]]`
- mypy/checkexpr.py:4405:35 error[invalid-assignment] Object of type `dict[Expression, UninhabitedType]` is not assignable to `dict[Expression, Type]`
+ mypy/checkexpr.py:4405:35 error[invalid-assignment] Object of type `dict[Unknown, UninhabitedType]` is not assignable to `dict[Unknown, Type]`
- mypy/checkmember.py:1305:24 warning[redundant-cast] Value is already of type `Decorator`
- mypy/dmypy_server.py:1117:39 error[invalid-argument-type] Argument to bound method `FileSystemCache.listdir` is incorrect: Expected `str`, found `PathLike[PathLike[Never] | str] | str`
+ mypy/nodes.py:891:30 error[unresolved-attribute] Attribute `line` is not defined on `None` in union `Unknown | None | FuncDef | Decorator`
- mypy/types.py:3170:18 error[invalid-assignment] Object of type `object` is not assignable to `T@accept`
- mypy/types.py:3609:18 error[invalid-assignment] Object of type `object` is not assignable to `T@accept`
+ mypyc/irbuild/statement.py:1083:46 error[invalid-argument-type] Argument to function `transform_try_finally_stmt` is incorrect: Expected `() -> None`, found `() -> Value`

pandera (https://github.com/pandera-dev/pandera)
+ pandera/api/polars/model.py:252:39 error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | UnionType | tuple[Divergent, ...]`, found `(...) -> Unknown`
- pandera/engines/numpy_engine.py:276:15 warning[unsupported-base] Unsupported class base with type `<class 'pandera.engines.numpy_engine.Float64 @ pandera/engines/numpy_engine.py:261:11'> | <class 'pandera.engines.numpy_engine.Float64 @ pandera/engines/numpy_engine.py:269:11'>`
+ pandera/typing/common.py:50:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/common.py:52:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/common.py:54:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/common.py:57:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/common.py:59:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/common.py:61:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/common.py:62:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/pandas.py:92:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/pandas.py:97:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/pandas.py:104:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ pandera/typing/pandas.py:112:9 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
- pandera/typing/pyspark_sql.py:35:29 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pandera/typing/pyspark_sql.py:41:28 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ tests/io/test_pandas_io.py:1602:23 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ tests/pandas/test_model.py:935:28 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ tests/pandas/test_model.py:2202:19 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ tests/pandas/test_model.py:2216:19 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ tests/pandas/test_typing.py:22:17 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ tests/pandas/test_typing.py:42:17 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ tests/pandas/test_typing.py:66:17 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ tests/pandas/test_typing.py:90:17 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
+ tests/pandas/test_typing.py:94:17 error[invalid-type-form] Variable of type `type[Unknown]` is not allowed in a type expression
- tests/pyspark/test_schemas_on_pyspark_pandas.py:69:36 error[invalid-argument-type] Argument to bound method `set.add` is incorrect: Expected `<class 'pandera.engines.numpy_engine.Complex128 @ pandera/engines/numpy_engine.py:310:11'> | <class 'pandera.engines.numpy_engine.Complex128 @ pandera/engines/numpy_engine.py:318:11'> | <class 'Complex64'> | ... omitted 15 union elements`, found `<class 'Timedelta64'>`
- tests/strategies/test_strategies.py:389:13 error[invalid-argument-type] Argument to function `str_length_strategy` is incorrect: Expected `pandera.engines.numpy_engine.DataType | pandera.engines.pandas_engine.DataType`, found `<class 'String'>`
+ tests/strategies/test_strategies.py:389:13 error[invalid-argument-type] Argument to function `str_length_strategy` is incorrect: Expected `pandera.engines.numpy_engine.DataType | pandera.engines.pandas_engine.DataType`, found `type[Unknown]`

scrapy (https://github.com/scrapy/scrapy)
- tests/test_feedexport.py:1240:24 error[unresolved-attribute] Class `Storage` has no attribute `open_file`
- tests/test_feedexport.py:1261:17 error[unresolved-attribute] Unresolved attribute `open_file` on type `<class 'Storage'>`.

spack (https://github.com/spack/spack)
- lib/spack/spack/cray_manifest.py:182:5 error[unresolved-attribute] Unresolved attribute `_hashes_final` on type `Spec`
- lib/spack/spack/cray_manifest.py:184:5 error[unresolved-attribute] Unresolved attribute `origin` on type `Spec`
- lib/spack/spack/database.py:1213:25 error[unresolved-attribute] Object of type `Spec` has no attribute `_package_hash`
- lib/spack/spack/environment/environment.py:2505:26 error[invalid-assignment] Object of type `None | str | bool | Unknown` is not assignable to `str`
- lib/spack/spack/environment/environment.py:2236:42 error[invalid-argument-type] Argument to function `traverse_nodes` is incorrect: Expected `Sequence[Spec]`, found `dict_values[str, Spec]`
+ lib/spack/spack/environment/environment.py:2236:42 error[invalid-argument-type] Argument to function `traverse_nodes` is incorrect: Expected `Sequence[Unknown]`, found `dict_values[str, Unknown]`
- lib/spack/spack/modules/lmod.py:220:59 error[too-many-positional-arguments] Too many positional arguments to `Spec.__init__`: expected 2, got 3
- lib/spack/spack/solver/asp.py:1450:18 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | ArchSpec | Unknown`
- lib/spack/spack/solver/asp.py:2939:9 error[invalid-argument-type] Argument to bound method `list.sort` is incorrect: Argument type `Spec` does not satisfy upper bound `SupportsDunderLT[Any] | SupportsDunderGT[Any]` of type variable `SupportsRichComparisonT`
- lib/spack/spack/solver/asp.py:3288:21 error[invalid-argument-type] Method `__getitem__` of type `bound method dict[GitVersion | StandardVersion, list[Provenance]].__getitem__(key: GitVersion | StandardVersion, /) -> list[Provenance]` cannot be called with key of type `ConcreteVersion` on object of type `dict[GitVersion | StandardVersion, list[Provenance]]`
- lib/spack/spack/spec.py:2527:13 error[invalid-assignment] Invalid subscript assignment with key of type `Literal["compiler"]` and value of type `str` on object of type `dict[str, int]`
- lib/spack/spack/spec.py:3177:21 error[unresolved-attribute] Attribute `intersects` is not defined on `None` in union `None | ArchSpec | Unknown`
+ lib/spack/spack/spec.py:3177:21 error[unresolved-attribute] Attribute `intersects` is not defined on `None` in union `None | Unknown`
- lib/spack/spack/spec.py:4704:16 error[unresolved-attribute] Attribute `os` is not defined on `None` in union `None | ArchSpec | Unknown`
+ lib/spack/spack/spec.py:4704:16 error[unresolved-attribute] Attribute `os` is not defined on `None` in union `None | Unknown`
- lib/spack/spack/spec.py:5039:45 error[unresolved-attribute] Attribute `os` is not defined on `None` in union `None | ArchSpec | Unknown`
+ lib/spack/spack/spec.py:5039:45 error[unresolved-attribute] Attribute `os` is not defined on `None` in union `None | Unknown`
- lib/spack/spack/spec.py:5040:17 error[invalid-assignment] Object of type `Unknown & ~AlwaysFalsy` is not assignable to attribute `os` on type `None | ArchSpec | Unknown`
+ lib/spack/spack/spec.py:5040:17 error[invalid-assignment] Object of type `Unknown & ~AlwaysFalsy` is not assignable to attribute `os` on type `None | Unknown`
- lib/spack/spack/spec.py:5042:53 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | ArchSpec | Unknown`
+ lib/spack/spack/spec.py:5042:53 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | Unknown`
- lib/spack/spack/test/cmd/dependents.py:63:44 error[unresolved-attribute] Attribute `dependents` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/cmd/dependents.py:63:44 error[unresolved-attribute] Attribute `dependents` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/cmd/env.py:3004:41 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | ArchSpec | Unknown`
- lib/spack/spack/test/cmd/env.py:3017:41 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | ArchSpec | Unknown`
- lib/spack/spack/test/cmd/env.py:3067:41 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | ArchSpec | Unknown`
- lib/spack/spack/test/cmd/env.py:3149:41 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | ArchSpec | Unknown`
- lib/spack/spack/test/cmd/env.py:3288:41 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | ArchSpec | Unknown`
- lib/spack/spack/test/cmd/env.py:4580:38 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | ArchSpec | Unknown`
- lib/spack/spack/test/cmd/spec.py:50:9 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/cmd/spec.py:50:9 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/cmd/spec.py:214:27 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/cmd/spec.py:214:27 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/cmd/uninstall.py:119:16 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/cmd/uninstall.py:119:16 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/cmd/uninstall.py:126:20 error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `list[Spec] | None`
+ lib/spack/spack/test/cmd/uninstall.py:126:20 error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `list[Unknown] | None`
- lib/spack/spack/test/cmd/uninstall.py:135:20 error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `list[Spec] | None`
+ lib/spack/spack/test/cmd/uninstall.py:135:20 error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `list[Unknown] | None`
- lib/spack/spack/test/concretization/core.py:2259:64 error[unresolved-attribute] Attribute `target` is not defined on `None` in union `None | ArchSpec | Unknown`
- lib/spack/spack/test/cray_manifest.py:204:12 error[unresolved-attribute] Attribute `extra_attributes` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/cray_manifest.py:204:12 error[unresolved-attribute] Attribute `extra_attributes` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/database.py:899:16 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/database.py:899:16 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/database.py:900:17 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/database.py:900:17 error[unresolved-attribute] Attribute `dag_hash` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/directives.py:135:5 error[invalid-assignment] Object of type `dict[Spec, str]` is not assignable to attribute `licenses` of type `property`
+ lib/spack/spack/test/directives.py:135:5 error[invalid-assignment] Object of type `dict[Unknown, str]` is not assignable to attribute `licenses` of type `property`
- lib/spack/spack/test/directory_layout.py:117:30 error[invalid-argument-type] Argument to bound method `Spec.copy` is incorrect: Expected `int | str | list[str] | tuple[str, ...]`, found `SpecHashDescriptor`
- lib/spack/spack/test/env.py:82:13 error[unresolved-attribute] Object of type `Spec` has no attribute `_hash`
- lib/spack/spack/test/installer_tui.py:623:30 error[invalid-argument-type] Argument to bound method `BuildStatus.add_build` is incorrect: Expected `Spec`, found `MockSpec`
- lib/spack/spack/test/installer_tui.py:678:30 error[invalid-argument-type] Argument to bound method `BuildStatus.add_build` is incorrect: Expected `Spec`, found `MockSpec`
- lib/spack/spack/test/installer_tui.py:747:37 error[invalid-argument-type] Argument to `BuildInfo.__init__` is incorrect: Expected `Spec`, found `MockSpec`
- lib/spack/spack/test/installer_tui.py:1141:30 error[invalid-argument-type] Argument to bound method `BuildStatus.add_build` is incorrect: Expected `Spec`, found `MockSpec`
- lib/spack/spack/test/modules/common.py:169:51 error[invalid-argument-type] Argument to function `get_module` is incorrect: Expected `Spec`, found `MockSpec`
- lib/spack/spack/test/patch.py:210:12 error[unsupported-operator] Operator `in` is not supported between objects of type `Literal["a69b288d7393261e613c276c6d38a01461028291f6e381623acc58139d01f54d"]` and `tuple[bool | str, ...] | bool | str`
- lib/spack/spack/test/spec_semantics.py:2177:42 error[unsupported-operator] Operator `<` is not supported between two objects of type `Spec`
- lib/spack/spack/test/spec_syntax.py:1440:5 error[unresolved-attribute] Unresolved attribute `_hash` on type `Spec`
- lib/spack/spack/test/spec_syntax.py:1291:5 error[unresolved-attribute] Attribute `replace_hash` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/spec_syntax.py:1291:5 error[unresolved-attribute] Attribute `replace_hash` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/spec_syntax.py:1312:5 error[unresolved-attribute] Attribute `replace_hash` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/spec_syntax.py:1312:5 error[unresolved-attribute] Attribute `replace_hash` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/spec_syntax.py:1313:12 error[unsupported-operator] Operator `in` is not supported between objects of type `Literal["zmpi"]` and `Spec | None`
+ lib/spack/spack/test/spec_syntax.py:1313:12 error[unsupported-operator] Operator `in` is not supported between objects of type `Literal["zmpi"]` and `Unknown | None`
- lib/spack/spack/test/spec_syntax.py:1757:12 error[unresolved-attribute] Attribute `intersects` is not defined on `None` in union `Spec | None`
+ lib/spack/spack/test/spec_syntax.py:1757:12 error[unresolved-attribute] Attribute `intersects` is not defined on `None` in union `Unknown | None`
- lib/spack/spack/test/spec_syntax.py:1757:27 error[invalid-argument-type] Argument to bound method `Spec.intersects` is incorrect: Expected `str | Spec`, found `Spec | None`
- lib/spack/spack/variant.py:512:55 error[invalid-argument-type] Argument to `VariantValue.__init__` is incorrect: Expected `tuple[bool | str, ...]`, found `tuple[None]`
+ lib/spack/spack/vendor/jinja2/environment.py:91:28 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive

xarray (https://github.com/pydata/xarray)
- xarray/tests/test_plot.py:226:13 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:320:9 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:323:9 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:327:13 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:343:9 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:684:9 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:694:13 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:721:9 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:767:9 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:771:9 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:870:15 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:889:9 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:918:9 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:2499:9 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:2666:13 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:2683:13 error[missing-argument] No argument provided for required parameter `self` of bound method `_Wrapped.__call__`
- xarray/tests/test_plot.py:2711:19 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:2717:13 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:2891:13 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:2947:9 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:2950:9 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:2985:14 error[no-matching-overload] No overload matches arguments
- xarray/tests/test_plot.py:3055:13 error[no-matching-overload] No overload matches arguments

zulip (https://github.com/zulip/zulip)
+ zerver/tests/test_auth_backends.py:2640:37 error[unresolved-attribute] Object of type `type[ExternalAuthMethod]` has no attribute `put_data_in_redis`
+ zerver/tests/test_auth_backends.py:2796:29 error[unresolved-attribute] Object of type `type[ExternalAuthMethod]` has no attribute `put_data_in_redis`
+ zerver/tests/test_auth_backends.py:4374:17 error[unresolved-attribute] Object of type `type[ExternalAuthMethod]` has no attribute `full_name_validated`
- zerver/tests/test_import_export.py:3213:17 error[unknown-argument] Argument `sender` does not match any known parameter of `object.__init__`
- zerver/tests/test_import_export.py:3214:17 error[unknown-argument] Argument `message_id` does not match any known parameter of `object.__init__`
- zerver/tests/test_import_export.py:3218:17 error[unknown-argument] Argument `sender` does not match any known parameter of `object.__init__`
- zerver/tests/test_import_export.py:3219:17 error[unknown-argument] Argument `message_id` does not match any known parameter of `object.__init__`
- zerver/tests/test_import_export.py:3224:17 error[unknown-argument] Argument `message_id` does not match any known parameter of `object.__init__`
- zerver/tests/test_import_export.py:3235:17 error[unknown-argument] Argument `content` does not match any known parameter of `object.__init__`
- zerver/tests/test_import_export.py:3236:17 error[unknown-argument] Argument `sender` does not match any known parameter of `object.__init__`
- zerver/tests/test_import_export.py:3241:17 error[unknown-argument] Argument `sender` does not match any known parameter of `object.__init__`
- zerver/tests/test_import_export.py:3251:17 error[unknown-argument] Argument `sender` does not match any known parameter of `object.__init__`
- zerver/tests/test_typed_endpoint.py:76:27 error[too-many-positional-arguments] Too many positional arguments to `object.__init__`: expected 1, got 3
- zerver/tests/test_typed_endpoint.py:599:17 error[unknown-argument] Argument `param_type` does not match any known parameter of `object.__init__`
- zerver/tests/test_typed_endpoint.py:600:17 error[unknown-argument] Argument `input_data` does not match any known parameter of `object.__init__`
- zerver/tests/test_typed_endpoint.py:601:17 error[unknown-argument] Argument `error_message` does not match any known parameter of `object.__init__`
- zerver/tests/test_typed_endpoint.py:607:17 error[unknown-argument] Argument `error_message` does not match any known parameter of `object.__init__`
- zerver/tests/test_typed_endpoint.py:610:17 error[unknown-argument] Argument `error_type` does not match any known parameter of `object.__init__`
- zerver/tests/test_typed_endpoint.py:613:17 error[unknown-argument] Argument `error_message` does not match any known parameter of `object.__init__`
- zerver/tests/test_typed_endpoint.py:617:17 error[unknown-argument] Argument `param_type` does not match any known parameter of `object.__init__`

Full report with detailed diff (timing results)

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 10, 2026

Merging this PR will not alter performance

✅ 57 untouched benchmarks
⏩ 60 skipped benchmarks1


Comparing charlie/class-decorators (84f3a3a) with main (c130dce)

Open in CodSpeed

Footnotes

  1. 60 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@charliermarsh charliermarsh force-pushed the charlie/class-decorators branch 9 times, most recently from e0a9944 to 2b3f474 Compare May 16, 2026 14:48
};

let mut decorators_to_apply = Vec::with_capacity(decorator_types_and_nodes.len());
let mut metadata_applies_to_original_class = true;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is used to figure out whether a decorator like @dataclass should be applied to the original class or not. An example of the negative case would be something like:

def replace(cls: type[object]) -> int:
    return 1

@dataclass
@replace
class C:
    x: int

Because C gets replaced by int, we don't apply @dataclass metadata to C.

@charliermarsh charliermarsh force-pushed the charlie/class-decorators branch 4 times, most recently from 1438094 to 025b1a5 Compare May 18, 2026 11:33
@charliermarsh charliermarsh marked this pull request as ready for review May 18, 2026 12:09
@astral-sh-bot astral-sh-bot Bot requested a review from dhruvmanila May 18, 2026 12:09
Comment thread crates/ty_python_semantic/resources/mdtest/decorators.md Outdated
Comment on lines +424 to +430
# error: [no-matching-overload]
@dataclass
@WrapBackend
class WrappedThenDataclass:
value: int

reveal_type(WrappedThenDataclass) # revealed: Unknown
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.

(This is just me thinking out loud.)

This is an interesting behavior. I think it's correct given that dataclass is receiving an instance of WrapBackend instead of the class itself but I wonder if the diagnostics could be improved to highlight that it's an invalid-argument-type. I don't think this is a priority and it doesn't look easy to do either.

Comment thread crates/ty_python_semantic/resources/mdtest/decorators.md
Comment thread crates/ty_python_semantic/resources/mdtest/decorators.md
Comment thread crates/ty_python_semantic/resources/mdtest/decorators.md
Comment thread crates/ty_python_semantic/resources/mdtest/typed_dict.md Outdated
Comment thread crates/ty_python_semantic/src/types/function.rs Outdated
Self::known_from_decorator(db, alias.value_type(db))
.unwrap_or(Self::ReplaceBinding),
),
Type::Callable(_) => Some(Self::PreserveBinding),
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.

Is this intentional that Callable always preserves binding while function and method literals checks for return type annotation?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added a TODO here for now -- will revisit shortly.

@charliermarsh charliermarsh force-pushed the charlie/class-decorators branch from 025b1a5 to 8d1d4b6 Compare May 19, 2026 21:49
@charliermarsh charliermarsh merged commit 85c9e74 into main May 19, 2026
59 checks passed
@charliermarsh charliermarsh deleted the charlie/class-decorators branch May 19, 2026 22:21
charliermarsh added a commit that referenced this pull request May 21, 2026
…5250)

## Summary

This PR addresses a TODO from #25091 whereby we preserved the class
binding for every `Callable`
decorator. We now respect explicit return annotations on `Callable`.

For example, this now remains a replacement rather than being treated as
class-preserving:

```python
from typing import Callable, TypeVar

T = TypeVar("T")

def decorator_factory() -> Callable[[type[object]], T]:
    raise NotImplementedError

@decorator_factory()
class Decorated: ...

reveal_type(Decorated)  # Unknown
```
thejchap pushed a commit to thejchap/ruff that referenced this pull request May 23, 2026
## Summary

This PR adds support for class decorator return types, following Carl's
comment in
astral-sh/ty#2604 (comment):
assume unannotated decorators preserve the class binding when their
result is otherwise `Unknown`, but support explicit spelling of an
annotated decorator return type.

In more detail, the rule is roughly:

- If applying the decorator gives a non-`Unknown` result...
- And that result still retains the original class object, we preserve
the class.
  - Otherwise, we replace the public binding with that result.
- If applying the decorator gives an `Unknown` result:
  - We fall back to the decorator’s own shape.
- Unannotated function/method decorators are treated as
"identity-preserving", so we keep the current class binding.
- Decorators with an explicit return annotation are not, so we do _not_
preserve the binding.

As a concrete example, an unannotated decorator like the personify
example from astral-sh#2604 is still treated as preserving the original class
(since we don't have a static replacement type):

```python
def personify(cls):
    class Wrapped(cls):
        full_name: str

        def set_full_name(self, full_name: str) -> None:
            self.full_name = full_name

    return Wrapped

@personify
class Animal: ...

reveal_type(Animal)  # <class 'Animal'>
Animal().set_full_name("John")  # error: unresolved attribute
```

But if the decorator has an explicit return type, we use it for the
public class binding:

```python
class WrapBackend:
    def __init__(self, cls: type[object]) -> None: ...

    def get(self, key: str) -> bytes | None: ...

@WrapBackend
class CacheClient: ...

reveal_type(CacheClient)  # WrapBackend
reveal_type(CacheClient.get("x"))  # bytes | None
```

This gives us stable behavior for common untyped identity decorators
while leaving the advanced and unsound returned-class inference path out
of scope...

Closes astral-sh/ty#143.
thejchap pushed a commit to thejchap/ruff that referenced this pull request May 23, 2026
…tral-sh#25250)

## Summary

This PR addresses a TODO from astral-sh#25091 whereby we preserved the class
binding for every `Callable`
decorator. We now respect explicit return annotations on `Callable`.

For example, this now remains a replacement rather than being treated as
class-preserving:

```python
from typing import Callable, TypeVar

T = TypeVar("T")

def decorator_factory() -> Callable[[type[object]], T]:
    raise NotImplementedError

@decorator_factory()
class Decorated: ...

reveal_type(Decorated)  # Unknown
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add proper support for class decorators

2 participants