-
-
Notifications
You must be signed in to change notification settings - Fork 53
Description
Has your issue already been fixed?
- Have you checked to see if your issue still exists on the
master
branch? 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:
pass
Emits 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.0
Python Version
Python 3.12.7
Config File
# N/A
Extra 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
.