Skip to content

Commit

Permalink
Recursively resolve TypeDicts for N815 violations (#10719)
Browse files Browse the repository at this point in the history
## Summary

Only works within a single file for now.

Closes #10671.
  • Loading branch information
charliermarsh committed Apr 1, 2024
1 parent 200ebee commit 67f0f61
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 18 deletions.
Expand Up @@ -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
8 changes: 2 additions & 6 deletions crates/ruff_linter/src/checkers/ast/analyze/expression.rs
Expand Up @@ -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,
);
}
}
Expand Down
13 changes: 5 additions & 8 deletions crates/ruff_linter/src/rules/pep8_naming/helpers.rs
@@ -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 {
Expand Down Expand Up @@ -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")
})
}

Expand Down
@@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down

0 comments on commit 67f0f61

Please sign in to comment.