diff --git a/crates/ruff/resources/test/fixtures/pep8_naming/N806.py b/crates/ruff/resources/test/fixtures/pep8_naming/N806.py index 25fdd914c7..0a9a95954c 100644 --- a/crates/ruff/resources/test/fixtures/pep8_naming/N806.py +++ b/crates/ruff/resources/test/fixtures/pep8_naming/N806.py @@ -1,8 +1,6 @@ import collections from collections import namedtuple -from typing import TypeVar -from typing import NewType -from typing import NamedTuple, TypedDict +from typing import TypeAlias, TypeVar, NewType, NamedTuple, TypedDict GLOBAL: str = "foo" @@ -21,9 +19,11 @@ def assign(): T = TypeVar("T") UserId = NewType("UserId", int) - Employee = NamedTuple('Employee', [('name', str), ('id', int)]) + Employee = NamedTuple("Employee", [("name", str), ("id", int)]) - Point2D = TypedDict('Point2D', {'in': int, 'x-y': int}) + Point2D = TypedDict("Point2D", {"in": int, "x-y": int}) + + IntOrStr: TypeAlias = int | str def aug_assign(rank, world_size): diff --git a/crates/ruff/src/rules/pep8_naming/helpers.rs b/crates/ruff/src/rules/pep8_naming/helpers.rs index ac23f6c511..6d09971253 100644 --- a/crates/ruff/src/rules/pep8_naming/helpers.rs +++ b/crates/ruff/src/rules/pep8_naming/helpers.rs @@ -22,6 +22,7 @@ pub(super) fn is_acronym(name: &str, asname: &str) -> bool { name.chars().filter(|c| c.is_uppercase()).join("") == asname } +/// Returns `true` if the statement is an assignment to a named tuple. pub(super) fn is_named_tuple_assignment(stmt: &Stmt, semantic: &SemanticModel) -> bool { let Stmt::Assign(ast::StmtAssign { value, .. }) = stmt else { return false; @@ -30,13 +31,12 @@ pub(super) fn is_named_tuple_assignment(stmt: &Stmt, semantic: &SemanticModel) - return false; }; semantic.resolve_call_path(func).is_some_and(|call_path| { - matches!( - call_path.as_slice(), - ["collections", "namedtuple"] | ["typing", "NamedTuple"] - ) + matches!(call_path.as_slice(), ["collections", "namedtuple"]) + || semantic.match_typing_call_path(&call_path, "NamedTuple") }) } +/// Returns `true` if the statement is an assignment to a `TypedDict`. pub(super) fn is_typed_dict_assignment(stmt: &Stmt, semantic: &SemanticModel) -> bool { let Stmt::Assign(ast::StmtAssign { value, .. }) = stmt else { return false; @@ -44,11 +44,10 @@ pub(super) fn is_typed_dict_assignment(stmt: &Stmt, semantic: &SemanticModel) -> let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() else { return false; }; - semantic - .resolve_call_path(func) - .is_some_and(|call_path| matches!(call_path.as_slice(), ["typing", "TypedDict"])) + semantic.match_typing_expr(func, "TypedDict") } +/// Returns `true` if the statement is an assignment to a `TypeVar` or `NewType`. pub(super) fn is_type_var_assignment(stmt: &Stmt, semantic: &SemanticModel) -> bool { let Stmt::Assign(ast::StmtAssign { value, .. }) = stmt else { return false; @@ -56,9 +55,18 @@ pub(super) fn is_type_var_assignment(stmt: &Stmt, semantic: &SemanticModel) -> b let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() else { return false; }; - semantic - .resolve_call_path(func) - .is_some_and(|call_path| matches!(call_path.as_slice(), ["typing", "TypeVar" | "NewType"])) + semantic.resolve_call_path(func).is_some_and(|call_path| { + semantic.match_typing_call_path(&call_path, "TypeVar") + || semantic.match_typing_call_path(&call_path, "NewType") + }) +} + +/// Returns `true` if the statement is an assignment to a `TypeAlias`. +pub(super) fn is_type_alias_assignment(stmt: &Stmt, semantic: &SemanticModel) -> bool { + let Stmt::AnnAssign(ast::StmtAnnAssign { annotation, .. }) = stmt else { + return false; + }; + semantic.match_typing_expr(annotation, "TypeAlias") } pub(super) fn is_typed_dict_class(arguments: Option<&Arguments>, semantic: &SemanticModel) -> bool { diff --git a/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs b/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs index 9cbb325e53..e8bae1c0ee 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs @@ -70,6 +70,7 @@ pub(crate) fn non_lowercase_variable_in_function(checker: &mut Checker, expr: &E if helpers::is_named_tuple_assignment(parent, checker.semantic()) || helpers::is_typed_dict_assignment(parent, checker.semantic()) || helpers::is_type_var_assignment(parent, checker.semantic()) + || helpers::is_type_alias_assignment(parent, checker.semantic()) { return; } diff --git a/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__N806_N806.py.snap b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__N806_N806.py.snap index dc5a0080a2..f2a3d321b4 100644 --- a/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__N806_N806.py.snap +++ b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__N806_N806.py.snap @@ -1,23 +1,23 @@ --- source: crates/ruff/src/rules/pep8_naming/mod.rs --- -N806.py:14:5: N806 Variable `Camel` in function should be lowercase +N806.py:12:5: N806 Variable `Camel` in function should be lowercase | -12 | GLOBAL = "bar" -13 | lower = 0 -14 | Camel = 0 +10 | GLOBAL = "bar" +11 | lower = 0 +12 | Camel = 0 | ^^^^^ N806 -15 | CONSTANT = 0 -16 | _ = 0 +13 | CONSTANT = 0 +14 | _ = 0 | -N806.py:15:5: N806 Variable `CONSTANT` in function should be lowercase +N806.py:13:5: N806 Variable `CONSTANT` in function should be lowercase | -13 | lower = 0 -14 | Camel = 0 -15 | CONSTANT = 0 +11 | lower = 0 +12 | Camel = 0 +13 | CONSTANT = 0 | ^^^^^^^^ N806 -16 | _ = 0 +14 | _ = 0 |