Skip to content

Commit

Permalink
Merge pull request pandas-dev#6803 from cpcloud/bool-arith-ops-6762
Browse files Browse the repository at this point in the history
BUG/API: disallow boolean arithmetic operations
  • Loading branch information
cpcloud committed Apr 5, 2014
2 parents 7c073c4 + a228d1e commit fe9aa12
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 4 deletions.
5 changes: 5 additions & 0 deletions doc/source/release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ API Changes
- ``to_excel`` now converts ``np.inf`` into a string representation,
customizable by the ``inf_rep`` keyword argument (Excel has no native inf
representation) (:issue:`6782`)
- Arithmetic ops are now disallowed when passed two bool dtype Series or
DataFrames (:issue:`6762`).

Deprecations
~~~~~~~~~~~~
Expand Down Expand Up @@ -307,6 +309,9 @@ Bug Fixes
- Bug in ``DataFrame.replace()`` where regex metacharacters were being treated
as regexs even when ``regex=False`` (:issue:`6777`).
- Bug in timedelta ops on 32-bit platforms (:issue:`6808`)
- Bug in setting a tz-aware index directly via ``.index`` (:issue:`6785`)
- Bug in expressions.py where numexpr would try to evaluate arithmetic ops
(:issue:`6762`).

pandas 0.13.1
-------------
Expand Down
16 changes: 15 additions & 1 deletion pandas/computation/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,20 @@ def _where_numexpr(cond, a, b, raise_on_error=False):
set_use_numexpr(True)


def _has_bool_dtype(x):
try:
return x.dtype == bool
except AttributeError:
return 'bool' in x.blocks


def _bool_arith_check(op_str, a, b, not_allowed=frozenset(('+', '*', '-', '/',
'//', '**'))):
if op_str in not_allowed and _has_bool_dtype(a) and _has_bool_dtype(b):
raise NotImplementedError("operator %r not implemented for bool "
"dtypes" % op_str)


def evaluate(op, op_str, a, b, raise_on_error=False, use_numexpr=True,
**eval_kwargs):
""" evaluate and return the expression of the op on a and b
Expand All @@ -170,7 +184,7 @@ def evaluate(op, op_str, a, b, raise_on_error=False, use_numexpr=True,
return the results
use_numexpr : whether to try to use numexpr (default True)
"""

_bool_arith_check(op_str, a, b)
if use_numexpr:
return _evaluate(op, op_str, a, b, raise_on_error=raise_on_error,
**eval_kwargs)
Expand Down
19 changes: 19 additions & 0 deletions pandas/tests/test_expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# pylint: disable-msg=W0612,E1101

import nose
import re

from numpy.random import randn

Expand Down Expand Up @@ -339,6 +340,24 @@ def testit():
expr.set_numexpr_threads()
testit()

def test_bool_ops_raise_on_arithmetic(self):
df = DataFrame({'a': np.random.rand(10) > 0.5,
'b': np.random.rand(10) > 0.5})
names = 'add', 'mul', 'sub', 'div', 'truediv', 'floordiv', 'pow'
ops = '+', '*', '-', '/', '/', '//', '**'
msg = 'operator %r not implemented for bool dtypes'
for op, name in zip(ops, names):
if not compat.PY3 or name != 'div':
f = getattr(operator, name)
err_msg = re.escape(msg % op)

with tm.assertRaisesRegexp(NotImplementedError, err_msg):
f(df, df)

with tm.assertRaisesRegexp(NotImplementedError, err_msg):
f(df.a, df.b)


if __name__ == '__main__':
import nose
nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],
Expand Down
6 changes: 3 additions & 3 deletions pandas/tests/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -4761,13 +4761,13 @@ def _check_unary_op(op):
_check_unary_op(operator.neg)

def test_logical_typeerror(self):
if compat.PY3:
pass
else:
if not compat.PY3:
self.assertRaises(TypeError, self.frame.__eq__, 'foo')
self.assertRaises(TypeError, self.frame.__lt__, 'foo')
self.assertRaises(TypeError, self.frame.__gt__, 'foo')
self.assertRaises(TypeError, self.frame.__ne__, 'foo')
else:
raise nose.SkipTest('test_logical_typeerror not tested on PY3')

def test_constructor_lists_to_object_dtype(self):
# from #1074
Expand Down

0 comments on commit fe9aa12

Please sign in to comment.