mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 13:51:16 +00:00
[flake8-pyi
] Mark PYI030
fix unsafe when comments are deleted (#16322)
This commit is contained in:
parent
c814745643
commit
b312b53c2e
5 changed files with 150 additions and 9 deletions
|
@ -91,3 +91,15 @@ field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typ
|
||||||
from typing import IO, Literal
|
from typing import IO, Literal
|
||||||
|
|
||||||
InlineOption = Literal["a"] | Literal["b"] | IO[str]
|
InlineOption = Literal["a"] | Literal["b"] | IO[str]
|
||||||
|
|
||||||
|
# Should use unsafe fix when comments are deleted
|
||||||
|
field26: (
|
||||||
|
# First comment
|
||||||
|
Literal["a", "b"]
|
||||||
|
# Second comment
|
||||||
|
| Literal["c", "d"]
|
||||||
|
)
|
||||||
|
field27: (
|
||||||
|
Literal["a", "b"] # First comment
|
||||||
|
| Literal["c", "d"] # Second comment
|
||||||
|
)
|
||||||
|
|
|
@ -87,3 +87,15 @@ field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[
|
||||||
|
|
||||||
# Should use the first literal subscript attribute when fixing
|
# Should use the first literal subscript attribute when fixing
|
||||||
field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
|
field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
|
||||||
|
|
||||||
|
# Should use unsafe fix when comments are deleted
|
||||||
|
field26: (
|
||||||
|
# First comment
|
||||||
|
Literal["a", "b"]
|
||||||
|
# Second comment
|
||||||
|
| Literal["c", "d"]
|
||||||
|
)
|
||||||
|
field27: (
|
||||||
|
Literal["a", "b"] # First comment
|
||||||
|
| Literal["c", "d"] # Second comment
|
||||||
|
)
|
||||||
|
|
|
@ -28,6 +28,22 @@ use crate::checkers::ast::Checker;
|
||||||
/// field: Literal[1, 2] | str
|
/// field: Literal[1, 2] | str
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// ## Fix safety
|
||||||
|
/// This fix is marked unsafe if it would delete any comments within the replacement range.
|
||||||
|
///
|
||||||
|
/// An example to illustrate where comments are preserved and where they are not:
|
||||||
|
///
|
||||||
|
/// ```pyi
|
||||||
|
/// from typing import Literal
|
||||||
|
///
|
||||||
|
/// field: (
|
||||||
|
/// # deleted comment
|
||||||
|
/// Literal["a", "b"] # deleted comment
|
||||||
|
/// # deleted comment
|
||||||
|
/// | Literal["c", "d"] # preserved comment
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: `typing.Literal`](https://docs.python.org/3/library/typing.html#typing.Literal)
|
/// - [Python documentation: `typing.Literal`](https://docs.python.org/3/library/typing.html#typing.Literal)
|
||||||
#[derive(ViolationMetadata)]
|
#[derive(ViolationMetadata)]
|
||||||
|
@ -131,12 +147,8 @@ pub(crate) fn unnecessary_literal_union<'a>(checker: &Checker, expr: &'a Expr) {
|
||||||
ctx: ExprContext::Load,
|
ctx: ExprContext::Load,
|
||||||
});
|
});
|
||||||
|
|
||||||
if other_exprs.is_empty() {
|
let edit = if other_exprs.is_empty() {
|
||||||
// if the union is only literals, we just replace the whole thing with a single literal
|
Edit::range_replacement(checker.generator().expr(&literal), expr.range())
|
||||||
Fix::safe_edit(Edit::range_replacement(
|
|
||||||
checker.generator().expr(&literal),
|
|
||||||
expr.range(),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
let elts: Vec<Expr> = std::iter::once(literal)
|
let elts: Vec<Expr> = std::iter::once(literal)
|
||||||
.chain(other_exprs.into_iter().cloned())
|
.chain(other_exprs.into_iter().cloned())
|
||||||
|
@ -159,8 +171,13 @@ pub(crate) fn unnecessary_literal_union<'a>(checker: &Checker, expr: &'a Expr) {
|
||||||
} else {
|
} else {
|
||||||
checker.generator().expr(&pep_604_union(&elts))
|
checker.generator().expr(&pep_604_union(&elts))
|
||||||
};
|
};
|
||||||
|
Edit::range_replacement(content, expr.range())
|
||||||
|
};
|
||||||
|
|
||||||
Fix::safe_edit(Edit::range_replacement(content, expr.range()))
|
if checker.comment_ranges().intersects(expr.range()) {
|
||||||
|
Fix::unsafe_edit(edit)
|
||||||
|
} else {
|
||||||
|
Fix::safe_edit(edit)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -377,7 +377,7 @@ PYI030.py:63:10: PYI030 [*] Multiple literal members in a union. Use a single li
|
||||||
|
|
|
|
||||||
= help: Replace with a single `Literal`
|
= help: Replace with a single `Literal`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Unsafe fix
|
||||||
60 60 | field19: typing.Literal[1] | typing.Literal[2] # Error
|
60 60 | field19: typing.Literal[1] | typing.Literal[2] # Error
|
||||||
61 61 |
|
61 61 |
|
||||||
62 62 | # Should emit in cases with newlines
|
62 62 | # Should emit in cases with newlines
|
||||||
|
@ -538,6 +538,8 @@ PYI030.py:93:16: PYI030 [*] Multiple literal members in a union. Use a single li
|
||||||
92 |
|
92 |
|
||||||
93 | InlineOption = Literal["a"] | Literal["b"] | IO[str]
|
93 | InlineOption = Literal["a"] | Literal["b"] | IO[str]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030
|
||||||
|
94 |
|
||||||
|
95 | # Should use unsafe fix when comments are deleted
|
||||||
|
|
|
|
||||||
= help: Replace with a single `Literal`
|
= help: Replace with a single `Literal`
|
||||||
|
|
||||||
|
@ -547,3 +549,51 @@ PYI030.py:93:16: PYI030 [*] Multiple literal members in a union. Use a single li
|
||||||
92 92 |
|
92 92 |
|
||||||
93 |-InlineOption = Literal["a"] | Literal["b"] | IO[str]
|
93 |-InlineOption = Literal["a"] | Literal["b"] | IO[str]
|
||||||
93 |+InlineOption = Literal["a", "b"] | IO[str]
|
93 |+InlineOption = Literal["a", "b"] | IO[str]
|
||||||
|
94 94 |
|
||||||
|
95 95 | # Should use unsafe fix when comments are deleted
|
||||||
|
96 96 | field26: (
|
||||||
|
|
||||||
|
PYI030.py:98:5: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal["a", "b", "c", "d"]`
|
||||||
|
|
|
||||||
|
96 | field26: (
|
||||||
|
97 | # First comment
|
||||||
|
98 | / Literal["a", "b"]
|
||||||
|
99 | | # Second comment
|
||||||
|
100 | | | Literal["c", "d"]
|
||||||
|
| |_______________________^ PYI030
|
||||||
|
101 | )
|
||||||
|
102 | field27: (
|
||||||
|
|
|
||||||
|
= help: Replace with a single `Literal`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
95 95 | # Should use unsafe fix when comments are deleted
|
||||||
|
96 96 | field26: (
|
||||||
|
97 97 | # First comment
|
||||||
|
98 |- Literal["a", "b"]
|
||||||
|
99 |- # Second comment
|
||||||
|
100 |- | Literal["c", "d"]
|
||||||
|
98 |+ Literal["a", "b", "c", "d"]
|
||||||
|
101 99 | )
|
||||||
|
102 100 | field27: (
|
||||||
|
103 101 | Literal["a", "b"] # First comment
|
||||||
|
|
||||||
|
PYI030.py:103:5: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal["a", "b", "c", "d"]`
|
||||||
|
|
|
||||||
|
101 | )
|
||||||
|
102 | field27: (
|
||||||
|
103 | / Literal["a", "b"] # First comment
|
||||||
|
104 | | | Literal["c", "d"] # Second comment
|
||||||
|
| |_______________________^ PYI030
|
||||||
|
105 | )
|
||||||
|
|
|
||||||
|
= help: Replace with a single `Literal`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
100 100 | | Literal["c", "d"]
|
||||||
|
101 101 | )
|
||||||
|
102 102 | field27: (
|
||||||
|
103 |- Literal["a", "b"] # First comment
|
||||||
|
104 |- | Literal["c", "d"] # Second comment
|
||||||
|
103 |+ Literal["a", "b", "c", "d"] # Second comment
|
||||||
|
105 104 | )
|
||||||
|
|
|
@ -377,7 +377,7 @@ PYI030.pyi:63:10: PYI030 [*] Multiple literal members in a union. Use a single l
|
||||||
|
|
|
|
||||||
= help: Replace with a single `Literal`
|
= help: Replace with a single `Literal`
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Unsafe fix
|
||||||
60 60 | field19: typing.Literal[1] | typing.Literal[2] # Error
|
60 60 | field19: typing.Literal[1] | typing.Literal[2] # Error
|
||||||
61 61 |
|
61 61 |
|
||||||
62 62 | # Should emit in cases with newlines
|
62 62 | # Should emit in cases with newlines
|
||||||
|
@ -517,6 +517,8 @@ PYI030.pyi:89:10: PYI030 [*] Multiple literal members in a union. Use a single l
|
||||||
88 | # Should use the first literal subscript attribute when fixing
|
88 | # Should use the first literal subscript attribute when fixing
|
||||||
89 | field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
|
89 | field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI030
|
||||||
|
90 |
|
||||||
|
91 | # Should use unsafe fix when comments are deleted
|
||||||
|
|
|
|
||||||
= help: Replace with a single `Literal`
|
= help: Replace with a single `Literal`
|
||||||
|
|
||||||
|
@ -526,3 +528,51 @@ PYI030.pyi:89:10: PYI030 [*] Multiple literal members in a union. Use a single l
|
||||||
88 88 | # Should use the first literal subscript attribute when fixing
|
88 88 | # Should use the first literal subscript attribute when fixing
|
||||||
89 |-field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
|
89 |-field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
|
||||||
89 |+field25: typing.Union[typing_extensions.Literal[1, 2, 3, 4], str] # Error
|
89 |+field25: typing.Union[typing_extensions.Literal[1, 2, 3, 4], str] # Error
|
||||||
|
90 90 |
|
||||||
|
91 91 | # Should use unsafe fix when comments are deleted
|
||||||
|
92 92 | field26: (
|
||||||
|
|
||||||
|
PYI030.pyi:94:5: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal["a", "b", "c", "d"]`
|
||||||
|
|
|
||||||
|
92 | field26: (
|
||||||
|
93 | # First comment
|
||||||
|
94 | / Literal["a", "b"]
|
||||||
|
95 | | # Second comment
|
||||||
|
96 | | | Literal["c", "d"]
|
||||||
|
| |_______________________^ PYI030
|
||||||
|
97 | )
|
||||||
|
98 | field27: (
|
||||||
|
|
|
||||||
|
= help: Replace with a single `Literal`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
91 91 | # Should use unsafe fix when comments are deleted
|
||||||
|
92 92 | field26: (
|
||||||
|
93 93 | # First comment
|
||||||
|
94 |- Literal["a", "b"]
|
||||||
|
95 |- # Second comment
|
||||||
|
96 |- | Literal["c", "d"]
|
||||||
|
94 |+ Literal["a", "b", "c", "d"]
|
||||||
|
97 95 | )
|
||||||
|
98 96 | field27: (
|
||||||
|
99 97 | Literal["a", "b"] # First comment
|
||||||
|
|
||||||
|
PYI030.pyi:99:5: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal["a", "b", "c", "d"]`
|
||||||
|
|
|
||||||
|
97 | )
|
||||||
|
98 | field27: (
|
||||||
|
99 | / Literal["a", "b"] # First comment
|
||||||
|
100 | | | Literal["c", "d"] # Second comment
|
||||||
|
| |_______________________^ PYI030
|
||||||
|
101 | )
|
||||||
|
|
|
||||||
|
= help: Replace with a single `Literal`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
96 96 | | Literal["c", "d"]
|
||||||
|
97 97 | )
|
||||||
|
98 98 | field27: (
|
||||||
|
99 |- Literal["a", "b"] # First comment
|
||||||
|
100 |- | Literal["c", "d"] # Second comment
|
||||||
|
99 |+ Literal["a", "b", "c", "d"] # Second comment
|
||||||
|
101 100 | )
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue