Skip to content

Commit

Permalink
Convert single-argument %-style format calls
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Mar 18, 2023
1 parent c21eb06 commit c8cd2e9
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 3 deletions.
13 changes: 13 additions & 0 deletions crates/ruff/resources/test/fixtures/pyupgrade/UP031_0.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,16 @@
print("%(foo)s \N{snowman}" % {"foo": 1})

print(("foo %s " "bar %s") % (x, y))

# Single-value expressions
print('Hello %s' % "World")
print('Hello %s' % f"World")
print('Hello %s' % bar)
print('Hello %s' % bar.baz)
print('Hello %s' % bar['bop'])
print('Hello %s (%s)' % bar)
print('Hello %s (%s)' % bar.baz)
print('Hello %s (%s)' % bar['bop'])
print('Hello %(arg)s' % bar)
print('Hello %(arg)s' % bar.baz)
print('Hello %(arg)s' % bar['bop'])
2 changes: 0 additions & 2 deletions crates/ruff/resources/test/fixtures/pyupgrade/UP031_1.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# OK
"%s" % unknown_type

b"%s" % (b"bytestring",)

"%*s" % (5, "hi")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,9 @@ pub(crate) fn printf_string_formatting(
}

// Parse each string segment.
let mut format_strings = vec![];
let mut num_positional = 0;
let mut num_keyword = 0;
let mut format_strings = Vec::with_capacity(strings.len());
for (start, end) in &strings {
let string = checker.locator.slice(Range::new(*start, *end));
let (Some(leader), Some(trailer)) = (leading_quote(string), trailing_quote(string)) else {
Expand All @@ -351,12 +353,45 @@ pub(crate) fn printf_string_formatting(
return;
}

// Count the number of positional and keyword arguments.
for (.., format_part) in format_string.iter() {
let CFormatPart::Spec(ref fmt) = format_part else {
continue;
};
if fmt.mapping_key.is_none() {
num_positional += 1;
} else {
num_keyword += 1;
}
}

// Convert the `%`-format string to a `.format` string.
let format_string = percent_to_format(&format_string);
format_strings.push(format!("{leader}{format_string}{trailer}"));
}

// Parse the parameters.
let params_string = match right.node {
ExprKind::Constant { .. } | ExprKind::JoinedStr { .. } => {
format!("({})", checker.locator.slice(right))
}
ExprKind::Name { .. }
| ExprKind::Attribute { .. }
| ExprKind::Subscript { .. }
| ExprKind::Call { .. } => {
if num_keyword > 0 {
// If we have _any_ named fields, assume the right-hand side is a mapping.
format!("(**{})", checker.locator.slice(right))
} else if num_positional > 1 {
// If we have multiple fields, but no named fields, assume the right-hand side is a
// tuple.
format!("(*{})", checker.locator.slice(right))
} else {
// Otherwise, if we have a single field, assume the right-hand side is a single
// value.
format!("({})", checker.locator.slice(right))
}
}
ExprKind::Tuple { .. } => clean_params_tuple(checker, right),
ExprKind::Dict { .. } => {
if let Some(params_string) = clean_params_dictionary(checker, right) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -582,4 +582,224 @@ expression: diagnostics
row: 75
column: 35
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 78
column: 6
end_location:
row: 78
column: 26
fix:
content: "'Hello {}'.format(\"World\")"
location:
row: 78
column: 6
end_location:
row: 78
column: 26
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 79
column: 6
end_location:
row: 79
column: 27
fix:
content: "'Hello {}'.format(f\"World\")"
location:
row: 79
column: 6
end_location:
row: 79
column: 27
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 80
column: 6
end_location:
row: 80
column: 22
fix:
content: "'Hello {}'.format(bar)"
location:
row: 80
column: 6
end_location:
row: 80
column: 22
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 81
column: 6
end_location:
row: 81
column: 26
fix:
content: "'Hello {}'.format(bar.baz)"
location:
row: 81
column: 6
end_location:
row: 81
column: 26
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 82
column: 6
end_location:
row: 82
column: 29
fix:
content: "'Hello {}'.format(bar['bop'])"
location:
row: 82
column: 6
end_location:
row: 82
column: 29
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 83
column: 6
end_location:
row: 83
column: 27
fix:
content: "'Hello {} ({})'.format(*bar)"
location:
row: 83
column: 6
end_location:
row: 83
column: 27
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 84
column: 6
end_location:
row: 84
column: 31
fix:
content: "'Hello {} ({})'.format(*bar.baz)"
location:
row: 84
column: 6
end_location:
row: 84
column: 31
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 85
column: 6
end_location:
row: 85
column: 34
fix:
content: "'Hello {} ({})'.format(*bar['bop'])"
location:
row: 85
column: 6
end_location:
row: 85
column: 34
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 86
column: 6
end_location:
row: 86
column: 27
fix:
content: "'Hello {arg}'.format(**bar)"
location:
row: 86
column: 6
end_location:
row: 86
column: 27
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 87
column: 6
end_location:
row: 87
column: 31
fix:
content: "'Hello {arg}'.format(**bar.baz)"
location:
row: 87
column: 6
end_location:
row: 87
column: 31
parent: ~
- kind:
name: PrintfStringFormatting
body: Use format specifiers instead of percent format
suggestion: Replace with format specifiers
fixable: true
location:
row: 88
column: 6
end_location:
row: 88
column: 34
fix:
content: "'Hello {arg}'.format(**bar['bop'])"
location:
row: 88
column: 6
end_location:
row: 88
column: 34
parent: ~

0 comments on commit c8cd2e9

Please sign in to comment.