mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-18 11:41:21 +00:00
[ty] Add support for properties that return Self (#21335)
## Summary Detect usages of implicit `self` in property getters, which allows us to treat their signature as being generic. closes https://github.com/astral-sh/ty/issues/1502 ## Typing conformance Two new type assertions that are succeeding. ## Ecosystem results Mostly look good. There are a few new false positives related to a bug with constrained typevars that is unrelated to the work here. I reported this as https://github.com/astral-sh/ty/issues/1503. ## Test Plan Added regression tests.
This commit is contained in:
parent
a6f2dee33b
commit
ab46c8de0f
3 changed files with 88 additions and 22 deletions
|
|
@ -139,7 +139,7 @@ The first parameter of instance methods always has type `Self`, if it is not exp
|
|||
The name `self` is not special in any way.
|
||||
|
||||
```py
|
||||
def some_decorator(f: Callable) -> Callable:
|
||||
def some_decorator[**P, R](f: Callable[P, R]) -> Callable[P, R]:
|
||||
return f
|
||||
|
||||
class B:
|
||||
|
|
@ -188,10 +188,10 @@ class B:
|
|||
reveal_type(B().name_does_not_matter()) # revealed: B
|
||||
reveal_type(B().positional_only(1)) # revealed: B
|
||||
reveal_type(B().keyword_only(x=1)) # revealed: B
|
||||
# TODO: This should deally be `B`
|
||||
reveal_type(B().decorated_method()) # revealed: Unknown
|
||||
|
||||
# TODO: this should be B
|
||||
reveal_type(B().a_property) # revealed: Unknown
|
||||
reveal_type(B().a_property) # revealed: B
|
||||
|
||||
async def _():
|
||||
reveal_type(await B().async_method()) # revealed: B
|
||||
|
|
|
|||
|
|
@ -49,6 +49,40 @@ c.my_property = 2
|
|||
c.my_property = "a"
|
||||
```
|
||||
|
||||
## Properties returning `Self`
|
||||
|
||||
A property that returns `Self` refers to an instance of the class:
|
||||
|
||||
```py
|
||||
from typing_extensions import Self
|
||||
|
||||
class Path:
|
||||
@property
|
||||
def parent(self) -> Self:
|
||||
raise NotImplementedError
|
||||
|
||||
reveal_type(Path().parent) # revealed: Path
|
||||
```
|
||||
|
||||
This also works when a setter is defined:
|
||||
|
||||
```py
|
||||
class Node:
|
||||
@property
|
||||
def parent(self) -> Self:
|
||||
raise NotImplementedError
|
||||
|
||||
@parent.setter
|
||||
def parent(self, value: Self) -> None:
|
||||
pass
|
||||
|
||||
root = Node()
|
||||
child = Node()
|
||||
child.parent = root
|
||||
|
||||
reveal_type(child.parent) # revealed: Node
|
||||
```
|
||||
|
||||
## `property.getter`
|
||||
|
||||
`property.getter` can be used to overwrite the getter method of a property. This does not overwrite
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue