non-self-return-type (PYI034)#
Derived from the flake8-pyi linter.
What it does#
Checks for methods that are annotated with a fixed return type, which
should instead be returning self
.
Why is this bad?#
If methods like __new__
or __enter__
are annotated with a fixed return
type, and the class is subclassed, type checkers will not be able to infer
the correct return type.
For example:
class Shape:
def set_scale(self, scale: float) -> Shape:
self.scale = scale
return self
class Circle(Shape):
def set_radius(self, radius: float) -> Circle:
self.radius = radius
return self
# This returns `Shape`, not `Circle`.
Circle().set_scale(0.5)
# Thus, this expression is invalid, as `Shape` has no attribute `set_radius`.
Circle().set_scale(0.5).set_radius(2.7)
Specifically, this check enforces that the return type of the following
methods is Self
:
- In-place binary operations, like
__iadd__
,__imul__
, etc. __new__
,__enter__
, and__aenter__
, if those methods return the class name.__iter__
methods that returnIterator
, despite the class inheriting directly fromIterator
.__aiter__
methods that returnAsyncIterator
, despite the class inheriting directly fromAsyncIterator
.
Example#
class Foo:
def __new__(cls, *args: Any, **kwargs: Any) -> Bad:
...
def __enter__(self) -> Bad:
...
async def __aenter__(self) -> Bad:
...
def __iadd__(self, other: Bad) -> Bad:
...
Use instead:
from typing_extensions import Self
class Foo:
def __new__(cls, *args: Any, **kwargs: Any) -> Self:
...
def __enter__(self) -> Self:
...
async def __aenter__(self) -> Self:
...
def __iadd__(self, other: Bad) -> Self:
...