-
-
Notifications
You must be signed in to change notification settings - Fork 54
Description
Has your issue already been fixed?
- Have you checked to see if your issue still exists on the
masterbranch? See the docs for instructions on how to setup a local build of Refurb. - Have you looked at the open/closed issues to see if anyone has already reported your issue?
- If reporting a false positive/incorrect suggestion, have you double checked that the suggested fix changes the code semantics?
The Bug
The following code:
from bisect import bisect
from collections.abc import Sequence
def f(events: Sequence[int], threshold: int) -> None:
cutoff = bisect(events, threshold)
if cutoff == 0 or events[cutoff - 1] == 0:
passEmits the following error:
$ refurb file.py
file.py:6:8 [FURB108]: Replace `x == y or z == y` with `y in (x, z)`
However, this suggestion is unsafe because if events is empty, cutoff - 1 is not a valid index. With or this is fine, as lazy evaluation halts after it finds that cutoff == 0 is true, but the tuple notation always evaluates both expressions.
I don't expect Refurb to understand the details of bisect(), but it could perhaps detect that cutoff is checked in the left hand side and used in the right hand side of or and as a precaution not issue FURB108.
I'm also not sure the suggested change (de-duplicating the 0) would actually make the code more elegant, but that is subjective, while the unsafe behavior is an objective problem.
Version Info
Refurb: v2.0.0
Mypy: v1.13.0Python Version
Python 3.12.7
Config File
# N/AExtra Info
The double check:
from bisect import bisect
from collections.abc import Sequence
def f1(events: Sequence[int], threshold: int) -> None:
cutoff = bisect(events, threshold)
if cutoff == 0 or events[cutoff - 1] == 0:
pass
def f2(events: Sequence[int], threshold: int) -> None:
cutoff = bisect(events, threshold)
if 0 in (cutoff, events[cutoff - 1]):
pass
f1([], 123)
f2([], 123)Here, the f1() call returns, while the f2() call raises IndexError.