Skip to content

BUG: Fix #16363 - Prevent visit_BinOp from accessing value on UnaryOp #25928

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion doc/source/whatsnew/v0.25.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ Bug Fixes
~~~~~~~~~



Categorical
^^^^^^^^^^^

Expand Down Expand Up @@ -268,7 +269,7 @@ Numeric
- Bug in error messages in :meth:`DataFrame.corr` and :meth:`Series.corr`. Added the possibility of using a callable. (:issue:`25729`)
- 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`)
- Raises a helpful exception when a non-numeric index is sent to :meth:`interpolate` with methods which require numeric index. (:issue:`21662`)
-
- Bug in :meth:`~pandas.eval` when comparing floats with scalar operators, for example: ``x < -0.1`` (:issue:`25928`)
-


Expand Down
6 changes: 4 additions & 2 deletions pandas/core/computation/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,11 +418,13 @@ def _maybe_transform_eq_ne(self, node, left=None, right=None):

def _maybe_downcast_constants(self, left, right):
f32 = np.dtype(np.float32)
if left.is_scalar and not right.is_scalar and right.return_type == f32:
if (left.is_scalar and hasattr(left, 'value') and
not right.is_scalar and right.return_type == f32):
# right is a float32 array, left is a scalar
name = self.env.add_tmp(np.float32(left.value))
left = self.term_type(name, self.env)
if right.is_scalar and not left.is_scalar and left.return_type == f32:
if (right.is_scalar and hasattr(right, 'value') and
not left.is_scalar and left.return_type == f32):
# left is a float32 array, right is a scalar
name = self.env.add_tmp(np.float32(right.value))
right = self.term_type(name, self.env)
Expand Down
10 changes: 10 additions & 0 deletions pandas/tests/computation/test_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,16 @@ def test_unary_in_array(self):
-False, False, ~False, +False,
-37, 37, ~37, +37], dtype=np.object_))

@pytest.mark.parametrize('dtype', [np.float32, np.float64])
def test_float_comparison_bin_op(self, dtype):
# GH 16363
df = pd.DataFrame({'x': np.array([0], dtype=dtype)})
res = df.eval('x < -0.1')
assert res.values == np.array([False])

res = df.eval('-5 > x')
assert res.values == np.array([False])

def test_disallow_scalar_bool_ops(self):
exprs = '1 or 2', '1 and 2'
exprs += 'a and b', 'a or b'
Expand Down