Implement flake8-super check (#291)

This commit is contained in:
Nikita Sobolev 2022-09-30 16:12:09 +03:00 committed by GitHub
parent 5a1b6c32eb
commit 20989e12ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 104 additions and 3 deletions

View file

@ -263,6 +263,10 @@ Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis F
| R001 | UselessObjectInheritance | Class `...` inherits from object |
| R002 | NoAssertEquals | `assertEquals` is deprecated, use `assertEqual` instead |
| M001 | UnusedNOQA | Unused `noqa` directive |
| A001 | BuiltinVariableShadowing | Variable `...` is shadowing a python builtin |
| A002 | BuiltinArgumentShadowing | Argument `...` is shadowing a python builtin |
| A003 | BuiltinAttributeShadowing | class attribute `...` is shadowing a python builtin |
| SPR001 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` |
## Integrations

22
resources/test/fixtures/SPR001.py vendored Normal file
View file

@ -0,0 +1,22 @@
class Parent:
def method(self):
pass
def wrong(self):
pass
class Child(Parent):
def method(self):
parent = super() # ok
super().method() # ok
Parent.method(self) # ok
Parent.super(1, 2) # ok
def wrong(self):
parent = super(Child, self) # wrong
super(Child, self).method # wrong
super(
Child,
self,
).method() # wrong

View file

@ -680,3 +680,18 @@ pub fn check_builtin_shadowing(
None
}
}
// flake8-super
/// Check that `super()` has no args
pub fn check_super_args(expr: &Expr, args: &Vec<Expr>) -> Option<Check> {
if let ExprKind::Name { id, .. } = &expr.node {
if id == "super" && !args.is_empty() {
return Some(Check::new(
CheckKind::SuperCallWithParameters,
expr.location,
));
}
}
None
}

View file

@ -689,13 +689,20 @@ where
}
ExprContext::Del => self.handle_node_delete(expr),
},
ExprKind::Call { func, .. } => {
ExprKind::Call { func, args, .. } => {
if self.settings.select.contains(&CheckCode::R002) {
if let Some(check) = checks::check_assert_equals(func, self.autofix) {
self.checks.push(check)
}
}
// flake8-super
if self.settings.select.contains(&CheckCode::SPR001) {
if let Some(check) = checks::check_super_args(func, args) {
self.checks.push(check)
}
}
if let ExprKind::Name { id, ctx } = &func.node {
if id == "locals" && matches!(ctx, ExprContext::Load) {
let scope = &mut self.scopes[*(self

View file

@ -4,7 +4,7 @@ use anyhow::Result;
use rustpython_parser::ast::Location;
use serde::{Deserialize, Serialize};
pub const DEFAULT_CHECK_CODES: [CheckCode; 45] = [
pub const DEFAULT_CHECK_CODES: [CheckCode; 46] = [
CheckCode::E402,
CheckCode::E501,
CheckCode::E711,
@ -51,9 +51,11 @@ pub const DEFAULT_CHECK_CODES: [CheckCode; 45] = [
CheckCode::A001,
CheckCode::A002,
CheckCode::A003,
// flake8-super
CheckCode::SPR001,
];
pub const ALL_CHECK_CODES: [CheckCode; 48] = [
pub const ALL_CHECK_CODES: [CheckCode; 49] = [
CheckCode::E402,
CheckCode::E501,
CheckCode::E711,
@ -103,6 +105,8 @@ pub const ALL_CHECK_CODES: [CheckCode; 48] = [
CheckCode::A001,
CheckCode::A002,
CheckCode::A003,
// flake8-super
CheckCode::SPR001,
];
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Hash, PartialOrd, Ord)]
@ -156,6 +160,8 @@ pub enum CheckCode {
A001,
A002,
A003,
// flake8-super
SPR001,
}
impl FromStr for CheckCode {
@ -212,6 +218,8 @@ impl FromStr for CheckCode {
"A001" => Ok(CheckCode::A001),
"A002" => Ok(CheckCode::A002),
"A003" => Ok(CheckCode::A003),
// flake8-super
"SPR001" => Ok(CheckCode::SPR001),
_ => Err(anyhow::anyhow!("Unknown check code: {s}")),
}
}
@ -269,6 +277,8 @@ impl CheckCode {
CheckCode::A001 => "A001",
CheckCode::A002 => "A002",
CheckCode::A003 => "A003",
// flake8-super
CheckCode::SPR001 => "SPR001",
}
}
@ -333,6 +343,8 @@ impl CheckCode {
CheckCode::A001 => CheckKind::BuiltinVariableShadowing("...".to_string()),
CheckCode::A002 => CheckKind::BuiltinArgumentShadowing("...".to_string()),
CheckCode::A003 => CheckKind::BuiltinAttributeShadowing("...".to_string()),
// flake8-super
CheckCode::SPR001 => CheckKind::SuperCallWithParameters,
}
}
}
@ -401,6 +413,8 @@ pub enum CheckKind {
BuiltinVariableShadowing(String),
BuiltinArgumentShadowing(String),
BuiltinAttributeShadowing(String),
// flake8-super
SuperCallWithParameters,
}
impl CheckKind {
@ -458,6 +472,8 @@ impl CheckKind {
CheckKind::BuiltinVariableShadowing(_) => "BuiltinVariableShadowing",
CheckKind::BuiltinArgumentShadowing(_) => "BuiltinArgumentShadowing",
CheckKind::BuiltinAttributeShadowing(_) => "BuiltinAttributeShadowing",
// flake8-super
CheckKind::SuperCallWithParameters => "SuperCallWithParameters",
}
}
@ -513,6 +529,8 @@ impl CheckKind {
CheckKind::BuiltinVariableShadowing(_) => &CheckCode::A001,
CheckKind::BuiltinArgumentShadowing(_) => &CheckCode::A002,
CheckKind::BuiltinAttributeShadowing(_) => &CheckCode::A003,
// flake8-super
CheckKind::SuperCallWithParameters => &CheckCode::SPR001,
}
}
@ -657,6 +675,10 @@ impl CheckKind {
CheckKind::BuiltinAttributeShadowing(name) => {
format!("class attribute `{name}` is shadowing a python builtin")
}
// flake8-super
CheckKind::SuperCallWithParameters => {
"Use `super()` instead of `super(__class__, self)`".to_string()
}
}
}

View file

@ -762,4 +762,16 @@ mod tests {
insta::assert_yaml_snapshot!(checks);
Ok(())
}
#[test]
fn spr001() -> Result<()> {
let mut checks = check_path(
Path::new("./resources/test/fixtures/SPR001.py"),
&settings::Settings::for_rule(CheckCode::SPR001),
&fixer::Mode::Generate,
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(checks);
Ok(())
}
}

View file

@ -0,0 +1,19 @@
---
source: src/linter.rs
expression: checks
---
- kind: SuperCallWithParameters
location:
row: 17
column: 18
fix: ~
- kind: SuperCallWithParameters
location:
row: 18
column: 9
fix: ~
- kind: SuperCallWithParameters
location:
row: 19
column: 9
fix: ~