Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions pandas/tests/io/excel/test_openpyxl.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@

openpyxl = pytest.importorskip("openpyxl")

# xfail marker for pending autofilter feature; see #62994
xfail_autofilter = pytest.mark.xfail(
reason="Excel header autofilter not yet implemented on main; see #62994",
strict=False,
)


@pytest.fixture
def ext():
Expand Down Expand Up @@ -155,6 +161,90 @@ def test_engine_kwargs_append_data_only(tmp_excel, data_only, expected):
)


@xfail_autofilter
def test_to_excel_autofilter_openpyxl(tmp_excel):
# Ensure that writing with autofilter=True sets auto_filter.ref
df = DataFrame({"A": [1, 2], "B": [3, 4]})
df.to_excel(tmp_excel, engine="openpyxl", index=False, autofilter=True)

with contextlib.closing(openpyxl.load_workbook(tmp_excel)) as wb:
ws = wb[wb.sheetnames[0]]
# Expect filter over the full range, e.g. A1:B3 (header + 2 rows)
assert ws.auto_filter is not None
assert ws.auto_filter.ref is not None
# Verify filter covers all columns (A and B)
assert "A" in ws.auto_filter.ref
assert "B" in ws.auto_filter.ref


@xfail_autofilter
def test_to_excel_autofilter_startrow_startcol_openpyxl(tmp_excel):
# Test autofilter with nonzero startrow and startcol
df = DataFrame({"A": [1, 2], "B": [3, 4]})
df.to_excel(
tmp_excel,
engine="openpyxl",
index=False,
autofilter=True,
startrow=2,
startcol=1,
)

with contextlib.closing(openpyxl.load_workbook(tmp_excel)) as wb:
ws = wb[wb.sheetnames[0]]
assert ws.auto_filter is not None
assert ws.auto_filter.ref is not None
# Filter should be offset by startrow=2 and startcol=1 (B3:D5)
assert ws.auto_filter.ref.startswith("B")
assert "3" in ws.auto_filter.ref


@xfail_autofilter
def test_to_excel_autofilter_multiindex_merge_cells_openpyxl(tmp_excel):
# Test autofilter with MultiIndex columns and merge_cells=True
df = DataFrame(
[[1, 2, 3, 4], [5, 6, 7, 8]],
columns=pd.MultiIndex.from_tuples(
[("A", "a"), ("A", "b"), ("B", "a"), ("B", "b")]
),
)
df.to_excel(
tmp_excel,
engine="openpyxl",
index=False,
autofilter=True,
merge_cells=True,
)

with contextlib.closing(openpyxl.load_workbook(tmp_excel)) as wb:
ws = wb[wb.sheetnames[0]]
assert ws.auto_filter is not None
assert ws.auto_filter.ref is not None


@xfail_autofilter
def test_to_excel_autofilter_multiindex_no_merge_openpyxl(tmp_excel):
# Test autofilter with MultiIndex columns and merge_cells=False
df = DataFrame(
[[1, 2, 3, 4], [5, 6, 7, 8]],
columns=pd.MultiIndex.from_tuples(
[("A", "a"), ("A", "b"), ("B", "a"), ("B", "b")]
),
)
df.to_excel(
tmp_excel,
engine="openpyxl",
index=False,
autofilter=True,
merge_cells=False,
)

with contextlib.closing(openpyxl.load_workbook(tmp_excel)) as wb:
ws = wb[wb.sheetnames[0]]
assert ws.auto_filter is not None
assert ws.auto_filter.ref is not None


@pytest.mark.parametrize("kwarg_name", ["read_only", "data_only"])
@pytest.mark.parametrize("kwarg_value", [True, False])
def test_engine_kwargs_append_reader(datapath, ext, kwarg_name, kwarg_value):
Expand Down
107 changes: 107 additions & 0 deletions pandas/tests/io/excel/test_xlsxwriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@

import pytest

import pandas as pd
from pandas import DataFrame

from pandas.io.excel import ExcelWriter

xlsxwriter = pytest.importorskip("xlsxwriter")

# xfail marker for pending autofilter feature; see #62994
xfail_autofilter = pytest.mark.xfail(
reason="Excel header autofilter not yet implemented on main; see #62994",
strict=False,
)


@pytest.fixture
def ext():
Expand Down Expand Up @@ -84,3 +91,103 @@ def test_book_and_sheets_consistent(tmp_excel):
assert writer.sheets == {}
sheet = writer.book.add_worksheet("test_name")
assert writer.sheets == {"test_name": sheet}


@xfail_autofilter
def test_to_excel_autofilter_xlsxwriter(tmp_excel):
openpyxl = pytest.importorskip("openpyxl")

df = DataFrame({"A": [1, 2], "B": [3, 4]})
# Write with xlsxwriter, verify via openpyxl that an autofilter exists
df.to_excel(tmp_excel, engine="xlsxwriter", index=False, autofilter=True)

wb = openpyxl.load_workbook(tmp_excel)
try:
ws = wb[wb.sheetnames[0]]
assert ws.auto_filter is not None
assert ws.auto_filter.ref is not None
# Verify filter covers all columns (A and B)
assert "A" in ws.auto_filter.ref
assert "B" in ws.auto_filter.ref
finally:
wb.close()


@xfail_autofilter
def test_to_excel_autofilter_startrow_startcol_xlsxwriter(tmp_excel):
openpyxl = pytest.importorskip("openpyxl")

df = DataFrame({"A": [1, 2], "B": [3, 4]})
df.to_excel(
tmp_excel,
engine="xlsxwriter",
index=False,
autofilter=True,
startrow=2,
startcol=1,
)

wb = openpyxl.load_workbook(tmp_excel)
try:
ws = wb[wb.sheetnames[0]]
assert ws.auto_filter is not None
assert ws.auto_filter.ref is not None
# Filter should be offset by startrow=2 and startcol=1 (B3:D5)
assert ws.auto_filter.ref.startswith("B")
assert "3" in ws.auto_filter.ref
finally:
wb.close()


@xfail_autofilter
def test_to_excel_autofilter_multiindex_merge_cells_xlsxwriter(tmp_excel):
openpyxl = pytest.importorskip("openpyxl")

df = DataFrame(
[[1, 2, 3, 4], [5, 6, 7, 8]],
columns=pd.MultiIndex.from_tuples(
[("A", "a"), ("A", "b"), ("B", "a"), ("B", "b")]
),
)
df.to_excel(
tmp_excel,
engine="xlsxwriter",
index=False,
autofilter=True,
merge_cells=True,
)

wb = openpyxl.load_workbook(tmp_excel)
try:
ws = wb[wb.sheetnames[0]]
assert ws.auto_filter is not None
assert ws.auto_filter.ref is not None
finally:
wb.close()


@xfail_autofilter
def test_to_excel_autofilter_multiindex_no_merge_xlsxwriter(tmp_excel):
openpyxl = pytest.importorskip("openpyxl")

df = DataFrame(
[[1, 2, 3, 4], [5, 6, 7, 8]],
columns=pd.MultiIndex.from_tuples(
[("A", "a"), ("A", "b"), ("B", "a"), ("B", "b")]
),
)
df.to_excel(
tmp_excel,
engine="xlsxwriter",
index=False,
autofilter=True,
merge_cells=False,
)

wb = openpyxl.load_workbook(tmp_excel)
try:
ws = wb[wb.sheetnames[0]]
assert ws.auto_filter is not None
assert ws.auto_filter.ref is not None
finally:
wb.close()
Loading