This commit is contained in:
Dan Parizher 2025-11-16 12:38:01 -05:00 committed by GitHub
commit 28aaaed2c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 127 additions and 2 deletions

View file

@ -64,3 +64,12 @@ import logging
x = 1
logging.error(f"{x} -> %s", x)
# Test cases for control characters in f-strings
bar = "bar"
logging.getLogger().error(f"Lorem ipsum \n {bar}")
value = "test"
logging.info(f"Tab\t{value}")
logging.info(f"CR\r{value}")

View file

@ -14,6 +14,26 @@ use crate::rules::flake8_logging_format::violations::{
};
use crate::{Edit, Fix};
/// Escape control characters and quotes for use in a Python string literal.
/// Escapes newlines, tabs, carriage returns, backslashes, and quotes that match the quote style.
fn escape_string_for_literal(text: &str, quote_char: char) -> String {
let mut escaped = String::with_capacity(text.len() * 2);
for ch in text.chars() {
match ch {
'\n' => escaped.push_str("\\n"),
'\t' => escaped.push_str("\\t"),
'\r' => escaped.push_str("\\r"),
'\\' => escaped.push_str("\\\\"),
ch if ch == quote_char => {
escaped.push('\\');
escaped.push(ch);
}
_ => escaped.push(ch),
}
}
escaped
}
fn logging_f_string(
checker: &Checker,
msg: &Expr,
@ -50,6 +70,9 @@ fn logging_f_string(
.next()
.unwrap_or("\"");
// Extract the quote character for escaping
let quote_char = quote_str.chars().next().unwrap_or('"');
for part in &f_string.value {
match part {
ast::FStringPart::Literal(literal) => {
@ -57,7 +80,7 @@ fn logging_f_string(
if literal_text.contains('%') {
return;
}
format_string.push_str(literal_text);
format_string.push_str(&escape_string_for_literal(literal_text, quote_char));
}
ast::FStringPart::FString(f) => {
for element in &f.elements {
@ -69,7 +92,10 @@ fn logging_f_string(
if lit.value.as_ref().contains('%') {
return;
}
format_string.push_str(lit.value.as_ref());
format_string.push_str(&escape_string_for_literal(
lit.value.as_ref(),
quote_char,
));
}
InterpolatedStringElement::Interpolation(interpolated) => {
if interpolated.format_spec.is_some()

View file

@ -217,5 +217,40 @@ G004 Logging statement uses f-string
65 | x = 1
66 | logging.error(f"{x} -> %s", x)
| ^^^^^^^^^^^^
67 |
68 | # Test cases for control characters in f-strings
|
help: Convert to lazy `%` formatting
G004 Logging statement uses f-string
--> G004.py:70:27
|
68 | # Test cases for control characters in f-strings
69 | bar = "bar"
70 | logging.getLogger().error(f"Lorem ipsum \n {bar}")
| ^^^^^^^^^^^^^^^^^^^^^^^
71 |
72 | value = "test"
|
help: Convert to lazy `%` formatting
G004 Logging statement uses f-string
--> G004.py:73:14
|
72 | value = "test"
73 | logging.info(f"Tab\t{value}")
| ^^^^^^^^^^^^^^^
74 |
75 | logging.info(f"CR\r{value}")
|
help: Convert to lazy `%` formatting
G004 Logging statement uses f-string
--> G004.py:75:14
|
73 | logging.info(f"Tab\t{value}")
74 |
75 | logging.info(f"CR\r{value}")
| ^^^^^^^^^^^^^^
|
help: Convert to lazy `%` formatting

View file

@ -273,5 +273,60 @@ G004 Logging statement uses f-string
65 | x = 1
66 | logging.error(f"{x} -> %s", x)
| ^^^^^^^^^^^^
67 |
68 | # Test cases for control characters in f-strings
|
help: Convert to lazy `%` formatting
G004 [*] Logging statement uses f-string
--> G004.py:70:27
|
68 | # Test cases for control characters in f-strings
69 | bar = "bar"
70 | logging.getLogger().error(f"Lorem ipsum \n {bar}")
| ^^^^^^^^^^^^^^^^^^^^^^^
71 |
72 | value = "test"
|
help: Convert to lazy `%` formatting
67 |
68 | # Test cases for control characters in f-strings
69 | bar = "bar"
- logging.getLogger().error(f"Lorem ipsum \n {bar}")
70 + logging.getLogger().error("Lorem ipsum \n %s", bar)
71 |
72 | value = "test"
73 | logging.info(f"Tab\t{value}")
G004 [*] Logging statement uses f-string
--> G004.py:73:14
|
72 | value = "test"
73 | logging.info(f"Tab\t{value}")
| ^^^^^^^^^^^^^^^
74 |
75 | logging.info(f"CR\r{value}")
|
help: Convert to lazy `%` formatting
70 | logging.getLogger().error(f"Lorem ipsum \n {bar}")
71 |
72 | value = "test"
- logging.info(f"Tab\t{value}")
73 + logging.info("Tab\t%s", value)
74 |
75 | logging.info(f"CR\r{value}")
G004 [*] Logging statement uses f-string
--> G004.py:75:14
|
73 | logging.info(f"Tab\t{value}")
74 |
75 | logging.info(f"CR\r{value}")
| ^^^^^^^^^^^^^^
|
help: Convert to lazy `%` formatting
72 | value = "test"
73 | logging.info(f"Tab\t{value}")
74 |
- logging.info(f"CR\r{value}")
75 + logging.info("CR\r%s", value)