projektAI/venv/Lib/site-packages/pandas/tests/io/excel/test_style.py

166 lines
6.3 KiB
Python
Raw Normal View History

2021-06-06 22:13:05 +02:00
import numpy as np
import pytest
from pandas import DataFrame
import pandas._testing as tm
from pandas.io.excel import ExcelWriter
from pandas.io.formats.excel import ExcelFormatter
@pytest.mark.parametrize(
"engine",
[
pytest.param(
"xlwt",
marks=pytest.mark.xfail(
reason="xlwt does not support openpyxl-compatible style dicts"
),
),
"xlsxwriter",
"openpyxl",
],
)
def test_styler_to_excel(engine):
def style(df):
# TODO: RGB colors not supported in xlwt
return DataFrame(
[
["font-weight: bold", "", ""],
["", "color: blue", ""],
["", "", "text-decoration: underline"],
["border-style: solid", "", ""],
["", "font-style: italic", ""],
["", "", "text-align: right"],
["background-color: red", "", ""],
["number-format: 0%", "", ""],
["", "", ""],
["", "", ""],
["", "", ""],
],
index=df.index,
columns=df.columns,
)
def assert_equal_style(cell1, cell2, engine):
if engine in ["xlsxwriter", "openpyxl"]:
pytest.xfail(
reason=(f"GH25351: failing on some attribute comparisons in {engine}")
)
# TODO: should find a better way to check equality
assert cell1.alignment.__dict__ == cell2.alignment.__dict__
assert cell1.border.__dict__ == cell2.border.__dict__
assert cell1.fill.__dict__ == cell2.fill.__dict__
assert cell1.font.__dict__ == cell2.font.__dict__
assert cell1.number_format == cell2.number_format
assert cell1.protection.__dict__ == cell2.protection.__dict__
def custom_converter(css):
# use bold iff there is custom style attached to the cell
if css.strip(" \n;"):
return {"font": {"bold": True}}
return {}
pytest.importorskip("jinja2")
pytest.importorskip(engine)
# Prepare spreadsheets
df = DataFrame(np.random.randn(11, 3))
with tm.ensure_clean(".xlsx" if engine != "xlwt" else ".xls") as path:
with ExcelWriter(path, engine=engine) as writer:
df.to_excel(writer, sheet_name="frame")
df.style.to_excel(writer, sheet_name="unstyled")
styled = df.style.apply(style, axis=None)
styled.to_excel(writer, sheet_name="styled")
ExcelFormatter(styled, style_converter=custom_converter).write(
writer, sheet_name="custom"
)
if engine not in ("openpyxl", "xlsxwriter"):
# For other engines, we only smoke test
return
openpyxl = pytest.importorskip("openpyxl")
wb = openpyxl.load_workbook(path)
# (1) compare DataFrame.to_excel and Styler.to_excel when unstyled
n_cells = 0
for col1, col2 in zip(wb["frame"].columns, wb["unstyled"].columns):
assert len(col1) == len(col2)
for cell1, cell2 in zip(col1, col2):
assert cell1.value == cell2.value
assert_equal_style(cell1, cell2, engine)
n_cells += 1
# ensure iteration actually happened:
assert n_cells == (11 + 1) * (3 + 1)
# (2) check styling with default converter
# TODO: openpyxl (as at 2.4) prefixes colors with 00, xlsxwriter with FF
alpha = "00" if engine == "openpyxl" else "FF"
n_cells = 0
for col1, col2 in zip(wb["frame"].columns, wb["styled"].columns):
assert len(col1) == len(col2)
for cell1, cell2 in zip(col1, col2):
ref = f"{cell2.column}{cell2.row:d}"
# TODO: this isn't as strong a test as ideal; we should
# confirm that differences are exclusive
if ref == "B2":
assert not cell1.font.bold
assert cell2.font.bold
elif ref == "C3":
assert cell1.font.color.rgb != cell2.font.color.rgb
assert cell2.font.color.rgb == alpha + "0000FF"
elif ref == "D4":
assert cell1.font.underline != cell2.font.underline
assert cell2.font.underline == "single"
elif ref == "B5":
assert not cell1.border.left.style
assert (
cell2.border.top.style
== cell2.border.right.style
== cell2.border.bottom.style
== cell2.border.left.style
== "medium"
)
elif ref == "C6":
assert not cell1.font.italic
assert cell2.font.italic
elif ref == "D7":
assert cell1.alignment.horizontal != cell2.alignment.horizontal
assert cell2.alignment.horizontal == "right"
elif ref == "B8":
assert cell1.fill.fgColor.rgb != cell2.fill.fgColor.rgb
assert cell1.fill.patternType != cell2.fill.patternType
assert cell2.fill.fgColor.rgb == alpha + "FF0000"
assert cell2.fill.patternType == "solid"
elif ref == "B9":
assert cell1.number_format == "General"
assert cell2.number_format == "0%"
else:
assert_equal_style(cell1, cell2, engine)
assert cell1.value == cell2.value
n_cells += 1
assert n_cells == (11 + 1) * (3 + 1)
# (3) check styling with custom converter
n_cells = 0
for col1, col2 in zip(wb["frame"].columns, wb["custom"].columns):
assert len(col1) == len(col2)
for cell1, cell2 in zip(col1, col2):
ref = f"{cell2.column}{cell2.row:d}"
if ref in ("B2", "C3", "D4", "B5", "C6", "D7", "B8", "B9"):
assert not cell1.font.bold
assert cell2.font.bold
else:
assert_equal_style(cell1, cell2, engine)
assert cell1.value == cell2.value
n_cells += 1
assert n_cells == (11 + 1) * (3 + 1)