Skip to content

Commit bad7c0f

Browse files
committed
COMPAT: blacklist numexpr=2.4.4
closes pandas-dev#12489 closes pandas-dev#12511
1 parent eba7803 commit bad7c0f

File tree

8 files changed

+110
-53
lines changed

8 files changed

+110
-53
lines changed

ci/requirements-3.4_SLOW.run

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ html5lib
99
patsy
1010
beautiful-soup
1111
scipy
12-
numexpr
12+
numexpr=2.4.4
1313
pytables
1414
matplotlib
1515
lxml

doc/source/install.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ Recommended Dependencies
225225

226226
* `numexpr <https://github.com/pydata/numexpr>`__: for accelerating certain numerical operations.
227227
``numexpr`` uses multiple cores as well as smart chunking and caching to achieve large speedups.
228-
If installed, must be Version 2.1 or higher. Version 2.4.6 or higher on Windows is highly recommended.
228+
If installed, must be Version 2.1 or higher (excluding a buggy 2.4.4). Version 2.4.6 or higher is highly recommended.
229229

230230
* `bottleneck <http://berkeleyanalytics.com/bottleneck>`__: for accelerating certain types of ``nan``
231231
evaluations. ``bottleneck`` uses specialized cython routines to achieve large speedups.

doc/source/whatsnew/v0.18.0.txt

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ users upgrade to this version.
1212
pandas >= 0.18.0 no longer supports compatibility with Python version 2.6
1313
and 3.3 (:issue:`7718`, :issue:`11273`)
1414

15+
.. warning::
16+
17+
``numexpr`` version 2.4.4 will now show a warning and not be used as a computation back-end for pandas because of some buggy behavior. This does not affect other versions (>= 2.1 and >= 2.4.6). (:issue:`12489`)
18+
1519
Highlights include:
1620

1721
- Moving and expanding window functions are now methods on Series and DataFrame,

pandas/computation/__init__.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
import warnings
3+
from distutils.version import LooseVersion
4+
5+
_NUMEXPR_INSTALLED = False
6+
7+
try:
8+
import numexpr as ne
9+
ver = ne.__version__
10+
_NUMEXPR_INSTALLED = ver >= LooseVersion('2.1')
11+
12+
# we specifically disallow 2.4.4 as
13+
# has some hard-to-diagnose bugs
14+
if ver == LooseVersion('2.4.4'):
15+
_NUMEXPR_INSTALLED = False
16+
warnings.warn(
17+
"The installed version of numexpr {ver} is not supported "
18+
"in pandas and will be not be used\n".format(ver=ver),
19+
UserWarning)
20+
21+
elif not _NUMEXPR_INSTALLED:
22+
warnings.warn(
23+
"The installed version of numexpr {ver} is not supported "
24+
"in pandas and will be not be used\nThe minimum supported "
25+
"version is 2.1\n".format(ver=ver), UserWarning)
26+
27+
except ImportError: # pragma: no cover
28+
pass
29+
30+
__all__ = ['_NUMEXPR_INSTALLED']

pandas/computation/eval.py

+4-10
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
import warnings
77
import tokenize
88
from pandas.core import common as com
9+
from pandas.computation import _NUMEXPR_INSTALLED
910
from pandas.computation.expr import Expr, _parsers, tokenize_string
1011
from pandas.computation.scope import _ensure_scope
1112
from pandas.compat import string_types
1213
from pandas.computation.engines import _engines
13-
from distutils.version import LooseVersion
1414

1515

