Skip to content

Commit aee662a

Browse files
authored
TST: fixturize test_eval (#44675)
1 parent 6861fc5 commit aee662a

File tree

1 file changed

+68
-117
lines changed

1 file changed

+68
-117
lines changed

pandas/tests/computation/test_eval.py

Lines changed: 68 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)