mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-16 00:20:22 +00:00
[pep8-naming
] Avoid false positive for class Bar(type(foo))
(N804
) (#14683)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
This commit is contained in:
parent
56ae73a925
commit
9e017634cb
4 changed files with 43 additions and 16 deletions
|
@ -76,3 +76,8 @@ class RenamingInMethodBodyClass(ABCMeta):
|
||||||
|
|
||||||
def func(x):
|
def func(x):
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
foo = {}
|
||||||
|
class Bar(type(foo)):
|
||||||
|
def foo_method(self):
|
||||||
|
pass
|
||||||
|
|
|
@ -126,7 +126,7 @@ pub(crate) fn non_self_return_type(
|
||||||
};
|
};
|
||||||
|
|
||||||
// PEP 673 forbids the use of `typing(_extensions).Self` in metaclasses.
|
// PEP 673 forbids the use of `typing(_extensions).Self` in metaclasses.
|
||||||
if analyze::class::is_metaclass(class_def, semantic) {
|
if analyze::class::is_metaclass(class_def, semantic).into() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use ruff_python_ast::ParameterWithDefault;
|
use ruff_python_ast::ParameterWithDefault;
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
use ruff_python_semantic::analyze::class::is_metaclass;
|
use ruff_python_semantic::analyze::class::{is_metaclass, IsMetaclass};
|
||||||
use ruff_python_semantic::analyze::function_type;
|
use ruff_python_semantic::analyze::function_type;
|
||||||
use ruff_python_semantic::{Scope, ScopeKind, SemanticModel};
|
use ruff_python_semantic::{Scope, ScopeKind, SemanticModel};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
@ -212,13 +212,11 @@ pub(crate) fn invalid_first_argument_name(
|
||||||
function_type::FunctionType::Function | function_type::FunctionType::StaticMethod => {
|
function_type::FunctionType::Function | function_type::FunctionType::StaticMethod => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
function_type::FunctionType::Method => {
|
function_type::FunctionType::Method => match is_metaclass(parent, semantic) {
|
||||||
if is_metaclass(parent, semantic) {
|
IsMetaclass::Yes => FunctionType::ClassMethod,
|
||||||
FunctionType::ClassMethod
|
IsMetaclass::No => FunctionType::Method,
|
||||||
} else {
|
IsMetaclass::Maybe => return,
|
||||||
FunctionType::Method
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
function_type::FunctionType::ClassMethod => FunctionType::ClassMethod,
|
function_type::FunctionType::ClassMethod => FunctionType::ClassMethod,
|
||||||
};
|
};
|
||||||
if !checker.enabled(function_type.rule()) {
|
if !checker.enabled(function_type.rule()) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub fn any_qualified_base_class(
|
||||||
semantic: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
func: &dyn Fn(QualifiedName) -> bool,
|
func: &dyn Fn(QualifiedName) -> bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
any_base_class(class_def, semantic, &|expr| {
|
any_base_class(class_def, semantic, &mut |expr| {
|
||||||
semantic
|
semantic
|
||||||
.resolve_qualified_name(map_subscript(expr))
|
.resolve_qualified_name(map_subscript(expr))
|
||||||
.is_some_and(func)
|
.is_some_and(func)
|
||||||
|
@ -23,12 +23,12 @@ pub fn any_qualified_base_class(
|
||||||
pub fn any_base_class(
|
pub fn any_base_class(
|
||||||
class_def: &ast::StmtClassDef,
|
class_def: &ast::StmtClassDef,
|
||||||
semantic: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
func: &dyn Fn(&Expr) -> bool,
|
func: &mut dyn FnMut(&Expr) -> bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
fn inner(
|
fn inner(
|
||||||
class_def: &ast::StmtClassDef,
|
class_def: &ast::StmtClassDef,
|
||||||
semantic: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
func: &dyn Fn(&Expr) -> bool,
|
func: &mut dyn FnMut(&Expr) -> bool,
|
||||||
seen: &mut FxHashSet<BindingId>,
|
seen: &mut FxHashSet<BindingId>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
class_def.bases().iter().any(|expr| {
|
class_def.bases().iter().any(|expr| {
|
||||||
|
@ -121,12 +121,30 @@ pub fn is_enumeration(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the given class is a metaclass.
|
/// Whether or not a class is a metaclass. Constructed by [`is_metaclass`].
|
||||||
pub fn is_metaclass(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool {
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
any_base_class(class_def, semantic, &|expr| match expr {
|
pub enum IsMetaclass {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
Maybe,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IsMetaclass> for bool {
|
||||||
|
fn from(value: IsMetaclass) -> Self {
|
||||||
|
matches!(value, IsMetaclass::Yes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `IsMetaclass::Yes` if the given class is definitely a metaclass,
|
||||||
|
/// `IsMetaclass::No` if it's definitely *not* a metaclass, and
|
||||||
|
/// `IsMetaclass::Maybe` otherwise.
|
||||||
|
pub fn is_metaclass(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> IsMetaclass {
|
||||||
|
let mut maybe = false;
|
||||||
|
let is_base_class = any_base_class(class_def, semantic, &mut |expr| match expr {
|
||||||
Expr::Call(ast::ExprCall {
|
Expr::Call(ast::ExprCall {
|
||||||
func, arguments, ..
|
func, arguments, ..
|
||||||
}) => {
|
}) => {
|
||||||
|
maybe = true;
|
||||||
// Ex) `class Foo(type(Protocol)): ...`
|
// Ex) `class Foo(type(Protocol)): ...`
|
||||||
arguments.len() == 1 && semantic.match_builtin_expr(func.as_ref(), "type")
|
arguments.len() == 1 && semantic.match_builtin_expr(func.as_ref(), "type")
|
||||||
}
|
}
|
||||||
|
@ -144,5 +162,11 @@ pub fn is_metaclass(class_def: &ast::StmtClassDef, semantic: &SemanticModel) ->
|
||||||
| ["enum", "EnumMeta" | "EnumType"]
|
| ["enum", "EnumMeta" | "EnumType"]
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
})
|
});
|
||||||
|
|
||||||
|
match (is_base_class, maybe) {
|
||||||
|
(true, true) => IsMetaclass::Maybe,
|
||||||
|
(true, false) => IsMetaclass::Yes,
|
||||||
|
(false, _) => IsMetaclass::No,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue