Skip to content

Commit

Permalink
Add check to PLE1300 for nested format specs and snapshots
Browse files Browse the repository at this point in the history
  • Loading branch information
zanieb committed Aug 16, 2023
1 parent 78fa45d commit e5d6ec3
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@

"{:s} {:y}".format("hello", "world") # [bad-format-character]

"{:*^30s}".format("centered")
"{:*^30s}".format("centered") # OK
"{:{s}}".format("hello", s="s") # OK (nested replacement value not checked)

"{:{s:y}}".format("hello", s="s") # [bad-format-character] (nested replacement format spec checked)

## f-strings

Expand Down
43 changes: 33 additions & 10 deletions crates/ruff/src/rules/pylint/rules/bad_string_format_character.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,39 @@ pub(crate) fn call(checker: &mut Checker, string: &str, range: TextRange) {
continue;
};

if let Err(FormatSpecError::InvalidFormatType) = FormatSpec::parse(format_spec) {
checker.diagnostics.push(Diagnostic::new(
BadStringFormatCharacter {
// The format type character is always the last one.
// More info in the official spec:
// https://docs.python.org/3/library/string.html#format-specification-mini-language
format_char: format_spec.chars().last().unwrap(),
},
range,
));
match FormatSpec::parse(format_spec) {
Err(FormatSpecError::InvalidFormatType) => {
checker.diagnostics.push(Diagnostic::new(
BadStringFormatCharacter {
// The format type character is always the last one.
// More info in the official spec:
// https://docs.python.org/3/library/string.html#format-specification-mini-language
format_char: format_spec.chars().last().unwrap(),
},
range,
));
}
Err(_) => {}
Ok(format_spec) => {
for replacement in format_spec.replacements {
let FormatPart::Field { format_spec, .. } = replacement else {
continue;
};
if let Err(FormatSpecError::InvalidFormatType) =
FormatSpec::parse(&format_spec)
{
checker.diagnostics.push(Diagnostic::new(
BadStringFormatCharacter {
// The format type character is always the last one.
// More info in the official spec:
// https://docs.python.org/3/library/string.html#format-specification-mini-language
format_char: format_spec.chars().last().unwrap(),
},
range,
));
}
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,17 @@ bad_string_format_character.py:15:1: PLE1300 Unsupported format character 'y'
15 | "{:s} {:y}".format("hello", "world") # [bad-format-character]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLE1300
16 |
17 | "{:*^30s}".format("centered")
17 | "{:*^30s}".format("centered") # OK
|

bad_string_format_character.py:20:1: PLE1300 Unsupported format character 'y'
|
18 | "{:{s}}".format("hello", s="s") # OK (nested replacement value not checked)
19 |
20 | "{:{s:y}}".format("hello", s="s") # [bad-format-character] (nested replacement format spec checked)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLE1300
21 |
22 | ## f-strings
|


2 changes: 1 addition & 1 deletion crates/ruff_python_literal/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub struct FormatSpec {
// Ex) `f` in `'{:+f}'`
format_type: Option<FormatType>,
// Ex) `x` and `y` in `'{:*{x},{y}b}'`
replacements: Vec<FormatPart>,
pub replacements: Vec<FormatPart>,
}

fn get_num_digits(text: &str) -> usize {
Expand Down

0 comments on commit e5d6ec3

Please sign in to comment.