@@ -1066,20 +1066,12 @@ def test_performance_warning_for_poor_alignment(self, engine, parser):
10661066# Slightly more complex ops
10671067
10681068
1069- @td .skip_if_no_ne
1070- class TestOperationsNumExprPandas :
1071- exclude_arith : list [str ] = []
1072-
1073- engine = "numexpr"
1074- parser = "pandas"
1075-
1076- @classmethod
1077- def setup_class (cls ):
1078- cls .arith_ops = [
1079- op
1080- for op in expr .ARITH_OPS_SYMS + expr .CMP_OPS_SYMS
1081- if op not in cls .exclude_arith
1082- ]
1069+ class TestOperations :
1070+ @pytest .fixture (autouse = True )
1071+ def set_engine_parser_attrs (self , engine , parser ):
1072+ # Older tests look for these as attributes, so we set them here.
1073+ self .engine = engine
1074+ self .parser = parser
10831075
10841076 def eval (self , * args , ** kwargs ):
10851077 kwargs ["engine" ] = self .engine
@@ -1088,7 +1080,17 @@ def eval(self, *args, **kwargs):
10881080 return pd .eval (* args , ** kwargs )
10891081
10901082 def test_simple_arith_ops (self ):
1091- ops = (op for op in self .arith_ops if op != "//" )
1083+ exclude_arith = []
1084+ if self .parser == "python" :
1085+ exclude_arith = ["in" , "not in" ]
1086+
1087+ arith_ops = [
1088+ op
1089+ for op in expr .ARITH_OPS_SYMS + expr .CMP_OPS_SYMS
1090+ if op not in exclude_arith
1091+ ]
1092+
1093+ ops = (op for op in arith_ops if op != "//" )
10921094
10931095 for op in ops :
10941096 ex = f"1 { op } 1"
@@ -1121,6 +1123,13 @@ def test_simple_arith_ops(self):
11211123 @pytest .mark .parametrize ("op" , expr .BOOL_OPS_SYMS )
11221124 def test_simple_bool_ops (self , rhs , lhs , op ):
11231125 ex = f"{ lhs } { op } { rhs } "
1126+
1127+ if self .parser == "python" and op in ["and" , "or" ]:
1128+ msg = "'BoolOp' nodes are not implemented"
1129+ with pytest .raises (NotImplementedError , match = msg ):
1130+ self .eval (ex )
1131+ return
1132+
11241133 res = self .eval (ex )
11251134 exp = eval (ex )
11261135 assert res == exp
@@ -1130,6 +1139,13 @@ def test_simple_bool_ops(self, rhs, lhs, op):
11301139 @pytest .mark .parametrize ("op" , expr .BOOL_OPS_SYMS )
11311140 def test_bool_ops_with_constants (self , rhs , lhs , op ):
11321141 ex = f"{ lhs } { op } { rhs } "
1142+
1143+ if self .parser == "python" and op in ["and" , "or" ]:
1144+ msg = "'BoolOp' nodes are not implemented"
1145+ with pytest .raises (NotImplementedError , match = msg ):
1146+ self .eval (ex )
1147+ return
1148+
11331149 res = self .eval (ex )
11341150 exp = eval (ex )
11351151 assert res == exp
@@ -1567,113 +1583,63 @@ def test_simple_in_ops(self):
15671583 "[3] not in (1, 2, [[3]])" , engine = self .engine , parser = self .parser
15681584 )
15691585
1570-
1571- @td .skip_if_no_ne
1572- class TestOperationsNumExprPython (TestOperationsNumExprPandas ):
1573- exclude_arith : list [str ] = ["in" , "not in" ]
1574-
1575- engine = "numexpr"
1576- parser = "python"
1577-
15781586 def test_check_many_exprs (self ):
15791587 a = 1 # noqa:F841
15801588 expr = " * " .join ("a" * 33 )
15811589 expected = 1
15821590 res = pd .eval (expr , engine = self .engine , parser = self .parser )
15831591 assert res == expected
15841592
1585- def test_fails_and (self ):
1586- df = DataFrame (np .random .randn (5 , 3 ))
1587- msg = "'BoolOp' nodes are not implemented"
1588- with pytest .raises (NotImplementedError , match = msg ):
1589- pd .eval (
1590- "df > 2 and df > 3" ,
1591- local_dict = {"df" : df },
1592- parser = self .parser ,
1593- engine = self .engine ,
1594- )
1595-
1596- def test_fails_or (self ):
1593+ @pytest .mark .parametrize (
1594+ "expr" ,
1595+ [
1596+ "df > 2 and df > 3" ,
1597+ "df > 2 or df > 3" ,
1598+ "not df > 2" ,
1599+ ],
1600+ )
1601+ def test_fails_and_or_not (self , expr ):
15971602 df = DataFrame (np .random .randn (5 , 3 ))
1598- msg = "'BoolOp' nodes are not implemented"
1599- with pytest .raises (NotImplementedError , match = msg ):
1600- pd .eval (
1601- "df > 2 or df > 3" ,
1602- local_dict = {"df" : df },
1603- parser = self .parser ,
1604- engine = self .engine ,
1605- )
1603+ if self .parser == "python" :
1604+ msg = "'BoolOp' nodes are not implemented"
1605+ if "not" in expr :
1606+ msg = "'Not' nodes are not implemented"
16061607
1607- def test_fails_not (self ):
1608- df = DataFrame (np .random .randn (5 , 3 ))
1609- msg = "'Not' nodes are not implemented"
1610- with pytest .raises (NotImplementedError , match = msg ):
1608+ with pytest .raises (NotImplementedError , match = msg ):
1609+ pd .eval (
1610+ expr ,
1611+ local_dict = {"df" : df },
1612+ parser = self .parser ,
1613+ engine = self .engine ,
1614+ )
1615+ else :
1616+ # smoke-test, should not raise
16111617 pd .eval (
1612- "not df > 2" ,
1618+ expr ,
16131619 local_dict = {"df" : df },
16141620 parser = self .parser ,
16151621 engine = self .engine ,
16161622 )
16171623
1618- def test_fails_ampersand (self ):
1619- df = DataFrame (np .random .randn (5 , 3 )) # noqa:F841
1620- ex = "(df + 2)[df > 1] > 0 & (df > 0)"
1621- msg = "cannot evaluate scalar only bool ops"
1622- with pytest .raises (NotImplementedError , match = msg ):
1623- pd .eval (ex , parser = self .parser , engine = self .engine )
1624-
1625- def test_fails_pipe (self ):
1624+ @pytest .mark .parametrize ("char" , ["|" , "&" ])
1625+ def test_fails_ampersand_pipe (self , char ):
16261626 df = DataFrame (np .random .randn (5 , 3 )) # noqa:F841
1627- ex = "(df + 2)[df > 1] > 0 | (df > 0)"
1628- msg = "cannot evaluate scalar only bool ops"
1629- with pytest .raises (NotImplementedError , match = msg ):
1630- pd .eval (ex , parser = self .parser , engine = self .engine )
1631-
1632- @pytest .mark .parametrize ("rhs" , [True , False ])
1633- @pytest .mark .parametrize ("lhs" , [True , False ])
1634- @pytest .mark .parametrize ("op" , expr .BOOL_OPS_SYMS )
1635- def test_bool_ops_with_constants (self , lhs , rhs , op ):
1636- ex = f"{ lhs } { op } { rhs } "
1637- if op in ("and" , "or" ):
1638- msg = "'BoolOp' nodes are not implemented"
1639- with pytest .raises (NotImplementedError , match = msg ):
1640- self .eval (ex )
1641- else :
1642- res = self .eval (ex )
1643- exp = eval (ex )
1644- assert res == exp
1645-
1646- @pytest .mark .parametrize ("rhs" , [True , False ])
1647- @pytest .mark .parametrize ("lhs" , [True , False ])
1648- @pytest .mark .parametrize ("op" , expr .BOOL_OPS_SYMS )
1649- def test_simple_bool_ops (self , lhs , rhs , op ):
1650- ex = f"lhs { op } rhs"
1651- if op in ("and" , "or" ):
1652- msg = "'BoolOp' nodes are not implemented"
1627+ ex = f"(df + 2)[df > 1] > 0 { char } (df > 0)"
1628+ if self .parser == "python" :
1629+ msg = "cannot evaluate scalar only bool ops"
16531630 with pytest .raises (NotImplementedError , match = msg ):
1654- pd .eval (ex , engine = self .engine , parser = self .parser )
1631+ pd .eval (ex , parser = self .parser , engine = self .engine )
16551632 else :
1656- res = pd .eval (ex , engine = self .engine , parser = self .parser )
1657- exp = eval (ex )
1658- assert res == exp
1659-
1660-
1661- class TestOperationsPythonPython (TestOperationsNumExprPython ):
1662- engine = "python"
1663- parser = "python"
1664-
1665-
1666- class TestOperationsPythonPandas (TestOperationsNumExprPandas ):
1667- exclude_arith : list [str ] = []
1668-
1669- engine = "python"
1670- parser = "pandas"
1633+ # smoke-test, should not raise
1634+ pd .eval (ex , parser = self .parser , engine = self .engine )
16711635
16721636
1673- @td .skip_if_no_ne
1674- class TestMathPythonPython :
1675- engine = "python"
1676- parser = "pandas"
1637+ class TestMath :
1638+ @pytest .fixture (autouse = True )
1639+ def set_engine_parser_attrs (self , engine , parser ):
1640+ # Older tests look for these as attributes, so we set them here.
1641+ self .engine = engine
1642+ self .parser = parser
16771643
16781644 def eval (self , * args , ** kwargs ):
16791645 kwargs ["engine" ] = self .engine
@@ -1764,21 +1730,6 @@ def test_keyword_arg(self):
17641730 df .eval ("sin(x=a)" , engine = self .engine , parser = self .parser )
17651731
17661732
1767- class TestMathPythonPandas (TestMathPythonPython ):
1768- engine = "python"
1769- parser = "pandas"
1770-
1771-
1772- class TestMathNumExprPandas (TestMathPythonPython ):
1773- engine = "numexpr"
1774- parser = "pandas"
1775-
1776-
1777- class TestMathNumExprPython (TestMathPythonPython ):
1778- engine = "numexpr"
1779- parser = "python"
1780-
1781-
17821733_var_s = np .random .randn (10 )
17831734
17841735
0 commit comments