mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 10:22:24 +00:00
Implement R002 (NoAssertEquals) (#98)
This commit is contained in:
parent
79b6472c7c
commit
198e5cf27f
9 changed files with 126 additions and 17 deletions
|
@ -136,7 +136,8 @@ lint rules that are obviated by Black (e.g., stylistic rules).
|
|||
| F831 | DuplicateArgumentName | Duplicate argument name in function definition |
|
||||
| F841 | UnusedVariable | Local variable `...` is assigned to but never used |
|
||||
| F901 | RaiseNotImplemented | `raise NotImplemented` should be `raise NotImplementedError` |
|
||||
| R0205 | UselessObjectInheritance | Class `...` inherits from object |
|
||||
| R001 | UselessObjectInheritance | Class `...` inherits from object |
|
||||
| R002 | NoAssertEquals | `assertEquals` is deprecated, use `assertEqual` instead |
|
||||
|
||||
## Development
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ fn main() {
|
|||
CheckKind::ImportStarUsage,
|
||||
CheckKind::LineTooLong,
|
||||
CheckKind::ModuleImportNotAtTopOfFile,
|
||||
CheckKind::NoAssertEquals,
|
||||
CheckKind::RaiseNotImplemented,
|
||||
CheckKind::ReturnOutsideFunction,
|
||||
CheckKind::UndefinedExport("...".to_string()),
|
||||
|
|
3
resources/test/fixtures/R002.py
vendored
Normal file
3
resources/test/fixtures/R002.py
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
self.assertEquals (1, 2)
|
||||
self.assertEquals(1, 2)
|
||||
self.assertEqual(3, 4)
|
3
resources/test/fixtures/pyproject.toml
vendored
3
resources/test/fixtures/pyproject.toml
vendored
|
@ -18,5 +18,6 @@ select = [
|
|||
"F831",
|
||||
"F841",
|
||||
"F901",
|
||||
"R0205",
|
||||
"R001",
|
||||
"R002",
|
||||
]
|
||||
|
|
|
@ -2,8 +2,8 @@ use std::collections::BTreeSet;
|
|||
use std::path::Path;
|
||||
|
||||
use rustpython_parser::ast::{
|
||||
Arg, Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, Stmt,
|
||||
StmtKind, Suite,
|
||||
Arg, Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind,
|
||||
Location, Stmt, StmtKind, Suite,
|
||||
};
|
||||
use rustpython_parser::parser;
|
||||
|
||||
|
@ -11,7 +11,7 @@ use crate::ast_ops::{
|
|||
extract_all_names, Binding, BindingKind, Scope, ScopeKind, SourceCodeLocator,
|
||||
};
|
||||
use crate::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
use crate::checks::{Check, CheckCode, CheckKind, Fix};
|
||||
use crate::settings::Settings;
|
||||
use crate::visitor::{walk_excepthandler, Visitor};
|
||||
use crate::{autofix, fixer, visitor};
|
||||
|
@ -132,7 +132,7 @@ impl Visitor for Checker<'_> {
|
|||
decorator_list,
|
||||
..
|
||||
} => {
|
||||
if self.settings.select.contains(&CheckCode::R0205) {
|
||||
if self.settings.select.contains(&CheckCode::R001) {
|
||||
for expr in bases {
|
||||
if let ExprKind::Name { id, .. } = &expr.node {
|
||||
if id == "object" {
|
||||
|
@ -159,6 +159,7 @@ impl Visitor for Checker<'_> {
|
|||
) {
|
||||
check.amend(fix);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
self.checks.push(check);
|
||||
}
|
||||
|
@ -442,6 +443,37 @@ impl Visitor for Checker<'_> {
|
|||
ExprContext::Store => self.handle_node_store(expr, parent),
|
||||
ExprContext::Del => self.handle_node_delete(expr),
|
||||
},
|
||||
ExprKind::Call { func, .. } => {
|
||||
if self.settings.select.contains(&CheckCode::R002) {
|
||||
if let ExprKind::Attribute { value, attr, .. } = &func.node {
|
||||
if attr == "assertEquals" {
|
||||
if let ExprKind::Name { id, .. } = &value.node {
|
||||
if id == "self" {
|
||||
let mut check =
|
||||
Check::new(CheckKind::NoAssertEquals, expr.location);
|
||||
if matches!(self.autofix, autofix::Mode::Generate)
|
||||
|| matches!(self.autofix, autofix::Mode::Apply)
|
||||
{
|
||||
check.amend(Fix {
|
||||
content: "assertEqual".to_string(),
|
||||
start: Location::new(
|
||||
func.location.row(),
|
||||
func.location.column() + 1,
|
||||
),
|
||||
end: Location::new(
|
||||
func.location.row(),
|
||||
func.location.column() + 1 + "assertEquals".len(),
|
||||
),
|
||||
applied: false,
|
||||
});
|
||||
}
|
||||
self.checks.push(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ExprKind::GeneratorExp { .. }
|
||||
| ExprKind::ListComp { .. }
|
||||
| ExprKind::DictComp { .. }
|
||||
|
|
|
@ -24,7 +24,8 @@ pub enum CheckCode {
|
|||
F831,
|
||||
F841,
|
||||
F901,
|
||||
R0205,
|
||||
R001,
|
||||
R002,
|
||||
}
|
||||
|
||||
impl FromStr for CheckCode {
|
||||
|
@ -48,7 +49,8 @@ impl FromStr for CheckCode {
|
|||
"F831" => Ok(CheckCode::F831),
|
||||
"F841" => Ok(CheckCode::F841),
|
||||
"F901" => Ok(CheckCode::F901),
|
||||
"R0205" => Ok(CheckCode::R0205),
|
||||
"R001" => Ok(CheckCode::R001),
|
||||
"R002" => Ok(CheckCode::R002),
|
||||
_ => Err(anyhow::anyhow!("Unknown check code: {s}")),
|
||||
}
|
||||
}
|
||||
|
@ -68,12 +70,13 @@ impl CheckCode {
|
|||
CheckCode::F706 => "F706",
|
||||
CheckCode::F707 => "F707",
|
||||
CheckCode::F821 => "F821",
|
||||
CheckCode::F823 => "F823",
|
||||
CheckCode::F822 => "F822",
|
||||
CheckCode::F823 => "F823",
|
||||
CheckCode::F831 => "F831",
|
||||
CheckCode::F841 => "F841",
|
||||
CheckCode::F901 => "F901",
|
||||
CheckCode::R0205 => "R0205",
|
||||
CheckCode::R001 => "R001",
|
||||
CheckCode::R002 => "R002",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +99,8 @@ impl CheckCode {
|
|||
CheckCode::F831 => &LintSource::AST,
|
||||
CheckCode::F841 => &LintSource::AST,
|
||||
CheckCode::F901 => &LintSource::AST,
|
||||
CheckCode::R0205 => &LintSource::AST,
|
||||
CheckCode::R001 => &LintSource::AST,
|
||||
CheckCode::R002 => &LintSource::AST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,6 +121,7 @@ pub enum CheckKind {
|
|||
ImportStarUsage,
|
||||
LineTooLong,
|
||||
ModuleImportNotAtTopOfFile,
|
||||
NoAssertEquals,
|
||||
RaiseNotImplemented,
|
||||
ReturnOutsideFunction,
|
||||
UndefinedExport(String),
|
||||
|
@ -140,6 +145,7 @@ impl CheckKind {
|
|||
CheckKind::ImportStarUsage => "ImportStarUsage",
|
||||
CheckKind::LineTooLong => "LineTooLong",
|
||||
CheckKind::ModuleImportNotAtTopOfFile => "ModuleImportNotAtTopOfFile",
|
||||
CheckKind::NoAssertEquals => "NoAssertEquals",
|
||||
CheckKind::RaiseNotImplemented => "RaiseNotImplemented",
|
||||
CheckKind::ReturnOutsideFunction => "ReturnOutsideFunction",
|
||||
CheckKind::UndefinedExport(_) => "UndefinedExport",
|
||||
|
@ -163,6 +169,7 @@ impl CheckKind {
|
|||
CheckKind::ImportStarUsage => &CheckCode::F403,
|
||||
CheckKind::LineTooLong => &CheckCode::E501,
|
||||
CheckKind::ModuleImportNotAtTopOfFile => &CheckCode::E402,
|
||||
CheckKind::NoAssertEquals => &CheckCode::R002,
|
||||
CheckKind::RaiseNotImplemented => &CheckCode::F901,
|
||||
CheckKind::ReturnOutsideFunction => &CheckCode::F706,
|
||||
CheckKind::UndefinedExport(_) => &CheckCode::F822,
|
||||
|
@ -170,7 +177,7 @@ impl CheckKind {
|
|||
CheckKind::UndefinedName(_) => &CheckCode::F821,
|
||||
CheckKind::UnusedImport(_) => &CheckCode::F401,
|
||||
CheckKind::UnusedVariable(_) => &CheckCode::F841,
|
||||
CheckKind::UselessObjectInheritance(_) => &CheckCode::R0205,
|
||||
CheckKind::UselessObjectInheritance(_) => &CheckCode::R001,
|
||||
CheckKind::YieldOutsideFunction => &CheckCode::F704,
|
||||
}
|
||||
}
|
||||
|
@ -196,6 +203,9 @@ impl CheckKind {
|
|||
CheckKind::ModuleImportNotAtTopOfFile => {
|
||||
"Module level import not at top of file".to_string()
|
||||
}
|
||||
CheckKind::NoAssertEquals => {
|
||||
"`assertEquals` is deprecated, use `assertEqual` instead".to_string()
|
||||
}
|
||||
CheckKind::RaiseNotImplemented => {
|
||||
"`raise NotImplemented` should be `raise NotImplementedError`".to_string()
|
||||
}
|
||||
|
@ -226,7 +236,26 @@ impl CheckKind {
|
|||
|
||||
/// Whether the check kind is (potentially) fixable.
|
||||
pub fn fixable(&self) -> bool {
|
||||
matches!(self, CheckKind::UselessObjectInheritance(_))
|
||||
match self {
|
||||
CheckKind::AssertTuple => false,
|
||||
CheckKind::DefaultExceptNotLast => false,
|
||||
CheckKind::DuplicateArgumentName => false,
|
||||
CheckKind::FStringMissingPlaceholders => false,
|
||||
CheckKind::IfTuple => false,
|
||||
CheckKind::ImportStarUsage => false,
|
||||
CheckKind::LineTooLong => false,
|
||||
CheckKind::ModuleImportNotAtTopOfFile => false,
|
||||
CheckKind::NoAssertEquals => true,
|
||||
CheckKind::RaiseNotImplemented => false,
|
||||
CheckKind::ReturnOutsideFunction => false,
|
||||
CheckKind::UndefinedExport(_) => false,
|
||||
CheckKind::UndefinedLocal(_) => false,
|
||||
CheckKind::UndefinedName(_) => false,
|
||||
CheckKind::UnusedImport(_) => false,
|
||||
CheckKind::UnusedVariable(_) => false,
|
||||
CheckKind::UselessObjectInheritance(_) => true,
|
||||
CheckKind::YieldOutsideFunction => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -591,13 +591,13 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn r0205() -> Result<()> {
|
||||
fn r001() -> Result<()> {
|
||||
let actual = check_path(
|
||||
Path::new("./resources/test/fixtures/R0205.py"),
|
||||
Path::new("./resources/test/fixtures/R001.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
select: BTreeSet::from([CheckCode::R0205]),
|
||||
select: BTreeSet::from([CheckCode::R001]),
|
||||
},
|
||||
&autofix::Mode::Generate,
|
||||
)?;
|
||||
|
@ -810,4 +810,45 @@ mod tests {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn r002() -> Result<()> {
|
||||
let actual = check_path(
|
||||
Path::new("./resources/test/fixtures/R002.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
select: BTreeSet::from([CheckCode::R002]),
|
||||
},
|
||||
&autofix::Mode::Generate,
|
||||
)?;
|
||||
let expected = vec![
|
||||
Check {
|
||||
kind: CheckKind::NoAssertEquals,
|
||||
location: Location::new(1, 19),
|
||||
fix: Some(Fix {
|
||||
content: "assertEqual".to_string(),
|
||||
start: Location::new(1, 6),
|
||||
end: Location::new(1, 18),
|
||||
applied: false,
|
||||
}),
|
||||
},
|
||||
Check {
|
||||
kind: CheckKind::NoAssertEquals,
|
||||
location: Location::new(2, 18),
|
||||
fix: Some(Fix {
|
||||
content: "assertEqual".to_string(),
|
||||
start: Location::new(2, 6),
|
||||
end: Location::new(2, 18),
|
||||
applied: false,
|
||||
}),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
for i in 0..actual.len() {
|
||||
assert_eq!(actual[i], expected[i]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -253,7 +253,8 @@ other-attribute = 1
|
|||
CheckCode::F831,
|
||||
CheckCode::F841,
|
||||
CheckCode::F901,
|
||||
CheckCode::R0205,
|
||||
CheckCode::R001,
|
||||
CheckCode::R002,
|
||||
])),
|
||||
}
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue