Implement R002 (NoAssertEquals) (#98)

This commit is contained in:
Charlie Marsh 2022-09-05 12:27:47 -04:00 committed by GitHub
parent 79b6472c7c
commit 198e5cf27f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 126 additions and 17 deletions

View file

@ -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

View file

@ -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
View file

@ -0,0 +1,3 @@
self.assertEquals (1, 2)
self.assertEquals(1, 2)
self.assertEqual(3, 4)

View file

@ -18,5 +18,6 @@ select = [
"F831",
"F841",
"F901",
"R0205",
"R001",
"R002",
]

View file

@ -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 { .. }

View file

@ -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,
}
}
}

View file

@ -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(())
}
}

View file

@ -253,7 +253,8 @@ other-attribute = 1
CheckCode::F831,
CheckCode::F841,
CheckCode::F901,
CheckCode::R0205,
CheckCode::R001,
CheckCode::R002,
])),
}
);