Skip to content

Commit 3aba9bb

Browse files
jrw34FBruzzesi
andauthored
test: div by zero returns nan (#2636)
* Add tests for div by zero * Use constructor eager for to cover backend testing * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add lazy div by zero testing * add collect call to lazy constructors * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Created individual tests for floordiv and truediv by zero * Add polars backend specific division by zero return value * Exclude floordiv tests for pandas versions < 2.0 * Added pandas[nullable] conditional for floordiv by zero * Add float div by zero test for truediv, make new test file * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Ruff fixes --------- Co-authored-by: Francesco Bruzzesi <[email protected]>
1 parent ac32577 commit 3aba9bb

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
5+
import narwhals as nw
6+
from tests.utils import PANDAS_VERSION, Constructor, ConstructorEager, assert_equal_data
7+
8+
9+
@pytest.mark.parametrize(
10+
("left", "right", "expected"),
11+
[
12+
(-2, 0, float("-inf")),
13+
(-2.0, 0.0, float("-inf")),
14+
(0, 0, None),
15+
(0.0, 0.0, None),
16+
(2, 0, float("inf")),
17+
(2.0, 0.0, float("inf")),
18+
],
19+
)
20+
def test_series_truediv_by_zero(
21+
left: float, right: float, expected: float | None, constructor_eager: ConstructorEager
22+
) -> None:
23+
data: dict[str, list[int | float]] = {"a": [left], "b": [right]}
24+
df = nw.from_native(constructor_eager(data), eager_only=True)
25+
truediv_result = df["a"] / df["b"]
26+
assert_equal_data({"a": truediv_result}, {"a": [expected]})
27+
28+
29+
@pytest.mark.parametrize(
30+
("left", "right", "expected"),
31+
[(-2, 0, float("-inf")), (0, 0, None), (2, 0, float("inf"))],
32+
)
33+
@pytest.mark.skipif(PANDAS_VERSION < (2, 0), reason="converts floordiv by zero to 0")
34+
def test_series_floordiv_int_by_zero(
35+
left: int,
36+
right: int,
37+
expected: float | None,
38+
constructor_eager: ConstructorEager,
39+
request: pytest.FixtureRequest,
40+
) -> None:
41+
data: dict[str, list[int]] = {"a": [left], "b": [right]}
42+
df = nw.from_native(constructor_eager(data), eager_only=True)
43+
# pyarrow backend floordiv raises divide by zero error
44+
if "pyarrow" in str(constructor_eager):
45+
request.applymarker(pytest.mark.xfail)
46+
# polars backend floordiv by zero always returns null
47+
if "polars" in str(constructor_eager):
48+
floordiv_result = df["a"] // df["b"]
49+
assert all(floordiv_result.is_null())
50+
# pandas[nullable] backend floordiv always returns 0
51+
elif all(x in str(constructor_eager) for x in ["pandas", "nullable"]):
52+
floordiv_result = df["a"] // df["b"]
53+
assert_equal_data({"a": floordiv_result}, {"a": [0]})
54+
else:
55+
floordiv_result = df["a"] // df["b"]
56+
assert_equal_data({"a": floordiv_result}, {"a": [expected]})
57+
58+
59+
@pytest.mark.parametrize(
60+
("left", "right", "expected"),
61+
[
62+
(-2, 0, float("-inf")),
63+
(-2.0, 0.0, float("-inf")),
64+
(0, 0, None),
65+
(0.0, 0.0, None),
66+
(2, 0, float("inf")),
67+
(2.0, 0.0, float("inf")),
68+
],
69+
)
70+
def test_truediv_by_zero(
71+
left: float, right: float, expected: float | None, constructor: Constructor
72+
) -> None:
73+
data: dict[str, list[int | float]] = {"a": [left]}
74+
df = nw.from_native(constructor(data))
75+
truediv_result = df.select(nw.col("a") / right)
76+
assert_equal_data(truediv_result, {"a": [expected]})
77+
78+
79+
@pytest.mark.parametrize(
80+
("left", "right", "expected"),
81+
[(-2, 0, float("-inf")), (0, 0, None), (2, 0, float("inf"))],
82+
)
83+
@pytest.mark.skipif(PANDAS_VERSION < (2, 0), reason="converts floordiv by zero to 0")
84+
def test_floordiv_int_by_zero(
85+
left: int,
86+
right: int,
87+
expected: float | None,
88+
constructor: Constructor,
89+
request: pytest.FixtureRequest,
90+
) -> None:
91+
data: dict[str, list[int]] = {"a": [left]}
92+
df = nw.from_native(constructor(data))
93+
# pyarrow backend floordiv raises divide by zero error
94+
# ibis backend floordiv cannot cast value to inf or -inf
95+
if any(x in str(constructor) for x in ["ibis", "pyarrow"]):
96+
request.applymarker(pytest.mark.xfail)
97+
# duckdb backend floordiv return None
98+
if "duckdb" in str(constructor):
99+
floordiv_result = df.select(nw.col("a") // right)
100+
assert_equal_data(floordiv_result, {"a": [None]})
101+
# polars backend floordiv returns null
102+
elif "polars" in str(constructor) and "lazy" not in str(constructor):
103+
floordiv_result = df.select(nw.col("a") // right)
104+
assert all(floordiv_result["a"].is_null())
105+
# polars lazy floordiv cannot be sliced and returns None
106+
elif all(x in str(constructor) for x in ["polars", "lazy"]):
107+
floordiv_result = df.select(nw.col("a") // right)
108+
assert_equal_data(floordiv_result, {"a": [None]})
109+
# pandas[nullable] backend floordiv always returns 0
110+
elif all(x in str(constructor) for x in ["pandas", "nullable"]):
111+
floordiv_result = df.select(nw.col("a") // right)
112+
assert_equal_data(floordiv_result, {"a": [0]})
113+
else:
114+
floordiv_result = df.select(nw.col("a") // right)
115+
assert_equal_data(floordiv_result, {"a": [expected]})

0 commit comments

Comments
 (0)