mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 14:21:24 +00:00
[pylint
] Implement E1205 and E106 (#3084)
This commit is contained in:
parent
97338e4cd6
commit
8fde63b323
14 changed files with 238 additions and 25 deletions
12
crates/ruff/resources/test/fixtures/pylint/logging_too_few_args.py
vendored
Normal file
12
crates/ruff/resources/test/fixtures/pylint/logging_too_few_args.py
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.warning("Hello %s %s", "World!") # [logging-too-few-args]
|
||||||
|
|
||||||
|
# do not handle calls with kwargs (like pylint)
|
||||||
|
logging.warning("Hello %s", "World!", "again", something="else")
|
||||||
|
|
||||||
|
logging.warning("Hello %s", "World!")
|
||||||
|
|
||||||
|
import warning
|
||||||
|
|
||||||
|
warning.warning("Hello %s %s", "World!")
|
12
crates/ruff/resources/test/fixtures/pylint/logging_too_many_args.py
vendored
Normal file
12
crates/ruff/resources/test/fixtures/pylint/logging_too_many_args.py
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.warning("Hello %s", "World!", "again") # [logging-too-many-args]
|
||||||
|
|
||||||
|
# do not handle calls with kwargs (like pylint)
|
||||||
|
logging.warning("Hello %s", "World!", "again", something="else")
|
||||||
|
|
||||||
|
logging.warning("Hello %s", "World!")
|
||||||
|
|
||||||
|
import warning
|
||||||
|
|
||||||
|
warning.warning("Hello %s", "World!", "again")
|
24
crates/ruff/src/ast/logging.rs
Normal file
24
crates/ruff/src/ast/logging.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
pub enum LoggingLevel {
|
||||||
|
Debug,
|
||||||
|
Critical,
|
||||||
|
Error,
|
||||||
|
Exception,
|
||||||
|
Info,
|
||||||
|
Warn,
|
||||||
|
Warning,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoggingLevel {
|
||||||
|
pub fn from_str(level: &str) -> Option<Self> {
|
||||||
|
match level {
|
||||||
|
"debug" => Some(LoggingLevel::Debug),
|
||||||
|
"critical" => Some(LoggingLevel::Critical),
|
||||||
|
"error" => Some(LoggingLevel::Error),
|
||||||
|
"exception" => Some(LoggingLevel::Exception),
|
||||||
|
"info" => Some(LoggingLevel::Info),
|
||||||
|
"warn" => Some(LoggingLevel::Warn),
|
||||||
|
"warning" => Some(LoggingLevel::Warning),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ pub mod comparable;
|
||||||
pub mod function_type;
|
pub mod function_type;
|
||||||
pub mod hashable;
|
pub mod hashable;
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
|
pub mod logging;
|
||||||
pub mod operations;
|
pub mod operations;
|
||||||
pub mod relocate;
|
pub mod relocate;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
|
@ -2918,6 +2918,13 @@ where
|
||||||
{
|
{
|
||||||
flake8_logging_format::rules::logging_call(self, func, args, keywords);
|
flake8_logging_format::rules::logging_call(self, func, args, keywords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pylint logging checker
|
||||||
|
if self.settings.rules.enabled(&Rule::LoggingTooFewArgs)
|
||||||
|
|| self.settings.rules.enabled(&Rule::LoggingTooManyArgs)
|
||||||
|
{
|
||||||
|
pylint::rules::logging_call(self, func, args, keywords);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Dict { keys, values } => {
|
ExprKind::Dict { keys, values } => {
|
||||||
if self
|
if self
|
||||||
|
|
|
@ -126,6 +126,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||||
(Pylint, "E0101") => Rule::ReturnInInit,
|
(Pylint, "E0101") => Rule::ReturnInInit,
|
||||||
(Pylint, "E0604") => Rule::InvalidAllObject,
|
(Pylint, "E0604") => Rule::InvalidAllObject,
|
||||||
(Pylint, "E0605") => Rule::InvalidAllFormat,
|
(Pylint, "E0605") => Rule::InvalidAllFormat,
|
||||||
|
(Pylint, "E1205") => Rule::LoggingTooManyArgs,
|
||||||
|
(Pylint, "E1206") => Rule::LoggingTooFewArgs,
|
||||||
(Pylint, "E1307") => Rule::BadStringFormatType,
|
(Pylint, "E1307") => Rule::BadStringFormatType,
|
||||||
(Pylint, "E2502") => Rule::BidirectionalUnicode,
|
(Pylint, "E2502") => Rule::BidirectionalUnicode,
|
||||||
(Pylint, "E1310") => Rule::BadStrStripCall,
|
(Pylint, "E1310") => Rule::BadStrStripCall,
|
||||||
|
|
|
@ -150,6 +150,8 @@ ruff_macros::register_rules!(
|
||||||
rules::pylint::rules::TooManyBranches,
|
rules::pylint::rules::TooManyBranches,
|
||||||
rules::pylint::rules::TooManyStatements,
|
rules::pylint::rules::TooManyStatements,
|
||||||
rules::pylint::rules::RedefinedLoopName,
|
rules::pylint::rules::RedefinedLoopName,
|
||||||
|
rules::pylint::rules::LoggingTooFewArgs,
|
||||||
|
rules::pylint::rules::LoggingTooManyArgs,
|
||||||
// flake8-builtins
|
// flake8-builtins
|
||||||
rules::flake8_builtins::rules::BuiltinVariableShadowing,
|
rules::flake8_builtins::rules::BuiltinVariableShadowing,
|
||||||
rules::flake8_builtins::rules::BuiltinArgumentShadowing,
|
rules::flake8_builtins::rules::BuiltinArgumentShadowing,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Location, Operator};
|
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Location, Operator};
|
||||||
|
|
||||||
use crate::ast::helpers::{find_keyword, is_logger_candidate, SimpleCallArgs};
|
use crate::ast::helpers::{find_keyword, is_logger_candidate, SimpleCallArgs};
|
||||||
|
use crate::ast::logging::LoggingLevel;
|
||||||
use crate::ast::types::Range;
|
use crate::ast::types::Range;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::Fix;
|
use crate::fix::Fix;
|
||||||
|
@ -10,31 +11,6 @@ use crate::rules::flake8_logging_format::violations::{
|
||||||
LoggingRedundantExcInfo, LoggingStringConcat, LoggingStringFormat, LoggingWarn,
|
LoggingRedundantExcInfo, LoggingStringConcat, LoggingStringFormat, LoggingWarn,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LoggingLevel {
|
|
||||||
Debug,
|
|
||||||
Critical,
|
|
||||||
Error,
|
|
||||||
Exception,
|
|
||||||
Info,
|
|
||||||
Warn,
|
|
||||||
Warning,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LoggingLevel {
|
|
||||||
fn from_str(level: &str) -> Option<Self> {
|
|
||||||
match level {
|
|
||||||
"debug" => Some(LoggingLevel::Debug),
|
|
||||||
"critical" => Some(LoggingLevel::Critical),
|
|
||||||
"error" => Some(LoggingLevel::Error),
|
|
||||||
"exception" => Some(LoggingLevel::Exception),
|
|
||||||
"info" => Some(LoggingLevel::Info),
|
|
||||||
"warn" => Some(LoggingLevel::Warn),
|
|
||||||
"warning" => Some(LoggingLevel::Warning),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const RESERVED_ATTRS: &[&str; 22] = &[
|
const RESERVED_ATTRS: &[&str; 22] = &[
|
||||||
"args",
|
"args",
|
||||||
"asctime",
|
"asctime",
|
||||||
|
|
|
@ -17,6 +17,8 @@ mod tests {
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
use crate::test::test_path;
|
use crate::test::test_path;
|
||||||
|
|
||||||
|
#[test_case(Rule::LoggingTooManyArgs, Path::new("logging_too_many_args.py"); "PLE1205")]
|
||||||
|
#[test_case(Rule::LoggingTooFewArgs, Path::new("logging_too_few_args.py"); "PLE1206")]
|
||||||
#[test_case(Rule::ReturnInInit, Path::new("return_in_init.py"); "PLE0101")]
|
#[test_case(Rule::ReturnInInit, Path::new("return_in_init.py"); "PLE0101")]
|
||||||
#[test_case(Rule::UselessImportAlias, Path::new("import_aliasing.py"); "PLC0414")]
|
#[test_case(Rule::UselessImportAlias, Path::new("import_aliasing.py"); "PLC0414")]
|
||||||
#[test_case(Rule::UnnecessaryDirectLambdaCall, Path::new("unnecessary_direct_lambda_call.py"); "PLC3002")]
|
#[test_case(Rule::UnnecessaryDirectLambdaCall, Path::new("unnecessary_direct_lambda_call.py"); "PLC3002")]
|
||||||
|
|
139
crates/ruff/src/rules/pylint/rules/logging.rs
Normal file
139
crates/ruff/src/rules/pylint/rules/logging.rs
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword};
|
||||||
|
|
||||||
|
use ruff_macros::{define_violation, derive_message_formats};
|
||||||
|
|
||||||
|
use crate::ast::helpers::{is_logger_candidate, SimpleCallArgs};
|
||||||
|
use crate::ast::logging::LoggingLevel;
|
||||||
|
use crate::ast::types::Range;
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::registry::{Diagnostic, Rule};
|
||||||
|
use crate::rules::pyflakes::cformat::CFormatSummary;
|
||||||
|
use crate::violation::Violation;
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for too few positional arguments for a `logging` format string.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// A `TypeError` will be raised if the statement is run.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// import logging
|
||||||
|
///
|
||||||
|
/// try:
|
||||||
|
/// function()
|
||||||
|
/// except Exception as e:
|
||||||
|
/// logging.error('%s error occurred: %s', e) # [logging-too-few-args]
|
||||||
|
/// raise
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// import logging
|
||||||
|
///
|
||||||
|
/// try:
|
||||||
|
/// function()
|
||||||
|
/// except Exception as e:
|
||||||
|
/// logging.error('%s error occurred: %s', type(e), e)
|
||||||
|
/// raise
|
||||||
|
/// ```
|
||||||
|
pub struct LoggingTooFewArgs;
|
||||||
|
);
|
||||||
|
impl Violation for LoggingTooFewArgs {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
format!("Not enough arguments for `logging` format string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define_violation!(
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for too many positional arguments for a `logging` format string.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// A `TypeError` will be raised if the statement is run.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// import logging
|
||||||
|
///
|
||||||
|
/// try:
|
||||||
|
/// function()
|
||||||
|
/// except Exception as e:
|
||||||
|
/// logging.error('Error occurred: %s', type(e), e) # [logging-too-many-args]
|
||||||
|
/// raise
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// import logging
|
||||||
|
///
|
||||||
|
/// try:
|
||||||
|
/// function()
|
||||||
|
/// except Exception as e:
|
||||||
|
/// logging.error('%s error occurred: %s', type(e), e)
|
||||||
|
/// raise
|
||||||
|
/// ```
|
||||||
|
pub struct LoggingTooManyArgs;
|
||||||
|
);
|
||||||
|
impl Violation for LoggingTooManyArgs {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
format!("Too many arguments for `logging` format string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check logging calls for violations.
|
||||||
|
pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) {
|
||||||
|
if !is_logger_candidate(func) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ExprKind::Attribute { attr, .. } = &func.node {
|
||||||
|
if LoggingLevel::from_str(attr.as_str()).is_some() {
|
||||||
|
let call_args = SimpleCallArgs::new(args, keywords);
|
||||||
|
|
||||||
|
// E1205 - E1206
|
||||||
|
if let Some(msg) = call_args.get_argument("msg", Some(0)) {
|
||||||
|
if let ExprKind::Constant {
|
||||||
|
value: Constant::Str(value),
|
||||||
|
..
|
||||||
|
} = &msg.node
|
||||||
|
{
|
||||||
|
if let Ok(summary) = CFormatSummary::try_from(value.as_str()) {
|
||||||
|
if summary.starred {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !call_args.kwargs.is_empty() {
|
||||||
|
// Keyword checking on logging strings is complicated by
|
||||||
|
// special keywords - out of scope.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message_args = call_args.args.len() - 1;
|
||||||
|
|
||||||
|
if checker.settings.rules.enabled(&Rule::LoggingTooManyArgs)
|
||||||
|
&& summary.num_positional < message_args
|
||||||
|
{
|
||||||
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
LoggingTooManyArgs,
|
||||||
|
Range::from_located(func),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker.settings.rules.enabled(&Rule::LoggingTooFewArgs)
|
||||||
|
&& summary.num_positional > message_args
|
||||||
|
{
|
||||||
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
LoggingTooFewArgs,
|
||||||
|
Range::from_located(func),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ pub use consider_using_sys_exit::{consider_using_sys_exit, ConsiderUsingSysExit}
|
||||||
pub use global_variable_not_assigned::GlobalVariableNotAssigned;
|
pub use global_variable_not_assigned::GlobalVariableNotAssigned;
|
||||||
pub use invalid_all_format::{invalid_all_format, InvalidAllFormat};
|
pub use invalid_all_format::{invalid_all_format, InvalidAllFormat};
|
||||||
pub use invalid_all_object::{invalid_all_object, InvalidAllObject};
|
pub use invalid_all_object::{invalid_all_object, InvalidAllObject};
|
||||||
|
pub use logging::{logging_call, LoggingTooFewArgs, LoggingTooManyArgs};
|
||||||
pub use magic_value_comparison::{magic_value_comparison, MagicValueComparison};
|
pub use magic_value_comparison::{magic_value_comparison, MagicValueComparison};
|
||||||
pub use merge_isinstance::{merge_isinstance, ConsiderMergingIsinstance};
|
pub use merge_isinstance::{merge_isinstance, ConsiderMergingIsinstance};
|
||||||
pub use nonlocal_without_binding::NonlocalWithoutBinding;
|
pub use nonlocal_without_binding::NonlocalWithoutBinding;
|
||||||
|
@ -37,6 +38,7 @@ mod consider_using_sys_exit;
|
||||||
mod global_variable_not_assigned;
|
mod global_variable_not_assigned;
|
||||||
mod invalid_all_format;
|
mod invalid_all_format;
|
||||||
mod invalid_all_object;
|
mod invalid_all_object;
|
||||||
|
mod logging;
|
||||||
mod magic_value_comparison;
|
mod magic_value_comparison;
|
||||||
mod merge_isinstance;
|
mod merge_isinstance;
|
||||||
mod nonlocal_without_binding;
|
mod nonlocal_without_binding;
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/pylint/mod.rs
|
||||||
|
expression: diagnostics
|
||||||
|
---
|
||||||
|
- kind:
|
||||||
|
LoggingTooManyArgs: ~
|
||||||
|
location:
|
||||||
|
row: 3
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 3
|
||||||
|
column: 15
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/pylint/mod.rs
|
||||||
|
expression: diagnostics
|
||||||
|
---
|
||||||
|
- kind:
|
||||||
|
LoggingTooFewArgs: ~
|
||||||
|
location:
|
||||||
|
row: 3
|
||||||
|
column: 0
|
||||||
|
end_location:
|
||||||
|
row: 3
|
||||||
|
column: 15
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
|
4
ruff.schema.json
generated
4
ruff.schema.json
generated
|
@ -1793,6 +1793,10 @@
|
||||||
"PLE11",
|
"PLE11",
|
||||||
"PLE114",
|
"PLE114",
|
||||||
"PLE1142",
|
"PLE1142",
|
||||||
|
"PLE12",
|
||||||
|
"PLE120",
|
||||||
|
"PLE1205",
|
||||||
|
"PLE1206",
|
||||||
"PLE13",
|
"PLE13",
|
||||||
"PLE130",
|
"PLE130",
|
||||||
"PLE1307",
|
"PLE1307",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue