mirror of https://github.com/astral-sh/ruff
Allow aliased `logging` module as a logger candidate (#3718)
This commit is contained in:
parent
7af83460ce
commit
63adf9f5e8
|
|
@ -1,3 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
import logging as foo
|
||||||
|
|
||||||
logging.info("Hello {}".format("World!"))
|
logging.info("Hello {}".format("World!"))
|
||||||
|
foo.info("Hello {}".format("World!"))
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ pub fn blind_except(
|
||||||
if body.iter().any(|stmt| {
|
if body.iter().any(|stmt| {
|
||||||
if let StmtKind::Expr { value } = &stmt.node {
|
if let StmtKind::Expr { value } = &stmt.node {
|
||||||
if let ExprKind::Call { func, keywords, .. } = &value.node {
|
if let ExprKind::Call { func, keywords, .. } = &value.node {
|
||||||
if helpers::is_logger_candidate(func) {
|
if helpers::is_logger_candidate(&checker.ctx, func) {
|
||||||
if let ExprKind::Attribute { attr, .. } = &func.node {
|
if let ExprKind::Attribute { attr, .. } = &func.node {
|
||||||
if attr == "exception" {
|
if attr == "exception" {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
|
||||||
|
|
||||||
/// Check logging calls for violations.
|
/// Check logging calls for violations.
|
||||||
pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) {
|
pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) {
|
||||||
if !is_logger_candidate(func) {
|
if !is_logger_candidate(&checker.ctx, func) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,24 @@ expression: diagnostics
|
||||||
suggestion: ~
|
suggestion: ~
|
||||||
fixable: false
|
fixable: false
|
||||||
location:
|
location:
|
||||||
row: 3
|
row: 4
|
||||||
column: 13
|
column: 13
|
||||||
end_location:
|
end_location:
|
||||||
row: 3
|
row: 4
|
||||||
column: 40
|
column: 40
|
||||||
fix: ~
|
fix: ~
|
||||||
parent: ~
|
parent: ~
|
||||||
|
- kind:
|
||||||
|
name: LoggingStringFormat
|
||||||
|
body: "Logging statement uses `string.format()`"
|
||||||
|
suggestion: ~
|
||||||
|
fixable: false
|
||||||
|
location:
|
||||||
|
row: 5
|
||||||
|
column: 9
|
||||||
|
end_location:
|
||||||
|
row: 5
|
||||||
|
column: 36
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_logger_candidate(func) {
|
if !is_logger_candidate(&checker.ctx, func) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,32 @@
|
||||||
use rustpython_parser::ast::{Expr, ExprKind};
|
use rustpython_parser::ast::{Expr, ExprKind};
|
||||||
|
|
||||||
|
use ruff_python_ast::context::Context;
|
||||||
use ruff_python_ast::helpers::is_logger_candidate;
|
use ruff_python_ast::helpers::is_logger_candidate;
|
||||||
use ruff_python_ast::visitor;
|
use ruff_python_ast::visitor;
|
||||||
use ruff_python_ast::visitor::Visitor;
|
use ruff_python_ast::visitor::Visitor;
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
/// Collect `logging`-like calls from an AST.
|
/// Collect `logging`-like calls from an AST.
|
||||||
pub struct LoggerCandidateVisitor<'a> {
|
pub struct LoggerCandidateVisitor<'a> {
|
||||||
|
context: &'a Context<'a>,
|
||||||
pub calls: Vec<(&'a Expr, &'a Expr)>,
|
pub calls: Vec<(&'a Expr, &'a Expr)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> LoggerCandidateVisitor<'a> {
|
||||||
|
pub fn new(context: &'a Context<'a>) -> Self {
|
||||||
|
LoggerCandidateVisitor {
|
||||||
|
context,
|
||||||
|
calls: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Visitor<'b> for LoggerCandidateVisitor<'a>
|
impl<'a, 'b> Visitor<'b> for LoggerCandidateVisitor<'a>
|
||||||
where
|
where
|
||||||
'b: 'a,
|
'b: 'a,
|
||||||
{
|
{
|
||||||
fn visit_expr(&mut self, expr: &'b Expr) {
|
fn visit_expr(&mut self, expr: &'b Expr) {
|
||||||
if let ExprKind::Call { func, .. } = &expr.node {
|
if let ExprKind::Call { func, .. } = &expr.node {
|
||||||
if is_logger_candidate(func) {
|
if is_logger_candidate(self.context, func) {
|
||||||
self.calls.push((expr, func));
|
self.calls.push((expr, func));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ pub fn error_instead_of_exception(checker: &mut Checker, handlers: &[Excepthandl
|
||||||
for handler in handlers {
|
for handler in handlers {
|
||||||
let ExcepthandlerKind::ExceptHandler { body, .. } = &handler.node;
|
let ExcepthandlerKind::ExceptHandler { body, .. } = &handler.node;
|
||||||
let calls = {
|
let calls = {
|
||||||
let mut visitor = LoggerCandidateVisitor::default();
|
let mut visitor = LoggerCandidateVisitor::new(&checker.ctx);
|
||||||
visitor.visit_body(body);
|
visitor.visit_body(body);
|
||||||
visitor.calls
|
visitor.calls
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ pub fn verbose_log_message(checker: &mut Checker, handlers: &[Excepthandler]) {
|
||||||
|
|
||||||
// Find all calls to `logging.exception`.
|
// Find all calls to `logging.exception`.
|
||||||
let calls = {
|
let calls = {
|
||||||
let mut visitor = LoggerCandidateVisitor::default();
|
let mut visitor = LoggerCandidateVisitor::new(&checker.ctx);
|
||||||
visitor.visit_body(body);
|
visitor.visit_body(body);
|
||||||
visitor.calls
|
visitor.calls
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1288,9 +1288,20 @@ impl<'a> SimpleCallArgs<'a> {
|
||||||
/// Return `true` if the given `Expr` is a potential logging call. Matches
|
/// Return `true` if the given `Expr` is a potential logging call. Matches
|
||||||
/// `logging.error`, `logger.error`, `self.logger.error`, etc., but not
|
/// `logging.error`, `logger.error`, `self.logger.error`, etc., but not
|
||||||
/// arbitrary `foo.error` calls.
|
/// arbitrary `foo.error` calls.
|
||||||
pub fn is_logger_candidate(func: &Expr) -> bool {
|
///
|
||||||
|
/// It even matches direct `logging.error` calls even if the `logging` module
|
||||||
|
/// is aliased. Example:
|
||||||
|
/// ```python
|
||||||
|
/// import logging as bar
|
||||||
|
///
|
||||||
|
/// # This is detected to be a logger candidate
|
||||||
|
/// bar.error()
|
||||||
|
/// ```
|
||||||
|
pub fn is_logger_candidate(context: &Context, func: &Expr) -> bool {
|
||||||
if let ExprKind::Attribute { value, .. } = &func.node {
|
if let ExprKind::Attribute { value, .. } = &func.node {
|
||||||
let call_path = collect_call_path(value);
|
let call_path = context
|
||||||
|
.resolve_call_path(value)
|
||||||
|
.unwrap_or_else(|| collect_call_path(value));
|
||||||
if let Some(tail) = call_path.last() {
|
if let Some(tail) = call_path.last() {
|
||||||
if tail.starts_with("log") || tail.ends_with("logger") || tail.ends_with("logging") {
|
if tail.starts_with("log") || tail.ends_with("logger") || tail.ends_with("logging") {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue