Recursively resolve `TypeDicts` for N815 violations (#10719)

## Summary

Only works within a single file for now.

Closes https://github.com/astral-sh/ruff/issues/10671.
This commit is contained in:
Charlie Marsh 2024-04-01 13:40:55 -04:00 committed by GitHub
parent 200ebeebdc
commit 67f0f615b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 17 additions and 18 deletions

View File

@ -21,3 +21,10 @@ class D(TypedDict):
mixedCase: bool
_mixedCase: list
mixed_Case: set
class E(D):
lower: int
CONSTANT: str
mixedCase: bool
_mixedCase: list
mixed_Case: set

View File

@ -223,14 +223,10 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
}
}
if checker.enabled(Rule::MixedCaseVariableInClassScope) {
if let ScopeKind::Class(ast::StmtClassDef { arguments, .. }) =
&checker.semantic.current_scope().kind
if let ScopeKind::Class(class_def) = &checker.semantic.current_scope().kind
{
pep8_naming::rules::mixed_case_variable_in_class_scope(
checker,
expr,
id,
arguments.as_deref(),
checker, expr, id, class_def,
);
}
}

View File

@ -1,8 +1,8 @@
use itertools::Itertools;
use ruff_python_ast::name::UnqualifiedName;
use ruff_python_ast::{self as ast, Arguments, Expr, Stmt};
use ruff_python_semantic::SemanticModel;
use ruff_python_ast::{self as ast, Expr, Stmt};
use ruff_python_semantic::{analyze, SemanticModel};
use ruff_python_stdlib::str::{is_cased_lowercase, is_cased_uppercase};
pub(super) fn is_camelcase(name: &str) -> bool {
@ -86,16 +86,13 @@ pub(super) fn is_type_alias_assignment(stmt: &Stmt, semantic: &SemanticModel) ->
}
/// Returns `true` if the statement is an assignment to a `TypedDict`.
pub(super) fn is_typed_dict_class(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool {
pub(super) fn is_typed_dict_class(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool {
if !semantic.seen_typing() {
return false;
}
arguments.is_some_and(|arguments| {
arguments
.args
.iter()
.any(|base| semantic.match_typing_expr(base, "TypedDict"))
analyze::class::any_qualified_name(class_def, semantic, &|qualified_name| {
semantic.match_typing_qualified_name(&qualified_name, "TypedDict")
})
}

View File

@ -1,7 +1,6 @@
use ruff_python_ast::{Arguments, Expr};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Expr};
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
@ -55,7 +54,7 @@ pub(crate) fn mixed_case_variable_in_class_scope(
checker: &mut Checker,
expr: &Expr,
name: &str,
arguments: Option<&Arguments>,
class_def: &ast::StmtClassDef,
) {
if !helpers::is_mixed_case(name) {
return;
@ -64,7 +63,7 @@ pub(crate) fn mixed_case_variable_in_class_scope(
let parent = checker.semantic().current_statement();
if helpers::is_named_tuple_assignment(parent, checker.semantic())
|| helpers::is_typed_dict_class(arguments, checker.semantic())
|| helpers::is_typed_dict_class(class_def, checker.semantic())
{
return;
}