Skip to content

Commit 352db84

Browse files
committed
Merge pull request #6205 from havoc-io/master
BUG: Add type promotion support for eval() expressions with many properties
2 parents 7d3e41c + bd7d0c7 commit 352db84

File tree

5 files changed

+33
-5
lines changed

5 files changed

+33
-5
lines changed

doc/source/release.rst

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ Bug Fixes
7676
- Indexing bugs with reordered indexes (:issue:`6252`, :issue:`6254`)
7777
- Bug in ``.xs`` with a Series multiindex (:issue:`6258`, :issue:`5684`)
7878
- Bug in conversion of a string types to a DatetimeIndex with a specified frequency (:issue:`6273`, :issue:`6274`)
79+
- Bug in ``eval`` where type-promotion failed for large expressions (:issue:`6205`)
7980

8081
pandas 0.13.1
8182
-------------

pandas/computation/align.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import pandas as pd
1111
from pandas import compat
1212
import pandas.core.common as com
13+
from pandas.computation.common import _result_type_many
1314

1415

1516
def _align_core_single_unary_op(term):
@@ -85,11 +86,11 @@ def wrapper(terms):
8586
# only scalars or indexes
8687
if all(isinstance(term.value, pd.Index) or term.isscalar for term in
8788
terms):
88-
return np.result_type(*term_values), None
89+
return _result_type_many(*term_values), None
8990

9091
# no pandas objects
9192
if not _any_pandas_objects(terms):
92-
return np.result_type(*term_values), None
93+
return _result_type_many(*term_values), None
9394

9495
return f(terms)
9596
return wrapper
@@ -199,7 +200,7 @@ def _align(terms):
199200

200201
# if all resolved variables are numeric scalars
201202
if all(term.isscalar for term in terms):
202-
return np.result_type(*(term.value for term in terms)).type, None
203+
return _result_type_many(*(term.value for term in terms)).type, None
203204

204205
# perform the main alignment
205206
typ, axes = _align_core(terms)

pandas/computation/common.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22
import pandas as pd
3+
from pandas.compat import reduce
34

45

56
def _ensure_decoded(s):
@@ -9,5 +10,18 @@ def _ensure_decoded(s):
910
return s
1011

1112

13+
def _result_type_many(*arrays_and_dtypes):
14+
""" wrapper around numpy.result_type which overcomes the NPY_MAXARGS (32)
15+
argument limit """
16+
try:
17+
return np.result_type(*arrays_and_dtypes)
18+
except ValueError:
19+
# length 0 or length > NPY_MAXARGS both throw a ValueError, so check
20+
# which one we're dealing with
21+
if len(arrays_and_dtypes) == 0:
22+
raise ValueError('at least one array or dtype is required')
23+
return reduce(np.result_type, arrays_and_dtypes)
24+
25+
1226
class NameResolutionError(NameError):
1327
pass

pandas/computation/ops.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from pandas.compat import PY3, string_types, text_type
1414
import pandas.core.common as com
1515
from pandas.core.base import StringMixin
16-
from pandas.computation.common import _ensure_decoded
16+
from pandas.computation.common import _ensure_decoded, _result_type_many
1717

1818

1919
_reductions = 'sum', 'prod'
@@ -240,7 +240,7 @@ def return_type(self):
240240
# clobber types to bool if the op is a boolean operator
241241
if self.op in (_cmp_ops_syms + _bool_ops_syms):
242242
return np.bool_
243-
return np.result_type(*(term.type for term in com.flatten(self)))
243+
return _result_type_many(*(term.type for term in com.flatten(self)))
244244

245245
@property
246246
def isscalar(self):

pandas/computation/tests/test_eval.py

+12
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,18 @@ def test_invalid_numexpr_version():
15751575
yield check_invalid_numexpr_version, engine, parser
15761576

15771577

1578+
def check_many_exprs(engine, parser):
1579+
a = 1
1580+
expr = ' * '.join('a' * 33)
1581+
expected = 1
1582+
res = pd.eval(expr, engine=engine, parser=parser)
1583+
tm.assert_equal(res, expected)
1584+
1585+
def test_many_exprs():
1586+
for engine, parser in ENGINES_PARSERS:
1587+
yield check_many_exprs, engine, parser
1588+
1589+
15781590
if __name__ == '__main__':
15791591
nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],
15801592
exit=False)

0 commit comments

Comments
 (0)