1616
def _check_engine(engine):
@@ -35,17 +35,11 @@ def _check_engine(engine):
3535
# that won't necessarily be import-able)
3636
# Could potentially be done on engine instantiation
3737
if engine == 'numexpr':
38-
try:
39-
import numexpr
40-
except ImportError:
41-
raise ImportError("'numexpr' not found. Cannot use "
38+
if not _NUMEXPR_INSTALLED:
39+
raise ImportError("'numexpr' is not installed or an "
40+
"unsupported version. Cannot use "
4241
"engine='numexpr' for query/eval "
4342
"if 'numexpr' is not installed")
44-
else:
45-
ne_version = numexpr.__version__
46-
if ne_version < LooseVersion('2.1'):
47-
raise ImportError("'numexpr' version is %s, "
48-
"must be >= 2.1" % ne_version)
4943

5044

5145
def _check_parser(parser):

pandas/computation/expressions.py

+1-14
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,7 @@
99
import warnings
1010
import numpy as np
1111
from pandas.core.common import _values_from_object
12-
from distutils.version import LooseVersion
13-
14-
try:
15-
import numexpr as ne
16-
ver = ne.__version__
17-
_NUMEXPR_INSTALLED = ver >= LooseVersion('2.1')
18-
if not _NUMEXPR_INSTALLED:
19-
warnings.warn(
20-
"The installed version of numexpr {ver} is not supported "
21-
"in pandas and will be not be used\nThe minimum supported "
22-
"version is 2.1\n".format(ver=ver), UserWarning)
23-
24-
except ImportError: # pragma: no cover
25-
_NUMEXPR_INSTALLED = False
12+
from pandas.computation import _NUMEXPR_INSTALLED
2613

2714
_TEST_MODE = None
2815
_TEST_RESULT = None
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python
2+
3+
# flake8: noqa
4+
5+
import nose
6+
from itertools import product
7+
from distutils.version import LooseVersion
8+
9+
import pandas as pd
10+
from pandas.util import testing as tm
11+
12+
from pandas.computation.engines import _engines
13+
import pandas.computation.expr as expr
14+
15+
ENGINES_PARSERS = list(product(_engines, expr._parsers))
16+
17+
18+
def test_compat():
19+
# test we have compat with our version of nu
20+
21+
from pandas.computation import _NUMEXPR_INSTALLED
22+
try:
23+
import numexpr as ne
24+
ver = ne.__version__
25+
if ver == LooseVersion('2.4.4'):
26+
assert not _NUMEXPR_INSTALLED
27+
elif ver < LooseVersion('2.1'):
28+
with tm.assert_produces_warning(UserWarning,
29+
check_stacklevel=False):
30+
assert not _NUMEXPR_INSTALLED
31+
else:
32+
assert _NUMEXPR_INSTALLED
33+
34+
except ImportError:
35+
raise nose.SkipTest("not testing numexpr version compat")
36+
37+
38+
def test_invalid_numexpr_version():
39+
for engine, parser in ENGINES_PARSERS:
40+
yield check_invalid_numexpr_version, engine, parser
41+
42+
43+
def check_invalid_numexpr_version(engine, parser):
44+
def testit():
45+
a, b = 1, 2
46+
res = pd.eval('a + b', engine=engine, parser=parser)
47+
tm.assert_equal(res, 3)
48+
49+
if engine == 'numexpr':
50+
try:
51+
import numexpr as ne
52+
except ImportError:
53+
raise nose.SkipTest("no numexpr")
54+
else:
55+
if ne.__version__ < LooseVersion('2.1'):
56+
with tm.assertRaisesRegexp(ImportError, "'numexpr' version is "
57+
".+, must be >= 2.1"):
58+
testit()
59+
elif ne.__version__ == LooseVersion('2.4.4'):
60+
raise nose.SkipTest("numexpr version==2.4.4")
61+
else:
62+
testit()
63+
else:
64+
testit()
65+
66+
67+
if __name__ == '__main__':
68+
nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],
69+
exit=False)

pandas/computation/tests/test_eval.py

-27
Original file line numberDiff line numberDiff line change
@@ -1782,33 +1782,6 @@ def test_name_error_exprs():
17821782
yield check_name_error_exprs, engine, parser
17831783

17841784

1785-
def check_invalid_numexpr_version(engine, parser):
1786-
def testit():
1787-
a, b = 1, 2
1788-
res = pd.eval('a + b', engine=engine, parser=parser)
1789-
tm.assert_equal(res, 3)
1790-
1791-
if engine == 'numexpr':
1792-
try:
1793-
import numexpr as ne
1794-
except ImportError:
1795-
raise nose.SkipTest("no numexpr")
1796-
else:
1797-
if ne.__version__ < LooseVersion('2.1'):
1798-
with tm.assertRaisesRegexp(ImportError, "'numexpr' version is "
1799-
".+, must be >= 2.1"):
1800-
testit()
1801-
else:
1802-
testit()
1803-
else:
1804-
testit()
1805-
1806-
1807-
def test_invalid_numexpr_version():
1808-
for engine, parser in ENGINES_PARSERS:
1809-
yield check_invalid_numexpr_version, engine, parser
1810-
1811-
18121785
def check_invalid_local_variable_reference(engine, parser):
18131786
tm.skip_if_no_ne(engine)
18141787

0 commit comments

Comments
 (0)