FBT001: exclude boolean operators (#14203)

Fixes #14202

## Summary

Exclude rule FBT001 for boolean operators.

## Test Plan

Updated existing `FBT.py` test.
This commit is contained in:
Randolf Scholz 2024-11-10 23:40:37 +01:00 committed by GitHub
parent a7e9f0c4b9
commit 5d91ba0b10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 104 additions and 2 deletions

View file

@ -94,7 +94,7 @@ class Registry:
object.__setattr__(self, "flag", True)
from typing import Optional, Union
from typing import Optional, Union, Self
def func(x: Union[list, Optional[int | str | float | bool]]):
@ -154,3 +154,23 @@ from pydantic_settings import BaseSettings
class Settings(BaseSettings):
foo: bool = Field(True, exclude=True)
# https://github.com/astral-sh/ruff/issues/14202
class SupportsXorBool:
def __xor__(self, other: bool) -> Self: ...
# check overload
class CustomFloat:
@overload
def __mul__(self, other: bool) -> Self: ...
@overload
def __mul__(self, other: float) -> Self: ...
@overload
def __mul__(self, other: Self) -> Self: ...
# check union
class BooleanArray:
def __or__(self, other: Self | bool) -> Self: ...
def __ror__(self, other: Self | bool) -> Self: ...
def __ior__(self, other: Self | bool) -> Self: ...

View file

@ -66,9 +66,88 @@ pub(super) fn is_user_allowed_func_call(
})
}
/// Returns `true` if a function defines a binary operator.
///
/// This only includes operators, i.e., functions that are usually not called directly.
///
/// See: <https://docs.python.org/3/library/operator.html>
pub(super) fn is_operator_method(name: &str) -> bool {
matches!(
name,
"__contains__" // in
// item access ([])
| "__getitem__" // []
| "__setitem__" // []=
| "__delitem__" // del []
// addition (+)
| "__add__" // +
| "__radd__" // +
| "__iadd__" // +=
// subtraction (-)
| "__sub__" // -
| "__rsub__" // -
| "__isub__" // -=
// multiplication (*)
| "__mul__" // *
| "__rmul__" // *
| "__imul__" // *=
// division (/)
| "__truediv__" // /
| "__rtruediv__" // /
| "__itruediv__" // /=
// floor division (//)
| "__floordiv__" // //
| "__rfloordiv__" // //
| "__ifloordiv__" // //=
// remainder (%)
| "__mod__" // %
| "__rmod__" // %
| "__imod__" // %=
// exponentiation (**)
| "__pow__" // **
| "__rpow__" // **
| "__ipow__" // **=
// left shift (<<)
| "__lshift__" // <<
| "__rlshift__" // <<
| "__ilshift__" // <<=
// right shift (>>)
| "__rshift__" // >>
| "__rrshift__" // >>
| "__irshift__" // >>=
// matrix multiplication (@)
| "__matmul__" // @
| "__rmatmul__" // @
| "__imatmul__" // @=
// meet (&)
| "__and__" // &
| "__rand__" // &
| "__iand__" // &=
// join (|)
| "__or__" // |
| "__ror__" // |
| "__ior__" // |=
// xor (^)
| "__xor__" // ^
| "__rxor__" // ^
| "__ixor__" // ^=
// comparison (>, <, >=, <=, ==, !=)
| "__gt__" // >
| "__lt__" // <
| "__ge__" // >=
| "__le__" // <=
| "__eq__" // ==
| "__ne__" // !=
// unary operators (included for completeness)
| "__pos__" // +
| "__neg__" // -
| "__invert__" // ~
)
}
/// Returns `true` if a function definition is allowed to use a boolean trap.
pub(super) fn is_allowed_func_def(name: &str) -> bool {
matches!(name, "__setitem__" | "__post_init__")
matches!(name, "__post_init__") || is_operator_method(name)
}
/// Returns `true` if an argument is allowed to use a boolean trap. To return

View file

@ -27,6 +27,9 @@ use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
/// keyword-only argument, to force callers to be explicit when providing
/// the argument.
///
/// Dunder methods that define operators are exempt from this rule, as are
/// setters and `@override` definitions.
///
/// In [preview], this rule will also flag annotations that include boolean
/// variants, like `bool | int`.
///