Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,11 @@ def f():
int # TC006
, 6.0
)


def f():
# Keyword arguments
from typing import cast

cast(typ=int, val=3.0) # TC006
cast(val=3.0, typ=int) # TC006
51 changes: 36 additions & 15 deletions crates/ruff_linter/src/checkers/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1539,25 +1539,37 @@ impl<'a> Visitor<'a> for Checker<'a> {
}
}
Some(typing::Callable::Cast) => {
let mut args = arguments.args.iter();
if let Some(arg) = args.next() {
self.visit_type_definition(arg);

if !self.source_type.is_stub() && self.enabled(Rule::RuntimeCastValue) {
flake8_type_checking::rules::runtime_cast_value(self, arg);
for (i, arg) in arguments.arguments_source_order().enumerate() {
match (i, arg) {
(0, ArgOrKeyword::Arg(arg)) => self.visit_cast_type_argument(arg),
(_, ArgOrKeyword::Arg(arg)) => self.visit_non_type_definition(arg),
(_, ArgOrKeyword::Keyword(Keyword { arg, value, .. })) => {
if let Some(id) = arg {
if id == "typ" {
self.visit_cast_type_argument(value);
} else {
self.visit_non_type_definition(value);
}
}
}
}
}
for arg in args {
self.visit_expr(arg);
}
}
Some(typing::Callable::NewType) => {
let mut args = arguments.args.iter();
if let Some(arg) = args.next() {
self.visit_non_type_definition(arg);
}
for arg in args {
self.visit_type_definition(arg);
for (i, arg) in arguments.arguments_source_order().enumerate() {
match (i, arg) {
(1, ArgOrKeyword::Arg(arg)) => self.visit_type_definition(arg),
(_, ArgOrKeyword::Arg(arg)) => self.visit_non_type_definition(arg),
(_, ArgOrKeyword::Keyword(Keyword { arg, value, .. })) => {
if let Some(id) = arg {
if id == "tp" {
self.visit_type_definition(value);
} else {
self.visit_non_type_definition(value);
}
}
}
}
}
}
Some(typing::Callable::TypeVar) => {
Expand Down Expand Up @@ -2209,6 +2221,15 @@ impl<'a> Checker<'a> {
self.semantic.flags = snapshot;
}

/// Visit an [`Expr`], and treat it as the `typ` argument to `typing.cast`.
fn visit_cast_type_argument(&mut self, arg: &'a Expr) {
self.visit_type_definition(arg);

if !self.source_type.is_stub() && self.enabled(Rule::RuntimeCastValue) {
flake8_type_checking::rules::runtime_cast_value(self, arg);
}
}

/// Visit an [`Expr`], and treat it as a boolean test. This is useful for detecting whether an
/// expressions return value is significant, or whether the calling context only relies on
/// its truthiness.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,37 @@ TC006.py:89:9: TC006 [*] Add quotes to type expression in `typing.cast()`
89 |+ "int" # TC006
90 90 | , 6.0
91 91 | )
92 92 |

TC006.py:98:14: TC006 [*] Add quotes to type expression in `typing.cast()`
|
96 | from typing import cast
97 |
98 | cast(typ=int, val=3.0) # TC006
| ^^^ TC006
99 | cast(val=3.0, typ=int) # TC006
|
= help: Add quotes

ℹ Safe fix
95 95 | # Keyword arguments
96 96 | from typing import cast
97 97 |
98 |- cast(typ=int, val=3.0) # TC006
98 |+ cast(typ="int", val=3.0) # TC006
99 99 | cast(val=3.0, typ=int) # TC006

TC006.py:99:23: TC006 [*] Add quotes to type expression in `typing.cast()`
|
98 | cast(typ=int, val=3.0) # TC006
99 | cast(val=3.0, typ=int) # TC006
| ^^^ TC006
|
= help: Add quotes

ℹ Safe fix
96 96 | from typing import cast
97 97 |
98 98 | cast(typ=int, val=3.0) # TC006
99 |- cast(val=3.0, typ=int) # TC006
99 |+ cast(val=3.0, typ="int") # TC006
Loading