mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 05:44:56 +00:00
[flake8-pyi
] Skip fix if all Union
members are None
(PYI016
) (#19416)
patches #19403 --------- Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
This commit is contained in:
parent
9af8597608
commit
9d5ecacdc5
4 changed files with 53 additions and 1 deletions
|
@ -142,3 +142,7 @@ field47: typing.Optional[int] | typing.Optional[dict]
|
||||||
# avoid reporting twice
|
# avoid reporting twice
|
||||||
field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
field49: typing.Optional[complex | complex] | complex
|
field49: typing.Optional[complex | complex] | complex
|
||||||
|
|
||||||
|
# Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
# Should throw duplicate union member but not fix
|
||||||
|
isinstance(None, typing.Union[None, None])
|
|
@ -64,6 +64,7 @@ pub(crate) fn duplicate_union_member<'a>(checker: &Checker, expr: &'a Expr) {
|
||||||
let mut diagnostics = Vec::new();
|
let mut diagnostics = Vec::new();
|
||||||
|
|
||||||
let mut union_type = UnionKind::TypingUnion;
|
let mut union_type = UnionKind::TypingUnion;
|
||||||
|
let mut optional_present = false;
|
||||||
// Adds a member to `literal_exprs` if it is a `Literal` annotation
|
// Adds a member to `literal_exprs` if it is a `Literal` annotation
|
||||||
let mut check_for_duplicate_members = |expr: &'a Expr, parent: &'a Expr| {
|
let mut check_for_duplicate_members = |expr: &'a Expr, parent: &'a Expr| {
|
||||||
if matches!(parent, Expr::BinOp(_)) {
|
if matches!(parent, Expr::BinOp(_)) {
|
||||||
|
@ -74,6 +75,7 @@ pub(crate) fn duplicate_union_member<'a>(checker: &Checker, expr: &'a Expr) {
|
||||||
&& is_optional_type(checker, expr)
|
&& is_optional_type(checker, expr)
|
||||||
{
|
{
|
||||||
// If the union member is an `Optional`, add a virtual `None` literal.
|
// If the union member is an `Optional`, add a virtual `None` literal.
|
||||||
|
optional_present = true;
|
||||||
&VIRTUAL_NONE_LITERAL
|
&VIRTUAL_NONE_LITERAL
|
||||||
} else {
|
} else {
|
||||||
expr
|
expr
|
||||||
|
@ -87,7 +89,7 @@ pub(crate) fn duplicate_union_member<'a>(checker: &Checker, expr: &'a Expr) {
|
||||||
DuplicateUnionMember {
|
DuplicateUnionMember {
|
||||||
duplicate_name: checker.generator().expr(virtual_expr),
|
duplicate_name: checker.generator().expr(virtual_expr),
|
||||||
},
|
},
|
||||||
// Use the real expression's range for diagnostics,
|
// Use the real expression's range for diagnostics.
|
||||||
expr.range(),
|
expr.range(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -104,6 +106,13 @@ pub(crate) fn duplicate_union_member<'a>(checker: &Checker, expr: &'a Expr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do not reduce `Union[None, ... None]` to avoid introducing a `TypeError` unintentionally
|
||||||
|
// e.g. `isinstance(None, Union[None, None])`, if reduced to `isinstance(None, None)`, causes
|
||||||
|
// `TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union` to throw.
|
||||||
|
if unique_nodes.iter().all(|expr| expr.is_none_literal_expr()) && !optional_present {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Mark [`Fix`] as unsafe when comments are in range.
|
// Mark [`Fix`] as unsafe when comments are in range.
|
||||||
let applicability = if checker.comment_ranges().intersects(expr.range()) {
|
let applicability = if checker.comment_ranges().intersects(expr.range()) {
|
||||||
Applicability::Unsafe
|
Applicability::Unsafe
|
||||||
|
|
|
@ -974,6 +974,8 @@ PYI016.py:143:61: PYI016 [*] Duplicate union member `complex`
|
||||||
143 |-field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
143 |-field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
143 |+field48: typing.Union[typing.Optional[complex], complex]
|
143 |+field48: typing.Union[typing.Optional[complex], complex]
|
||||||
144 144 | field49: typing.Optional[complex | complex] | complex
|
144 144 | field49: typing.Optional[complex | complex] | complex
|
||||||
|
145 145 |
|
||||||
|
146 146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
|
||||||
PYI016.py:144:36: PYI016 [*] Duplicate union member `complex`
|
PYI016.py:144:36: PYI016 [*] Duplicate union member `complex`
|
||||||
|
|
|
|
||||||
|
@ -981,6 +983,8 @@ PYI016.py:144:36: PYI016 [*] Duplicate union member `complex`
|
||||||
143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
144 | field49: typing.Optional[complex | complex] | complex
|
144 | field49: typing.Optional[complex | complex] | complex
|
||||||
| ^^^^^^^ PYI016
|
| ^^^^^^^ PYI016
|
||||||
|
145 |
|
||||||
|
146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
|
|
|
||||||
= help: Remove duplicate union member `complex`
|
= help: Remove duplicate union member `complex`
|
||||||
|
|
||||||
|
@ -990,3 +994,15 @@ PYI016.py:144:36: PYI016 [*] Duplicate union member `complex`
|
||||||
143 143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
143 143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
144 |-field49: typing.Optional[complex | complex] | complex
|
144 |-field49: typing.Optional[complex | complex] | complex
|
||||||
144 |+field49: typing.Optional[complex] | complex
|
144 |+field49: typing.Optional[complex] | complex
|
||||||
|
145 145 |
|
||||||
|
146 146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
147 147 | # Should throw duplicate union member but not fix
|
||||||
|
|
||||||
|
PYI016.py:148:37: PYI016 Duplicate union member `None`
|
||||||
|
|
|
||||||
|
146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
147 | # Should throw duplicate union member but not fix
|
||||||
|
148 | isinstance(None, typing.Union[None, None])
|
||||||
|
| ^^^^ PYI016
|
||||||
|
|
|
||||||
|
= help: Remove duplicate union member `None`
|
||||||
|
|
|
@ -1162,6 +1162,8 @@ PYI016.py:143:61: PYI016 [*] Duplicate union member `complex`
|
||||||
143 |-field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
143 |-field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
143 |+field48: typing.Union[None, complex]
|
143 |+field48: typing.Union[None, complex]
|
||||||
144 144 | field49: typing.Optional[complex | complex] | complex
|
144 144 | field49: typing.Optional[complex | complex] | complex
|
||||||
|
145 145 |
|
||||||
|
146 146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
|
||||||
PYI016.py:143:72: PYI016 [*] Duplicate union member `complex`
|
PYI016.py:143:72: PYI016 [*] Duplicate union member `complex`
|
||||||
|
|
|
|
||||||
|
@ -1179,6 +1181,8 @@ PYI016.py:143:72: PYI016 [*] Duplicate union member `complex`
|
||||||
143 |-field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
143 |-field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
143 |+field48: typing.Union[None, complex]
|
143 |+field48: typing.Union[None, complex]
|
||||||
144 144 | field49: typing.Optional[complex | complex] | complex
|
144 144 | field49: typing.Optional[complex | complex] | complex
|
||||||
|
145 145 |
|
||||||
|
146 146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
|
||||||
PYI016.py:144:36: PYI016 [*] Duplicate union member `complex`
|
PYI016.py:144:36: PYI016 [*] Duplicate union member `complex`
|
||||||
|
|
|
|
||||||
|
@ -1186,6 +1190,8 @@ PYI016.py:144:36: PYI016 [*] Duplicate union member `complex`
|
||||||
143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
144 | field49: typing.Optional[complex | complex] | complex
|
144 | field49: typing.Optional[complex | complex] | complex
|
||||||
| ^^^^^^^ PYI016
|
| ^^^^^^^ PYI016
|
||||||
|
145 |
|
||||||
|
146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
|
|
|
||||||
= help: Remove duplicate union member `complex`
|
= help: Remove duplicate union member `complex`
|
||||||
|
|
||||||
|
@ -1195,6 +1201,9 @@ PYI016.py:144:36: PYI016 [*] Duplicate union member `complex`
|
||||||
143 143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
143 143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
144 |-field49: typing.Optional[complex | complex] | complex
|
144 |-field49: typing.Optional[complex | complex] | complex
|
||||||
144 |+field49: None | complex
|
144 |+field49: None | complex
|
||||||
|
145 145 |
|
||||||
|
146 146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
147 147 | # Should throw duplicate union member but not fix
|
||||||
|
|
||||||
PYI016.py:144:47: PYI016 [*] Duplicate union member `complex`
|
PYI016.py:144:47: PYI016 [*] Duplicate union member `complex`
|
||||||
|
|
|
|
||||||
|
@ -1202,6 +1211,8 @@ PYI016.py:144:47: PYI016 [*] Duplicate union member `complex`
|
||||||
143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
144 | field49: typing.Optional[complex | complex] | complex
|
144 | field49: typing.Optional[complex | complex] | complex
|
||||||
| ^^^^^^^ PYI016
|
| ^^^^^^^ PYI016
|
||||||
|
145 |
|
||||||
|
146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
|
|
|
||||||
= help: Remove duplicate union member `complex`
|
= help: Remove duplicate union member `complex`
|
||||||
|
|
||||||
|
@ -1211,3 +1222,15 @@ PYI016.py:144:47: PYI016 [*] Duplicate union member `complex`
|
||||||
143 143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
143 143 | field48: typing.Union[typing.Optional[typing.Union[complex, complex]], complex]
|
||||||
144 |-field49: typing.Optional[complex | complex] | complex
|
144 |-field49: typing.Optional[complex | complex] | complex
|
||||||
144 |+field49: None | complex
|
144 |+field49: None | complex
|
||||||
|
145 145 |
|
||||||
|
146 146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
147 147 | # Should throw duplicate union member but not fix
|
||||||
|
|
||||||
|
PYI016.py:148:37: PYI016 Duplicate union member `None`
|
||||||
|
|
|
||||||
|
146 | # Regression test for https://github.com/astral-sh/ruff/issues/19403
|
||||||
|
147 | # Should throw duplicate union member but not fix
|
||||||
|
148 | isinstance(None, typing.Union[None, None])
|
||||||
|
| ^^^^ PYI016
|
||||||
|
|
|
||||||
|
= help: Remove duplicate union member `None`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue