diff --git a/README.md b/README.md index e059c468e0..59c8f79aa9 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,7 @@ lint rules that are obviated by Black (e.g., stylistic rules). | ---- | ----- | ------- | | E402 | ModuleImportNotAtTopOfFile | Module level import not at top of file | | E501 | LineTooLong | Line too long | +| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | | E902 | IOError | No such file or directory: `...` | | F401 | UnusedImport | `...` imported but unused | | F403 | ImportStarUsage | Unable to detect undefined names | diff --git a/examples/generate_rules_table.rs b/examples/generate_rules_table.rs index f442973584..c6bed78158 100644 --- a/examples/generate_rules_table.rs +++ b/examples/generate_rules_table.rs @@ -11,6 +11,7 @@ fn main() { CheckKind::IOError("...".to_string()), CheckKind::ImportStarUsage, CheckKind::LineTooLong, + CheckKind::DoNotAssignLambda, CheckKind::ModuleImportNotAtTopOfFile, CheckKind::NoAssertEquals, CheckKind::RaiseNotImplemented, diff --git a/resources/test/fixtures/E731.py b/resources/test/fixtures/E731.py new file mode 100644 index 0000000000..8057f9cc07 --- /dev/null +++ b/resources/test/fixtures/E731.py @@ -0,0 +1,2 @@ +a = lambda x: x**2 +b = map(lambda x: 2 * x, range(3)) diff --git a/src/check_ast.rs b/src/check_ast.rs index 20bf59a67c..09bb2e5b14 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -377,7 +377,20 @@ impl Visitor for Checker<'_> { self.seen_non_import = true; } } - StmtKind::Delete { .. } | StmtKind::Assign { .. } | StmtKind::AnnAssign { .. } => { + StmtKind::Assign { value, .. } => { + self.seen_non_import = true; + if self + .settings + .select + .contains(CheckKind::DoNotAssignLambda.code()) + { + if let ExprKind::Lambda { .. } = &value.node { + self.checks + .push(Check::new(CheckKind::DoNotAssignLambda, stmt.location)); + } + } + } + StmtKind::Delete { .. } | StmtKind::AnnAssign { .. } => { self.seen_non_import = true; } _ => {} diff --git a/src/checks.rs b/src/checks.rs index a70f41269c..f4588e1fa9 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize}; pub enum CheckCode { E402, E501, + E731, E902, F401, F403, @@ -36,6 +37,7 @@ impl FromStr for CheckCode { match s { "E402" => Ok(CheckCode::E402), "E501" => Ok(CheckCode::E501), + "E731" => Ok(CheckCode::E731), "E902" => Ok(CheckCode::E902), "F401" => Ok(CheckCode::F401), "F403" => Ok(CheckCode::F403), @@ -63,6 +65,7 @@ impl CheckCode { match self { CheckCode::E402 => "E402", CheckCode::E501 => "E501", + CheckCode::E731 => "E731", CheckCode::E902 => "E902", CheckCode::F401 => "F401", CheckCode::F403 => "F403", @@ -88,6 +91,7 @@ impl CheckCode { match self { CheckCode::E402 => &LintSource::AST, CheckCode::E501 => &LintSource::Lines, + CheckCode::E731 => &LintSource::AST, CheckCode::E902 => &LintSource::FileSystem, CheckCode::F401 => &LintSource::AST, CheckCode::F403 => &LintSource::AST, @@ -126,6 +130,7 @@ pub enum CheckKind { IfTuple, ImportStarUsage, LineTooLong, + DoNotAssignLambda, ModuleImportNotAtTopOfFile, NoAssertEquals, RaiseNotImplemented, @@ -151,6 +156,7 @@ impl CheckKind { CheckKind::IfTuple => "IfTuple", CheckKind::ImportStarUsage => "ImportStarUsage", CheckKind::LineTooLong => "LineTooLong", + CheckKind::DoNotAssignLambda => "DoNotAssignLambda", CheckKind::ModuleImportNotAtTopOfFile => "ModuleImportNotAtTopOfFile", CheckKind::NoAssertEquals => "NoAssertEquals", CheckKind::RaiseNotImplemented => "RaiseNotImplemented", @@ -176,6 +182,7 @@ impl CheckKind { CheckKind::IfTuple => &CheckCode::F634, CheckKind::ImportStarUsage => &CheckCode::F403, CheckKind::LineTooLong => &CheckCode::E501, + CheckKind::DoNotAssignLambda => &CheckCode::E731, CheckKind::ModuleImportNotAtTopOfFile => &CheckCode::E402, CheckKind::NoAssertEquals => &CheckCode::R002, CheckKind::RaiseNotImplemented => &CheckCode::F901, @@ -211,6 +218,9 @@ impl CheckKind { CheckKind::IfTuple => "If test is a tuple, which is always `True`".to_string(), CheckKind::ImportStarUsage => "Unable to detect undefined names".to_string(), CheckKind::LineTooLong => "Line too long".to_string(), + CheckKind::DoNotAssignLambda => { + "Do not assign a lambda expression, use a def".to_string() + } CheckKind::ModuleImportNotAtTopOfFile => { "Module level import not at top of file".to_string() } @@ -255,6 +265,7 @@ impl CheckKind { CheckKind::IfTuple => false, CheckKind::IOError(_) => false, CheckKind::ImportStarUsage => false, + CheckKind::DoNotAssignLambda => false, CheckKind::LineTooLong => false, CheckKind::ModuleImportNotAtTopOfFile => false, CheckKind::NoAssertEquals => true, diff --git a/src/linter.rs b/src/linter.rs index 290816b21e..34c0935952 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -136,6 +136,30 @@ mod tests { Ok(()) } + #[test] + fn e731() -> Result<()> { + let actual = check_path( + Path::new("./resources/test/fixtures/E731.py"), + &settings::Settings { + line_length: 88, + exclude: vec![], + select: BTreeSet::from([CheckCode::E731]), + }, + &autofix::Mode::Generate, + )?; + let expected = vec![Check { + kind: CheckKind::DoNotAssignLambda, + location: Location::new(1, 1), + fix: None, + }]; + assert_eq!(actual.len(), expected.len()); + for i in 0..actual.len() { + assert_eq!(actual[i], expected[i]); + } + + Ok(()) + } + #[test] fn f401() -> Result<()> { let actual = check_path( diff --git a/src/pyproject.rs b/src/pyproject.rs index e7d98bad62..ad185e5df1 100644 --- a/src/pyproject.rs +++ b/src/pyproject.rs @@ -239,6 +239,7 @@ other-attribute = 1 select: Some(BTreeSet::from([ CheckCode::E402, CheckCode::E501, + CheckCode::E731, CheckCode::E902, CheckCode::F401, CheckCode::F403, diff --git a/src/settings.rs b/src/settings.rs index 596e87b084..2a81bc7a16 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -46,6 +46,7 @@ impl Settings { BTreeSet::from([ CheckCode::E402, CheckCode::E501, + CheckCode::E731, CheckCode::E902, CheckCode::F401, CheckCode::F403,