Description
Code Sample, a copy-pastable example if possible
# Your code here
import pandas as pd
event = pd.Series({"a": "hello"})
pd.eval("event.str.match('hello').a") # returns numpy.bool_(True)
pd.eval("event.str.match('hello').a and event.str.match('hello').a") # raises TypeError
Problem description
When running the last line of the code above, the following error is produced:
TypeError Traceback (most recent call last)
<ipython-input-1-4a1286720430> in <module>
5 pd.eval("event.str.match('hello').a") # returns np.bool_(True)
6
----> 7 pd.eval("event.str.match('hello').a and event.str.match('hello').a") # raises TypeError
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/eval.py in eval(expr, parser, engine, truediv, local_dict, global_dict, resolvers, level, target, inplace)
292
293 parsed_expr = Expr(expr, engine=engine, parser=parser, env=env,
--> 294 truediv=truediv)
295
296 # construct the engine and evaluate the parsed expression
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in __init__(self, expr, engine, parser, env, truediv, level)
747 self.env.scope['truediv'] = truediv
748 self._visitor = _parsers[parser](self.env, self.engine, self.parser)
--> 749 self.terms = self.parse()
750
751 @property
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in parse(self)
764 def parse(self):
765 """Parse an expression"""
--> 766 return self._visitor.visit(self.expr)
767
768 @property
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in visit(self, node, **kwargs)
329 method = 'visit_' + node.__class__.__name__
330 visitor = getattr(self, method)
--> 331 return visitor(node, **kwargs)
332
333 def visit_Module(self, node, **kwargs):
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in visit_Module(self, node, **kwargs)
335 raise SyntaxError('only a single expression is allowed')
336 expr = node.body[0]
--> 337 return self.visit(expr, **kwargs)
338
339 def visit_Expr(self, node, **kwargs):
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in visit(self, node, **kwargs)
329 method = 'visit_' + node.__class__.__name__
330 visitor = getattr(self, method)
--> 331 return visitor(node, **kwargs)
332
333 def visit_Module(self, node, **kwargs):
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in visit_Expr(self, node, **kwargs)
338
339 def visit_Expr(self, node, **kwargs):
--> 340 return self.visit(node.value, **kwargs)
341
342 def _rewrite_membership_op(self, node, left, right):
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in visit(self, node, **kwargs)
329 method = 'visit_' + node.__class__.__name__
330 visitor = getattr(self, method)
--> 331 return visitor(node, **kwargs)
332
333 def visit_Module(self, node, **kwargs):
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in visit_BoolOp(self, node, **kwargs)
691
692 operands = node.values
--> 693 return reduce(visitor, operands)
694
695
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in visitor(x, y)
688 op, op_class, lhs, rhs = self._maybe_transform_eq_ne(
689 node, lhs, rhs)
--> 690 return self._maybe_evaluate_binop(op, node.op, lhs, rhs)
691
692 operands = node.values
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expr.py in _maybe_evaluate_binop(self, op, op_class, lhs, rhs, eval_in_python, maybe_eval_in_python)
404 maybe_eval_in_python=('==', '!=', '<', '>',
405 '<=', '>=')):
--> 406 res = op(lhs, rhs)
407
408 if res.has_invalid_return_type:
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/ops.py in __init__(self, op, lhs, rhs, **kwargs)
335 self.rhs = rhs
336
--> 337 self._disallow_scalar_only_bool_ops()
338
339 self.convert_values()
~/anaconda3/lib/python3.7/site-packages/pandas/core/computation/ops.py in _disallow_scalar_only_bool_ops(self)
440 if ((self.lhs.is_scalar or self.rhs.is_scalar) and
441 self.op in _bool_ops_dict and
--> 442 (not (issubclass(self.rhs.return_type, (bool, np.bool_)) and
443 issubclass(self.lhs.return_type, (bool, np.bool_))))):
444 raise NotImplementedError("cannot evaluate scalar only bool ops")
TypeError: issubclass() arg 1 must be a class
The expected output of this operation is a boolean indicating numpy.bool_(True)
or numpy.bool_(False)
. This is the output when running the following code.
event.str.match("hello").a and event.str.match("hello").a # outputs numpy.bool_(True)
Also, when using Python's builtin booleans with pd.eval
, the behavior is as expected.
pd.eval("True and True") # returns True
I think that this behavior should be used when running boolean operations on numpy.bool_
types.
Expected Output
Expected output of pd.eval("event.str.match('hello').a and event.str.match('hello').a")
:
True
Output of pd.show_versions()
[paste the output of pd.show_versions()
here below this line]
INSTALLED VERSIONS
commit: None
python: 3.7.2.final.0
python-bits: 64
OS: Linux
OS-release: 3.10.0-957.5.1.el7.x86_64
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8
pandas: 0.24.2
pytest: 4.2.0
pip: 19.0.1
setuptools: 40.7.3
Cython: 0.29.4
numpy: 1.15.4
scipy: 1.1.0
pyarrow: None
xarray: None
IPython: 7.2.0
sphinx: 1.8.4
patsy: 0.5.0
dateutil: 2.7.5
pytz: 2018.9
blosc: None
bottleneck: 1.2.1
tables: 3.4.4
numexpr: 2.6.8
feather: None
matplotlib: 2.2.3
openpyxl: 2.5.14
xlrd: 1.2.0
xlwt: 1.3.0
xlsxwriter: 1.1.2
lxml.etree: 4.3.0
bs4: 4.7.1
html5lib: 1.0.1
sqlalchemy: 1.2.17
pymysql: None
psycopg2: None
jinja2: 2.10
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None
gcsfs: None