mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
Update Markdown tests
This commit is contained in:
parent
eea69f2357
commit
390513dc18
1 changed files with 94 additions and 65 deletions
|
@ -48,11 +48,11 @@ class Outer:
|
||||||
return self
|
return self
|
||||||
```
|
```
|
||||||
|
|
||||||
## Detection of implicit Self
|
## Type of (unannotated) `self` parameters
|
||||||
|
|
||||||
In instance methods, the first parameter (regardless of its name) is assumed to have type
|
In instance methods, the first parameter (regardless of its name) is assumed to have the type
|
||||||
`typing.Self` unless it has an explicit annotation. This does not apply to `@classmethod` and
|
`typing.Self`, unless it has an explicit annotation. This does not apply to `@classmethod` and
|
||||||
`@staticmethod`.
|
`@staticmethod`s.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[environment]
|
[environment]
|
||||||
|
@ -64,74 +64,108 @@ from typing import Self
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
def implicit_self(self) -> Self:
|
def implicit_self(self) -> Self:
|
||||||
# TODO: first argument in a method should be considered as "typing.Self"
|
# TODO: This should be Self@implicit_self
|
||||||
reveal_type(self) # revealed: Unknown
|
reveal_type(self) # revealed: Unknown
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def foo(self) -> int:
|
def a_method(self) -> int:
|
||||||
def first_arg_is_not_self(a: int) -> int:
|
def first_arg_is_not_self(a: int) -> int:
|
||||||
|
reveal_type(a) # revealed: int
|
||||||
return a
|
return a
|
||||||
return first_arg_is_not_self(1)
|
return first_arg_is_not_self(1)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def bar(cls): ...
|
def a_classmethod(cls) -> Self:
|
||||||
|
# TODO: This should be type[Self@bar]
|
||||||
|
reveal_type(cls) # revealed: Unknown
|
||||||
|
return cls()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def static(x): ...
|
def a_staticmethod(x: int): ...
|
||||||
|
|
||||||
a = A()
|
a = A()
|
||||||
# TODO: Should reveal Self@implicit_self. Requires implicit self in method body(https://github.com/astral-sh/ruff/pull/18473)
|
|
||||||
reveal_type(a.implicit_self()) # revealed: A
|
reveal_type(a.implicit_self()) # revealed: A
|
||||||
reveal_type(a.implicit_self) # revealed: bound method A.implicit_self() -> A
|
reveal_type(a.implicit_self) # revealed: bound method A.implicit_self() -> A
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Calling an instance method explicitly verifies the first argument:
|
||||||
|
|
||||||
|
```py
|
||||||
|
A.implicit_self(a)
|
||||||
|
|
||||||
|
# error: [invalid-argument-type] "Argument to function `implicit_self` is incorrect: Argument type `Literal[1]` does not satisfy upper bound `A` of type variable `Self`"
|
||||||
|
A.implicit_self(1)
|
||||||
|
```
|
||||||
|
|
||||||
If the method is a class or static method then first argument is not self:
|
If the method is a class or static method then first argument is not self:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
A.bar()
|
A.a_classmethod()
|
||||||
a.static(1)
|
|
||||||
|
A.a_classmethod(a) # error: [too-many-positional-arguments]
|
||||||
|
|
||||||
|
A.a_staticmethod(1)
|
||||||
|
a.a_staticmethod(1)
|
||||||
|
|
||||||
|
A.a_staticmethod(a) # error: [invalid-argument-type]
|
||||||
```
|
```
|
||||||
|
|
||||||
"self" name is not special; any first parameter name is treated as Self.
|
The first parameter of instance methods always has type `Self`, if it is not explicitly annotated.
|
||||||
|
The name `self` is not special in any way.
|
||||||
|
|
||||||
|
```py
|
||||||
|
class B:
|
||||||
|
def name_does_not_matter(this) -> Self:
|
||||||
|
# TODO: Should reveal Self@name_does_not_matter
|
||||||
|
reveal_type(this) # revealed: Unknown
|
||||||
|
|
||||||
|
return this
|
||||||
|
|
||||||
|
def positional_only(self, /, x: int) -> Self:
|
||||||
|
# TODO: Should reveal Self@positional_only
|
||||||
|
reveal_type(self) # revealed: Unknown
|
||||||
|
return self
|
||||||
|
|
||||||
|
def keyword_only(self, *, x: int) -> Self:
|
||||||
|
# TODO: Should reveal Self@keyword_only
|
||||||
|
reveal_type(self) # revealed: Unknown
|
||||||
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def a_property(self) -> Self:
|
||||||
|
# TODO: Should reveal Self@a_property
|
||||||
|
reveal_type(self) # revealed: Unknown
|
||||||
|
return self
|
||||||
|
|
||||||
|
reveal_type(B().name_does_not_matter()) # revealed: B
|
||||||
|
|
||||||
|
# TODO: this should be B
|
||||||
|
reveal_type(B().positional_only(1)) # revealed: Unknown
|
||||||
|
|
||||||
|
reveal_type(B().keyword_only(x=1)) # revealed: B
|
||||||
|
|
||||||
|
# TODO: this should be B
|
||||||
|
reveal_type(B().a_property) # revealed: Unknown
|
||||||
|
```
|
||||||
|
|
||||||
|
This also works for generic classes:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing import Self, Generic, TypeVar
|
from typing import Self, Generic, TypeVar
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
class B:
|
|
||||||
def implicit_this(this) -> Self:
|
|
||||||
# TODO: Should reveal Self@implicit_this
|
|
||||||
reveal_type(this) # revealed: Unknown
|
|
||||||
return this
|
|
||||||
|
|
||||||
def ponly(self, /, x: int) -> None:
|
|
||||||
# TODO: Should reveal Self@ponly
|
|
||||||
reveal_type(self) # revealed: Unknown
|
|
||||||
|
|
||||||
def kwonly(self, *, x: int) -> None:
|
|
||||||
# TODO: Should reveal Self@kwonly
|
|
||||||
reveal_type(self) # revealed: Unknown
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
# TODO: Should reveal Self@name
|
|
||||||
reveal_type(self) # revealed: Unknown
|
|
||||||
return "b"
|
|
||||||
|
|
||||||
B.ponly(B(), 1)
|
|
||||||
B.name
|
|
||||||
B.kwonly(B(), x=1)
|
|
||||||
|
|
||||||
class G(Generic[T]):
|
class G(Generic[T]):
|
||||||
def id(self) -> Self:
|
def id(self) -> Self:
|
||||||
# TODO: Should reveal Self@id
|
# TODO: Should reveal Self@id
|
||||||
reveal_type(self) # revealed: Unknown
|
reveal_type(self) # revealed: Unknown
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
g = G[int]()
|
reveal_type(G[int]().id()) # revealed: G[int]
|
||||||
|
reveal_type(G[str]().id()) # revealed: G[str]
|
||||||
# TODO: Should reveal Self@id Requires implicit self in method body(https://github.com/astral-sh/ruff/pull/18473)
|
|
||||||
reveal_type(G[int].id(g)) # revealed: G[int]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Free functions and nested functions do not use implicit `Self`:
|
Free functions and nested functions do not use implicit `Self`:
|
||||||
|
@ -140,10 +174,16 @@ Free functions and nested functions do not use implicit `Self`:
|
||||||
def not_a_method(self):
|
def not_a_method(self):
|
||||||
reveal_type(self) # revealed: Unknown
|
reveal_type(self) # revealed: Unknown
|
||||||
|
|
||||||
|
# error: [invalid-type-form]
|
||||||
|
def does_not_return_self(self) -> Self:
|
||||||
|
return self
|
||||||
|
|
||||||
class C:
|
class C:
|
||||||
def outer(self) -> None:
|
def outer(self) -> None:
|
||||||
def inner(self):
|
def inner(self):
|
||||||
reveal_type(self) # revealed: Unknown
|
reveal_type(self) # revealed: Unknown
|
||||||
|
|
||||||
|
reveal_type(not_a_method) # revealed: def not_a_method(self) -> Unknown
|
||||||
```
|
```
|
||||||
|
|
||||||
## typing_extensions
|
## typing_extensions
|
||||||
|
@ -301,51 +341,40 @@ class MyMetaclass(type):
|
||||||
return super().__new__(cls)
|
return super().__new__(cls)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Explicit Annotation Overrides Implicit `Self`
|
## Explicit annotations override implicit `Self`
|
||||||
|
|
||||||
If the first parameter is explicitly annotated, that annotation takes precedence over the implicit
|
If the first parameter is explicitly annotated, that annotation takes precedence over the implicit
|
||||||
`Self` treatment.
|
`Self` type.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[environment]
|
[environment]
|
||||||
python-version = "3.11"
|
python-version = "3.12"
|
||||||
```
|
```
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
class Explicit:
|
class Explicit:
|
||||||
# TODO: We could emit a warning if the annotated type of `self` is disjoint from `Explicit`
|
# TODO: We could emit a warning if the annotated type of `self` is disjoint from `Explicit`
|
||||||
def bad(self: int) -> None:
|
def bad(self: int) -> None:
|
||||||
reveal_type(self) # revealed: int
|
reveal_type(self) # revealed: int
|
||||||
|
|
||||||
def forward(self: "Explicit") -> None:
|
def forward(self: Explicit) -> None:
|
||||||
reveal_type(self) # revealed: Explicit
|
reveal_type(self) # revealed: Explicit
|
||||||
|
|
||||||
e = Explicit()
|
|
||||||
# error: [invalid-argument-type] "Argument to bound method `bad` is incorrect: Expected `int`, found `Explicit`"
|
# error: [invalid-argument-type] "Argument to bound method `bad` is incorrect: Expected `int`, found `Explicit`"
|
||||||
e.bad()
|
Explicit().bad()
|
||||||
```
|
|
||||||
|
|
||||||
## Type of Implicit Self
|
Explicit().forward()
|
||||||
|
|
||||||
The assigned type to self argument depends on the method signature. When the method is defined in a
|
class ExplicitGeneric[T]:
|
||||||
non-generic class and has no other mention of `typing.Self` (for example in return type) then type
|
def special(self: ExplicitGeneric[int]) -> None:
|
||||||
of `self` is instance of the class.
|
reveal_type(self) # revealed: ExplicitGeneric[int]
|
||||||
|
|
||||||
```py
|
ExplicitGeneric[int]().special()
|
||||||
from typing import Self
|
|
||||||
|
|
||||||
class C:
|
# TODO: this should be an `invalid-argument-type` error
|
||||||
def f(self) -> Self:
|
ExplicitGeneric[str]().special()
|
||||||
return self
|
|
||||||
|
|
||||||
def z(self) -> None: ...
|
|
||||||
|
|
||||||
C.z(1) # error: [invalid-argument-type] "Argument to function `z` is incorrect: Expected `C`, found `Literal[1]`"
|
|
||||||
```
|
|
||||||
|
|
||||||
```py
|
|
||||||
# error: [invalid-argument-type] "Argument to function `f` is incorrect: Argument type `Literal[1]` does not satisfy upper bound `C` of type variable `Self`"
|
|
||||||
C.f(1)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Binding a method fixes `Self`
|
## Binding a method fixes `Self`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue