Skip to content

Commit 5d91ba0

Browse files
FBT001: exclude boolean operators (#14203)
Fixes #14202 ## Summary Exclude rule FBT001 for boolean operators. ## Test Plan Updated existing `FBT.py` test.
1 parent a7e9f0c commit 5d91ba0

File tree

3 files changed

+104
-2
lines changed

3 files changed

+104
-2
lines changed

crates/ruff_linter/resources/test/fixtures/flake8_boolean_trap/FBT.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def foo(self) -> None:
9494
object.__setattr__(self, "flag", True)
9595

9696

97-
from typing import Optional, Union
97+
from typing import Optional, Union, Self
9898

9999

100100
def func(x: Union[list, Optional[int | str | float | bool]]):
@@ -154,3 +154,23 @@ def __post_init__(self, force: bool) -> None:
154154

155155
class Settings(BaseSettings):
156156
foo: bool = Field(True, exclude=True)
157+
158+
159+
# https://github.com/astral-sh/ruff/issues/14202
160+
class SupportsXorBool:
161+
def __xor__(self, other: bool) -> Self: ...
162+
163+
# check overload
164+
class CustomFloat:
165+
@overload
166+
def __mul__(self, other: bool) -> Self: ...
167+
@overload
168+
def __mul__(self, other: float) -> Self: ...
169+
@overload
170+
def __mul__(self, other: Self) -> Self: ...
171+
172+
# check union
173+
class BooleanArray:
174+
def __or__(self, other: Self | bool) -> Self: ...
175+
def __ror__(self, other: Self | bool) -> Self: ...
176+
def __ior__(self, other: Self | bool) -> Self: ...

crates/ruff_linter/src/rules/flake8_boolean_trap/helpers.rs

+80-1
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,88 @@ pub(super) fn is_user_allowed_func_call(
6666
})
6767
}
6868

69+
/// Returns `true` if a function defines a binary operator.
70+
///
71+
/// This only includes operators, i.e., functions that are usually not called directly.
72+
///
73+
/// See: <https://docs.python.org/3/library/operator.html>
74+
pub(super) fn is_operator_method(name: &str) -> bool {
75+
matches!(
76+
name,
77+
"__contains__" // in
78+
// item access ([])
79+
| "__getitem__" // []
80+
| "__setitem__" // []=
81+
| "__delitem__" // del []
82+
// addition (+)
83+
| "__add__" // +
84+
| "__radd__" // +
85+
| "__iadd__" // +=
86+
// subtraction (-)
87+
| "__sub__" // -
88+
| "__rsub__" // -
89+
| "__isub__" // -=
90+
// multiplication (*)
91+
| "__mul__" // *
92+
| "__rmul__" // *
93+
| "__imul__" // *=
94+
// division (/)
95+
| "__truediv__" // /
96+
| "__rtruediv__" // /
97+
| "__itruediv__" // /=
98+
// floor division (//)
99+
| "__floordiv__" // //
100+
| "__rfloordiv__" // //
101+
| "__ifloordiv__" // //=
102+
// remainder (%)
103+
| "__mod__" // %
104+
| "__rmod__" // %
105+
| "__imod__" // %=
106+
// exponentiation (**)
107+
| "__pow__" // **
108+
| "__rpow__" // **
109+
| "__ipow__" // **=
110+
// left shift (<<)
111+
| "__lshift__" // <<
112+
| "__rlshift__" // <<
113+
| "__ilshift__" // <<=
114+
// right shift (>>)
115+
| "__rshift__" // >>
116+
| "__rrshift__" // >>
117+
| "__irshift__" // >>=
118+
// matrix multiplication (@)
119+
| "__matmul__" // @
120+
| "__rmatmul__" // @
121+
| "__imatmul__" // @=
122+
// meet (&)
123+
| "__and__" // &
124+
| "__rand__" // &
125+
| "__iand__" // &=
126+
// join (|)
127+
| "__or__" // |
128+
| "__ror__" // |
129+
| "__ior__" // |=
130+
// xor (^)
131+
| "__xor__" // ^
132+
| "__rxor__" // ^
133+
| "__ixor__" // ^=
134+
// comparison (>, <, >=, <=, ==, !=)
135+
| "__gt__" // >
136+
| "__lt__" // <
137+
| "__ge__" // >=
138+
| "__le__" // <=
139+
| "__eq__" // ==
140+
| "__ne__" // !=
141+
// unary operators (included for completeness)
142+
| "__pos__" // +
143+
| "__neg__" // -
144+
| "__invert__" // ~
145+
)
146+
}
147+
69148
/// Returns `true` if a function definition is allowed to use a boolean trap.
70149
pub(super) fn is_allowed_func_def(name: &str) -> bool {
71-
matches!(name, "__setitem__" | "__post_init__")
150+
matches!(name, "__post_init__") || is_operator_method(name)
72151
}
73152

74153
/// Returns `true` if an argument is allowed to use a boolean trap. To return

crates/ruff_linter/src/rules/flake8_boolean_trap/rules/boolean_type_hint_positional_argument.rs

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
2727
/// keyword-only argument, to force callers to be explicit when providing
2828
/// the argument.
2929
///
30+
/// Dunder methods that define operators are exempt from this rule, as are
31+
/// setters and `@override` definitions.
32+
///
3033
/// In [preview], this rule will also flag annotations that include boolean
3134
/// variants, like `bool | int`.
3235
///

0 commit comments

Comments
 (0)