Skip to content

Commit 6e0672d

Browse files
[WIP/rolling] test: Scope dataframe library imports to fixtures in conftest.py (#2241)
* test: Work towards making polars optional for tests This is a batch of changes aiming at making it possible to run the test suite without `polars` installed. Whenever easily feasible, the use of `pyarrow` and `pandas` was made optional as well. Part of bug #1726 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent ed29904 commit 6e0672d

25 files changed

+135
-63
lines changed

tests/conftest.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,14 @@
88
from typing import Callable
99
from typing import Sequence
1010

11-
import pandas as pd
12-
import polars as pl
13-
import pyarrow as pa
1411
import pytest
1512

1613
from narwhals.utils import generate_temporary_column_name
1714
from tests.utils import PANDAS_VERSION
1815

1916
if TYPE_CHECKING:
2017
import duckdb
18+
import polars as pl
2119

2220
from narwhals.typing import IntoDataFrame
2321
from narwhals.typing import IntoFrame
@@ -72,19 +70,26 @@ def pytest_collection_modifyitems(
7270

7371

7472
def pandas_constructor(obj: dict[str, list[Any]]) -> IntoDataFrame:
73+
import pandas as pd
74+
7575
return pd.DataFrame(obj)
7676

7777

7878
def pandas_nullable_constructor(obj: dict[str, list[Any]]) -> IntoDataFrame:
79+
import pandas as pd
80+
7981
return pd.DataFrame(obj).convert_dtypes(dtype_backend="numpy_nullable")
8082

8183

8284
def pandas_pyarrow_constructor(obj: dict[str, list[Any]]) -> IntoDataFrame:
85+
import pandas as pd
86+
8387
return pd.DataFrame(obj).convert_dtypes(dtype_backend="pyarrow")
8488

8589

8690
def modin_constructor(obj: dict[str, list[Any]]) -> IntoDataFrame: # pragma: no cover
8791
import modin.pandas as mpd
92+
import pandas as pd
8893

8994
return mpd.DataFrame(pd.DataFrame(obj)) # type: ignore[no-any-return]
9095

@@ -93,6 +98,7 @@ def modin_pyarrow_constructor(
9398
obj: dict[str, list[Any]],
9499
) -> IntoDataFrame: # pragma: no cover
95100
import modin.pandas as mpd
101+
import pandas as pd
96102

97103
return mpd.DataFrame(pd.DataFrame(obj)).convert_dtypes(dtype_backend="pyarrow") # type: ignore[no-any-return]
98104

@@ -104,15 +110,20 @@ def cudf_constructor(obj: dict[str, list[Any]]) -> IntoDataFrame: # pragma: no
104110

105111

106112
def polars_eager_constructor(obj: dict[str, list[Any]]) -> IntoDataFrame:
113+
import polars as pl
114+
107115
return pl.DataFrame(obj)
108116

109117

110118
def polars_lazy_constructor(obj: dict[str, list[Any]]) -> pl.LazyFrame:
119+
import polars as pl
120+
111121
return pl.LazyFrame(obj)
112122

113123

114124
def duckdb_lazy_constructor(obj: dict[str, list[Any]]) -> duckdb.DuckDBPyRelation:
115125
import duckdb
126+
import polars as pl
116127

117128
_df = pl.LazyFrame(obj)
118129
return duckdb.table("_df")
@@ -131,6 +142,8 @@ def dask_lazy_p2_constructor(obj: dict[str, list[Any]]) -> IntoFrame: # pragma:
131142

132143

133144
def pyarrow_table_constructor(obj: dict[str, Any]) -> IntoDataFrame:
145+
import pyarrow as pa
146+
134147
return pa.table(obj)
135148

136149

tests/dependencies/is_into_dataframe_test.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
from typing import Mapping
66

77
import numpy as np
8-
import pandas as pd
9-
import polars as pl
10-
import pyarrow as pa
8+
import pytest
119

1210
import narwhals as nw
1311
from narwhals.stable.v1.dependencies import is_into_dataframe
1412

1513
if TYPE_CHECKING:
1614
from typing_extensions import Self
1715

16+
DATA: dict[str, Any] = {"a": [1, 2, 3], "b": [4, 5, 6]}
17+
1818

1919
class DictDataFrame:
2020
def __init__(self: Self, data: Mapping[str, Any]) -> None:
@@ -27,12 +27,23 @@ def __narwhals_dataframe__(self) -> Self: # pragma: no cover
2727
return self
2828

2929

30-
def test_is_into_dataframe() -> None:
31-
data: dict[str, Any] = {"a": [1, 2, 3], "b": [4, 5, 6]}
32-
assert is_into_dataframe(pa.table(data))
33-
assert is_into_dataframe(pl.DataFrame(data))
34-
assert is_into_dataframe(pd.DataFrame(data))
35-
assert is_into_dataframe(nw.from_native(pd.DataFrame(data)))
36-
assert is_into_dataframe(DictDataFrame(data))
30+
def test_is_into_dataframe_pyarrow() -> None:
31+
pa = pytest.importorskip("pyarrow")
32+
assert is_into_dataframe(pa.table(DATA))
33+
34+
35+
def test_is_into_dataframe_polars() -> None:
36+
pl = pytest.importorskip("polars")
37+
assert is_into_dataframe(pl.DataFrame(DATA))
38+
39+
40+
def test_is_into_dataframe_pandas() -> None:
41+
pd = pytest.importorskip("pandas")
42+
assert is_into_dataframe(pd.DataFrame(DATA))
43+
assert is_into_dataframe(nw.from_native(pd.DataFrame(DATA)))
44+
45+
46+
def test_is_into_dataframe_other() -> None:
47+
assert is_into_dataframe(DictDataFrame(DATA))
3748
assert not is_into_dataframe(np.array([[1, 4], [2, 5], [3, 6]]))
38-
assert not is_into_dataframe(data)
49+
assert not is_into_dataframe(DATA)

tests/dependencies/is_into_series_test.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
from typing import Any
55

66
import numpy as np
7-
import pandas as pd
8-
import polars as pl
9-
import pyarrow as pa
7+
import pytest
108

119
import narwhals as nw
1210
from narwhals.stable.v1.dependencies import is_into_series
@@ -27,11 +25,23 @@ def __narwhals_series__(self) -> Self: # pragma: no cover
2725
return self
2826

2927

30-
def test_is_into_series() -> None:
28+
def test_is_into_series_pyarrow() -> None:
29+
pa = pytest.importorskip("pyarrow")
3130
assert is_into_series(pa.chunked_array([["a", "b"]]))
31+
32+
33+
def test_is_into_series_polars() -> None:
34+
pl = pytest.importorskip("polars")
3235
assert is_into_series(pl.Series([1, 2, 3]))
36+
37+
38+
def test_is_into_series_pandas() -> None:
39+
pd = pytest.importorskip("pandas")
3340
assert is_into_series(pd.Series([1, 2, 3]))
3441
assert is_into_series(nw.from_native(pd.Series([1, 2, 3]), series_only=True))
42+
43+
44+
def test_is_into_series() -> None:
3545
assert is_into_series(ListBackedSeries("a", [1, 4, 2]))
3646
assert not is_into_series(np.array([1, 2, 3]))
3747
assert not is_into_series([1, 2, 3])
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
from __future__ import annotations
22

33
import pandas as pd
4-
import polars as pl
4+
import pytest
55

66
from narwhals.stable.v1.dependencies import is_pandas_dataframe
77

88

99
def test_is_pandas_dataframe() -> None:
1010
assert is_pandas_dataframe(pd.DataFrame())
11+
12+
13+
def test_not_is_pandas_dataframe() -> None:
14+
pl = pytest.importorskip("polars")
1115
assert not is_pandas_dataframe(pl.DataFrame())

tests/dtypes_test.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import numpy as np
1010
import pandas as pd
11-
import polars as pl
1211
import pyarrow as pa
1312
import pytest
1413

@@ -222,6 +221,7 @@ def test_pandas_fixed_offset_1302() -> None:
222221

223222
def test_huge_int() -> None:
224223
duckdb = pytest.importorskip("duckdb")
224+
pl = pytest.importorskip("polars")
225225
df = pl.DataFrame({"a": [1, 2, 3]})
226226

227227
if POLARS_VERSION >= (1, 18):
@@ -252,6 +252,7 @@ def test_huge_int() -> None:
252252
@pytest.mark.skipif(PANDAS_VERSION < (1, 5), reason="too old for pyarrow")
253253
def test_decimal() -> None:
254254
duckdb = pytest.importorskip("duckdb")
255+
pl = pytest.importorskip("polars")
255256
df = pl.DataFrame({"a": [1]}, schema={"a": pl.Decimal})
256257
result = nw.from_native(df).schema
257258
assert result["a"] == nw.Decimal
@@ -325,6 +326,7 @@ def test_dtype_is_x() -> None:
325326
@pytest.mark.skipif(POLARS_VERSION < (1, 18), reason="too old for Int128")
326327
def test_huge_int_to_native() -> None:
327328
duckdb = pytest.importorskip("duckdb")
329+
pl = pytest.importorskip("polars")
328330
df = pl.DataFrame({"a": [1, 2, 3]})
329331
df_casted = (
330332
nw.from_native(df).with_columns(a_int=nw.col("a").cast(nw.Int128())).to_native()
@@ -350,6 +352,7 @@ def test_huge_int_to_native() -> None:
350352

351353
def test_cast_decimal_to_native() -> None:
352354
duckdb = pytest.importorskip("duckdb")
355+
pl = pytest.importorskip("polars")
353356
data = {"a": [1, 2, 3]}
354357

355358
df = pl.DataFrame(data)

tests/expr_and_series/cast_test.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
from datetime import time
55
from datetime import timedelta
66
from datetime import timezone
7-
from typing import Any
87

98
import pandas as pd
10-
import polars as pl
119
import pytest
1210

1311
import narwhals.stable.v1 as nw
@@ -312,11 +310,13 @@ def test_cast_struct(request: pytest.FixtureRequest, constructor: Constructor) -
312310
assert result.schema == {"a": dtype}
313311

314312

315-
@pytest.mark.parametrize("dtype", [pl.String, pl.String()])
316-
def test_raise_if_polars_dtype(constructor: Constructor, dtype: Any) -> None:
317-
df = nw.from_native(constructor({"a": [1, 2, 3], "b": [4, 5, 6]}))
318-
with pytest.raises(TypeError, match="Expected Narwhals dtype, got:"):
319-
df.select(nw.col("a").cast(dtype))
313+
def test_raise_if_polars_dtype(constructor: Constructor) -> None:
314+
pl = pytest.importorskip("polars")
315+
316+
for dtype in [pl.String, pl.String()]:
317+
df = nw.from_native(constructor({"a": [1, 2, 3], "b": [4, 5, 6]}))
318+
with pytest.raises(TypeError, match="Expected Narwhals dtype, got:"):
319+
df.select(nw.col("a").cast(dtype))
320320

321321

322322
def test_cast_time(request: pytest.FixtureRequest, constructor: Constructor) -> None:

tests/expr_and_series/nth_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from typing import Any
44
from typing import Mapping
55

6-
import polars as pl
76
import pytest
87

98
import narwhals.stable.v1 as nw
@@ -40,6 +39,7 @@ def test_nth(
4039
reason="1.0.0",
4140
)
4241
def test_nth_not_supported() -> None: # pragma: no cover
42+
pl = pytest.importorskip("polars")
4343
df = nw.from_native(pl.DataFrame(data))
4444
with pytest.raises(
4545
AttributeError, match="`nth` is only supported for Polars>=1.0.0."

tests/frame/arrow_c_stream_test.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
from __future__ import annotations
22

3-
import polars as pl
4-
import pyarrow as pa
5-
import pyarrow.compute as pc
63
import pytest
74

85
import narwhals.stable.v1 as nw
96
from tests.utils import POLARS_VERSION
107
from tests.utils import PYARROW_VERSION
118

9+
pl = pytest.importorskip("polars")
10+
pa = pytest.importorskip("pyarrow")
11+
pc = pytest.importorskip("pyarrow.compute")
12+
1213

1314
@pytest.mark.skipif(POLARS_VERSION < (1, 3), reason="too old for pycapsule in Polars")
1415
@pytest.mark.skipif(

tests/frame/getitem_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
import numpy as np
88
import pandas as pd
9-
import polars as pl
10-
import pyarrow as pa
119
import pytest
1210

1311
import narwhals.stable.v1 as nw
@@ -47,6 +45,7 @@ def test_slice_rows_with_step(
4745

4846

4947
def test_slice_rows_with_step_pyarrow() -> None:
48+
pa = pytest.importorskip("pyarrow")
5049
with pytest.raises(
5150
NotImplementedError,
5251
match="Slicing with step is not supported on PyArrow tables",
@@ -55,6 +54,7 @@ def test_slice_rows_with_step_pyarrow() -> None:
5554

5655

5756
def test_slice_lazy_fails() -> None:
57+
pl = pytest.importorskip("polars")
5858
with pytest.raises(TypeError, match="Slicing is not supported on LazyFrame"):
5959
_ = nw.from_native(pl.LazyFrame(data))[1:]
6060

tests/frame/interchange_native_namespace_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
from typing import Any
44
from typing import Mapping
55

6-
import polars as pl
76
import pytest
87

98
import narwhals.stable.v1 as nw
109

10+
pl = pytest.importorskip("polars")
11+
1112
data: Mapping[str, Any] = {"a": [1, 2, 3], "b": [4.5, 6.7, 8.9], "z": ["x", "y", "w"]}
1213

1314

0 commit comments

Comments
 (0)