From 48393abf3bda94c41c84ee14f7112b6df5c5564b Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Tue, 27 May 2025 11:58:03 -0700 Subject: [PATCH] put similar dunder-call tests next to each other --- .../resources/mdtest/call/dunder.md | 70 ++++++++++--------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/call/dunder.md b/crates/ty_python_semantic/resources/mdtest/call/dunder.md index 8c2a70a2c4deb2..15cf01b7a1f41f 100644 --- a/crates/ty_python_semantic/resources/mdtest/call/dunder.md +++ b/crates/ty_python_semantic/resources/mdtest/call/dunder.md @@ -59,6 +59,8 @@ ClassWithNormalDunder[0] ## Operating on instances +### Attaching dunder methods to instances in methods + When invoking a dunder method on an instance of a class, it is looked up on the class: ```py @@ -116,6 +118,40 @@ def _(flag: bool): reveal_type(this_fails[0]) # revealed: Unknown | str ``` +### Dunder methods as class-level annotations with no value + +Class-level annotations with no value assigned are considered instance-only, and aren't available as +dunder methods: + +```py +from typing import Callable + +class C: + __call__: Callable[..., None] + +# error: [call-non-callable] +C()() + +# error: [invalid-assignment] +_: Callable[..., None] = C() +``` + +And of course the same is true if we have only an implicit assignment inside a method: + +```py +from typing import Callable + +class C: + def __init__(self): + self.__call__ = lambda *a, **kw: None + +# error: [call-non-callable] +C()() + +# error: [invalid-assignment] +_: Callable[..., None] = C() +``` + ## When the dunder is not a method A dunder can also be a non-method callable: @@ -239,37 +275,3 @@ def _(flag: bool): # error: [possibly-unbound-implicit-call] reveal_type(c[0]) # revealed: str ``` - -## Dunder methods cannot be looked up on instances - -Class-level annotations with no value assigned are considered instance-only, and aren't available as -dunder methods: - -```py -from typing import Callable - -class C: - __call__: Callable[..., None] - -# error: [call-non-callable] -C()() - -# error: [invalid-assignment] -_: Callable[..., None] = C() -``` - -And of course the same is true if we have only an implicit assignment inside a method: - -```py -from typing import Callable - -class C: - def __init__(self): - self.__call__ = lambda *a, **kw: None - -# error: [call-non-callable] -C()() - -# error: [invalid-assignment] -_: Callable[..., None] = C() -```