Raise percent-format upgrade rule (UP031) for hanging modulos (#3953)

This commit is contained in:
Charlie Marsh 2023-04-12 23:59:20 -04:00 committed by GitHub
parent 9067ae47d1
commit e160a52bfd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 142 additions and 43 deletions

View file

@ -83,3 +83,26 @@ print('Hello %s (%s)' % bar['bop'])
print('Hello %(arg)s' % bar)
print('Hello %(arg)s' % bar.baz)
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,)
)

View file

@ -34,28 +34,6 @@ pytest.param('"%8s" % (None,)', id="unsafe width-string conversion"),
"%(and)s" % {"and": 2}
# 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.baz

View file

@ -3234,7 +3234,7 @@ where
}
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) {
pylint::rules::bad_string_format_type(self, expr, right);

View file

@ -296,17 +296,7 @@ fn convertible(format_string: &CFormatString, params: &Expr) -> bool {
}
/// UP031
pub(crate) fn printf_string_formatting(
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;
}
pub(crate) fn printf_string_formatting(checker: &mut Checker, expr: &Expr, right: &Expr) {
// Grab each string segment (in case there's an implicit concatenation).
let mut strings: Vec<(Location, Location)> = vec![];
let mut extension = None;

View file

@ -750,6 +750,7 @@ UP031_0.py:83:7: UP031 [*] Use format specifiers instead of percent format
83 |+print('Hello {arg}'.format(**bar))
84 84 | print('Hello %(arg)s' % bar.baz)
85 85 | print('Hello %(arg)s' % bar['bop'])
86 86 |
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}'.format(**bar.baz))
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
|
@ -775,6 +778,8 @@ UP031_0.py:85:7: UP031 [*] Use format specifiers instead of percent format
86 | print('Hello %(arg)s' % bar.baz)
87 | print('Hello %(arg)s' % bar['bop'])
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP031
88 |
89 | # Hanging modulos
|
= 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)
85 |-print('Hello %(arg)s' % 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 | )

View file

@ -103,23 +103,22 @@ def main(*, name: str, prefix: str, code: str, linter: str) -> None:
# Add the relevant rule function.
with (rules_dir / f"{rule_name_snake}.rs").open("w") as fp:
fp.write(
"""\
f"""\
use ruff_diagnostics::Violation;
use ruff_macros::{derive_message_formats, violation};
use ruff_macros::{{derive_message_formats, violation}};
use crate::checkers::ast::Checker;
#[violation]
pub struct %s;
impl Violation for %s {
pub struct {name};
impl Violation for {name} {{
#[derive_message_formats]
fn message(&self) -> String {
fn message(&self) -> String {{
todo!("implement message");
format!("TODO: write message")
}
}
"""
% (name, name),
}}
}}
""",
)
fp.write(
f"""