mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 01:51:30 +00:00
Use truthiness check in auto_attribs
detection (#14562)
This commit is contained in:
parent
d285717da8
commit
de62e39eba
7 changed files with 54 additions and 15 deletions
|
@ -99,3 +99,27 @@ class C:
|
||||||
b = field()
|
b = field()
|
||||||
c: int = foo()
|
c: int = foo()
|
||||||
d = list()
|
d = list()
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s(auto_attribs=False) # auto_attribs = False
|
||||||
|
class C:
|
||||||
|
a: str = 0
|
||||||
|
b = field()
|
||||||
|
c: int = foo()
|
||||||
|
d = list()
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s(auto_attribs=True) # auto_attribs = True
|
||||||
|
class C:
|
||||||
|
a: str = 0
|
||||||
|
b = field()
|
||||||
|
c: int = foo()
|
||||||
|
d = list()
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s(auto_attribs=[1, 2, 3]) # auto_attribs = False
|
||||||
|
class C:
|
||||||
|
a: str = 0
|
||||||
|
b = field()
|
||||||
|
c: int = foo()
|
||||||
|
d = list()
|
||||||
|
|
|
@ -311,7 +311,8 @@ pub(crate) fn shell_injection(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
}
|
}
|
||||||
// S603
|
// S603
|
||||||
Some(ShellKeyword {
|
Some(ShellKeyword {
|
||||||
truthiness: Truthiness::False | Truthiness::Falsey | Truthiness::Unknown,
|
truthiness:
|
||||||
|
Truthiness::False | Truthiness::Falsey | Truthiness::None | Truthiness::Unknown,
|
||||||
}) => {
|
}) => {
|
||||||
if checker.enabled(Rule::SubprocessWithoutShellEqualsTrue) {
|
if checker.enabled(Rule::SubprocessWithoutShellEqualsTrue) {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
|
|
@ -87,6 +87,6 @@ fn exc_info_arg_is_falsey(call: &ExprCall, checker: &mut Checker) -> bool {
|
||||||
.is_some_and(|value| {
|
.is_some_and(|value| {
|
||||||
let truthiness =
|
let truthiness =
|
||||||
Truthiness::from_expr(value, |id| checker.semantic().has_builtin_binding(id));
|
Truthiness::from_expr(value, |id| checker.semantic().has_builtin_binding(id));
|
||||||
matches!(truthiness, Truthiness::False | Truthiness::Falsey)
|
truthiness.into_bool() == Some(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -493,7 +493,7 @@ fn to_pytest_raises_args<'a>(
|
||||||
/// PT015
|
/// PT015
|
||||||
pub(crate) fn assert_falsy(checker: &mut Checker, stmt: &Stmt, test: &Expr) {
|
pub(crate) fn assert_falsy(checker: &mut Checker, stmt: &Stmt, test: &Expr) {
|
||||||
let truthiness = Truthiness::from_expr(test, |id| checker.semantic().has_builtin_binding(id));
|
let truthiness = Truthiness::from_expr(test, |id| checker.semantic().has_builtin_binding(id));
|
||||||
if matches!(truthiness, Truthiness::False | Truthiness::Falsey) {
|
if truthiness.into_bool() == Some(false) {
|
||||||
checker
|
checker
|
||||||
.diagnostics
|
.diagnostics
|
||||||
.push(Diagnostic::new(PytestAssertAlwaysFalse, stmt.range()));
|
.push(Diagnostic::new(PytestAssertAlwaysFalse, stmt.range()));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use ruff_python_ast::helpers::{map_callable, map_subscript};
|
use ruff_python_ast::helpers::{map_callable, map_subscript, Truthiness};
|
||||||
use ruff_python_ast::{self as ast, Expr, ExprCall};
|
use ruff_python_ast::{self as ast, Expr, ExprCall};
|
||||||
use ruff_python_semantic::{analyze, BindingKind, Modules, SemanticModel};
|
use ruff_python_semantic::{analyze, BindingKind, Modules, SemanticModel};
|
||||||
|
|
||||||
|
@ -148,16 +148,19 @@ pub(super) fn dataclass_kind(
|
||||||
return Some(DataclassKind::Attrs(AttrsAutoAttribs::None));
|
return Some(DataclassKind::Attrs(AttrsAutoAttribs::None));
|
||||||
};
|
};
|
||||||
|
|
||||||
let auto_attribs = match &auto_attribs.value {
|
let auto_attribs = match Truthiness::from_expr(&auto_attribs.value, |id| {
|
||||||
Expr::BooleanLiteral(literal) => {
|
semantic.has_builtin_binding(id)
|
||||||
if literal.value {
|
}) {
|
||||||
AttrsAutoAttribs::True
|
// `auto_attribs` requires an exact `True` to be true
|
||||||
} else {
|
Truthiness::True => AttrsAutoAttribs::True,
|
||||||
AttrsAutoAttribs::False
|
// Or an exact `None` to auto-detect.
|
||||||
}
|
Truthiness::None => AttrsAutoAttribs::None,
|
||||||
|
// Otherwise, anything else (even a truthy value, like `1`) is considered `False`.
|
||||||
|
Truthiness::Truthy | Truthiness::False | Truthiness::Falsey => {
|
||||||
|
AttrsAutoAttribs::False
|
||||||
}
|
}
|
||||||
Expr::NoneLiteral(..) => AttrsAutoAttribs::None,
|
// Unless, of course, we can't determine the value.
|
||||||
_ => AttrsAutoAttribs::Unknown,
|
Truthiness::Unknown => AttrsAutoAttribs::Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Some(DataclassKind::Attrs(auto_attribs));
|
return Some(DataclassKind::Attrs(auto_attribs));
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
RUF009_attrs_auto_attribs.py:12:14: RUF009 Do not perform function call `foo` in dataclass defaults
|
RUF009_attrs_auto_attribs.py:12:14: RUF009 Do not perform function call `foo` in dataclass defaults
|
||||||
|
|
|
|
||||||
|
@ -100,3 +99,12 @@ RUF009_attrs_auto_attribs.py:100:14: RUF009 Do not perform function call `foo` i
|
||||||
| ^^^^^ RUF009
|
| ^^^^^ RUF009
|
||||||
101 | d = list()
|
101 | d = list()
|
||||||
|
|
|
|
||||||
|
|
||||||
|
RUF009_attrs_auto_attribs.py:116:14: RUF009 Do not perform function call `foo` in dataclass defaults
|
||||||
|
|
|
||||||
|
114 | a: str = 0
|
||||||
|
115 | b = field()
|
||||||
|
116 | c: int = foo()
|
||||||
|
| ^^^^^ RUF009
|
||||||
|
117 | d = list()
|
||||||
|
|
|
||||||
|
|
|
@ -1118,6 +1118,8 @@ pub enum Truthiness {
|
||||||
Falsey,
|
Falsey,
|
||||||
/// The expression evaluates to a `True`-like value (e.g., `1`, `"foo"`).
|
/// The expression evaluates to a `True`-like value (e.g., `1`, `"foo"`).
|
||||||
Truthy,
|
Truthy,
|
||||||
|
/// The expression evaluates to `None`.
|
||||||
|
None,
|
||||||
/// The expression evaluates to an unknown value (e.g., a variable `x` of unknown type).
|
/// The expression evaluates to an unknown value (e.g., a variable `x` of unknown type).
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
@ -1173,7 +1175,7 @@ impl Truthiness {
|
||||||
Self::False
|
Self::False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::NoneLiteral(_) => Self::Falsey,
|
Expr::NoneLiteral(_) => Self::None,
|
||||||
Expr::EllipsisLiteral(_) => Self::Truthy,
|
Expr::EllipsisLiteral(_) => Self::Truthy,
|
||||||
Expr::FString(f_string) => {
|
Expr::FString(f_string) => {
|
||||||
if is_empty_f_string(f_string) {
|
if is_empty_f_string(f_string) {
|
||||||
|
@ -1247,6 +1249,7 @@ impl Truthiness {
|
||||||
match self {
|
match self {
|
||||||
Self::True | Self::Truthy => Some(true),
|
Self::True | Self::Truthy => Some(true),
|
||||||
Self::False | Self::Falsey => Some(false),
|
Self::False | Self::Falsey => Some(false),
|
||||||
|
Self::None => Some(false),
|
||||||
Self::Unknown => None,
|
Self::Unknown => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue