Skip to content

Commit d062858

Browse files
alexcwattjreback
authored andcommitted
BUG: Fix #16363 - Prevent visit_BinOp from accessing value on UnaryOp (#25928)
1 parent 685d31f commit d062858

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

doc/source/whatsnew/v0.25.0.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ Bug Fixes
255255
~~~~~~~~~
256256

257257

258+
258259
Categorical
259260
^^^^^^^^^^^
260261

@@ -295,7 +296,7 @@ Numeric
295296
- Bug in error messages in :meth:`DataFrame.corr` and :meth:`Series.corr`. Added the possibility of using a callable. (:issue:`25729`)
296297
- Bug in :meth:`Series.divmod` and :meth:`Series.rdivmod` which would raise an (incorrect) ``ValueError`` rather than return a pair of :class:`Series` objects as result (:issue:`25557`)
297298
- Raises a helpful exception when a non-numeric index is sent to :meth:`interpolate` with methods which require numeric index. (:issue:`21662`)
298-
-
299+
- Bug in :meth:`~pandas.eval` when comparing floats with scalar operators, for example: ``x < -0.1`` (:issue:`25928`)
299300
-
300301

301302

pandas/core/computation/expr.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -418,11 +418,13 @@ def _maybe_transform_eq_ne(self, node, left=None, right=None):
418418

419419
def _maybe_downcast_constants(self, left, right):
420420
f32 = np.dtype(np.float32)
421-
if left.is_scalar and not right.is_scalar and right.return_type == f32:
421+
if (left.is_scalar and hasattr(left, 'value') and
422+
not right.is_scalar and right.return_type == f32):
422423
# right is a float32 array, left is a scalar
423424
name = self.env.add_tmp(np.float32(left.value))
424425
left = self.term_type(name, self.env)
425-
if right.is_scalar and not left.is_scalar and left.return_type == f32:
426+
if (right.is_scalar and hasattr(right, 'value') and
427+
not left.is_scalar and left.return_type == f32):
426428
# left is a float32 array, right is a scalar
427429
name = self.env.add_tmp(np.float32(right.value))
428430
right = self.term_type(name, self.env)

pandas/tests/computation/test_eval.py

+10
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,16 @@ def test_unary_in_array(self):
608608
-False, False, ~False, +False,
609609
-37, 37, ~37, +37], dtype=np.object_))
610610

611+
@pytest.mark.parametrize('dtype', [np.float32, np.float64])
612+
def test_float_comparison_bin_op(self, dtype):
613+
# GH 16363
614+
df = pd.DataFrame({'x': np.array([0], dtype=dtype)})
615+
res = df.eval('x < -0.1')
616+
assert res.values == np.array([False])
617+
618+
res = df.eval('-5 > x')
619+
assert res.values == np.array([False])
620+
611621
def test_disallow_scalar_bool_ops(self):
612622
exprs = '1 or 2', '1 and 2'
613623
exprs += 'a and b', 'a or b'

0 commit comments

Comments
 (0)