Add flake8-pie PIE796: prefer-unique-enum (#1923)

I accept any suggestion. By the way, I have a doubt, I have checked and all flake8-pie plugins can be fixed by ruff, but is it necessary that this one is also fixed automatically ?

rel #1543
This commit is contained in:
Leonardo Esparis 2023-01-17 01:27:34 +01:00 committed by GitHub
parent 2ed1f78873
commit 6e88c60c46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 192 additions and 0 deletions

View file

@ -1141,6 +1141,7 @@ For more, see [flake8-pie](https://pypi.org/project/flake8-pie/0.16.0/) on PyPI.
| ---- | ---- | ------- | --- |
| PIE790 | NoUnnecessaryPass | Unnecessary `pass` statement | 🛠 |
| PIE794 | DupeClassFieldDefinitions | Class field `...` is defined multiple times | 🛠 |
| PIE796 | PreferUniqueEnums | Enum contains duplicate value: `...` | |
| PIE807 | PreferListBuiltin | Prefer `list()` over useless lambda | 🛠 |
### flake8-commas (COM)

View file

@ -0,0 +1,54 @@
class FakeEnum(enum.Enum):
A = "A"
B = "B"
C = "B" # PIE796
class FakeEnum2(Enum):
A = 1
B = 2
C = 2 # PIE796
class FakeEnum3(str, Enum):
A = "1"
B = "2"
C = "2" # PIE796
class FakeEnum4(Enum):
A = 1.0
B = 2.5
C = 2.5 # PIE796
class FakeEnum5(Enum):
A = 1.0
B = True
C = False
D = False # PIE796
class FakeEnum6(Enum):
A = 1
B = 2
C = None
D = None # PIE796
@enum.unique
class FakeEnum7(enum.Enum):
A = "A"
B = "B"
C = "C"
@unique
class FakeEnum8(Enum):
A = 1
B = 2
C = 2 # PIE796
class FakeEnum9(enum.Enum):
A = "A"
B = "B"
C = "C"

View file

@ -1431,6 +1431,7 @@
"PIE79",
"PIE790",
"PIE794",
"PIE796",
"PIE8",
"PIE80",
"PIE807",

View file

@ -701,6 +701,10 @@ where
flake8_pie::rules::dupe_class_field_definitions(self, stmt, body);
}
if self.settings.enabled.contains(&RuleCode::PIE796) {
flake8_pie::rules::prefer_unique_enums(self, stmt, body);
}
self.check_builtin_shadowing(name, stmt, false);
for expr in bases {

View file

@ -410,6 +410,7 @@ ruff_macros::define_rule_mapping!(
// flake8-pie
PIE790 => violations::NoUnnecessaryPass,
PIE794 => violations::DupeClassFieldDefinitions,
PIE796 => violations::PreferUniqueEnums,
PIE807 => violations::PreferListBuiltin,
// flake8-commas
COM812 => violations::TrailingCommaMissing,

View file

@ -14,6 +14,7 @@ mod tests {
#[test_case(RuleCode::PIE790, Path::new("PIE790.py"); "PIE790")]
#[test_case(RuleCode::PIE794, Path::new("PIE794.py"); "PIE794")]
#[test_case(RuleCode::PIE796, Path::new("PIE796.py"); "PIE796")]
#[test_case(RuleCode::PIE807, Path::new("PIE807.py"); "PIE807")]
fn rules(rule_code: RuleCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());

View file

@ -2,6 +2,8 @@ use log::error;
use rustc_hash::FxHashSet;
use rustpython_ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
use crate::ast::comparable::ComparableExpr;
use crate::ast::helpers::unparse_expr;
use crate::ast::types::{Range, RefEquality};
use crate::autofix::helpers::delete_stmt;
use crate::checkers::ast::Checker;
@ -106,6 +108,41 @@ pub fn dupe_class_field_definitions<'a, 'b>(
}
}
/// PIE796
pub fn prefer_unique_enums<'a, 'b>(checker: &mut Checker<'a>, parent: &'b Stmt, body: &'b [Stmt])
where
'b: 'a,
{
let StmtKind::ClassDef { bases, .. } = &parent.node else {
return;
};
if !bases.iter().any(|expr| {
checker
.resolve_call_path(expr)
.map_or(false, |call_path| call_path == ["enum", "Enum"])
}) {
return;
}
let mut seen_targets: FxHashSet<ComparableExpr> = FxHashSet::default();
for stmt in body {
let StmtKind::Assign { value, .. } = &stmt.node else {
continue;
};
if !seen_targets.insert(ComparableExpr::from(value)) {
let diagnostic = Diagnostic::new(
violations::PreferUniqueEnums {
value: unparse_expr(value, checker.stylist),
},
Range::from_located(stmt),
);
checker.diagnostics.push(diagnostic);
}
}
}
/// PIE807
pub fn prefer_list_builtin(checker: &mut Checker, expr: &Expr) {
let ExprKind::Lambda { args, body } = &expr.node else {

View file

@ -0,0 +1,75 @@
---
source: src/rules/flake8_pie/mod.rs
expression: diagnostics
---
- kind:
PreferUniqueEnums: "\"B\""
location:
row: 4
column: 4
end_location:
row: 4
column: 11
fix: ~
parent: ~
- kind:
PreferUniqueEnums: "2"
location:
row: 10
column: 4
end_location:
row: 10
column: 9
fix: ~
parent: ~
- kind:
PreferUniqueEnums: "\"2\""
location:
row: 16
column: 4
end_location:
row: 16
column: 11
fix: ~
parent: ~
- kind:
PreferUniqueEnums: "2.5"
location:
row: 21
column: 4
end_location:
row: 21
column: 11
fix: ~
parent: ~
- kind:
PreferUniqueEnums: "False"
location:
row: 28
column: 4
end_location:
row: 28
column: 13
fix: ~
parent: ~
- kind:
PreferUniqueEnums: None
location:
row: 35
column: 4
end_location:
row: 35
column: 12
fix: ~
parent: ~
- kind:
PreferUniqueEnums: "2"
location:
row: 48
column: 4
end_location:
row: 48
column: 9
fix: ~
parent: ~

View file

@ -5970,6 +5970,24 @@ impl AlwaysAutofixableViolation for DupeClassFieldDefinitions {
}
}
define_violation!(
pub struct PreferUniqueEnums {
pub value: String,
}
);
impl Violation for PreferUniqueEnums {
fn message(&self) -> String {
let PreferUniqueEnums { value } = self;
format!("Enum contains duplicate value: `{value}`")
}
fn placeholder() -> Self {
PreferUniqueEnums {
value: "...".to_string(),
}
}
}
define_violation!(
pub struct PreferListBuiltin;
);