mirror of https://github.com/astral-sh/ruff
[`flake8-pie`] Avoid false positive for multiple assignment with `auto()` (`PIE796`) (#17274)
This fix closes #16868 I noticed the issue is assigned, but the assignee appears to be actively working on another pull request. I hope that’s okay! <!-- Thank you for contributing to Ruff! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? - Does this pull request include references to any relevant issues? --> ## Summary <!-- What's the purpose of the change? What does it do, and why? --> As of Python 3.11.1, `enum.auto()` can be used in multiple assignments. This pattern should not trigger non-unique-enums check. Reference: [Python docs on enum.auto()](https://docs.python.org/3/library/enum.html#enum.auto) This fix updates the check logic to skip enum variant statements where the right-hand side is a tuple containing a call to `enum.auto()`. ## Test Plan <!-- How was it tested? --> The added test case uses the example from the original issue. It previously triggered a false positive, but now passes successfully.
This commit is contained in:
parent
058439d5d3
commit
ed14dbb1a2
|
|
@ -78,3 +78,9 @@ class FakeEnum11(enum.Enum):
|
|||
A = cast(SomeType, ...)
|
||||
B = cast(SomeType, ...) # PIE796
|
||||
C = cast(SomeType, ...) # PIE796
|
||||
|
||||
|
||||
class FakeEnum12(enum.Enum):
|
||||
A = enum.auto(), 0
|
||||
B = enum.auto(), 1
|
||||
C = enum.auto(), 0
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use ruff_python_semantic::SemanticModel;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
|
|
@ -75,17 +76,15 @@ pub(crate) fn non_unique_enums(checker: &Checker, parent: &Stmt, body: &[Stmt])
|
|||
continue;
|
||||
};
|
||||
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
|
||||
if checker
|
||||
.semantic()
|
||||
.resolve_qualified_name(func)
|
||||
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["enum", "auto"]))
|
||||
{
|
||||
if is_call_to_enum_auto(semantic, value) {
|
||||
continue;
|
||||
} else if let Expr::Tuple(ast::ExprTuple { elts, .. }) = value.as_ref() {
|
||||
if elts.iter().any(|elt| is_call_to_enum_auto(semantic, elt)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if checker.source_type.is_stub() && member_has_unknown_value(checker, value) {
|
||||
if checker.source_type.is_stub() && member_has_unknown_value(semantic, value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -103,16 +102,24 @@ pub(crate) fn non_unique_enums(checker: &Checker, parent: &Stmt, body: &[Stmt])
|
|||
}
|
||||
}
|
||||
|
||||
fn is_call_to_enum_auto(semantic: &SemanticModel, expr: &Expr) -> bool {
|
||||
expr.as_call_expr().is_some_and(|call| {
|
||||
semantic
|
||||
.resolve_qualified_name(&call.func)
|
||||
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["enum", "auto"]))
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether the value is a bare ellipsis literal (`A = ...`)
|
||||
/// or a casted one (`A = cast(SomeType, ...)`).
|
||||
fn member_has_unknown_value(checker: &Checker, expr: &Expr) -> bool {
|
||||
fn member_has_unknown_value(semantic: &SemanticModel, expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::EllipsisLiteral(_) => true,
|
||||
|
||||
Expr::Call(ExprCall {
|
||||
func, arguments, ..
|
||||
}) => {
|
||||
if !checker.semantic().match_typing_expr(func, "cast") {
|
||||
if !semantic.match_typing_expr(func, "cast") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue