From 3d3c40b162398714da1d37bce3f2af30cb9aab95 Mon Sep 17 00:00:00 2001 From: Steve C Date: Tue, 10 Oct 2023 01:10:40 -0400 Subject: [PATCH 1/4] add autofix for `PYI055` --- .../test/fixtures/flake8_pyi/PYI055.py | 1 + .../test/fixtures/flake8_pyi/PYI055.pyi | 1 + .../rules/unnecessary_type_union.rs | 39 ++++-- ...__flake8_pyi__tests__PYI055_PYI055.py.snap | 28 ++++- ..._flake8_pyi__tests__PYI055_PYI055.pyi.snap | 119 ++++++++++++++++-- 5 files changed, 170 insertions(+), 18 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py index adbc1f737a814..bf863ae34ad02 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py @@ -29,3 +29,4 @@ def func(arg: type[int, float] | str) -> None: def func(): # PYI055 item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker + item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi index 3cc530f770517..f59d0569e32c6 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi @@ -22,3 +22,4 @@ item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker def func(): # PYI055 item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker + item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs index 4eb4e8de3a848..b2a7ef1a69924 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs @@ -1,9 +1,9 @@ -use ruff_diagnostics::{Diagnostic, Violation}; +use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::Expr; use ruff_text_size::Ranged; -use crate::{checkers::ast::Checker, rules::flake8_pyi::helpers::traverse_union}; +use crate::{checkers::ast::Checker, registry::AsRule, rules::flake8_pyi::helpers::traverse_union}; /// ## What it does /// Checks for the presence of multiple `type`s in a union. @@ -27,7 +27,7 @@ pub struct UnnecessaryTypeUnion { is_pep604_union: bool, } -impl Violation for UnnecessaryTypeUnion { +impl AlwaysFixableViolation for UnnecessaryTypeUnion { #[derive_message_formats] fn message(&self) -> String { let union_str = if self.is_pep604_union { @@ -40,6 +40,10 @@ impl Violation for UnnecessaryTypeUnion { "Multiple `type` members in a union. Combine them into one, e.g., `type[{union_str}]`." ) } + + fn fix_title(&self) -> String { + format!("Combine multiple `type` members into one union") + } } /// PYI055 @@ -74,15 +78,32 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr) traverse_union(&mut collect_type_exprs, checker.semantic(), union, None); if type_exprs.len() > 1 { - checker.diagnostics.push(Diagnostic::new( + let type_members: Vec = type_exprs + .into_iter() + .map(|type_expr| checker.locator().slice(type_expr.as_ref()).to_string()) + .collect(); + + let mut diagnostic = Diagnostic::new( UnnecessaryTypeUnion { - members: type_exprs - .into_iter() - .map(|type_expr| checker.locator().slice(type_expr.as_ref()).to_string()) - .collect(), + members: type_members.clone(), is_pep604_union, }, union.range(), - )); + ); + + if checker.patch(diagnostic.kind.rule()) { + let union_str = if is_pep604_union { + format!("type[{}]", type_members.join(" | ")) + } else { + format!("type[Union[{}]]", type_members.join(", ")) + }; + + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + union_str, + union.range(), + ))); + } + + checker.diagnostics.push(diagnostic); } } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap index 8addf09918645..f4ff3daab9e15 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap @@ -1,12 +1,38 @@ --- source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs --- -PYI055.py:31:11: PYI055 Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. +PYI055.py:31:11: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. | 29 | def func(): 30 | # PYI055 31 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 +32 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker | + = help: Combine multiple `type` members into one union + +ℹ Fix +28 28 | +29 29 | def func(): +30 30 | # PYI055 +31 |- item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker + 31 |+ item: type[requests_mock.Mocker | httpretty] = requests_mock.Mocker +32 32 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker + +PYI055.py:32:12: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty]]`. + | +30 | # PYI055 +31 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker +32 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 + | + = help: Combine multiple `type` members into one union + +ℹ Fix +29 29 | def func(): +30 30 | # PYI055 +31 31 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker +32 |- item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker + 32 |+ item2: type[Union[requests_mock.Mocker, httpretty]] = requests_mock.Mocker diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap index f28020e40050f..2ba5cc1220bfd 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs --- -PYI055.pyi:4:4: PYI055 Multiple `type` members in a union. Combine them into one, e.g., `type[int | str | complex]`. +PYI055.pyi:4:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | str | complex]`. | 2 | from typing import Union 3 | @@ -10,8 +10,19 @@ PYI055.pyi:4:4: PYI055 Multiple `type` members in a union. Combine them into one 5 | x: type[int] | type[str] | type[float] 6 | y: builtins.type[int] | type[str] | builtins.type[complex] | + = help: Combine multiple `type` members into one union -PYI055.pyi:5:4: PYI055 Multiple `type` members in a union. Combine them into one, e.g., `type[int | str | float]`. +ℹ Fix +1 1 | import builtins +2 2 | from typing import Union +3 3 | +4 |-w: builtins.type[int] | builtins.type[str] | builtins.type[complex] + 4 |+w: type[int | str | complex] +5 5 | x: type[int] | type[str] | type[float] +6 6 | y: builtins.type[int] | type[str] | builtins.type[complex] +7 7 | z: Union[type[float], type[complex]] + +PYI055.pyi:5:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | str | float]`. | 4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] 5 | x: type[int] | type[str] | type[float] @@ -19,8 +30,19 @@ PYI055.pyi:5:4: PYI055 Multiple `type` members in a union. Combine them into one 6 | y: builtins.type[int] | type[str] | builtins.type[complex] 7 | z: Union[type[float], type[complex]] | + = help: Combine multiple `type` members into one union + +ℹ Fix +2 2 | from typing import Union +3 3 | +4 4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] +5 |-x: type[int] | type[str] | type[float] + 5 |+x: type[int | str | float] +6 6 | y: builtins.type[int] | type[str] | builtins.type[complex] +7 7 | z: Union[type[float], type[complex]] +8 8 | z: Union[type[float, int], type[complex]] -PYI055.pyi:6:4: PYI055 Multiple `type` members in a union. Combine them into one, e.g., `type[int | str | complex]`. +PYI055.pyi:6:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | str | complex]`. | 4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] 5 | x: type[int] | type[str] | type[float] @@ -29,8 +51,19 @@ PYI055.pyi:6:4: PYI055 Multiple `type` members in a union. Combine them into one 7 | z: Union[type[float], type[complex]] 8 | z: Union[type[float, int], type[complex]] | + = help: Combine multiple `type` members into one union -PYI055.pyi:7:4: PYI055 Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, complex]]`. +ℹ Fix +3 3 | +4 4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] +5 5 | x: type[int] | type[str] | type[float] +6 |-y: builtins.type[int] | type[str] | builtins.type[complex] + 6 |+y: type[int | str | complex] +7 7 | z: Union[type[float], type[complex]] +8 8 | z: Union[type[float, int], type[complex]] +9 9 | + +PYI055.pyi:7:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, complex]]`. | 5 | x: type[int] | type[str] | type[float] 6 | y: builtins.type[int] | type[str] | builtins.type[complex] @@ -38,8 +71,19 @@ PYI055.pyi:7:4: PYI055 Multiple `type` members in a union. Combine them into one | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 8 | z: Union[type[float, int], type[complex]] | + = help: Combine multiple `type` members into one union + +ℹ Fix +4 4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] +5 5 | x: type[int] | type[str] | type[float] +6 6 | y: builtins.type[int] | type[str] | builtins.type[complex] +7 |-z: Union[type[float], type[complex]] + 7 |+z: type[Union[float, complex]] +8 8 | z: Union[type[float, int], type[complex]] +9 9 | +10 10 | def func(arg: type[int] | str | type[float]) -> None: ... -PYI055.pyi:8:4: PYI055 Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, int, complex]]`. +PYI055.pyi:8:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, int, complex]]`. | 6 | y: builtins.type[int] | type[str] | builtins.type[complex] 7 | z: Union[type[float], type[complex]] @@ -48,8 +92,19 @@ PYI055.pyi:8:4: PYI055 Multiple `type` members in a union. Combine them into one 9 | 10 | def func(arg: type[int] | str | type[float]) -> None: ... | + = help: Combine multiple `type` members into one union -PYI055.pyi:10:15: PYI055 Multiple `type` members in a union. Combine them into one, e.g., `type[int | float]`. +ℹ Fix +5 5 | x: type[int] | type[str] | type[float] +6 6 | y: builtins.type[int] | type[str] | builtins.type[complex] +7 7 | z: Union[type[float], type[complex]] +8 |-z: Union[type[float, int], type[complex]] + 8 |+z: type[Union[float, int, complex]] +9 9 | +10 10 | def func(arg: type[int] | str | type[float]) -> None: ... +11 11 | + +PYI055.pyi:10:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | float]`. | 8 | z: Union[type[float, int], type[complex]] 9 | @@ -58,8 +113,19 @@ PYI055.pyi:10:15: PYI055 Multiple `type` members in a union. Combine them into o 11 | 12 | # OK | + = help: Combine multiple `type` members into one union + +ℹ Fix +7 7 | z: Union[type[float], type[complex]] +8 8 | z: Union[type[float, int], type[complex]] +9 9 | +10 |-def func(arg: type[int] | str | type[float]) -> None: ... + 10 |+def func(arg: type[int | float]) -> None: ... +11 11 | +12 12 | # OK +13 13 | x: type[int, str, float] -PYI055.pyi:20:7: PYI055 Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. +PYI055.pyi:20:7: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. | 19 | # OK 20 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker @@ -67,13 +133,50 @@ PYI055.pyi:20:7: PYI055 Multiple `type` members in a union. Combine them into on 21 | 22 | def func(): | + = help: Combine multiple `type` members into one union + +ℹ Fix +17 17 | def func(arg: type[int, float] | str) -> None: ... +18 18 | +19 19 | # OK +20 |-item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker + 20 |+item: type[requests_mock.Mocker | httpretty] = requests_mock.Mocker +21 21 | +22 22 | def func(): +23 23 | # PYI055 -PYI055.pyi:24:11: PYI055 Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. +PYI055.pyi:24:11: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. | 22 | def func(): 23 | # PYI055 24 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 +25 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker | + = help: Combine multiple `type` members into one union + +ℹ Fix +21 21 | +22 22 | def func(): +23 23 | # PYI055 +24 |- item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker + 24 |+ item: type[requests_mock.Mocker | httpretty] = requests_mock.Mocker +25 25 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker + +PYI055.pyi:25:12: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty]]`. + | +23 | # PYI055 +24 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker +25 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 + | + = help: Combine multiple `type` members into one union + +ℹ Fix +22 22 | def func(): +23 23 | # PYI055 +24 24 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker +25 |- item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker + 25 |+ item2: type[Union[requests_mock.Mocker, httpretty]] = requests_mock.Mocker From 05d81fb0582ed27e16b0c3bd568154f4c13b021a Mon Sep 17 00:00:00 2001 From: Steve C Date: Tue, 10 Oct 2023 21:43:31 -0400 Subject: [PATCH 2/4] better tweaks --- .../test/fixtures/flake8_pyi/PYI055.py | 4 +- .../test/fixtures/flake8_pyi/PYI055.pyi | 4 +- .../rules/unnecessary_type_union.rs | 73 ++++++++++++++++++- ...__flake8_pyi__tests__PYI055_PYI055.py.snap | 28 +++---- ..._flake8_pyi__tests__PYI055_PYI055.pyi.snap | 28 +++---- 5 files changed, 101 insertions(+), 36 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py index bf863ae34ad02..f8e6ca8f30ab0 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py @@ -28,5 +28,5 @@ def func(arg: type[int, float] | str) -> None: def func(): # PYI055 - item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker - item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker + item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi index f59d0569e32c6..530f395dfa359 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi @@ -21,5 +21,5 @@ item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker def func(): # PYI055 - item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker - item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker + item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs index b2a7ef1a69924..859f47ad1de5b 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs @@ -1,7 +1,8 @@ +use ast::{ExprContext, Operator}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::Expr; -use ruff_text_size::Ranged; +use ruff_python_ast::{self as ast, Expr}; +use ruff_text_size::{Ranged, TextRange}; use crate::{checkers::ast::Checker, registry::AsRule, rules::flake8_pyi::helpers::traverse_union}; @@ -46,6 +47,19 @@ impl AlwaysFixableViolation for UnnecessaryTypeUnion { } } +fn concatenate_bin_ors(exprs: Vec<&Expr>) -> Expr { + let mut exprs = exprs.into_iter(); + let first = exprs.next().unwrap(); + exprs.fold((*first).clone(), |acc, expr| { + Expr::BinOp(ast::ExprBinOp { + left: Box::new(acc), + op: Operator::BitOr, + right: Box::new((*expr).clone()), + range: TextRange::default(), + }) + }) +} + /// PYI055 pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr) { // The `|` operator isn't always safe to allow to runtime-evaluated annotations. @@ -79,6 +93,7 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr) if type_exprs.len() > 1 { let type_members: Vec = type_exprs + .clone() .into_iter() .map(|type_expr| checker.locator().slice(type_expr.as_ref()).to_string()) .collect(); @@ -93,9 +108,59 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr) if checker.patch(diagnostic.kind.rule()) { let union_str = if is_pep604_union { - format!("type[{}]", type_members.join(" | ")) + checker + .generator() + .expr(&Expr::Subscript(ast::ExprSubscript { + value: Box::new(Expr::Name(ast::ExprName { + id: "type".into(), + ctx: ExprContext::Load, + range: TextRange::default(), + })), + slice: Box::new(concatenate_bin_ors( + type_exprs + .clone() + .into_iter() + .map(std::convert::AsRef::as_ref) + .collect(), + )), + ctx: ExprContext::Load, + range: TextRange::default(), + })) } else { - format!("type[Union[{}]]", type_members.join(", ")) + checker + .generator() + .expr(&Expr::Subscript(ast::ExprSubscript { + value: Box::new(Expr::Name(ast::ExprName { + id: "type".into(), + ctx: ExprContext::Load, + range: TextRange::default(), + })), + slice: Box::new(Expr::Subscript(ast::ExprSubscript { + value: Box::new(Expr::Name(ast::ExprName { + id: "Union".into(), + ctx: ExprContext::Load, + range: TextRange::default(), + })), + slice: Box::new(Expr::Tuple(ast::ExprTuple { + elts: type_members + .into_iter() + .map(|type_member| { + Expr::Name(ast::ExprName { + id: type_member, + ctx: ExprContext::Load, + range: TextRange::default(), + }) + }) + .collect(), + ctx: ExprContext::Load, + range: TextRange::default(), + })), + ctx: ExprContext::Load, + range: TextRange::default(), + })), + ctx: ExprContext::Load, + range: TextRange::default(), + })) }; diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap index f4ff3daab9e15..8f5a82cbdfda7 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap @@ -1,13 +1,13 @@ --- source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs --- -PYI055.py:31:11: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. +PYI055.py:31:11: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty | str]`. | 29 | def func(): 30 | # PYI055 -31 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -32 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker +31 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 +32 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | = help: Combine multiple `type` members into one union @@ -15,24 +15,24 @@ PYI055.py:31:11: PYI055 [*] Multiple `type` members in a union. Combine them int 28 28 | 29 29 | def func(): 30 30 | # PYI055 -31 |- item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker - 31 |+ item: type[requests_mock.Mocker | httpretty] = requests_mock.Mocker -32 32 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker +31 |- item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + 31 |+ item: type[requests_mock.Mocker | httpretty | str] = requests_mock.Mocker +32 32 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker -PYI055.py:32:12: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty]]`. +PYI055.py:32:12: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. | 30 | # PYI055 -31 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker -32 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 +31 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +32 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 | = help: Combine multiple `type` members into one union ℹ Fix 29 29 | def func(): 30 30 | # PYI055 -31 31 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker -32 |- item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker - 32 |+ item2: type[Union[requests_mock.Mocker, httpretty]] = requests_mock.Mocker +31 31 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +32 |- item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + 32 |+ item2: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap index 2ba5cc1220bfd..e0a3dad47ef93 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap @@ -145,13 +145,13 @@ PYI055.pyi:20:7: PYI055 [*] Multiple `type` members in a union. Combine them int 22 22 | def func(): 23 23 | # PYI055 -PYI055.pyi:24:11: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. +PYI055.pyi:24:11: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty | str]`. | 22 | def func(): 23 | # PYI055 -24 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -25 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker +24 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 +25 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | = help: Combine multiple `type` members into one union @@ -159,24 +159,24 @@ PYI055.pyi:24:11: PYI055 [*] Multiple `type` members in a union. Combine them in 21 21 | 22 22 | def func(): 23 23 | # PYI055 -24 |- item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker - 24 |+ item: type[requests_mock.Mocker | httpretty] = requests_mock.Mocker -25 25 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker +24 |- item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + 24 |+ item: type[requests_mock.Mocker | httpretty | str] = requests_mock.Mocker +25 25 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker -PYI055.pyi:25:12: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty]]`. +PYI055.pyi:25:12: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. | 23 | # PYI055 -24 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker -25 | item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 +24 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +25 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 | = help: Combine multiple `type` members into one union ℹ Fix 22 22 | def func(): 23 23 | # PYI055 -24 24 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker -25 |- item2: Union[type[requests_mock.Mocker], type[httpretty]] = requests_mock.Mocker - 25 |+ item2: type[Union[requests_mock.Mocker, httpretty]] = requests_mock.Mocker +24 24 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +25 |- item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + 25 |+ item2: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker From aba1146c234eea733576d681b17802955a355399 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 12 Oct 2023 20:44:10 -0400 Subject: [PATCH 3/4] Respect Union binding --- .../test/fixtures/flake8_pyi/PYI055.py | 11 ++- .../rules/unnecessary_type_union.rs | 67 +++++++++---------- ...__flake8_pyi__tests__PYI055_PYI055.py.snap | 48 +++++++++---- 3 files changed, 76 insertions(+), 50 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py index f8e6ca8f30ab0..6471613f9838c 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py @@ -28,5 +28,12 @@ def func(arg: type[int, float] | str) -> None: def func(): # PYI055 - item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker - item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + + +def func(): + from typing import Union as U + + # PYI055 + x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs index 859f47ad1de5b..8581bde35fcf6 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs @@ -4,7 +4,7 @@ use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Expr}; use ruff_text_size::{Ranged, TextRange}; -use crate::{checkers::ast::Checker, registry::AsRule, rules::flake8_pyi::helpers::traverse_union}; +use crate::{checkers::ast::Checker, rules::flake8_pyi::helpers::traverse_union}; /// ## What it does /// Checks for the presence of multiple `type`s in a union. @@ -67,14 +67,17 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr) return; } - let mut type_exprs = Vec::new(); - // Check if `union` is a PEP604 union (e.g. `float | int`) or a `typing.Union[float, int]` - let is_pep604_union = !union.as_subscript_expr().is_some_and(|subscript| { - checker + let subscript = union.as_subscript_expr(); + if subscript.is_some_and(|subscript| { + !checker .semantic() .match_typing_expr(&subscript.value, "Union") - }); + }) { + return; + } + + let mut type_exprs = Vec::new(); let mut collect_type_exprs = |expr: &'a Expr, _| { let Some(subscript) = expr.as_subscript_expr() else { @@ -101,32 +104,13 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr) let mut diagnostic = Diagnostic::new( UnnecessaryTypeUnion { members: type_members.clone(), - is_pep604_union, + is_pep604_union: subscript.is_none(), }, union.range(), ); - if checker.patch(diagnostic.kind.rule()) { - let union_str = if is_pep604_union { - checker - .generator() - .expr(&Expr::Subscript(ast::ExprSubscript { - value: Box::new(Expr::Name(ast::ExprName { - id: "type".into(), - ctx: ExprContext::Load, - range: TextRange::default(), - })), - slice: Box::new(concatenate_bin_ors( - type_exprs - .clone() - .into_iter() - .map(std::convert::AsRef::as_ref) - .collect(), - )), - ctx: ExprContext::Load, - range: TextRange::default(), - })) - } else { + if checker.semantic().is_builtin("type") { + let content = if let Some(subscript) = subscript { checker .generator() .expr(&Expr::Subscript(ast::ExprSubscript { @@ -136,11 +120,7 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr) range: TextRange::default(), })), slice: Box::new(Expr::Subscript(ast::ExprSubscript { - value: Box::new(Expr::Name(ast::ExprName { - id: "Union".into(), - ctx: ExprContext::Load, - range: TextRange::default(), - })), + value: subscript.value.clone(), slice: Box::new(Expr::Tuple(ast::ExprTuple { elts: type_members .into_iter() @@ -161,10 +141,29 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr) ctx: ExprContext::Load, range: TextRange::default(), })) + } else { + checker + .generator() + .expr(&Expr::Subscript(ast::ExprSubscript { + value: Box::new(Expr::Name(ast::ExprName { + id: "type".into(), + ctx: ExprContext::Load, + range: TextRange::default(), + })), + slice: Box::new(concatenate_bin_ors( + type_exprs + .clone() + .into_iter() + .map(std::convert::AsRef::as_ref) + .collect(), + )), + ctx: ExprContext::Load, + range: TextRange::default(), + })) }; diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - union_str, + content, union.range(), ))); } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap index 8f5a82cbdfda7..8b0f31bf5916e 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap @@ -1,13 +1,13 @@ --- source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs --- -PYI055.py:31:11: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty | str]`. +PYI055.py:31:8: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty | str]`. | 29 | def func(): 30 | # PYI055 -31 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -32 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker +31 | x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 +32 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | = help: Combine multiple `type` members into one union @@ -15,24 +15,44 @@ PYI055.py:31:11: PYI055 [*] Multiple `type` members in a union. Combine them int 28 28 | 29 29 | def func(): 30 30 | # PYI055 -31 |- item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker - 31 |+ item: type[requests_mock.Mocker | httpretty | str] = requests_mock.Mocker -32 32 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker +31 |- x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + 31 |+ x: type[requests_mock.Mocker | httpretty | str] = requests_mock.Mocker +32 32 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker +33 33 | +34 34 | -PYI055.py:32:12: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. +PYI055.py:32:8: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. | 30 | # PYI055 -31 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker -32 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 +31 | x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +32 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 | = help: Combine multiple `type` members into one union ℹ Fix 29 29 | def func(): 30 30 | # PYI055 -31 31 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker -32 |- item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker - 32 |+ item2: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker +31 31 | x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +32 |- y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + 32 |+ y: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker +33 33 | +34 34 | +35 35 | def func(): + +PYI055.py:39:8: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. + | +38 | # PYI055 +39 | x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 + | + = help: Combine multiple `type` members into one union + +ℹ Fix +36 36 | from typing import Union as U +37 37 | +38 38 | # PYI055 +39 |- x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + 39 |+ x: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker From 14740d7072f8f6a237aea4a334a5e0ada768a064 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 12 Oct 2023 20:46:09 -0400 Subject: [PATCH 4/4] Tweak message --- .../flake8_pyi/rules/unnecessary_type_union.rs | 14 ++++++++------ ...s__flake8_pyi__tests__PYI055_PYI055.py.snap | 6 +++--- ...__flake8_pyi__tests__PYI055_PYI055.pyi.snap | 18 +++++++++--------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs index 8581bde35fcf6..75ba6ab9bc59f 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs @@ -1,5 +1,5 @@ use ast::{ExprContext, Operator}; -use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; +use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Expr}; use ruff_text_size::{Ranged, TextRange}; @@ -10,8 +10,8 @@ use crate::{checkers::ast::Checker, rules::flake8_pyi::helpers::traverse_union}; /// Checks for the presence of multiple `type`s in a union. /// /// ## Why is this bad? -/// The `type` built-in function accepts unions, and it is -/// clearer to explicitly specify them as a single `type`. +/// The `type` built-in function accepts unions, and it is clearer to +/// explicitly specify them as a single `type`. /// /// ## Example /// ```python @@ -28,7 +28,9 @@ pub struct UnnecessaryTypeUnion { is_pep604_union: bool, } -impl AlwaysFixableViolation for UnnecessaryTypeUnion { +impl Violation for UnnecessaryTypeUnion { + const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; + #[derive_message_formats] fn message(&self) -> String { let union_str = if self.is_pep604_union { @@ -42,8 +44,8 @@ impl AlwaysFixableViolation for UnnecessaryTypeUnion { ) } - fn fix_title(&self) -> String { - format!("Combine multiple `type` members into one union") + fn fix_title(&self) -> Option { + Some(format!("Combine multiple `type` members")) } } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap index 8b0f31bf5916e..691a671b4e7bc 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap @@ -9,7 +9,7 @@ PYI055.py:31:8: PYI055 [*] Multiple `type` members in a union. Combine them into | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 32 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 28 28 | @@ -28,7 +28,7 @@ PYI055.py:32:8: PYI055 [*] Multiple `type` members in a union. Combine them into 32 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 29 29 | def func(): @@ -46,7 +46,7 @@ PYI055.py:39:8: PYI055 [*] Multiple `type` members in a union. Combine them into 39 | x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 36 36 | from typing import Union as U diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap index e0a3dad47ef93..c8fc0694eaff5 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap @@ -10,7 +10,7 @@ PYI055.pyi:4:4: PYI055 [*] Multiple `type` members in a union. Combine them into 5 | x: type[int] | type[str] | type[float] 6 | y: builtins.type[int] | type[str] | builtins.type[complex] | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 1 1 | import builtins @@ -30,7 +30,7 @@ PYI055.pyi:5:4: PYI055 [*] Multiple `type` members in a union. Combine them into 6 | y: builtins.type[int] | type[str] | builtins.type[complex] 7 | z: Union[type[float], type[complex]] | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 2 2 | from typing import Union @@ -51,7 +51,7 @@ PYI055.pyi:6:4: PYI055 [*] Multiple `type` members in a union. Combine them into 7 | z: Union[type[float], type[complex]] 8 | z: Union[type[float, int], type[complex]] | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 3 3 | @@ -71,7 +71,7 @@ PYI055.pyi:7:4: PYI055 [*] Multiple `type` members in a union. Combine them into | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 8 | z: Union[type[float, int], type[complex]] | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 4 4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] @@ -92,7 +92,7 @@ PYI055.pyi:8:4: PYI055 [*] Multiple `type` members in a union. Combine them into 9 | 10 | def func(arg: type[int] | str | type[float]) -> None: ... | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 5 5 | x: type[int] | type[str] | type[float] @@ -113,7 +113,7 @@ PYI055.pyi:10:15: PYI055 [*] Multiple `type` members in a union. Combine them in 11 | 12 | # OK | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 7 7 | z: Union[type[float], type[complex]] @@ -133,7 +133,7 @@ PYI055.pyi:20:7: PYI055 [*] Multiple `type` members in a union. Combine them int 21 | 22 | def func(): | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 17 17 | def func(arg: type[int, float] | str) -> None: ... @@ -153,7 +153,7 @@ PYI055.pyi:24:11: PYI055 [*] Multiple `type` members in a union. Combine them in | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 25 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 21 21 | @@ -170,7 +170,7 @@ PYI055.pyi:25:12: PYI055 [*] Multiple `type` members in a union. Combine them in 25 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 | - = help: Combine multiple `type` members into one union + = help: Combine multiple `type` members ℹ Fix 22 22 | def func():