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.error("Error: %r", repr([1, 2, 3]))
|
||||||
logging.info("Debug info: %s", repr("test\nstring"))
|
logging.info("Debug info: %s", repr("test\nstring"))
|
||||||
logging.warning("Value: %s", repr(42))
|
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")]
|
#[violation_metadata(preview_since = "0.13.2")]
|
||||||
pub(crate) struct LoggingEagerConversion {
|
pub(crate) struct LoggingEagerConversion {
|
||||||
pub(crate) format_conversion: FormatConversion,
|
pub(crate) format_conversion: FormatConversion,
|
||||||
|
pub(crate) function_name: Option<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Violation for LoggingEagerConversion {
|
impl Violation for LoggingEagerConversion {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let LoggingEagerConversion { format_conversion } = self;
|
let LoggingEagerConversion {
|
||||||
let (format_str, call_arg) = match format_conversion {
|
format_conversion,
|
||||||
FormatConversion::Str => ("%s", "str()"),
|
function_name,
|
||||||
FormatConversion::Repr => ("%r", "repr()"),
|
} = self;
|
||||||
FormatConversion::Ascii => ("%a", "ascii()"),
|
match (format_conversion, function_name.as_deref()) {
|
||||||
FormatConversion::Bytes => ("%b", "bytes()"),
|
(FormatConversion::Str, Some("oct")) => {
|
||||||
};
|
"Unnecessary `oct()` conversion when formatting with `%s`. \
|
||||||
format!("Unnecessary `{call_arg}` conversion when formatting with `{format_str}`")
|
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;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check for use of %s with str()
|
// Check for various eager conversion patterns
|
||||||
if checker.semantic().match_builtin_expr(func.as_ref(), "str")
|
match format_conversion {
|
||||||
&& matches!(format_conversion, FormatConversion::Str)
|
// %s with str() - remove str() call
|
||||||
|
FormatConversion::Str
|
||||||
|
if checker.semantic().match_builtin_expr(func.as_ref(), "str") =>
|
||||||
{
|
{
|
||||||
checker
|
checker.report_diagnostic(
|
||||||
.report_diagnostic(LoggingEagerConversion { format_conversion }, arg.range());
|
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()
|
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 Unnecessary `str()` conversion when formatting with `%s`
|
||||||
--> RUF065.py:22:18
|
--> RUF065.py:22:18
|
||||||
|
|
|
|
||||||
|
|
@ -40,3 +60,160 @@ RUF065 Unnecessary `str()` conversion when formatting with `%s`
|
||||||
24 |
|
24 |
|
||||||
25 | # %s + repr()
|
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