Skip to content

Commit 46f318b

Browse files
authored
test: cover pandas and Dask integrations (#67)
1 parent 78dc2d3 commit 46f318b

4 files changed

Lines changed: 417 additions & 0 deletions

File tree

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ bench = [
2929
]
3030
test = [
3131
"boto3>=1.37.3",
32+
"dask[dataframe]==2026.8.0",
33+
"pandas==3.0.5",
3234
"pyarrow>=22.0.0",
3335
"pytest>=8.4.0",
3436
"pytest-asyncio>=1.0.0",
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""Dask dataframe fsspec entry points against OpenDAL services.
2+
3+
Adapted from Dask ``test_read_csv_files`` and
4+
``test_multiple_read_csv_has_deterministic_name`` in
5+
``dask/dataframe/io/tests/test_csv.py``, plus
6+
``test_fsspec_to_parquet_filesystem_option`` in
7+
``dask/dataframe/io/tests/test_parquet.py``, from the Dask 2026.8.0 release.
8+
"""
9+
10+
import dask.dataframe as dd
11+
import pandas as pd
12+
import pandas.testing as tm
13+
import pytest
14+
15+
from opendalfs import register_opendal_service
16+
17+
18+
@pytest.fixture
19+
def opendal_memory_url():
20+
import fsspec
21+
22+
register_opendal_service("memory")
23+
url = "opendal+memory://test/dask"
24+
fs, path = fsspec.core.url_to_fs(url)
25+
if fs.exists(path):
26+
fs.rm(path, recursive=True)
27+
yield fs, url, path
28+
if fs.exists(path):
29+
fs.rm(path, recursive=True)
30+
31+
32+
def test_read_csv_url_glob_and_tokenization(opendal_memory_url):
33+
fs, base_url, base_path = opendal_memory_url
34+
files = {
35+
"2014-01-01.csv": b"name,amount,id\nAlice,100,1\nBob,200,2\n",
36+
"2014-01-02.csv": b"name,amount,id\nCharlie,300,3\n",
37+
}
38+
for name, content in files.items():
39+
fs.pipe_file(f"{base_path}/{name}", content)
40+
41+
first = dd.read_csv(f"{base_url}/2014-01-*.csv")
42+
second = dd.read_csv(f"{base_url}/2014-01-*.csv")
43+
expected = pd.DataFrame({
44+
"name": ["Alice", "Bob", "Charlie"],
45+
"amount": [100, 200, 300],
46+
"id": [1, 2, 3],
47+
})
48+
49+
assert first._name == second._name
50+
assert sorted(first.dask.keys(), key=str) == sorted(second.dask.keys(), key=str)
51+
tm.assert_frame_equal(
52+
first.compute().reset_index(drop=True),
53+
expected.reset_index(drop=True),
54+
check_dtype=False,
55+
)
56+
57+
58+
def test_read_parquet_url(s3_fs, s3_config):
59+
expected = pd.DataFrame({"a": range(10)})
60+
path = "dask/url.parquet"
61+
expected.to_parquet(path, filesystem=s3_fs)
62+
url = f"opendal+s3://{s3_config.bucket}/{path}"
63+
storage_options = {
64+
"endpoint": s3_config.endpoint,
65+
"region": s3_config.region,
66+
"access_key_id": s3_config.access_key_id,
67+
"secret_access_key": s3_config.secret_access_key,
68+
}
69+
70+
result = dd.read_parquet(url, storage_options=storage_options).compute()
71+
72+
tm.assert_frame_equal(result, expected)
73+
74+
75+
def test_read_parquet_filesystem(s3_fs):
76+
expected = pd.DataFrame({"a": range(10)})
77+
path = "dask/filesystem.parquet"
78+
expected.to_parquet(path, filesystem=s3_fs)
79+
80+
result = dd.read_parquet(path, filesystem=s3_fs).compute()
81+
82+
tm.assert_frame_equal(result, expected)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""pandas fsspec entry points against OpenDAL's memory service.
2+
3+
Adapted from pandas ``test_read_csv`` and ``test_arrowparquet_options`` in
4+
``pandas/tests/io/test_fsspec.py``, plus ``test_s3_roundtrip_explicit_fs`` in
5+
``pandas/tests/io/test_parquet.py``, from the pandas 3.0.5 release.
6+
"""
7+
8+
import pandas as pd
9+
import pandas.testing as tm
10+
import pytest
11+
12+
from opendalfs import register_opendal_service
13+
14+
15+
@pytest.fixture
16+
def opendal_memory_url():
17+
import fsspec
18+
19+
register_opendal_service("memory")
20+
url = "opendal+memory://test/pandas"
21+
fs, path = fsspec.core.url_to_fs(url)
22+
if fs.exists(path):
23+
fs.rm(path, recursive=True)
24+
yield fs, url, path
25+
if fs.exists(path):
26+
fs.rm(path, recursive=True)
27+
28+
29+
def test_read_csv_url(opendal_memory_url):
30+
fs, base_url, base_path = opendal_memory_url
31+
expected = pd.DataFrame({
32+
"int": [1, 3],
33+
"float": [2.0, None],
34+
"str": ["t", "s"],
35+
"dt": pd.date_range("2018-06-18", periods=2),
36+
})
37+
fs.pipe_file(
38+
f"{base_path}/test.csv",
39+
expected.to_csv(index=False).encode(),
40+
)
41+
42+
result = pd.read_csv(f"{base_url}/test.csv", parse_dates=["dt"])
43+
44+
tm.assert_frame_equal(result, expected)
45+
46+
47+
def test_parquet_url_roundtrip(opendal_memory_url):
48+
_, base_url, _ = opendal_memory_url
49+
expected = pd.DataFrame({"a": [0, 1], "b": ["x", "y"]})
50+
url = f"{base_url}/test.parquet"
51+
52+
expected.to_parquet(url, engine="pyarrow", compression=None)
53+
result = pd.read_parquet(url, engine="pyarrow")
54+
55+
tm.assert_frame_equal(result, expected)
56+
57+
58+
def test_parquet_filesystem_roundtrip(opendal_memory_url):
59+
fs, _, base_path = opendal_memory_url
60+
expected = pd.DataFrame({"a": [0, 1], "b": ["x", "y"]})
61+
path = f"{base_path}/filesystem.parquet"
62+
63+
expected.to_parquet(path, engine="pyarrow", filesystem=fs, compression=None)
64+
result = pd.read_parquet(path, engine="pyarrow", filesystem=fs)
65+
66+
tm.assert_frame_equal(result, expected)

0 commit comments

Comments
 (0)