mirror of https://github.com/astral-sh/ruff
Raise percent-format upgrade rule (`UP031`) for hanging modulos (#3953)
This commit is contained in:
parent
9067ae47d1
commit
e160a52bfd
|
|
@ -83,3 +83,26 @@ print('Hello %s (%s)' % bar['bop'])
|
||||||
print('Hello %(arg)s' % bar)
|
print('Hello %(arg)s' % bar)
|
||||||
print('Hello %(arg)s' % bar.baz)
|
print('Hello %(arg)s' % bar.baz)
|
||||||
print('Hello %(arg)s' % bar['bop'])
|
print('Hello %(arg)s' % bar['bop'])
|
||||||
|
|
||||||
|
# Hanging modulos
|
||||||
|
(
|
||||||
|
"foo %s "
|
||||||
|
"bar %s"
|
||||||
|
) % (x, y)
|
||||||
|
|
||||||
|
(
|
||||||
|
"foo %(foo)s "
|
||||||
|
"bar %(bar)s"
|
||||||
|
) % {"foo": x, "bar": y}
|
||||||
|
|
||||||
|
(
|
||||||
|
"""foo %s"""
|
||||||
|
% (x,)
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
"""
|
||||||
|
foo %s
|
||||||
|
"""
|
||||||
|
% (x,)
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -34,28 +34,6 @@ pytest.param('"%8s" % (None,)', id="unsafe width-string conversion"),
|
||||||
"%(and)s" % {"and": 2}
|
"%(and)s" % {"and": 2}
|
||||||
|
|
||||||
# OK (arguably false negatives)
|
# OK (arguably false negatives)
|
||||||
(
|
|
||||||
"foo %s "
|
|
||||||
"bar %s"
|
|
||||||
) % (x, y)
|
|
||||||
|
|
||||||
(
|
|
||||||
"foo %(foo)s "
|
|
||||||
"bar %(bar)s"
|
|
||||||
) % {"foo": x, "bar": y}
|
|
||||||
|
|
||||||
(
|
|
||||||
"""foo %s"""
|
|
||||||
% (x,)
|
|
||||||
)
|
|
||||||
|
|
||||||
(
|
|
||||||
"""
|
|
||||||
foo %s
|
|
||||||
"""
|
|
||||||
% (x,)
|
|
||||||
)
|
|
||||||
|
|
||||||
'Hello %s' % bar
|
'Hello %s' % bar
|
||||||
|
|
||||||
'Hello %s' % bar.baz
|
'Hello %s' % bar.baz
|
||||||
|
|
|
||||||
|
|
@ -3234,7 +3234,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.settings.rules.enabled(Rule::PrintfStringFormatting) {
|
if self.settings.rules.enabled(Rule::PrintfStringFormatting) {
|
||||||
pyupgrade::rules::printf_string_formatting(self, expr, left, right);
|
pyupgrade::rules::printf_string_formatting(self, expr, right);
|
||||||
}
|
}
|
||||||
if self.settings.rules.enabled(Rule::BadStringFormatType) {
|
if self.settings.rules.enabled(Rule::BadStringFormatType) {
|
||||||
pylint::rules::bad_string_format_type(self, expr, right);
|
pylint::rules::bad_string_format_type(self, expr, right);
|
||||||
|
|
|
||||||
|
|
@ -296,17 +296,7 @@ fn convertible(format_string: &CFormatString, params: &Expr) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// UP031
|
/// UP031
|
||||||
pub(crate) fn printf_string_formatting(
|
pub(crate) fn printf_string_formatting(checker: &mut Checker, expr: &Expr, right: &Expr) {
|
||||||
checker: &mut Checker,
|
|
||||||
expr: &Expr,
|
|
||||||
left: &Expr,
|
|
||||||
right: &Expr,
|
|
||||||
) {
|
|
||||||
// If the modulo symbol is on a separate line, abort.
|
|
||||||
if right.location.row() != left.end_location.unwrap().row() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grab each string segment (in case there's an implicit concatenation).
|
// Grab each string segment (in case there's an implicit concatenation).
|
||||||
let mut strings: Vec<(Location, Location)> = vec![];
|
let mut strings: Vec<(Location, Location)> = vec![];
|
||||||
let mut extension = None;
|
let mut extension = None;
|
||||||
|
|
|
||||||
|
|
@ -750,6 +750,7 @@ UP031_0.py:83:7: UP031 [*] Use format specifiers instead of percent format
|
||||||
83 |+print('Hello {arg}'.format(**bar))
|
83 |+print('Hello {arg}'.format(**bar))
|
||||||
84 84 | print('Hello %(arg)s' % bar.baz)
|
84 84 | print('Hello %(arg)s' % bar.baz)
|
||||||
85 85 | print('Hello %(arg)s' % bar['bop'])
|
85 85 | print('Hello %(arg)s' % bar['bop'])
|
||||||
|
86 86 |
|
||||||
|
|
||||||
UP031_0.py:84:7: UP031 [*] Use format specifiers instead of percent format
|
UP031_0.py:84:7: UP031 [*] Use format specifiers instead of percent format
|
||||||
|
|
|
|
||||||
|
|
@ -768,6 +769,8 @@ UP031_0.py:84:7: UP031 [*] Use format specifiers instead of percent format
|
||||||
84 |-print('Hello %(arg)s' % bar.baz)
|
84 |-print('Hello %(arg)s' % bar.baz)
|
||||||
84 |+print('Hello {arg}'.format(**bar.baz))
|
84 |+print('Hello {arg}'.format(**bar.baz))
|
||||||
85 85 | print('Hello %(arg)s' % bar['bop'])
|
85 85 | print('Hello %(arg)s' % bar['bop'])
|
||||||
|
86 86 |
|
||||||
|
87 87 | # Hanging modulos
|
||||||
|
|
||||||
UP031_0.py:85:7: UP031 [*] Use format specifiers instead of percent format
|
UP031_0.py:85:7: UP031 [*] Use format specifiers instead of percent format
|
||||||
|
|
|
|
||||||
|
|
@ -775,6 +778,8 @@ UP031_0.py:85:7: UP031 [*] Use format specifiers instead of percent format
|
||||||
86 | print('Hello %(arg)s' % bar.baz)
|
86 | print('Hello %(arg)s' % bar.baz)
|
||||||
87 | print('Hello %(arg)s' % bar['bop'])
|
87 | print('Hello %(arg)s' % bar['bop'])
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP031
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP031
|
||||||
|
88 |
|
||||||
|
89 | # Hanging modulos
|
||||||
|
|
|
|
||||||
= help: Replace with format specifiers
|
= help: Replace with format specifiers
|
||||||
|
|
||||||
|
|
@ -784,5 +789,109 @@ UP031_0.py:85:7: UP031 [*] Use format specifiers instead of percent format
|
||||||
84 84 | print('Hello %(arg)s' % bar.baz)
|
84 84 | print('Hello %(arg)s' % bar.baz)
|
||||||
85 |-print('Hello %(arg)s' % bar['bop'])
|
85 |-print('Hello %(arg)s' % bar['bop'])
|
||||||
85 |+print('Hello {arg}'.format(**bar['bop']))
|
85 |+print('Hello {arg}'.format(**bar['bop']))
|
||||||
|
86 86 |
|
||||||
|
87 87 | # Hanging modulos
|
||||||
|
88 88 | (
|
||||||
|
|
||||||
|
UP031_0.py:88:1: UP031 [*] Use format specifiers instead of percent format
|
||||||
|
|
|
||||||
|
88 | # Hanging modulos
|
||||||
|
89 | / (
|
||||||
|
90 | | "foo %s "
|
||||||
|
91 | | "bar %s"
|
||||||
|
92 | | ) % (x, y)
|
||||||
|
| |__________^ UP031
|
||||||
|
93 |
|
||||||
|
94 | (
|
||||||
|
|
|
||||||
|
= help: Replace with format specifiers
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
86 86 |
|
||||||
|
87 87 | # Hanging modulos
|
||||||
|
88 88 | (
|
||||||
|
89 |- "foo %s "
|
||||||
|
90 |- "bar %s"
|
||||||
|
91 |-) % (x, y)
|
||||||
|
89 |+ "foo {} "
|
||||||
|
90 |+ "bar {}"
|
||||||
|
91 |+).format(x, y)
|
||||||
|
92 92 |
|
||||||
|
93 93 | (
|
||||||
|
94 94 | "foo %(foo)s "
|
||||||
|
|
||||||
|
UP031_0.py:93:1: UP031 [*] Use format specifiers instead of percent format
|
||||||
|
|
|
||||||
|
93 | ) % (x, y)
|
||||||
|
94 |
|
||||||
|
95 | / (
|
||||||
|
96 | | "foo %(foo)s "
|
||||||
|
97 | | "bar %(bar)s"
|
||||||
|
98 | | ) % {"foo": x, "bar": y}
|
||||||
|
| |________________________^ UP031
|
||||||
|
99 |
|
||||||
|
100 | (
|
||||||
|
|
|
||||||
|
= help: Replace with format specifiers
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
91 91 | ) % (x, y)
|
||||||
|
92 92 |
|
||||||
|
93 93 | (
|
||||||
|
94 |- "foo %(foo)s "
|
||||||
|
95 |- "bar %(bar)s"
|
||||||
|
96 |-) % {"foo": x, "bar": y}
|
||||||
|
94 |+ "foo {foo} "
|
||||||
|
95 |+ "bar {bar}"
|
||||||
|
96 |+).format(foo=x, bar=y)
|
||||||
|
97 97 |
|
||||||
|
98 98 | (
|
||||||
|
99 99 | """foo %s"""
|
||||||
|
|
||||||
|
UP031_0.py:99:5: UP031 [*] Use format specifiers instead of percent format
|
||||||
|
|
|
||||||
|
99 | (
|
||||||
|
100 | """foo %s"""
|
||||||
|
| _____^
|
||||||
|
101 | | % (x,)
|
||||||
|
| |__________^ UP031
|
||||||
|
102 | )
|
||||||
|
|
|
||||||
|
= help: Replace with format specifiers
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
96 96 | ) % {"foo": x, "bar": y}
|
||||||
|
97 97 |
|
||||||
|
98 98 | (
|
||||||
|
99 |- """foo %s"""
|
||||||
|
100 |- % (x,)
|
||||||
|
99 |+ """foo {}""".format(x)
|
||||||
|
101 100 | )
|
||||||
|
102 101 |
|
||||||
|
103 102 | (
|
||||||
|
|
||||||
|
UP031_0.py:104:5: UP031 [*] Use format specifiers instead of percent format
|
||||||
|
|
|
||||||
|
104 | (
|
||||||
|
105 | """
|
||||||
|
| _____^
|
||||||
|
106 | | foo %s
|
||||||
|
107 | | """
|
||||||
|
108 | | % (x,)
|
||||||
|
| |__________^ UP031
|
||||||
|
109 | )
|
||||||
|
|
|
||||||
|
= help: Replace with format specifiers
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
102 102 |
|
||||||
|
103 103 | (
|
||||||
|
104 104 | """
|
||||||
|
105 |- foo %s
|
||||||
|
106 |- """
|
||||||
|
107 |- % (x,)
|
||||||
|
105 |+ foo {}
|
||||||
|
106 |+ """.format(x)
|
||||||
|
108 107 | )
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,23 +103,22 @@ def main(*, name: str, prefix: str, code: str, linter: str) -> None:
|
||||||
# Add the relevant rule function.
|
# Add the relevant rule function.
|
||||||
with (rules_dir / f"{rule_name_snake}.rs").open("w") as fp:
|
with (rules_dir / f"{rule_name_snake}.rs").open("w") as fp:
|
||||||
fp.write(
|
fp.write(
|
||||||
"""\
|
f"""\
|
||||||
use ruff_diagnostics::Violation;
|
use ruff_diagnostics::Violation;
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{{derive_message_formats, violation}};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct %s;
|
pub struct {name};
|
||||||
impl Violation for %s {
|
impl Violation for {name} {{
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {{
|
||||||
todo!("implement message");
|
todo!("implement message");
|
||||||
format!("TODO: write message")
|
format!("TODO: write message")
|
||||||
}
|
}}
|
||||||
}
|
}}
|
||||||
"""
|
""",
|
||||||
% (name, name),
|
|
||||||
)
|
)
|
||||||
fp.write(
|
fp.write(
|
||||||
f"""
|
f"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue