[`pep8_naming`] Avoid false positives on standard library functions with uppercase names (`N802`) (#18907)

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
w0nder1ng 2025-07-14 04:26:57 -04:00 committed by GitHub
parent c9f95e8714
commit 26f736bc46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 88 additions and 4 deletions

View File

@ -48,6 +48,39 @@ from typing import override, overload
def BAD_FUNC(): def BAD_FUNC():
pass pass
@overload @overload
def BAD_FUNC(): def BAD_FUNC():
pass pass
import ast
from ast import NodeTransformer
class Visitor(ast.NodeVisitor):
def visit_Constant(self, node):
pass
def bad_Name(self):
pass
class ExtendsVisitor(Visitor):
def visit_Constant(self, node):
pass
class Transformer(NodeTransformer):
def visit_Constant(self, node):
pass
from http.server import BaseHTTPRequestHandler
class MyRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
pass
def dont_GET(self):
pass

View File

@ -1,9 +1,7 @@
use ruff_python_ast::{Decorator, Stmt};
use ruff_macros::{ViolationMetadata, derive_message_formats}; use ruff_macros::{ViolationMetadata, derive_message_formats};
use ruff_python_ast::identifier::Identifier; use ruff_python_ast::{Decorator, Stmt, identifier::Identifier};
use ruff_python_semantic::SemanticModel; use ruff_python_semantic::SemanticModel;
use ruff_python_semantic::analyze::visibility; use ruff_python_semantic::analyze::{class::any_base_class, visibility};
use ruff_python_stdlib::str; use ruff_python_stdlib::str;
use crate::Violation; use crate::Violation;
@ -84,6 +82,41 @@ pub(crate) fn invalid_function_name(
return; return;
} }
let parent_class = semantic
.current_statement_parent()
.and_then(|parent| parent.as_class_def_stmt());
// Ignore the visit_* methods of the ast.NodeVisitor and ast.NodeTransformer classes.
if name.starts_with("visit_")
&& parent_class.is_some_and(|class| {
any_base_class(class, semantic, &mut |superclass| {
let qualified = semantic.resolve_qualified_name(superclass);
qualified.is_some_and(|name| {
matches!(name.segments(), ["ast", "NodeVisitor" | "NodeTransformer"])
})
})
})
{
return;
}
// Ignore the do_* methods of the http.server.BaseHTTPRequestHandler class
if name.starts_with("do_")
&& parent_class.is_some_and(|class| {
any_base_class(class, semantic, &mut |superclass| {
let qualified = semantic.resolve_qualified_name(superclass);
qualified.is_some_and(|name| {
matches!(
name.segments(),
["http", "server", "BaseHTTPRequestHandler"]
)
})
})
})
{
return;
}
checker.report_diagnostic( checker.report_diagnostic(
InvalidFunctionName { InvalidFunctionName {
name: name.to_string(), name: name.to_string(),

View File

@ -37,3 +37,21 @@ N802.py:40:9: N802 Function name `testTest` should be lowercase
| ^^^^^^^^ N802 | ^^^^^^^^ N802
41 | assert True 41 | assert True
| |
N802.py:65:9: N802 Function name `bad_Name` should be lowercase
|
63 | pass
64 |
65 | def bad_Name(self):
| ^^^^^^^^ N802
66 | pass
|
N802.py:84:9: N802 Function name `dont_GET` should be lowercase
|
82 | pass
83 |
84 | def dont_GET(self):
| ^^^^^^^^ N802
85 | pass
|