diff --git a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI019.py b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI019.py index 72bc86ac036f6..37dd8dfb574c3 100644 --- a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI019.py +++ b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI019.py @@ -4,14 +4,14 @@ _S2 = TypeVar("_S2", BadClass, GoodClass) class BadClass: - def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # Ok + def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019 - def bad_instance_method(self: _S, arg: bytes) -> _S: ... # Ok + def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019 @classmethod - def bad_class_method(cls: type[_S], arg: int) -> _S: ... # Ok + def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019 @classmethod @@ -32,10 +32,10 @@ def static_method(arg1: _S) -> _S: ... # Python > 3.12 class PEP695BadDunderNew[T]: - def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # Ok + def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019 - def generic_instance_method[S](self: S) -> S: ... # Ok + def generic_instance_method[S](self: S) -> S: ... # PYI019 class PEP695GoodDunderNew[T]: diff --git a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI024.py b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI024.py index 3090ae76c3192..b3d3b67b9ed03 100644 --- a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI024.py +++ b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI024.py @@ -1,9 +1,11 @@ import collections -person: collections.namedtuple # OK +person: collections.namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple" from collections import namedtuple -person: namedtuple # OK +person: namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple" -person = namedtuple("Person", ["name", "age"]) # OK +person = namedtuple( + "Person", ["name", "age"] +) # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple" diff --git a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI030.py b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI030.py index cc199f1480479..3c9d0ac15c9c3 100644 --- a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI030.py +++ b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI030.py @@ -1,24 +1,38 @@ +import typing +import typing_extensions from typing import Literal -# Shouldn't emit for any cases in the non-stub file for compatibility with flake8-pyi. -# Note that this rule could be applied here in the future. +# Shouldn't affect non-union field types. field1: Literal[1] # OK -field2: Literal[1] | Literal[2] # OK -def func1(arg1: Literal[1] | Literal[2]): # OK +# Should emit for duplicate field types. +field2: Literal[1] | Literal[2] # Error + +# Should emit for union types in arguments. +def func1(arg1: Literal[1] | Literal[2]): # Error print(arg1) -def func2() -> Literal[1] | Literal[2]: # OK +# Should emit for unions in return types. +def func2() -> Literal[1] | Literal[2]: # Error return "my Literal[1]ing" -field3: Literal[1] | Literal[2] | str # OK -field4: str | Literal[1] | Literal[2] # OK -field5: Literal[1] | str | Literal[2] # OK -field6: Literal[1] | bool | Literal[2] | str # OK -field7 = Literal[1] | Literal[2] # OK -field8: Literal[1] | (Literal[2] | str) # OK -field9: Literal[1] | (Literal[2] | str) # OK -field10: (Literal[1] | str) | Literal[2] # OK -field11: dict[Literal[1] | Literal[2], str] # OK +# Should emit in longer unions, even if not directly adjacent. +field3: Literal[1] | Literal[2] | str # Error +field4: str | Literal[1] | Literal[2] # Error +field5: Literal[1] | str | Literal[2] # Error +field6: Literal[1] | bool | Literal[2] | str # Error + +# Should emit for non-type unions. +field7 = Literal[1] | Literal[2] # Error + +# Should emit for parenthesized unions. +field8: Literal[1] | (Literal[2] | str) # Error + +# Should handle user parentheses when fixing. +field9: Literal[1] | (Literal[2] | str) # Error +field10: (Literal[1] | str) | Literal[2] # Error + +# Should emit for union in generic parent type. +field11: dict[Literal[1] | Literal[2], str] # Error diff --git a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI032.py b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI032.py index 2d226ebe975f8..82cb899e3b323 100644 --- a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI032.py +++ b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI032.py @@ -3,8 +3,8 @@ class Bad: - def __eq__(self, other: Any) -> bool: ... # Fine because not a stub file - def __ne__(self, other: typing.Any) -> typing.Any: ... # Fine because not a stub file + def __eq__(self, other: Any) -> bool: ... # Y032 + def __ne__(self, other: typing.Any) -> typing.Any: ... # Y032 class Good: diff --git a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI042.py b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI042.py index 8b159057d71eb..2936c39c6c836 100644 --- a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI042.py +++ b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI042.py @@ -9,16 +9,16 @@ just_literals_pipe_union: TypeAlias = ( Literal[True] | Literal["idk"] -) # not PYI042 (not a stubfile) +) # PYI042, since not camel case PublicAliasT: TypeAlias = str | int PublicAliasT2: TypeAlias = Union[str, bytes] _ABCDEFGHIJKLMNOPQRST: TypeAlias = typing.Any _PrivateAliasS: TypeAlias = Literal["I", "guess", "this", "is", "okay"] _PrivateAliasS2: TypeAlias = Annotated[str, "also okay"] -snake_case_alias1: TypeAlias = str | int # not PYI042 (not a stubfile) -_snake_case_alias2: TypeAlias = Literal["whatever"] # not PYI042 (not a stubfile) -Snake_case_alias: TypeAlias = int | float # not PYI042 (not a stubfile) +snake_case_alias1: TypeAlias = str | int # PYI042, since not camel case +_snake_case_alias2: TypeAlias = Literal["whatever"] # PYI042, since not camel case +Snake_case_alias: TypeAlias = int | float # PYI042, since not camel case # check that this edge case doesn't crash _: TypeAlias = str | int diff --git a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI043.py b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI043.py index d129f5befa06b..b48f5e0fa8c47 100644 --- a/crates/ruff/resources/test/fixtures/flake8_pyi/PYI043.py +++ b/crates/ruff/resources/test/fixtures/flake8_pyi/PYI043.py @@ -7,11 +7,11 @@ Literal, ) -_PrivateAliasT: TypeAlias = str | int # not PYI043 (not a stubfile) -_PrivateAliasT2: TypeAlias = typing.Any # not PYI043 (not a stubfile) +_PrivateAliasT: TypeAlias = str | int # PYI043, since this ends in a T +_PrivateAliasT2: TypeAlias = typing.Any # PYI043, since this ends in a T _PrivateAliasT3: TypeAlias = Literal[ "not", "a", "chance" -] # not PYI043 (not a stubfile) +] # PYI043, since this ends in a T just_literals_pipe_union: TypeAlias = Literal[True] | Literal["idk"] PublicAliasT: TypeAlias = str | int PublicAliasT2: TypeAlias = Union[str, bytes] diff --git a/crates/ruff/src/checkers/ast/analyze/bindings.rs b/crates/ruff/src/checkers/ast/analyze/bindings.rs index 80c632308fbea..8cce5812eba53 100644 --- a/crates/ruff/src/checkers/ast/analyze/bindings.rs +++ b/crates/ruff/src/checkers/ast/analyze/bindings.rs @@ -56,13 +56,11 @@ pub(crate) fn bindings(checker: &mut Checker) { checker.diagnostics.push(diagnostic); } } - if checker.is_stub { - if checker.enabled(Rule::UnaliasedCollectionsAbcSetImport) { - if let Some(diagnostic) = - flake8_pyi::rules::unaliased_collections_abc_set_import(checker, binding) - { - checker.diagnostics.push(diagnostic); - } + if checker.enabled(Rule::UnaliasedCollectionsAbcSetImport) { + if let Some(diagnostic) = + flake8_pyi::rules::unaliased_collections_abc_set_import(checker, binding) + { + checker.diagnostics.push(diagnostic); } } } diff --git a/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs b/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs index f020fcadbb674..f17bd14763001 100644 --- a/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs +++ b/crates/ruff/src/checkers/ast/analyze/deferred_scopes.rs @@ -218,19 +218,17 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) { } } - if checker.is_stub { - if checker.enabled(Rule::UnusedPrivateTypeVar) { - flake8_pyi::rules::unused_private_type_var(checker, scope, &mut diagnostics); - } - if checker.enabled(Rule::UnusedPrivateProtocol) { - flake8_pyi::rules::unused_private_protocol(checker, scope, &mut diagnostics); - } - if checker.enabled(Rule::UnusedPrivateTypeAlias) { - flake8_pyi::rules::unused_private_type_alias(checker, scope, &mut diagnostics); - } - if checker.enabled(Rule::UnusedPrivateTypedDict) { - flake8_pyi::rules::unused_private_typed_dict(checker, scope, &mut diagnostics); - } + if checker.enabled(Rule::UnusedPrivateTypeVar) { + flake8_pyi::rules::unused_private_type_var(checker, scope, &mut diagnostics); + } + if checker.enabled(Rule::UnusedPrivateProtocol) { + flake8_pyi::rules::unused_private_protocol(checker, scope, &mut diagnostics); + } + if checker.enabled(Rule::UnusedPrivateTypeAlias) { + flake8_pyi::rules::unused_private_type_alias(checker, scope, &mut diagnostics); + } + if checker.enabled(Rule::UnusedPrivateTypedDict) { + flake8_pyi::rules::unused_private_typed_dict(checker, scope, &mut diagnostics); } if matches!( diff --git a/crates/ruff/src/checkers/ast/analyze/definitions.rs b/crates/ruff/src/checkers/ast/analyze/definitions.rs index 83068ca94c739..02339a232e840 100644 --- a/crates/ruff/src/checkers/ast/analyze/definitions.rs +++ b/crates/ruff/src/checkers/ast/analyze/definitions.rs @@ -30,8 +30,8 @@ pub(crate) fn definitions(checker: &mut Checker) { Rule::MissingTypeKwargs, Rule::MissingTypeSelf, ]); - let enforce_stubs = checker.is_stub - && checker.any_enabled(&[Rule::DocstringInStub, Rule::IterMethodReturnIterable]); + let enforce_stubs = checker.is_stub && checker.enabled(Rule::DocstringInStub); + let enforce_stubs_and_runtime = checker.enabled(Rule::IterMethodReturnIterable); let enforce_docstrings = checker.any_enabled(&[ Rule::BlankLineAfterLastSection, Rule::BlankLineAfterSummary, @@ -81,7 +81,7 @@ pub(crate) fn definitions(checker: &mut Checker) { Rule::UndocumentedPublicPackage, ]); - if !enforce_annotations && !enforce_docstrings && !enforce_stubs { + if !enforce_annotations && !enforce_docstrings && !enforce_stubs && !enforce_stubs_and_runtime { return; } @@ -141,6 +141,8 @@ pub(crate) fn definitions(checker: &mut Checker) { if checker.enabled(Rule::DocstringInStub) { flake8_pyi::rules::docstring_in_stubs(checker, docstring); } + } + if enforce_stubs_and_runtime { if checker.enabled(Rule::IterMethodReturnIterable) { flake8_pyi::rules::iter_method_return_iterable(checker, definition); } diff --git a/crates/ruff/src/checkers/ast/analyze/expression.rs b/crates/ruff/src/checkers/ast/analyze/expression.rs index 922ff248f2440..d064e086db5df 100644 --- a/crates/ruff/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff/src/checkers/ast/analyze/expression.rs @@ -159,10 +159,8 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::NumpyDeprecatedFunction) { numpy::rules::deprecated_function(checker, expr); } - if checker.is_stub { - if checker.enabled(Rule::CollectionsNamedTuple) { - flake8_pyi::rules::collections_named_tuple(checker, expr); - } + if checker.enabled(Rule::CollectionsNamedTuple) { + flake8_pyi::rules::collections_named_tuple(checker, expr); } // Ex) List[...] @@ -323,10 +321,8 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::PrivateMemberAccess) { flake8_self::rules::private_member_access(checker, expr); } - if checker.is_stub { - if checker.enabled(Rule::CollectionsNamedTuple) { - flake8_pyi::rules::collections_named_tuple(checker, expr); - } + if checker.enabled(Rule::CollectionsNamedTuple) { + flake8_pyi::rules::collections_named_tuple(checker, expr); } pandas_vet::rules::attr(checker, attr, value, expr); } @@ -868,7 +864,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::DjangoLocalsInRenderFunction) { flake8_django::rules::locals_in_render_function(checker, call); } - if checker.is_stub && checker.enabled(Rule::UnsupportedMethodCallOnAll) { + if checker.enabled(Rule::UnsupportedMethodCallOnAll) { flake8_pyi::rules::unsupported_method_call_on_all(checker, func); } } @@ -1079,35 +1075,33 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { ); } } - if checker.is_stub { - if checker.enabled(Rule::DuplicateUnionMember) - && checker.semantic.in_type_definition() - // Avoid duplicate checks if the parent is an `|` - && !matches!( - checker.semantic.expr_parent(), - Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) - ) - { - flake8_pyi::rules::duplicate_union_member(checker, expr); - } - if checker.enabled(Rule::UnnecessaryLiteralUnion) - // Avoid duplicate checks if the parent is an `|` - && !matches!( - checker.semantic.expr_parent(), - Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) - ) - { - flake8_pyi::rules::unnecessary_literal_union(checker, expr); - } - if checker.enabled(Rule::RedundantLiteralUnion) - // Avoid duplicate checks if the parent is an `|` - && !matches!( - checker.semantic.expr_parent(), - Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) - ) - { - flake8_pyi::rules::redundant_literal_union(checker, expr); - } + if checker.enabled(Rule::DuplicateUnionMember) + && checker.semantic.in_type_definition() + // Avoid duplicate checks if the parent is an `|` + && !matches!( + checker.semantic.expr_parent(), + Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) + ) + { + flake8_pyi::rules::duplicate_union_member(checker, expr); + } + if checker.enabled(Rule::UnnecessaryLiteralUnion) + // Avoid duplicate checks if the parent is an `|` + && !matches!( + checker.semantic.expr_parent(), + Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) + ) + { + flake8_pyi::rules::unnecessary_literal_union(checker, expr); + } + if checker.enabled(Rule::RedundantLiteralUnion) + // Avoid duplicate checks if the parent is an `|` + && !matches!( + checker.semantic.expr_parent(), + Some(Expr::BinOp(ast::ExprBinOp { op: Operator::BitOr, ..})) + ) + { + flake8_pyi::rules::redundant_literal_union(checker, expr); } } Expr::UnaryOp(ast::ExprUnaryOp { diff --git a/crates/ruff/src/checkers/ast/analyze/statement.rs b/crates/ruff/src/checkers/ast/analyze/statement.rs index e697d6a476e2d..1a1910dc7a14f 100644 --- a/crates/ruff/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff/src/checkers/ast/analyze/statement.rs @@ -143,47 +143,51 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::StubBodyMultipleStatements) { flake8_pyi::rules::stub_body_multiple_statements(checker, stmt, body); } - if checker.enabled(Rule::AnyEqNeAnnotation) { - flake8_pyi::rules::any_eq_ne_annotation(checker, name, parameters); - } - if checker.enabled(Rule::NonSelfReturnType) { - flake8_pyi::rules::non_self_return_type( - checker, - stmt, - name, - decorator_list, - returns.as_ref().map(AsRef::as_ref), - parameters, - stmt.is_async_function_def_stmt(), - ); - } - if checker.enabled(Rule::CustomTypeVarReturnType) { - flake8_pyi::rules::custom_type_var_return_type( - checker, - name, - decorator_list, - returns.as_ref().map(AsRef::as_ref), - parameters, - type_params.as_ref(), - ); - } + } + if checker.enabled(Rule::AnyEqNeAnnotation) { + flake8_pyi::rules::any_eq_ne_annotation(checker, name, parameters); + } + if checker.enabled(Rule::NonSelfReturnType) { + flake8_pyi::rules::non_self_return_type( + checker, + stmt, + name, + decorator_list, + returns.as_ref().map(AsRef::as_ref), + parameters, + stmt.is_async_function_def_stmt(), + ); + } + if checker.enabled(Rule::CustomTypeVarReturnType) { + flake8_pyi::rules::custom_type_var_return_type( + checker, + name, + decorator_list, + returns.as_ref().map(AsRef::as_ref), + parameters, + type_params.as_ref(), + ); + } + if checker.is_stub { if checker.enabled(Rule::StrOrReprDefinedInStub) { flake8_pyi::rules::str_or_repr_defined_in_stub(checker, stmt); } + } + if checker.is_stub || checker.settings.target_version >= PythonVersion::Py311 { if checker.enabled(Rule::NoReturnArgumentAnnotationInStub) { flake8_pyi::rules::no_return_argument_annotation(checker, parameters); } - if checker.enabled(Rule::BadExitAnnotation) { - flake8_pyi::rules::bad_exit_annotation( - checker, - stmt.is_async_function_def_stmt(), - name, - parameters, - ); - } - if checker.enabled(Rule::RedundantNumericUnion) { - flake8_pyi::rules::redundant_numeric_union(checker, parameters); - } + } + if checker.enabled(Rule::BadExitAnnotation) { + flake8_pyi::rules::bad_exit_annotation( + checker, + stmt.is_async_function_def_stmt(), + name, + parameters, + ); + } + if checker.enabled(Rule::RedundantNumericUnion) { + flake8_pyi::rules::redundant_numeric_union(checker, parameters); } if checker.enabled(Rule::DunderFunctionName) { if let Some(diagnostic) = pep8_naming::rules::dunder_function_name( @@ -470,9 +474,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::PassInClassBody) { flake8_pyi::rules::pass_in_class_body(checker, stmt, body); } - if checker.enabled(Rule::EllipsisInNonEmptyClassBody) { - flake8_pyi::rules::ellipsis_in_non_empty_class_body(checker, stmt, body); - } + } + if checker.enabled(Rule::EllipsisInNonEmptyClassBody) { + flake8_pyi::rules::ellipsis_in_non_empty_class_body(checker, stmt, body); } if checker.enabled(Rule::PytestIncorrectMarkParenthesesStyle) { flake8_pytest_style::rules::marks(checker, decorator_list); @@ -1407,13 +1411,13 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { ); } } - if checker.semantic.match_typing_expr(annotation, "TypeAlias") { - if checker.enabled(Rule::SnakeCaseTypeAlias) { - flake8_pyi::rules::snake_case_type_alias(checker, target); - } - if checker.enabled(Rule::TSuffixedTypeAlias) { - flake8_pyi::rules::t_suffixed_type_alias(checker, target); - } + } + if checker.semantic.match_typing_expr(annotation, "TypeAlias") { + if checker.enabled(Rule::SnakeCaseTypeAlias) { + flake8_pyi::rules::snake_case_type_alias(checker, target); + } + if checker.enabled(Rule::TSuffixedTypeAlias) { + flake8_pyi::rules::t_suffixed_type_alias(checker, target); } } } diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI013_PYI013.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI013_PYI013.py.snap index d1aa2e9116558..7e0954fb1cf64 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI013_PYI013.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI013_PYI013.py.snap @@ -1,4 +1,149 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI013.py:3:5: PYI013 [*] Non-empty class body must not contain `...` + | +1 | class OneAttributeClass: +2 | value: int +3 | ... + | ^^^ PYI013 + | + = help: Remove unnecessary `...` + +ℹ Fix +1 1 | class OneAttributeClass: +2 2 | value: int +3 |- ... +4 3 | +5 4 | +6 5 | class OneAttributeClass2: + +PYI013.py:7:5: PYI013 [*] Non-empty class body must not contain `...` + | +6 | class OneAttributeClass2: +7 | ... + | ^^^ PYI013 +8 | value: int + | + = help: Remove unnecessary `...` + +ℹ Fix +4 4 | +5 5 | +6 6 | class OneAttributeClass2: +7 |- ... +8 7 | value: int +9 8 | +10 9 | + +PYI013.py:12:5: PYI013 [*] Non-empty class body must not contain `...` + | +11 | class TwoEllipsesClass: +12 | ... + | ^^^ PYI013 +13 | ... + | + = help: Remove unnecessary `...` + +ℹ Fix +10 10 | +11 11 | class TwoEllipsesClass: +12 12 | ... +13 |- ... +14 13 | +15 14 | +16 15 | class DocstringClass: + +PYI013.py:13:5: PYI013 [*] Non-empty class body must not contain `...` + | +11 | class TwoEllipsesClass: +12 | ... +13 | ... + | ^^^ PYI013 + | + = help: Remove unnecessary `...` + +ℹ Fix +10 10 | +11 11 | class TwoEllipsesClass: +12 12 | ... +13 |- ... +14 13 | +15 14 | +16 15 | class DocstringClass: + +PYI013.py:21:5: PYI013 [*] Non-empty class body must not contain `...` + | +19 | """ +20 | +21 | ... + | ^^^ PYI013 + | + = help: Remove unnecessary `...` + +ℹ Fix +18 18 | My body only contains an ellipsis. +19 19 | """ +20 20 | +21 |- ... +22 21 | +23 22 | +24 23 | class NonEmptyChild(Exception): + +PYI013.py:26:5: PYI013 [*] Non-empty class body must not contain `...` + | +24 | class NonEmptyChild(Exception): +25 | value: int +26 | ... + | ^^^ PYI013 + | + = help: Remove unnecessary `...` + +ℹ Fix +23 23 | +24 24 | class NonEmptyChild(Exception): +25 25 | value: int +26 |- ... +27 26 | +28 27 | +29 28 | class NonEmptyChild2(Exception): + +PYI013.py:30:5: PYI013 [*] Non-empty class body must not contain `...` + | +29 | class NonEmptyChild2(Exception): +30 | ... + | ^^^ PYI013 +31 | value: int + | + = help: Remove unnecessary `...` + +ℹ Fix +27 27 | +28 28 | +29 29 | class NonEmptyChild2(Exception): +30 |- ... +31 30 | value: int +32 31 | +33 32 | + +PYI013.py:36:5: PYI013 [*] Non-empty class body must not contain `...` + | +34 | class NonEmptyWithInit: +35 | value: int +36 | ... + | ^^^ PYI013 +37 | +38 | def __init__(): + | + = help: Remove unnecessary `...` + +ℹ Fix +33 33 | +34 34 | class NonEmptyWithInit: +35 35 | value: int +36 |- ... +37 36 | +38 37 | def __init__(): +39 38 | pass + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI016_PYI016.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI016_PYI016.py.snap index d1aa2e9116558..23b1b08e703b9 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI016_PYI016.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI016_PYI016.py.snap @@ -1,4 +1,217 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI016.py:5:15: PYI016 [*] Duplicate union member `str` + | +4 | # Should emit for duplicate field types. +5 | field2: str | str # PYI016: Duplicate union member `str` + | ^^^ PYI016 + | + = help: Remove duplicate union member `str` + +ℹ Fix +2 2 | field1: str +3 3 | +4 4 | # Should emit for duplicate field types. +5 |-field2: str | str # PYI016: Duplicate union member `str` + 5 |+field2: str # PYI016: Duplicate union member `str` +6 6 | +7 7 | +8 8 | # Should emit for union types in arguments. + +PYI016.py:9:23: PYI016 [*] Duplicate union member `int` + | + 8 | # Should emit for union types in arguments. + 9 | def func1(arg1: int | int): # PYI016: Duplicate union member `int` + | ^^^ PYI016 +10 | print(arg1) + | + = help: Remove duplicate union member `int` + +ℹ Fix +6 6 | +7 7 | +8 8 | # Should emit for union types in arguments. +9 |-def func1(arg1: int | int): # PYI016: Duplicate union member `int` + 9 |+def func1(arg1: int): # PYI016: Duplicate union member `int` +10 10 | print(arg1) +11 11 | +12 12 | + +PYI016.py:14:22: PYI016 [*] Duplicate union member `str` + | +13 | # Should emit for unions in return types. +14 | def func2() -> str | str: # PYI016: Duplicate union member `str` + | ^^^ PYI016 +15 | return "my string" + | + = help: Remove duplicate union member `str` + +ℹ Fix +11 11 | +12 12 | +13 13 | # Should emit for unions in return types. +14 |-def func2() -> str | str: # PYI016: Duplicate union member `str` + 14 |+def func2() -> str: # PYI016: Duplicate union member `str` +15 15 | return "my string" +16 16 | +17 17 | + +PYI016.py:19:15: PYI016 [*] Duplicate union member `str` + | +18 | # Should emit in longer unions, even if not directly adjacent. +19 | field3: str | str | int # PYI016: Duplicate union member `str` + | ^^^ PYI016 +20 | field4: int | int | str # PYI016: Duplicate union member `int` +21 | field5: str | int | str # PYI016: Duplicate union member `str` + | + = help: Remove duplicate union member `str` + +ℹ Fix +16 16 | +17 17 | +18 18 | # Should emit in longer unions, even if not directly adjacent. +19 |-field3: str | str | int # PYI016: Duplicate union member `str` + 19 |+field3: str | int # PYI016: Duplicate union member `str` +20 20 | field4: int | int | str # PYI016: Duplicate union member `int` +21 21 | field5: str | int | str # PYI016: Duplicate union member `str` +22 22 | field6: int | bool | str | int # PYI016: Duplicate union member `int` + +PYI016.py:20:15: PYI016 [*] Duplicate union member `int` + | +18 | # Should emit in longer unions, even if not directly adjacent. +19 | field3: str | str | int # PYI016: Duplicate union member `str` +20 | field4: int | int | str # PYI016: Duplicate union member `int` + | ^^^ PYI016 +21 | field5: str | int | str # PYI016: Duplicate union member `str` +22 | field6: int | bool | str | int # PYI016: Duplicate union member `int` + | + = help: Remove duplicate union member `int` + +ℹ Fix +17 17 | +18 18 | # Should emit in longer unions, even if not directly adjacent. +19 19 | field3: str | str | int # PYI016: Duplicate union member `str` +20 |-field4: int | int | str # PYI016: Duplicate union member `int` + 20 |+field4: int | str # PYI016: Duplicate union member `int` +21 21 | field5: str | int | str # PYI016: Duplicate union member `str` +22 22 | field6: int | bool | str | int # PYI016: Duplicate union member `int` +23 23 | + +PYI016.py:21:21: PYI016 [*] Duplicate union member `str` + | +19 | field3: str | str | int # PYI016: Duplicate union member `str` +20 | field4: int | int | str # PYI016: Duplicate union member `int` +21 | field5: str | int | str # PYI016: Duplicate union member `str` + | ^^^ PYI016 +22 | field6: int | bool | str | int # PYI016: Duplicate union member `int` + | + = help: Remove duplicate union member `str` + +ℹ Fix +18 18 | # Should emit in longer unions, even if not directly adjacent. +19 19 | field3: str | str | int # PYI016: Duplicate union member `str` +20 20 | field4: int | int | str # PYI016: Duplicate union member `int` +21 |-field5: str | int | str # PYI016: Duplicate union member `str` + 21 |+field5: str | int # PYI016: Duplicate union member `str` +22 22 | field6: int | bool | str | int # PYI016: Duplicate union member `int` +23 23 | +24 24 | # Shouldn't emit for non-type unions. + +PYI016.py:22:28: PYI016 [*] Duplicate union member `int` + | +20 | field4: int | int | str # PYI016: Duplicate union member `int` +21 | field5: str | int | str # PYI016: Duplicate union member `str` +22 | field6: int | bool | str | int # PYI016: Duplicate union member `int` + | ^^^ PYI016 +23 | +24 | # Shouldn't emit for non-type unions. + | + = help: Remove duplicate union member `int` + +ℹ Fix +19 19 | field3: str | str | int # PYI016: Duplicate union member `str` +20 20 | field4: int | int | str # PYI016: Duplicate union member `int` +21 21 | field5: str | int | str # PYI016: Duplicate union member `str` +22 |-field6: int | bool | str | int # PYI016: Duplicate union member `int` + 22 |+field6: int | bool | str # PYI016: Duplicate union member `int` +23 23 | +24 24 | # Shouldn't emit for non-type unions. +25 25 | field7 = str | str + +PYI016.py:28:22: PYI016 [*] Duplicate union member `int` + | +27 | # Should emit for strangely-bracketed unions. +28 | field8: int | (str | int) # PYI016: Duplicate union member `int` + | ^^^ PYI016 +29 | +30 | # Should handle user brackets when fixing. + | + = help: Remove duplicate union member `int` + +ℹ Fix +25 25 | field7 = str | str +26 26 | +27 27 | # Should emit for strangely-bracketed unions. +28 |-field8: int | (str | int) # PYI016: Duplicate union member `int` + 28 |+field8: int | (str) # PYI016: Duplicate union member `int` +29 29 | +30 30 | # Should handle user brackets when fixing. +31 31 | field9: int | (int | str) # PYI016: Duplicate union member `int` + +PYI016.py:31:16: PYI016 [*] Duplicate union member `int` + | +30 | # Should handle user brackets when fixing. +31 | field9: int | (int | str) # PYI016: Duplicate union member `int` + | ^^^ PYI016 +32 | field10: (str | int) | str # PYI016: Duplicate union member `str` + | + = help: Remove duplicate union member `int` + +ℹ Fix +28 28 | field8: int | (str | int) # PYI016: Duplicate union member `int` +29 29 | +30 30 | # Should handle user brackets when fixing. +31 |-field9: int | (int | str) # PYI016: Duplicate union member `int` + 31 |+field9: int | (str) # PYI016: Duplicate union member `int` +32 32 | field10: (str | int) | str # PYI016: Duplicate union member `str` +33 33 | +34 34 | # Should emit for nested unions. + +PYI016.py:32:24: PYI016 [*] Duplicate union member `str` + | +30 | # Should handle user brackets when fixing. +31 | field9: int | (int | str) # PYI016: Duplicate union member `int` +32 | field10: (str | int) | str # PYI016: Duplicate union member `str` + | ^^^ PYI016 +33 | +34 | # Should emit for nested unions. + | + = help: Remove duplicate union member `str` + +ℹ Fix +29 29 | +30 30 | # Should handle user brackets when fixing. +31 31 | field9: int | (int | str) # PYI016: Duplicate union member `int` +32 |-field10: (str | int) | str # PYI016: Duplicate union member `str` + 32 |+field10: str | int # PYI016: Duplicate union member `str` +33 33 | +34 34 | # Should emit for nested unions. +35 35 | field11: dict[int | int, str] + +PYI016.py:35:21: PYI016 [*] Duplicate union member `int` + | +34 | # Should emit for nested unions. +35 | field11: dict[int | int, str] + | ^^^ PYI016 + | + = help: Remove duplicate union member `int` + +ℹ Fix +32 32 | field10: (str | int) | str # PYI016: Duplicate union member `str` +33 33 | +34 34 | # Should emit for nested unions. +35 |-field11: dict[int | int, str] + 35 |+field11: dict[int, str] + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI018_PYI018.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI018_PYI018.py.snap index d1aa2e9116558..d61c7d9e11861 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI018_PYI018.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI018_PYI018.py.snap @@ -1,4 +1,22 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI018.py:4:1: PYI018 Private TypeVar `_T` is never used + | +2 | from typing import TypeVar +3 | +4 | _T = typing.TypeVar("_T") + | ^^ PYI018 +5 | _P = TypeVar("_P") + | + +PYI018.py:5:1: PYI018 Private TypeVar `_P` is never used + | +4 | _T = typing.TypeVar("_T") +5 | _P = TypeVar("_P") + | ^^ PYI018 +6 | +7 | # OK + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI019_PYI019.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI019_PYI019.py.snap index d1aa2e9116558..d3a7e225a1dba 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI019_PYI019.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI019_PYI019.py.snap @@ -1,4 +1,38 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI019.py:7:62: PYI019 Methods like `__new__` should return `typing.Self` instead of a custom `TypeVar` + | +6 | class BadClass: +7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019 + | ^^ PYI019 + | + +PYI019.py:10:54: PYI019 Methods like `bad_instance_method` should return `typing.Self` instead of a custom `TypeVar` + | +10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019 + | ^^ PYI019 + | + +PYI019.py:14:54: PYI019 Methods like `bad_class_method` should return `typing.Self` instead of a custom `TypeVar` + | +13 | @classmethod +14 | def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019 + | ^^ PYI019 + | + +PYI019.py:35:63: PYI019 Methods like `__new__` should return `typing.Self` instead of a custom `TypeVar` + | +33 | # Python > 3.12 +34 | class PEP695BadDunderNew[T]: +35 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019 + | ^ PYI019 + | + +PYI019.py:38:46: PYI019 Methods like `generic_instance_method` should return `typing.Self` instead of a custom `TypeVar` + | +38 | def generic_instance_method[S](self: S) -> S: ... # PYI019 + | ^ PYI019 + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI024_PYI024.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI024_PYI024.py.snap index d1aa2e9116558..aacfa649848ca 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI024_PYI024.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI024_PYI024.py.snap @@ -1,4 +1,37 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI024.py:3:9: PYI024 Use `typing.NamedTuple` instead of `collections.namedtuple` + | +1 | import collections +2 | +3 | person: collections.namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple" + | ^^^^^^^^^^^^^^^^^^^^^^ PYI024 +4 | +5 | from collections import namedtuple + | + = help: Replace with `typing.NamedTuple` + +PYI024.py:7:9: PYI024 Use `typing.NamedTuple` instead of `collections.namedtuple` + | +5 | from collections import namedtuple +6 | +7 | person: namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple" + | ^^^^^^^^^^ PYI024 +8 | +9 | person = namedtuple( + | + = help: Replace with `typing.NamedTuple` + +PYI024.py:9:10: PYI024 Use `typing.NamedTuple` instead of `collections.namedtuple` + | + 7 | person: namedtuple # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple" + 8 | + 9 | person = namedtuple( + | ^^^^^^^^^^ PYI024 +10 | "Person", ["name", "age"] +11 | ) # Y024 Use "typing.NamedTuple" instead of "collections.namedtuple" + | + = help: Replace with `typing.NamedTuple` + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI025_PYI025.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI025_PYI025.py.snap index d1aa2e9116558..606cc41cafe43 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI025_PYI025.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI025_PYI025.py.snap @@ -1,4 +1,46 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI025.py:10:33: PYI025 [*] Use `from collections.abc import Set as AbstractSet` to avoid confusion with the `set` builtin + | + 9 | def f(): +10 | from collections.abc import Set # PYI025 + | ^^^ PYI025 + | + = help: Alias `Set` to `AbstractSet` + +ℹ Suggested fix +7 7 | +8 8 | +9 9 | def f(): +10 |- from collections.abc import Set # PYI025 + 10 |+ from collections.abc import Set as AbstractSet # PYI025 +11 11 | +12 12 | +13 13 | def f(): + +PYI025.py:14:51: PYI025 [*] Use `from collections.abc import Set as AbstractSet` to avoid confusion with the `set` builtin + | +13 | def f(): +14 | from collections.abc import Container, Sized, Set, ValuesView # PYI025 + | ^^^ PYI025 +15 | +16 | GLOBAL: Set[int] = set() + | + = help: Alias `Set` to `AbstractSet` + +ℹ Suggested fix +11 11 | +12 12 | +13 13 | def f(): +14 |- from collections.abc import Container, Sized, Set, ValuesView # PYI025 + 14 |+ from collections.abc import Container, Sized, Set as AbstractSet, ValuesView # PYI025 +15 15 | +16 |- GLOBAL: Set[int] = set() + 16 |+ GLOBAL: AbstractSet[int] = set() +17 17 | +18 18 | class Class: +19 |- member: Set[int] + 19 |+ member: AbstractSet[int] + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI030_PYI030.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI030_PYI030.py.snap index d1aa2e9116558..204ae03602c62 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI030_PYI030.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI030_PYI030.py.snap @@ -1,4 +1,110 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI030.py:9:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | + 8 | # Should emit for duplicate field types. + 9 | field2: Literal[1] | Literal[2] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +10 | +11 | # Should emit for union types in arguments. + | + +PYI030.py:12:17: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +11 | # Should emit for union types in arguments. +12 | def func1(arg1: Literal[1] | Literal[2]): # Error + | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +13 | print(arg1) + | + +PYI030.py:17:16: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +16 | # Should emit for unions in return types. +17 | def func2() -> Literal[1] | Literal[2]: # Error + | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +18 | return "my Literal[1]ing" + | + +PYI030.py:22:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +21 | # Should emit in longer unions, even if not directly adjacent. +22 | field3: Literal[1] | Literal[2] | str # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +23 | field4: str | Literal[1] | Literal[2] # Error +24 | field5: Literal[1] | str | Literal[2] # Error + | + +PYI030.py:23:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +21 | # Should emit in longer unions, even if not directly adjacent. +22 | field3: Literal[1] | Literal[2] | str # Error +23 | field4: str | Literal[1] | Literal[2] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +24 | field5: Literal[1] | str | Literal[2] # Error +25 | field6: Literal[1] | bool | Literal[2] | str # Error + | + +PYI030.py:24:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +22 | field3: Literal[1] | Literal[2] | str # Error +23 | field4: str | Literal[1] | Literal[2] # Error +24 | field5: Literal[1] | str | Literal[2] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +25 | field6: Literal[1] | bool | Literal[2] | str # Error + | + +PYI030.py:25:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +23 | field4: str | Literal[1] | Literal[2] # Error +24 | field5: Literal[1] | str | Literal[2] # Error +25 | field6: Literal[1] | bool | Literal[2] | str # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +26 | +27 | # Should emit for non-type unions. + | + +PYI030.py:28:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +27 | # Should emit for non-type unions. +28 | field7 = Literal[1] | Literal[2] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +29 | +30 | # Should emit for parenthesized unions. + | + +PYI030.py:31:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +30 | # Should emit for parenthesized unions. +31 | field8: Literal[1] | (Literal[2] | str) # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +32 | +33 | # Should handle user parentheses when fixing. + | + +PYI030.py:34:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +33 | # Should handle user parentheses when fixing. +34 | field9: Literal[1] | (Literal[2] | str) # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +35 | field10: (Literal[1] | str) | Literal[2] # Error + | + +PYI030.py:35:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +33 | # Should handle user parentheses when fixing. +34 | field9: Literal[1] | (Literal[2] | str) # Error +35 | field10: (Literal[1] | str) | Literal[2] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030 +36 | +37 | # Should emit for union in generic parent type. + | + +PYI030.py:38:15: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]` + | +37 | # Should emit for union in generic parent type. +38 | field11: dict[Literal[1] | Literal[2], str] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^ PYI030 + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI032_PYI032.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI032_PYI032.py.snap index d1aa2e9116558..ddf2b4d458f49 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI032_PYI032.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI032_PYI032.py.snap @@ -1,4 +1,42 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI032.py:6:29: PYI032 [*] Prefer `object` to `Any` for the second parameter to `__eq__` + | +5 | class Bad: +6 | def __eq__(self, other: Any) -> bool: ... # Y032 + | ^^^ PYI032 +7 | def __ne__(self, other: typing.Any) -> typing.Any: ... # Y032 + | + = help: Replace with `object` + +ℹ Fix +3 3 | +4 4 | +5 5 | class Bad: +6 |- def __eq__(self, other: Any) -> bool: ... # Y032 + 6 |+ def __eq__(self, other: object) -> bool: ... # Y032 +7 7 | def __ne__(self, other: typing.Any) -> typing.Any: ... # Y032 +8 8 | +9 9 | + +PYI032.py:7:29: PYI032 [*] Prefer `object` to `Any` for the second parameter to `__ne__` + | +5 | class Bad: +6 | def __eq__(self, other: Any) -> bool: ... # Y032 +7 | def __ne__(self, other: typing.Any) -> typing.Any: ... # Y032 + | ^^^^^^^^^^ PYI032 + | + = help: Replace with `object` + +ℹ Fix +4 4 | +5 5 | class Bad: +6 6 | def __eq__(self, other: Any) -> bool: ... # Y032 +7 |- def __ne__(self, other: typing.Any) -> typing.Any: ... # Y032 + 7 |+ def __ne__(self, other: object) -> typing.Any: ... # Y032 +8 8 | +9 9 | +10 10 | class Good: + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI034_PYI034.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI034_PYI034.py.snap index d1aa2e9116558..a1f33f746f1fb 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI034_PYI034.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI034_PYI034.py.snap @@ -1,4 +1,92 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI034.py:19: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: + | ^^^^^^^ 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: ..." + | + = 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 + | +32 | ... # Y032 Prefer "object" to "Any" for the second parameter in "__ne__" methods +33 | +34 | 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: ..." + | + = 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 + | +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: + | ^^^^^^^^^^ 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: ..." + | + = 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 + | +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: + | ^^^^^^^^ 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: ..." + | + = 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 + | +162 | class BadIterator1(Iterator[int]): +163 | 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: ..." + | + = 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 + | +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]: + | ^^^^^^^^ 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: ..." + | + = 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 + | +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]: + | ^^^^^^^^ 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: ..." + | + = 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 + | +181 | class BadIterator4(Iterator[int]): +182 | # Note: *Iterable*, not *Iterator*, returned! +183 | 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: ..." + | + = 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 + | +192 | class BadAsyncIterator(collections.abc.AsyncIterator[str]): +193 | 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) + | + = help: Consider using `typing_extensions.Self` as return type + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI036_PYI036.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI036_PYI036.py.snap index d1aa2e9116558..e4a422090f829 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI036_PYI036.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI036_PYI036.py.snap @@ -1,4 +1,161 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI036.py:54:31: PYI036 [*] Star-args in `__exit__` should be annotated with `object` + | +53 | class BadOne: +54 | def __exit__(self, *args: Any) -> None: ... # PYI036: Bad star-args annotation + | ^^^ PYI036 +55 | async def __aexit__(self) -> None: ... # PYI036: Missing args + | + = help: Annotate star-args with `object` + +ℹ Fix +51 51 | +52 52 | +53 53 | class BadOne: +54 |- def __exit__(self, *args: Any) -> None: ... # PYI036: Bad star-args annotation + 54 |+ def __exit__(self, *args: object) -> None: ... # PYI036: Bad star-args annotation +55 55 | async def __aexit__(self) -> None: ... # PYI036: Missing args +56 56 | +57 57 | class BadTwo: + +PYI036.py:55:24: PYI036 If there are no star-args, `__aexit__` should have at least 3 non-keyword-only args (excluding `self`) + | +53 | class BadOne: +54 | def __exit__(self, *args: Any) -> None: ... # PYI036: Bad star-args annotation +55 | async def __aexit__(self) -> None: ... # PYI036: Missing args + | ^^^^^^ PYI036 +56 | +57 | class BadTwo: + | + +PYI036.py:58:38: PYI036 All arguments after the first four in `__exit__` must have a default value + | +57 | class BadTwo: +58 | def __exit__(self, typ, exc, tb, weird_extra_arg) -> None: ... # PYI036: Extra arg must have default + | ^^^^^^^^^^^^^^^ PYI036 +59 | async def __aexit__(self, typ, exc, tb, *, weird_extra_arg) -> None: ...# PYI036: Extra arg must have default + | + +PYI036.py:59:48: PYI036 All keyword-only arguments in `__aexit__` must have a default value + | +57 | class BadTwo: +58 | def __exit__(self, typ, exc, tb, weird_extra_arg) -> None: ... # PYI036: Extra arg must have default +59 | async def __aexit__(self, typ, exc, tb, *, weird_extra_arg) -> None: ...# PYI036: Extra arg must have default + | ^^^^^^^^^^^^^^^ PYI036 +60 | +61 | class BadThree: + | + +PYI036.py:62:29: PYI036 The first argument in `__exit__` should be annotated with `object` or `type[BaseException] | None` + | +61 | class BadThree: +62 | def __exit__(self, typ: type[BaseException], exc: BaseException | None, tb: TracebackType | None) -> None: ... # PYI036: First arg has bad annotation + | ^^^^^^^^^^^^^^^^^^^ PYI036 +63 | async def __aexit__(self, __typ: type[BaseException] | None, __exc: BaseException, __tb: TracebackType) -> bool | None: ... # PYI036: Second arg has bad annotation + | + +PYI036.py:63:73: PYI036 The second argument in `__aexit__` should be annotated with `object` or `BaseException | None` + | +61 | class BadThree: +62 | def __exit__(self, typ: type[BaseException], exc: BaseException | None, tb: TracebackType | None) -> None: ... # PYI036: First arg has bad annotation +63 | async def __aexit__(self, __typ: type[BaseException] | None, __exc: BaseException, __tb: TracebackType) -> bool | None: ... # PYI036: Second arg has bad annotation + | ^^^^^^^^^^^^^ PYI036 +64 | +65 | class BadFour: + | + +PYI036.py:63:94: PYI036 The third argument in `__aexit__` should be annotated with `object` or `types.TracebackType | None` + | +61 | class BadThree: +62 | def __exit__(self, typ: type[BaseException], exc: BaseException | None, tb: TracebackType | None) -> None: ... # PYI036: First arg has bad annotation +63 | async def __aexit__(self, __typ: type[BaseException] | None, __exc: BaseException, __tb: TracebackType) -> bool | None: ... # PYI036: Second arg has bad annotation + | ^^^^^^^^^^^^^ PYI036 +64 | +65 | class BadFour: + | + +PYI036.py:66:111: PYI036 The third argument in `__exit__` should be annotated with `object` or `types.TracebackType | None` + | +65 | class BadFour: +66 | def __exit__(self, typ: typing.Optional[type[BaseException]], exc: typing.Union[BaseException, None], tb: TracebackType) -> None: ... # PYI036: Third arg has bad annotation + | ^^^^^^^^^^^^^ PYI036 +67 | async def __aexit__(self, __typ: type[BaseException] | None, __exc: BaseException | None, __tb: typing.Union[TracebackType, None, int]) -> bool | None: ... # PYI036: Third arg has bad annotation + | + +PYI036.py:67:101: PYI036 The third argument in `__aexit__` should be annotated with `object` or `types.TracebackType | None` + | +65 | class BadFour: +66 | def __exit__(self, typ: typing.Optional[type[BaseException]], exc: typing.Union[BaseException, None], tb: TracebackType) -> None: ... # PYI036: Third arg has bad annotation +67 | async def __aexit__(self, __typ: type[BaseException] | None, __exc: BaseException | None, __tb: typing.Union[TracebackType, None, int]) -> bool | None: ... # PYI036: Third arg has bad annotation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI036 +68 | +69 | class BadFive: + | + +PYI036.py:70:29: PYI036 The first argument in `__exit__` should be annotated with `object` or `type[BaseException] | None` + | +69 | class BadFive: +70 | def __exit__(self, typ: BaseException | None, *args: list[str]) -> bool: ... # PYI036: Bad star-args annotation + | ^^^^^^^^^^^^^^^^^^^^ PYI036 +71 | async def __aexit__(self, /, typ: type[BaseException] | None, *args: Any) -> Awaitable[None]: ... # PYI036: Bad star-args annotation + | + +PYI036.py:70:58: PYI036 [*] Star-args in `__exit__` should be annotated with `object` + | +69 | class BadFive: +70 | def __exit__(self, typ: BaseException | None, *args: list[str]) -> bool: ... # PYI036: Bad star-args annotation + | ^^^^^^^^^ PYI036 +71 | async def __aexit__(self, /, typ: type[BaseException] | None, *args: Any) -> Awaitable[None]: ... # PYI036: Bad star-args annotation + | + = help: Annotate star-args with `object` + +ℹ Fix +67 67 | async def __aexit__(self, __typ: type[BaseException] | None, __exc: BaseException | None, __tb: typing.Union[TracebackType, None, int]) -> bool | None: ... # PYI036: Third arg has bad annotation +68 68 | +69 69 | class BadFive: +70 |- def __exit__(self, typ: BaseException | None, *args: list[str]) -> bool: ... # PYI036: Bad star-args annotation + 70 |+ def __exit__(self, typ: BaseException | None, *args: object) -> bool: ... # PYI036: Bad star-args annotation +71 71 | async def __aexit__(self, /, typ: type[BaseException] | None, *args: Any) -> Awaitable[None]: ... # PYI036: Bad star-args annotation +72 72 | +73 73 | class BadSix: + +PYI036.py:71:74: PYI036 [*] Star-args in `__aexit__` should be annotated with `object` + | +69 | class BadFive: +70 | def __exit__(self, typ: BaseException | None, *args: list[str]) -> bool: ... # PYI036: Bad star-args annotation +71 | async def __aexit__(self, /, typ: type[BaseException] | None, *args: Any) -> Awaitable[None]: ... # PYI036: Bad star-args annotation + | ^^^ PYI036 +72 | +73 | class BadSix: + | + = help: Annotate star-args with `object` + +ℹ Fix +68 68 | +69 69 | class BadFive: +70 70 | def __exit__(self, typ: BaseException | None, *args: list[str]) -> bool: ... # PYI036: Bad star-args annotation +71 |- async def __aexit__(self, /, typ: type[BaseException] | None, *args: Any) -> Awaitable[None]: ... # PYI036: Bad star-args annotation + 71 |+ async def __aexit__(self, /, typ: type[BaseException] | None, *args: object) -> Awaitable[None]: ... # PYI036: Bad star-args annotation +72 72 | +73 73 | class BadSix: +74 74 | def __exit__(self, typ, exc, tb, weird_extra_arg, extra_arg2 = None) -> None: ... # PYI036: Extra arg must have default + +PYI036.py:74:38: PYI036 All arguments after the first four in `__exit__` must have a default value + | +73 | class BadSix: +74 | def __exit__(self, typ, exc, tb, weird_extra_arg, extra_arg2 = None) -> None: ... # PYI036: Extra arg must have default + | ^^^^^^^^^^^^^^^ PYI036 +75 | async def __aexit__(self, typ, exc, tb, *, weird_extra_arg) -> None: ... # PYI036: kwargs must have default + | + +PYI036.py:75:48: PYI036 All keyword-only arguments in `__aexit__` must have a default value + | +73 | class BadSix: +74 | def __exit__(self, typ, exc, tb, weird_extra_arg, extra_arg2 = None) -> None: ... # PYI036: Extra arg must have default +75 | async def __aexit__(self, typ, exc, tb, *, weird_extra_arg) -> None: ... # PYI036: kwargs must have default + | ^^^^^^^^^^^^^^^ PYI036 + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI041_PYI041.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI041_PYI041.py.snap index d1aa2e9116558..de8a65f4b9739 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI041_PYI041.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI041_PYI041.py.snap @@ -1,4 +1,50 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI041.py:22:14: PYI041 Use `float` instead of `int | float` + | +22 | def f0(arg1: float | int) -> None: + | ^^^^^^^^^^^ PYI041 +23 | ... + | + +PYI041.py:26:30: PYI041 Use `complex` instead of `float | complex` + | +26 | def f1(arg1: float, *, arg2: float | list[str] | type[bool] | complex) -> None: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI041 +27 | ... + | + +PYI041.py:30:28: PYI041 Use `float` instead of `int | float` + | +30 | def f2(arg1: int, /, arg2: int | int | float) -> None: + | ^^^^^^^^^^^^^^^^^ PYI041 +31 | ... + | + +PYI041.py:38:24: PYI041 Use `float` instead of `int | float` + | +38 | async def f4(**kwargs: int | int | float) -> None: + | ^^^^^^^^^^^^^^^^^ PYI041 +39 | ... + | + +PYI041.py:46:24: PYI041 Use `complex` instead of `float | complex` + | +44 | ... +45 | +46 | def bad(self, arg: int | float | complex) -> None: + | ^^^^^^^^^^^^^^^^^^^^^ PYI041 +47 | ... + | + +PYI041.py:46:24: PYI041 Use `complex` instead of `int | complex` + | +44 | ... +45 | +46 | def bad(self, arg: int | float | complex) -> None: + | ^^^^^^^^^^^^^^^^^^^^^ PYI041 +47 | ... + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI042_PYI042.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI042_PYI042.py.snap index d1aa2e9116558..e71725b7754c3 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI042_PYI042.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI042_PYI042.py.snap @@ -1,4 +1,32 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI042.py:10:1: PYI042 Type alias `just_literals_pipe_union` should be CamelCase + | + 8 | ) + 9 | +10 | just_literals_pipe_union: TypeAlias = ( + | ^^^^^^^^^^^^^^^^^^^^^^^^ PYI042 +11 | Literal[True] | Literal["idk"] +12 | ) # PYI042, since not camel case + | + +PYI042.py:19:1: PYI042 Type alias `snake_case_alias1` should be CamelCase + | +17 | _PrivateAliasS2: TypeAlias = Annotated[str, "also okay"] +18 | +19 | snake_case_alias1: TypeAlias = str | int # PYI042, since not camel case + | ^^^^^^^^^^^^^^^^^ PYI042 +20 | _snake_case_alias2: TypeAlias = Literal["whatever"] # PYI042, since not camel case +21 | Snake_case_alias: TypeAlias = int | float # PYI042, since not camel case + | + +PYI042.py:20:1: PYI042 Type alias `_snake_case_alias2` should be CamelCase + | +19 | snake_case_alias1: TypeAlias = str | int # PYI042, since not camel case +20 | _snake_case_alias2: TypeAlias = Literal["whatever"] # PYI042, since not camel case + | ^^^^^^^^^^^^^^^^^^ PYI042 +21 | Snake_case_alias: TypeAlias = int | float # PYI042, since not camel case + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI043_PYI043.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI043_PYI043.py.snap index d1aa2e9116558..84453cd4e7f5f 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI043_PYI043.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI043_PYI043.py.snap @@ -1,4 +1,33 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI043.py:10:1: PYI043 Private type alias `_PrivateAliasT` should not be suffixed with `T` (the `T` suffix implies that an object is a `TypeVar`) + | + 8 | ) + 9 | +10 | _PrivateAliasT: TypeAlias = str | int # PYI043, since this ends in a T + | ^^^^^^^^^^^^^^ PYI043 +11 | _PrivateAliasT2: TypeAlias = typing.Any # PYI043, since this ends in a T +12 | _PrivateAliasT3: TypeAlias = Literal[ + | + +PYI043.py:11:1: PYI043 Private type alias `_PrivateAliasT2` should not be suffixed with `T` (the `T` suffix implies that an object is a `TypeVar`) + | +10 | _PrivateAliasT: TypeAlias = str | int # PYI043, since this ends in a T +11 | _PrivateAliasT2: TypeAlias = typing.Any # PYI043, since this ends in a T + | ^^^^^^^^^^^^^^^ PYI043 +12 | _PrivateAliasT3: TypeAlias = Literal[ +13 | "not", "a", "chance" + | + +PYI043.py:12:1: PYI043 Private type alias `_PrivateAliasT3` should not be suffixed with `T` (the `T` suffix implies that an object is a `TypeVar`) + | +10 | _PrivateAliasT: TypeAlias = str | int # PYI043, since this ends in a T +11 | _PrivateAliasT2: TypeAlias = typing.Any # PYI043, since this ends in a T +12 | _PrivateAliasT3: TypeAlias = Literal[ + | ^^^^^^^^^^^^^^^ PYI043 +13 | "not", "a", "chance" +14 | ] # PYI043, since this ends in a T + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI045_PYI045.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI045_PYI045.py.snap index d1aa2e9116558..cb8af8e42ab5c 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI045_PYI045.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI045_PYI045.py.snap @@ -1,4 +1,60 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI045.py:12:27: PYI045 `__iter__` methods should return an `Iterator`, not an `Iterable` + | +11 | class TypingIterableTReturn: +12 | def __iter__(self) -> typing.Iterable[int]: + | ^^^^^^^^^^^^^^^^^^^^ PYI045 +13 | ... + | + +PYI045.py:20:27: PYI045 `__iter__` methods should return an `Iterator`, not an `Iterable` + | +19 | class TypingIterableReturn: +20 | def __iter__(self) -> typing.Iterable: + | ^^^^^^^^^^^^^^^ PYI045 +21 | ... + | + +PYI045.py:28:27: PYI045 `__iter__` methods should return an `Iterator`, not an `Iterable` + | +27 | class CollectionsIterableTReturn: +28 | def __iter__(self) -> collections.abc.Iterable[int]: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI045 +29 | ... + | + +PYI045.py:36:27: PYI045 `__iter__` methods should return an `Iterator`, not an `Iterable` + | +35 | class CollectionsIterableReturn: +36 | def __iter__(self) -> collections.abc.Iterable: + | ^^^^^^^^^^^^^^^^^^^^^^^^ PYI045 +37 | ... + | + +PYI045.py:44:27: PYI045 `__iter__` methods should return an `Iterator`, not an `Iterable` + | +43 | class IterableReturn: +44 | def __iter__(self) -> Iterable: + | ^^^^^^^^ PYI045 +45 | ... + | + +PYI045.py:79:28: PYI045 `__aiter__` methods should return an `AsyncIterator`, not an `AsyncIterable` + | +78 | class TypingAsyncIterableTReturn: +79 | def __aiter__(self) -> typing.AsyncIterable[int]: + | ^^^^^^^^^^^^^^^^^^^^^^^^^ PYI045 +80 | ... + | + +PYI045.py:84:28: PYI045 `__aiter__` methods should return an `AsyncIterator`, not an `AsyncIterable` + | +83 | class TypingAsyncIterableReturn: +84 | def __aiter__(self) -> typing.AsyncIterable: + | ^^^^^^^^^^^^^^^^^^^^ PYI045 +85 | ... + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI046_PYI046.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI046_PYI046.py.snap index d1aa2e9116558..463704b900ec9 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI046_PYI046.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI046_PYI046.py.snap @@ -1,4 +1,18 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI046.py:5:7: PYI046 Private protocol `_Foo` is never used + | +5 | class _Foo(Protocol): + | ^^^^ PYI046 +6 | bar: int + | + +PYI046.py:9:7: PYI046 Private protocol `_Bar` is never used + | + 9 | class _Bar(typing.Protocol): + | ^^^^ PYI046 +10 | bar: int + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI047_PYI047.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI047_PYI047.py.snap index d1aa2e9116558..ced54687f1a66 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI047_PYI047.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI047_PYI047.py.snap @@ -1,4 +1,20 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI047.py:6:1: PYI047 Private TypeAlias `_UnusedPrivateTypeAlias` is never used + | +6 | _UnusedPrivateTypeAlias: TypeAlias = int | None + | ^^^^^^^^^^^^^^^^^^^^^^^ PYI047 +7 | _T: typing.TypeAlias = str + | + +PYI047.py:7:1: PYI047 Private TypeAlias `_T` is never used + | +6 | _UnusedPrivateTypeAlias: TypeAlias = int | None +7 | _T: typing.TypeAlias = str + | ^^ PYI047 +8 | +9 | # OK + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI049_PYI049.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI049_PYI049.py.snap index d1aa2e9116558..46c42efa8cd57 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI049_PYI049.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI049_PYI049.py.snap @@ -1,4 +1,18 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI049.py:5:7: PYI049 Private TypedDict `_UnusedTypedDict` is never used + | +5 | class _UnusedTypedDict(TypedDict): + | ^^^^^^^^^^^^^^^^ PYI049 +6 | foo: str + | + +PYI049.py:9:7: PYI049 Private TypedDict `_UnusedTypedDict2` is never used + | + 9 | class _UnusedTypedDict2(typing.TypedDict): + | ^^^^^^^^^^^^^^^^^ PYI049 +10 | bar: int + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI051_PYI051.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI051_PYI051.py.snap index d1aa2e9116558..e825128300cdc 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI051_PYI051.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI051_PYI051.py.snap @@ -1,4 +1,24 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI051.py:4:18: PYI051 `Literal["foo"]` is redundant in a union with `str` + | +2 | from typing import Literal, TypeAlias, Union +3 | +4 | A: str | Literal["foo"] + | ^^^^^ PYI051 +5 | B: TypeAlias = typing.Union[Literal[b"bar", b"foo"], bytes, str] +6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] + | + +PYI051.py:9:31: PYI051 `Literal[1J]` is redundant in a union with `complex` + | + 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] + 8 | + 9 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... + | ^^ PYI051 +10 | +11 | # OK + | + diff --git a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI056_PYI056.py.snap b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI056_PYI056.py.snap index d1aa2e9116558..4c239c9c0725f 100644 --- a/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI056_PYI056.py.snap +++ b/crates/ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI056_PYI056.py.snap @@ -1,4 +1,32 @@ --- source: crates/ruff/src/rules/flake8_pyi/mod.rs --- +PYI056.py:4:1: PYI056 Calling `.append()` on `__all__` may not be supported by all type checkers (use `+=` instead) + | +3 | # Errors +4 | __all__.append("D") + | ^^^^^^^^^^^^^^ PYI056 +5 | __all__.extend(["E", "Foo"]) +6 | __all__.remove("A") + | + +PYI056.py:5:1: PYI056 Calling `.extend()` on `__all__` may not be supported by all type checkers (use `+=` instead) + | +3 | # Errors +4 | __all__.append("D") +5 | __all__.extend(["E", "Foo"]) + | ^^^^^^^^^^^^^^ PYI056 +6 | __all__.remove("A") + | + +PYI056.py:6:1: PYI056 Calling `.remove()` on `__all__` may not be supported by all type checkers (use `+=` instead) + | +4 | __all__.append("D") +5 | __all__.extend(["E", "Foo"]) +6 | __all__.remove("A") + | ^^^^^^^^^^^^^^ PYI056 +7 | +8 | # OK + | +