mirror of https://github.com/astral-sh/ruff
[`ruff`] Add support for additional eager conversion patterns (`RUF065`) (#20657)
## Summary Fixes #20583
This commit is contained in:
parent
980b4c55b2
commit
1ebedf6df5
|
|
@ -43,3 +43,29 @@ logging.warning("Value: %r", repr(42))
|
|||
logging.error("Error: %r", repr([1, 2, 3]))
|
||||
logging.info("Debug info: %s", repr("test\nstring"))
|
||||
logging.warning("Value: %s", repr(42))
|
||||
|
||||
# %s + ascii()
|
||||
logging.info("ASCII: %s", ascii("Hello\nWorld"))
|
||||
logging.warning("ASCII: %s", ascii("test"))
|
||||
|
||||
# %s + oct()
|
||||
logging.info("Octal: %s", oct(42))
|
||||
logging.warning("Octal: %s", oct(255))
|
||||
|
||||
# %s + hex()
|
||||
logging.info("Hex: %s", hex(42))
|
||||
logging.warning("Hex: %s", hex(255))
|
||||
|
||||
|
||||
# Test with imported functions
|
||||
from logging import info, log
|
||||
|
||||
info("ASCII: %s", ascii("Hello\nWorld"))
|
||||
log(logging.INFO, "ASCII: %s", ascii("test"))
|
||||
|
||||
info("Octal: %s", oct(42))
|
||||
log(logging.INFO, "Octal: %s", oct(255))
|
||||
|
||||
info("Hex: %s", hex(42))
|
||||
log(logging.INFO, "Hex: %s", hex(255))
|
||||
|
||||
|
|
|
|||
|
|
@ -63,19 +63,44 @@ use crate::rules::flake8_logging_format::rules::{LoggingCallType, find_logging_c
|
|||
#[violation_metadata(preview_since = "0.13.2")]
|
||||
pub(crate) struct LoggingEagerConversion {
|
||||
pub(crate) format_conversion: FormatConversion,
|
||||
pub(crate) function_name: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl Violation for LoggingEagerConversion {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let LoggingEagerConversion { format_conversion } = self;
|
||||
let (format_str, call_arg) = match format_conversion {
|
||||
FormatConversion::Str => ("%s", "str()"),
|
||||
FormatConversion::Repr => ("%r", "repr()"),
|
||||
FormatConversion::Ascii => ("%a", "ascii()"),
|
||||
FormatConversion::Bytes => ("%b", "bytes()"),
|
||||
};
|
||||
format!("Unnecessary `{call_arg}` conversion when formatting with `{format_str}`")
|
||||
let LoggingEagerConversion {
|
||||
format_conversion,
|
||||
function_name,
|
||||
} = self;
|
||||
match (format_conversion, function_name.as_deref()) {
|
||||
(FormatConversion::Str, Some("oct")) => {
|
||||
"Unnecessary `oct()` conversion when formatting with `%s`. \
|
||||
Use `%#o` instead of `%s`"
|
||||
.to_string()
|
||||
}
|
||||
(FormatConversion::Str, Some("hex")) => {
|
||||
"Unnecessary `hex()` conversion when formatting with `%s`. \
|
||||
Use `%#x` instead of `%s`"
|
||||
.to_string()
|
||||
}
|
||||
(FormatConversion::Str, _) => {
|
||||
"Unnecessary `str()` conversion when formatting with `%s`".to_string()
|
||||
}
|
||||
(FormatConversion::Repr, _) => {
|
||||
"Unnecessary `repr()` conversion when formatting with `%s`. \
|
||||
Use `%r` instead of `%s`"
|
||||
.to_string()
|
||||
}
|
||||
(FormatConversion::Ascii, _) => {
|
||||
"Unnecessary `ascii()` conversion when formatting with `%s`. \
|
||||
Use `%a` instead of `%s`"
|
||||
.to_string()
|
||||
}
|
||||
(FormatConversion::Bytes, _) => {
|
||||
"Unnecessary `bytes()` conversion when formatting with `%b`".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,12 +143,71 @@ pub(crate) fn logging_eager_conversion(checker: &Checker, call: &ast::ExprCall)
|
|||
continue;
|
||||
};
|
||||
|
||||
// Check for use of %s with str()
|
||||
if checker.semantic().match_builtin_expr(func.as_ref(), "str")
|
||||
&& matches!(format_conversion, FormatConversion::Str)
|
||||
// Check for various eager conversion patterns
|
||||
match format_conversion {
|
||||
// %s with str() - remove str() call
|
||||
FormatConversion::Str
|
||||
if checker.semantic().match_builtin_expr(func.as_ref(), "str") =>
|
||||
{
|
||||
checker
|
||||
.report_diagnostic(LoggingEagerConversion { format_conversion }, arg.range());
|
||||
checker.report_diagnostic(
|
||||
LoggingEagerConversion {
|
||||
format_conversion,
|
||||
function_name: None,
|
||||
},
|
||||
arg.range(),
|
||||
);
|
||||
}
|
||||
// %s with repr() - suggest using %r instead
|
||||
FormatConversion::Str
|
||||
if checker.semantic().match_builtin_expr(func.as_ref(), "repr") =>
|
||||
{
|
||||
checker.report_diagnostic(
|
||||
LoggingEagerConversion {
|
||||
format_conversion: FormatConversion::Repr,
|
||||
function_name: None,
|
||||
},
|
||||
arg.range(),
|
||||
);
|
||||
}
|
||||
// %s with ascii() - suggest using %a instead
|
||||
FormatConversion::Str
|
||||
if checker
|
||||
.semantic()
|
||||
.match_builtin_expr(func.as_ref(), "ascii") =>
|
||||
{
|
||||
checker.report_diagnostic(
|
||||
LoggingEagerConversion {
|
||||
format_conversion: FormatConversion::Ascii,
|
||||
function_name: None,
|
||||
},
|
||||
arg.range(),
|
||||
);
|
||||
}
|
||||
// %s with oct() - suggest using %#o instead
|
||||
FormatConversion::Str
|
||||
if checker.semantic().match_builtin_expr(func.as_ref(), "oct") =>
|
||||
{
|
||||
checker.report_diagnostic(
|
||||
LoggingEagerConversion {
|
||||
format_conversion: FormatConversion::Str,
|
||||
function_name: Some("oct"),
|
||||
},
|
||||
arg.range(),
|
||||
);
|
||||
}
|
||||
// %s with hex() - suggest using %#x instead
|
||||
FormatConversion::Str
|
||||
if checker.semantic().match_builtin_expr(func.as_ref(), "hex") =>
|
||||
{
|
||||
checker.report_diagnostic(
|
||||
LoggingEagerConversion {
|
||||
format_conversion: FormatConversion::Str,
|
||||
function_name: Some("hex"),
|
||||
},
|
||||
arg.range(),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,26 @@ RUF065 Unnecessary `str()` conversion when formatting with `%s`
|
|||
7 | # %s + repr()
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `repr()` conversion when formatting with `%s`. Use `%r` instead of `%s`
|
||||
--> RUF065.py:8:26
|
||||
|
|
||||
7 | # %s + repr()
|
||||
8 | logging.info("Hello %s", repr("World!"))
|
||||
| ^^^^^^^^^^^^^^
|
||||
9 | logging.log(logging.INFO, "Hello %s", repr("World!"))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `repr()` conversion when formatting with `%s`. Use `%r` instead of `%s`
|
||||
--> RUF065.py:9:39
|
||||
|
|
||||
7 | # %s + repr()
|
||||
8 | logging.info("Hello %s", repr("World!"))
|
||||
9 | logging.log(logging.INFO, "Hello %s", repr("World!"))
|
||||
| ^^^^^^^^^^^^^^
|
||||
10 |
|
||||
11 | # %r + str()
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `str()` conversion when formatting with `%s`
|
||||
--> RUF065.py:22:18
|
||||
|
|
||||
|
|
@ -40,3 +60,160 @@ RUF065 Unnecessary `str()` conversion when formatting with `%s`
|
|||
24 |
|
||||
25 | # %s + repr()
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `repr()` conversion when formatting with `%s`. Use `%r` instead of `%s`
|
||||
--> RUF065.py:26:18
|
||||
|
|
||||
25 | # %s + repr()
|
||||
26 | info("Hello %s", repr("World!"))
|
||||
| ^^^^^^^^^^^^^^
|
||||
27 | log(logging.INFO, "Hello %s", repr("World!"))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `repr()` conversion when formatting with `%s`. Use `%r` instead of `%s`
|
||||
--> RUF065.py:27:31
|
||||
|
|
||||
25 | # %s + repr()
|
||||
26 | info("Hello %s", repr("World!"))
|
||||
27 | log(logging.INFO, "Hello %s", repr("World!"))
|
||||
| ^^^^^^^^^^^^^^
|
||||
28 |
|
||||
29 | # %r + str()
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `repr()` conversion when formatting with `%s`. Use `%r` instead of `%s`
|
||||
--> RUF065.py:44:32
|
||||
|
|
||||
42 | logging.warning("Value: %r", repr(42))
|
||||
43 | logging.error("Error: %r", repr([1, 2, 3]))
|
||||
44 | logging.info("Debug info: %s", repr("test\nstring"))
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
45 | logging.warning("Value: %s", repr(42))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `repr()` conversion when formatting with `%s`. Use `%r` instead of `%s`
|
||||
--> RUF065.py:45:30
|
||||
|
|
||||
43 | logging.error("Error: %r", repr([1, 2, 3]))
|
||||
44 | logging.info("Debug info: %s", repr("test\nstring"))
|
||||
45 | logging.warning("Value: %s", repr(42))
|
||||
| ^^^^^^^^
|
||||
46 |
|
||||
47 | # %s + ascii()
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `ascii()` conversion when formatting with `%s`. Use `%a` instead of `%s`
|
||||
--> RUF065.py:48:27
|
||||
|
|
||||
47 | # %s + ascii()
|
||||
48 | logging.info("ASCII: %s", ascii("Hello\nWorld"))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
49 | logging.warning("ASCII: %s", ascii("test"))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `ascii()` conversion when formatting with `%s`. Use `%a` instead of `%s`
|
||||
--> RUF065.py:49:30
|
||||
|
|
||||
47 | # %s + ascii()
|
||||
48 | logging.info("ASCII: %s", ascii("Hello\nWorld"))
|
||||
49 | logging.warning("ASCII: %s", ascii("test"))
|
||||
| ^^^^^^^^^^^^^
|
||||
50 |
|
||||
51 | # %s + oct()
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `oct()` conversion when formatting with `%s`. Use `%#o` instead of `%s`
|
||||
--> RUF065.py:52:27
|
||||
|
|
||||
51 | # %s + oct()
|
||||
52 | logging.info("Octal: %s", oct(42))
|
||||
| ^^^^^^^
|
||||
53 | logging.warning("Octal: %s", oct(255))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `oct()` conversion when formatting with `%s`. Use `%#o` instead of `%s`
|
||||
--> RUF065.py:53:30
|
||||
|
|
||||
51 | # %s + oct()
|
||||
52 | logging.info("Octal: %s", oct(42))
|
||||
53 | logging.warning("Octal: %s", oct(255))
|
||||
| ^^^^^^^^
|
||||
54 |
|
||||
55 | # %s + hex()
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `hex()` conversion when formatting with `%s`. Use `%#x` instead of `%s`
|
||||
--> RUF065.py:56:25
|
||||
|
|
||||
55 | # %s + hex()
|
||||
56 | logging.info("Hex: %s", hex(42))
|
||||
| ^^^^^^^
|
||||
57 | logging.warning("Hex: %s", hex(255))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `hex()` conversion when formatting with `%s`. Use `%#x` instead of `%s`
|
||||
--> RUF065.py:57:28
|
||||
|
|
||||
55 | # %s + hex()
|
||||
56 | logging.info("Hex: %s", hex(42))
|
||||
57 | logging.warning("Hex: %s", hex(255))
|
||||
| ^^^^^^^^
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `ascii()` conversion when formatting with `%s`. Use `%a` instead of `%s`
|
||||
--> RUF065.py:63:19
|
||||
|
|
||||
61 | from logging import info, log
|
||||
62 |
|
||||
63 | info("ASCII: %s", ascii("Hello\nWorld"))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
64 | log(logging.INFO, "ASCII: %s", ascii("test"))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `ascii()` conversion when formatting with `%s`. Use `%a` instead of `%s`
|
||||
--> RUF065.py:64:32
|
||||
|
|
||||
63 | info("ASCII: %s", ascii("Hello\nWorld"))
|
||||
64 | log(logging.INFO, "ASCII: %s", ascii("test"))
|
||||
| ^^^^^^^^^^^^^
|
||||
65 |
|
||||
66 | info("Octal: %s", oct(42))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `oct()` conversion when formatting with `%s`. Use `%#o` instead of `%s`
|
||||
--> RUF065.py:66:19
|
||||
|
|
||||
64 | log(logging.INFO, "ASCII: %s", ascii("test"))
|
||||
65 |
|
||||
66 | info("Octal: %s", oct(42))
|
||||
| ^^^^^^^
|
||||
67 | log(logging.INFO, "Octal: %s", oct(255))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `oct()` conversion when formatting with `%s`. Use `%#o` instead of `%s`
|
||||
--> RUF065.py:67:32
|
||||
|
|
||||
66 | info("Octal: %s", oct(42))
|
||||
67 | log(logging.INFO, "Octal: %s", oct(255))
|
||||
| ^^^^^^^^
|
||||
68 |
|
||||
69 | info("Hex: %s", hex(42))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `hex()` conversion when formatting with `%s`. Use `%#x` instead of `%s`
|
||||
--> RUF065.py:69:17
|
||||
|
|
||||
67 | log(logging.INFO, "Octal: %s", oct(255))
|
||||
68 |
|
||||
69 | info("Hex: %s", hex(42))
|
||||
| ^^^^^^^
|
||||
70 | log(logging.INFO, "Hex: %s", hex(255))
|
||||
|
|
||||
|
||||
RUF065 Unnecessary `hex()` conversion when formatting with `%s`. Use `%#x` instead of `%s`
|
||||
--> RUF065.py:70:30
|
||||
|
|
||||
69 | info("Hex: %s", hex(42))
|
||||
70 | log(logging.INFO, "Hex: %s", hex(255))
|
||||
| ^^^^^^^^
|
||||
|
|
||||
|
|
|
|||
Loading…
Reference in New Issue