diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI034.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI034.py index 850bd057ddd39..cb806763284b0 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI034.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI034.py @@ -3,9 +3,11 @@ import abc import builtins import collections.abc +import enum import typing -from abc import abstractmethod +from abc import ABCMeta, abstractmethod from collections.abc import AsyncIterable, AsyncIterator, Iterable, Iterator +from enum import EnumMeta from typing import Any, overload import typing_extensions @@ -199,6 +201,31 @@ def __aiter__(self) -> AsyncIterable[str]: ... # Y045 "__aiter__" methods should return an AsyncIterator, not an AsyncIterable +class MetaclassInWhichSelfCannotBeUsed(type): + def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed: ... + def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed: ... + async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed: ... + def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed) -> MetaclassInWhichSelfCannotBeUsed: ... + +class MetaclassInWhichSelfCannotBeUsed2(EnumMeta): + def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed2: ... + def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed2: ... + async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed2: ... + def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed2) -> MetaclassInWhichSelfCannotBeUsed2: ... + +class MetaclassInWhichSelfCannotBeUsed3(enum.EnumType): + def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed3: ... + def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed3: ... + async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed3: ... + def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed3) -> MetaclassInWhichSelfCannotBeUsed3: ... + +class MetaclassInWhichSelfCannotBeUsed4(ABCMeta): + def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed4: ... + def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed4: ... + async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed4: ... + def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed4) -> MetaclassInWhichSelfCannotBeUsed4: ... + + class Abstract(Iterator[str]): @abstractmethod def __iter__(self) -> Iterator[str]: diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI034.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI034.pyi index 800cf14512d9e..8188312a03833 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI034.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI034.pyi @@ -3,9 +3,11 @@ import abc import builtins import collections.abc +import enum import typing -from abc import abstractmethod +from abc import ABCMeta, abstractmethod from collections.abc import AsyncIterable, AsyncIterator, Iterable, Iterator +from enum import EnumMeta from typing import Any, overload import typing_extensions @@ -152,6 +154,30 @@ class AsyncIteratorReturningAsyncIterable: str ]: ... # Y045 "__aiter__" methods should return an AsyncIterator, not an AsyncIterable +class MetaclassInWhichSelfCannotBeUsed(type): + def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed: ... + def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed: ... + async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed: ... + def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed) -> MetaclassInWhichSelfCannotBeUsed: ... + +class MetaclassInWhichSelfCannotBeUsed2(EnumMeta): + def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed2: ... + def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed2: ... + async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed2: ... + def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed2) -> MetaclassInWhichSelfCannotBeUsed2: ... + +class MetaclassInWhichSelfCannotBeUsed3(enum.EnumType): + def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed3: ... + def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed3: ... + async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed3: ... + def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed3) -> MetaclassInWhichSelfCannotBeUsed3: ... + +class MetaclassInWhichSelfCannotBeUsed4(ABCMeta): + def __new__(cls) -> MetaclassInWhichSelfCannotBeUsed4: ... + def __enter__(self) -> MetaclassInWhichSelfCannotBeUsed4: ... + async def __aenter__(self) -> MetaclassInWhichSelfCannotBeUsed4: ... + def __isub__(self, other: MetaclassInWhichSelfCannotBeUsed4) -> MetaclassInWhichSelfCannotBeUsed4: ... + class Abstract(Iterator[str]): @abstractmethod def __iter__(self) -> Iterator[str]: ... diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/non_self_return_type.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/non_self_return_type.rs index ad8902dd46570..d0766353df239 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/non_self_return_type.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/non_self_return_type.rs @@ -131,6 +131,11 @@ pub(crate) fn non_self_return_type( return; }; + // PEP 673 forbids the use of `typing(_extensions).Self` in metaclasses. + if is_metaclass(class_def, checker.semantic()) { + return; + } + // Skip any abstract or overloaded methods. if is_abstract(decorator_list, checker.semantic()) || is_overload(decorator_list, checker.semantic()) @@ -214,6 +219,26 @@ pub(crate) fn non_self_return_type( } } +/// Returns `true` if the given class is a metaclass. +fn is_metaclass(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool { + class_def.arguments.as_ref().is_some_and(|arguments| { + arguments + .args + .iter() + .any(|expr| is_metaclass_base(expr, semantic)) + }) +} + +/// Returns `true` if the given expression resolves to a metaclass. +fn is_metaclass_base(base: &Expr, semantic: &SemanticModel) -> bool { + semantic.resolve_call_path(base).is_some_and(|call_path| { + matches!( + call_path.as_slice(), + ["" | "builtins", "type"] | ["abc", "ABCMeta"] | ["enum", "EnumMeta" | "EnumType"] + ) + }) +} + /// Returns `true` if the method is an in-place binary operator. fn is_inplace_bin_op(name: &str) -> bool { matches!( diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI034_PYI034.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI034_PYI034.py.snap index 9b00478bf5967..93d267a767f36 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI034_PYI034.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI034_PYI034.py.snap @@ -1,91 +1,91 @@ --- source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs --- -PYI034.py:19:9: PYI034 `__new__` methods in classes like `Bad` usually return `self` at runtime +PYI034.py:21:9: PYI034 `__new__` methods in classes like `Bad` usually return `self` at runtime | -17 | object -18 | ): # Y040 Do not inherit from "object" explicitly, as it is redundant in Python 3 -19 | def __new__(cls, *args: Any, **kwargs: Any) -> Bad: +19 | object +20 | ): # Y040 Do not inherit from "object" explicitly, as it is redundant in Python 3 +21 | def __new__(cls, *args: Any, **kwargs: Any) -> Bad: | ^^^^^^^ PYI034 -20 | ... # Y034 "__new__" methods usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__new__", e.g. "def __new__(cls, *args: Any, **kwargs: Any) -> Self: ..." +22 | ... # Y034 "__new__" methods usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__new__", e.g. "def __new__(cls, *args: Any, **kwargs: Any) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.py:34:9: PYI034 `__enter__` methods in classes like `Bad` usually return `self` at runtime +PYI034.py:36:9: PYI034 `__enter__` methods in classes like `Bad` usually return `self` at runtime | -32 | ... # Y032 Prefer "object" to "Any" for the second parameter in "__ne__" methods -33 | -34 | def __enter__(self) -> Bad: +34 | ... # Y032 Prefer "object" to "Any" for the second parameter in "__ne__" methods +35 | +36 | def __enter__(self) -> Bad: | ^^^^^^^^^ PYI034 -35 | ... # Y034 "__enter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__enter__", e.g. "def __enter__(self) -> Self: ..." +37 | ... # Y034 "__enter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__enter__", e.g. "def __enter__(self) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.py:37:15: PYI034 `__aenter__` methods in classes like `Bad` usually return `self` at runtime +PYI034.py:39:15: PYI034 `__aenter__` methods in classes like `Bad` usually return `self` at runtime | -35 | ... # Y034 "__enter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__enter__", e.g. "def __enter__(self) -> Self: ..." -36 | -37 | async def __aenter__(self) -> Bad: +37 | ... # Y034 "__enter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__enter__", e.g. "def __enter__(self) -> Self: ..." +38 | +39 | async def __aenter__(self) -> Bad: | ^^^^^^^^^^ PYI034 -38 | ... # Y034 "__aenter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__aenter__", e.g. "async def __aenter__(self) -> Self: ..." +40 | ... # Y034 "__aenter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__aenter__", e.g. "async def __aenter__(self) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.py:40:9: PYI034 `__iadd__` methods in classes like `Bad` usually return `self` at runtime +PYI034.py:42:9: PYI034 `__iadd__` methods in classes like `Bad` usually return `self` at runtime | -38 | ... # Y034 "__aenter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__aenter__", e.g. "async def __aenter__(self) -> Self: ..." -39 | -40 | def __iadd__(self, other: Bad) -> Bad: +40 | ... # Y034 "__aenter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__aenter__", e.g. "async def __aenter__(self) -> Self: ..." +41 | +42 | def __iadd__(self, other: Bad) -> Bad: | ^^^^^^^^ PYI034 -41 | ... # Y034 "__iadd__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__iadd__", e.g. "def __iadd__(self, other: Bad) -> Self: ..." +43 | ... # Y034 "__iadd__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__iadd__", e.g. "def __iadd__(self, other: Bad) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.py:163:9: PYI034 `__iter__` methods in classes like `BadIterator1` usually return `self` at runtime +PYI034.py:165:9: PYI034 `__iter__` methods in classes like `BadIterator1` usually return `self` at runtime | -162 | class BadIterator1(Iterator[int]): -163 | def __iter__(self) -> Iterator[int]: +164 | class BadIterator1(Iterator[int]): +165 | def __iter__(self) -> Iterator[int]: | ^^^^^^^^ PYI034 -164 | ... # Y034 "__iter__" methods in classes like "BadIterator1" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadIterator1.__iter__", e.g. "def __iter__(self) -> Self: ..." +166 | ... # Y034 "__iter__" methods in classes like "BadIterator1" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadIterator1.__iter__", e.g. "def __iter__(self) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.py:170:9: PYI034 `__iter__` methods in classes like `BadIterator2` usually return `self` at runtime +PYI034.py:172:9: PYI034 `__iter__` methods in classes like `BadIterator2` usually return `self` at runtime | -168 | typing.Iterator[int] -169 | ): # Y022 Use "collections.abc.Iterator[T]" instead of "typing.Iterator[T]" (PEP 585 syntax) -170 | def __iter__(self) -> Iterator[int]: +170 | typing.Iterator[int] +171 | ): # Y022 Use "collections.abc.Iterator[T]" instead of "typing.Iterator[T]" (PEP 585 syntax) +172 | def __iter__(self) -> Iterator[int]: | ^^^^^^^^ PYI034 -171 | ... # Y034 "__iter__" methods in classes like "BadIterator2" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadIterator2.__iter__", e.g. "def __iter__(self) -> Self: ..." +173 | ... # Y034 "__iter__" methods in classes like "BadIterator2" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadIterator2.__iter__", e.g. "def __iter__(self) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.py:177:9: PYI034 `__iter__` methods in classes like `BadIterator3` usually return `self` at runtime +PYI034.py:179:9: PYI034 `__iter__` methods in classes like `BadIterator3` usually return `self` at runtime | -175 | typing.Iterator[int] -176 | ): # Y022 Use "collections.abc.Iterator[T]" instead of "typing.Iterator[T]" (PEP 585 syntax) -177 | def __iter__(self) -> collections.abc.Iterator[int]: +177 | typing.Iterator[int] +178 | ): # Y022 Use "collections.abc.Iterator[T]" instead of "typing.Iterator[T]" (PEP 585 syntax) +179 | def __iter__(self) -> collections.abc.Iterator[int]: | ^^^^^^^^ PYI034 -178 | ... # Y034 "__iter__" methods in classes like "BadIterator3" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadIterator3.__iter__", e.g. "def __iter__(self) -> Self: ..." +180 | ... # Y034 "__iter__" methods in classes like "BadIterator3" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadIterator3.__iter__", e.g. "def __iter__(self) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.py:183:9: PYI034 `__iter__` methods in classes like `BadIterator4` usually return `self` at runtime +PYI034.py:185:9: PYI034 `__iter__` methods in classes like `BadIterator4` usually return `self` at runtime | -181 | class BadIterator4(Iterator[int]): -182 | # Note: *Iterable*, not *Iterator*, returned! -183 | def __iter__(self) -> Iterable[int]: +183 | class BadIterator4(Iterator[int]): +184 | # Note: *Iterable*, not *Iterator*, returned! +185 | def __iter__(self) -> Iterable[int]: | ^^^^^^^^ PYI034 -184 | ... # Y034 "__iter__" methods in classes like "BadIterator4" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadIterator4.__iter__", e.g. "def __iter__(self) -> Self: ..." +186 | ... # Y034 "__iter__" methods in classes like "BadIterator4" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadIterator4.__iter__", e.g. "def __iter__(self) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.py:193:9: PYI034 `__aiter__` methods in classes like `BadAsyncIterator` usually return `self` at runtime +PYI034.py:195:9: PYI034 `__aiter__` methods in classes like `BadAsyncIterator` usually return `self` at runtime | -192 | class BadAsyncIterator(collections.abc.AsyncIterator[str]): -193 | def __aiter__(self) -> typing.AsyncIterator[str]: +194 | class BadAsyncIterator(collections.abc.AsyncIterator[str]): +195 | def __aiter__(self) -> typing.AsyncIterator[str]: | ^^^^^^^^^ PYI034 -194 | ... # Y034 "__aiter__" methods in classes like "BadAsyncIterator" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadAsyncIterator.__aiter__", e.g. "def __aiter__(self) -> Self: ..." # Y022 Use "collections.abc.AsyncIterator[T]" instead of "typing.AsyncIterator[T]" (PEP 585 syntax) +196 | ... # Y034 "__aiter__" methods in classes like "BadAsyncIterator" usually return "self" at runtime. Consider using "typing_extensions.Self" in "BadAsyncIterator.__aiter__", e.g. "def __aiter__(self) -> Self: ..." # Y022 Use "collections.abc.AsyncIterator[T]" instead of "typing.AsyncIterator[T]" (PEP 585 syntax) | = help: Consider using `typing_extensions.Self` as return type diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI034_PYI034.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI034_PYI034.pyi.snap index 416d321a775aa..6441209dd6cd4 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI034_PYI034.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI034_PYI034.pyi.snap @@ -1,100 +1,100 @@ --- source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs --- -PYI034.pyi:18:9: PYI034 `__new__` methods in classes like `Bad` usually return `self` at runtime +PYI034.pyi:20:9: PYI034 `__new__` methods in classes like `Bad` usually return `self` at runtime | -16 | object -17 | ): # Y040 Do not inherit from "object" explicitly, as it is redundant in Python 3 -18 | def __new__( +18 | object +19 | ): # Y040 Do not inherit from "object" explicitly, as it is redundant in Python 3 +20 | def __new__( | ^^^^^^^ PYI034 -19 | cls, *args: Any, **kwargs: Any -20 | ) -> Bad: ... # Y034 "__new__" methods usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__new__", e.g. "def __new__(cls, *args: Any, **kwargs: Any) -> Self: ..." +21 | cls, *args: Any, **kwargs: Any +22 | ) -> Bad: ... # Y034 "__new__" methods usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__new__", e.g. "def __new__(cls, *args: Any, **kwargs: Any) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.pyi:33:9: PYI034 `__enter__` methods in classes like `Bad` usually return `self` at runtime +PYI034.pyi:35:9: PYI034 `__enter__` methods in classes like `Bad` usually return `self` at runtime | -31 | self, other: typing.Any -32 | ) -> typing.Any: ... # Y032 Prefer "object" to "Any" for the second parameter in "__ne__" methods -33 | def __enter__( +33 | self, other: typing.Any +34 | ) -> typing.Any: ... # Y032 Prefer "object" to "Any" for the second parameter in "__ne__" methods +35 | def __enter__( | ^^^^^^^^^ PYI034 -34 | self, -35 | ) -> Bad: ... # Y034 "__enter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__enter__", e.g. "def __enter__(self) -> Self: ..." +36 | self, +37 | ) -> Bad: ... # Y034 "__enter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__enter__", e.g. "def __enter__(self) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.pyi:36:15: PYI034 `__aenter__` methods in classes like `Bad` usually return `self` at runtime +PYI034.pyi:38:15: PYI034 `__aenter__` methods in classes like `Bad` usually return `self` at runtime | -34 | self, -35 | ) -> Bad: ... # Y034 "__enter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__enter__", e.g. "def __enter__(self) -> Self: ..." -36 | async def __aenter__( +36 | self, +37 | ) -> Bad: ... # Y034 "__enter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__enter__", e.g. "def __enter__(self) -> Self: ..." +38 | async def __aenter__( | ^^^^^^^^^^ PYI034 -37 | self, -38 | ) -> Bad: ... # Y034 "__aenter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__aenter__", e.g. "async def __aenter__(self) -> Self: ..." +39 | self, +40 | ) -> Bad: ... # Y034 "__aenter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__aenter__", e.g. "async def __aenter__(self) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.pyi:39:9: PYI034 `__iadd__` methods in classes like `Bad` usually return `self` at runtime +PYI034.pyi:41:9: PYI034 `__iadd__` methods in classes like `Bad` usually return `self` at runtime | -37 | self, -38 | ) -> Bad: ... # Y034 "__aenter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__aenter__", e.g. "async def __aenter__(self) -> Self: ..." -39 | def __iadd__( +39 | self, +40 | ) -> Bad: ... # Y034 "__aenter__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__aenter__", e.g. "async def __aenter__(self) -> Self: ..." +41 | def __iadd__( | ^^^^^^^^ PYI034 -40 | self, other: Bad -41 | ) -> Bad: ... # Y034 "__iadd__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__iadd__", e.g. "def __iadd__(self, other: Bad) -> Self: ..." +42 | self, other: Bad +43 | ) -> Bad: ... # Y034 "__iadd__" methods in classes like "Bad" usually return "self" at runtime. Consider using "typing_extensions.Self" in "Bad.__iadd__", e.g. "def __iadd__(self, other: Bad) -> Self: ..." | = help: Consider using `typing_extensions.Self` as return type -PYI034.pyi:102:9: PYI034 `__iter__` methods in classes like `BadIterator1` usually return `self` at runtime +PYI034.pyi:104:9: PYI034 `__iter__` methods in classes like `BadIterator1` usually return `self` at runtime | -101 | class BadIterator1(Iterator[int]): -102 | def __iter__( +103 | class BadIterator1(Iterator[int]): +104 | def __iter__( | ^^^^^^^^ PYI034 -103 | self, -104 | ) -> Iterator[ +105 | self, +106 | ) -> Iterator[ | = help: Consider using `typing_extensions.Self` as return type -PYI034.pyi:111:9: PYI034 `__iter__` methods in classes like `BadIterator2` usually return `self` at runtime +PYI034.pyi:113:9: PYI034 `__iter__` methods in classes like `BadIterator2` usually return `self` at runtime | -109 | typing.Iterator[int] -110 | ): # Y022 Use "collections.abc.Iterator[T]" instead of "typing.Iterator[T]" (PEP 585 syntax) -111 | def __iter__( +111 | typing.Iterator[int] +112 | ): # Y022 Use "collections.abc.Iterator[T]" instead of "typing.Iterator[T]" (PEP 585 syntax) +113 | def __iter__( | ^^^^^^^^ PYI034 -112 | self, -113 | ) -> Iterator[ +114 | self, +115 | ) -> Iterator[ | = help: Consider using `typing_extensions.Self` as return type -PYI034.pyi:120:9: PYI034 `__iter__` methods in classes like `BadIterator3` usually return `self` at runtime +PYI034.pyi:122:9: PYI034 `__iter__` methods in classes like `BadIterator3` usually return `self` at runtime | -118 | typing.Iterator[int] -119 | ): # Y022 Use "collections.abc.Iterator[T]" instead of "typing.Iterator[T]" (PEP 585 syntax) -120 | def __iter__( +120 | typing.Iterator[int] +121 | ): # Y022 Use "collections.abc.Iterator[T]" instead of "typing.Iterator[T]" (PEP 585 syntax) +122 | def __iter__( | ^^^^^^^^ PYI034 -121 | self, -122 | ) -> collections.abc.Iterator[ +123 | self, +124 | ) -> collections.abc.Iterator[ | = help: Consider using `typing_extensions.Self` as return type -PYI034.pyi:128:9: PYI034 `__iter__` methods in classes like `BadIterator4` usually return `self` at runtime +PYI034.pyi:130:9: PYI034 `__iter__` methods in classes like `BadIterator4` usually return `self` at runtime | -126 | class BadIterator4(Iterator[int]): -127 | # Note: *Iterable*, not *Iterator*, returned! -128 | def __iter__( +128 | class BadIterator4(Iterator[int]): +129 | # Note: *Iterable*, not *Iterator*, returned! +130 | def __iter__( | ^^^^^^^^ PYI034 -129 | self, -130 | ) -> Iterable[ +131 | self, +132 | ) -> Iterable[ | = help: Consider using `typing_extensions.Self` as return type -PYI034.pyi:142:9: PYI034 `__aiter__` methods in classes like `BadAsyncIterator` usually return `self` at runtime +PYI034.pyi:144:9: PYI034 `__aiter__` methods in classes like `BadAsyncIterator` usually return `self` at runtime | -141 | class BadAsyncIterator(collections.abc.AsyncIterator[str]): -142 | def __aiter__( +143 | class BadAsyncIterator(collections.abc.AsyncIterator[str]): +144 | def __aiter__( | ^^^^^^^^^ PYI034 -143 | self, -144 | ) -> typing.AsyncIterator[ +145 | self, +146 | ) -> typing.AsyncIterator[ | = help: Consider using `typing_extensions.Self` as return type