Skip to content

Commit 3f687c4

Browse files
committed
Test xlsxwriter styling
1 parent b19ae90 commit 3f687c4

File tree

4 files changed

+90
-81
lines changed

4 files changed

+90
-81
lines changed

doc/source/style.ipynb

+1-1
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@
918918
"\n",
919919
"<span style=\"color: red\">*Experimental: This is a new feature and still under development. We'll be adding features and possibly making breaking changes in future releases. We'd love to hear your feedback.*</span>\n",
920920
"\n",
921-
"Some support is available for exporting styled `DataFrames` to Excel worksheets using the `OpenPyXL` engine. CSS2.2 properties handled include:\n",
921+
"Some support is available for exporting styled `DataFrames` to Excel worksheets using the `OpenPyXL` or `xlsxwriter` engines. CSS2.2 properties handled include:\n",
922922
"\n",
923923
"- `background-color`\n",
924924
"- `border-style`, `border-width`, `border-color` and their {`top`, `right`, `bottom`, `left` variants}\n",

doc/source/whatsnew/v0.20.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ To convert a ``SparseDataFrame`` back to sparse SciPy matrix in COO format, you
368368
Excel output for styled DataFrames
369369
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
370370

371-
Experimental support has been added to export ``DataFrame.style`` formats to Excel using the ``openpyxl`` engine. (:issue:`15530`)
371+
Experimental support has been added to export ``DataFrame.style`` formats to Excel using the ``openpyxl`` or ``xlsxwriter`` engines. (:issue:`15530`, :issue:`16149`)
372372

373373
For example, after running the following, ``styled.xlsx`` renders as below:
374374

pandas/io/excel.py

+1
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,7 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0,
16021602
(('font', 'sz'), 'font_size'),
16031603
(('font', 'size'), 'font_size'),
16041604
(('font', 'color', 'rgb'), 'font_color'),
1605+
(('font', 'color'), 'font_color'),
16051606
(('font', 'b'), 'bold'),
16061607
(('font', 'bold'), 'bold'),
16071608
(('font', 'i'), 'italic'),

pandas/tests/io/test_excel.py

+87-79
Original file line numberDiff line numberDiff line change
@@ -2408,85 +2408,93 @@ def custom_converter(css):
24082408
styled.to_excel(writer, sheet_name='styled')
24092409
ExcelFormatter(styled, style_converter=custom_converter).write(
24102410
writer, sheet_name='custom')
2411+
writer.save()
24112412

2412-
# For engines other than openpyxl 2, we only smoke test
2413-
if engine != 'openpyxl':
2414-
return
2415-
if not openpyxl_compat.is_compat(major_ver=2):
2416-
pytest.skip('incompatible openpyxl version')
2417-
2418-
# (1) compare DataFrame.to_excel and Styler.to_excel when unstyled
2419-
n_cells = 0
2420-
for col1, col2 in zip(writer.sheets['frame'].columns,
2421-
writer.sheets['unstyled'].columns):
2422-
assert len(col1) == len(col2)
2423-
for cell1, cell2 in zip(col1, col2):
2424-
assert cell1.value == cell2.value
2425-
assert_equal_style(cell1, cell2)
2426-
n_cells += 1
2427-
2428-
# ensure iteration actually happened:
2429-
assert n_cells == (10 + 1) * (3 + 1)
2430-
2431-
# (2) check styling with default converter
2432-
n_cells = 0
2433-
for col1, col2 in zip(writer.sheets['frame'].columns,
2434-
writer.sheets['styled'].columns):
2435-
assert len(col1) == len(col2)
2436-
for cell1, cell2 in zip(col1, col2):
2437-
ref = '%s%d' % (cell2.column, cell2.row)
2438-
# XXX: this isn't as strong a test as ideal; we should
2439-
# differences are exclusive
2440-
if ref == 'B2':
2441-
assert not cell1.font.bold
2442-
assert cell2.font.bold
2443-
elif ref == 'C3':
2444-
assert cell1.font.color.rgb != cell2.font.color.rgb
2445-
assert cell2.font.color.rgb == '000000FF'
2446-
elif ref == 'D4':
2447-
assert cell1.font.underline != cell2.font.underline
2448-
assert cell2.font.underline == 'single'
2449-
elif ref == 'B5':
2450-
assert not cell1.border.left.style
2451-
assert (cell2.border.top.style ==
2452-
cell2.border.right.style ==
2453-
cell2.border.bottom.style ==
2454-
cell2.border.left.style ==
2455-
'medium')
2456-
elif ref == 'C6':
2457-
assert not cell1.font.italic
2458-
assert cell2.font.italic
2459-
elif ref == 'D7':
2460-
assert (cell1.alignment.horizontal !=
2461-
cell2.alignment.horizontal)
2462-
assert cell2.alignment.horizontal == 'right'
2463-
elif ref == 'B8':
2464-
assert cell1.fill.fgColor.rgb != cell2.fill.fgColor.rgb
2465-
assert cell1.fill.patternType != cell2.fill.patternType
2466-
assert cell2.fill.fgColor.rgb == '00FF0000'
2467-
assert cell2.fill.patternType == 'solid'
2468-
else:
2469-
assert_equal_style(cell1, cell2)
2470-
2471-
assert cell1.value == cell2.value
2472-
n_cells += 1
2473-
2474-
assert n_cells == (10 + 1) * (3 + 1)
2475-
2476-
# (3) check styling with custom converter
2477-
n_cells = 0
2478-
for col1, col2 in zip(writer.sheets['frame'].columns,
2479-
writer.sheets['custom'].columns):
2480-
assert len(col1) == len(col2)
2481-
for cell1, cell2 in zip(col1, col2):
2482-
ref = '%s%d' % (cell2.column, cell2.row)
2483-
if ref in ('B2', 'C3', 'D4', 'B5', 'C6', 'D7', 'B8'):
2484-
assert not cell1.font.bold
2485-
assert cell2.font.bold
2486-
else:
2487-
assert_equal_style(cell1, cell2)
2413+
if engine not in ('openpyxl', 'xlsxwriter'):
2414+
# For other engines, we only smoke test
2415+
return
2416+
openpyxl = pytest.importorskip('openpyxl')
2417+
if not openpyxl_compat.is_compat(major_ver=2):
2418+
pytest.skip('incompatible openpyxl version')
24882419

2489-
assert cell1.value == cell2.value
2490-
n_cells += 1
2420+
wb = openpyxl.load_workbook(path)
24912421

2492-
assert n_cells == (10 + 1) * (3 + 1)
2422+
# (1) compare DataFrame.to_excel and Styler.to_excel when unstyled
2423+
n_cells = 0
2424+
for col1, col2 in zip(wb['frame'].columns,
2425+
wb['unstyled'].columns):
2426+
assert len(col1) == len(col2)
2427+
for cell1, cell2 in zip(col1, col2):
2428+
assert cell1.value == cell2.value
2429+
assert_equal_style(cell1, cell2)
2430+
n_cells += 1
2431+
2432+
# ensure iteration actually happened:
2433+
assert n_cells == (10 + 1) * (3 + 1)
2434+
2435+
# (2) check styling with default converter
2436+
2437+
# XXX: openpyxl (as at 2.4) prefixes colors with 00, xlsxwriter with FF
2438+
alpha = '00' if engine == 'openpyxl' else 'FF'
2439+
2440+
n_cells = 0
2441+
for col1, col2 in zip(wb['frame'].columns,
2442+
wb['styled'].columns):
2443+
assert len(col1) == len(col2)
2444+
for cell1, cell2 in zip(col1, col2):
2445+
ref = '%s%d' % (cell2.column, cell2.row)
2446+
# XXX: this isn't as strong a test as ideal; we should
2447+
# confirm that differences are exclusive
2448+
if ref == 'B2':
2449+
assert not cell1.font.bold
2450+
assert cell2.font.bold
2451+
elif ref == 'C3':
2452+
assert cell1.font.color.rgb != cell2.font.color.rgb
2453+
assert cell2.font.color.rgb == alpha + '0000FF'
2454+
elif ref == 'D4':
2455+
assert cell1.font.underline != cell2.font.underline
2456+
assert cell2.font.underline == 'single'
2457+
elif ref == 'B5':
2458+
assert not cell1.border.left.style
2459+
assert (cell2.border.top.style ==
2460+
cell2.border.right.style ==
2461+
cell2.border.bottom.style ==
2462+
cell2.border.left.style ==
2463+
'medium')
2464+
elif ref == 'C6':
2465+
assert not cell1.font.italic
2466+
assert cell2.font.italic
2467+
elif ref == 'D7':
2468+
assert (cell1.alignment.horizontal !=
2469+
cell2.alignment.horizontal)
2470+
assert cell2.alignment.horizontal == 'right'
2471+
elif ref == 'B8':
2472+
assert cell1.fill.fgColor.rgb != cell2.fill.fgColor.rgb
2473+
assert cell1.fill.patternType != cell2.fill.patternType
2474+
assert cell2.fill.fgColor.rgb == alpha + 'FF0000'
2475+
assert cell2.fill.patternType == 'solid'
2476+
else:
2477+
assert_equal_style(cell1, cell2)
2478+
2479+
assert cell1.value == cell2.value
2480+
n_cells += 1
2481+
2482+
assert n_cells == (10 + 1) * (3 + 1)
2483+
2484+
# (3) check styling with custom converter
2485+
n_cells = 0
2486+
for col1, col2 in zip(wb['frame'].columns,
2487+
wb['custom'].columns):
2488+
assert len(col1) == len(col2)
2489+
for cell1, cell2 in zip(col1, col2):
2490+
ref = '%s%d' % (cell2.column, cell2.row)
2491+
if ref in ('B2', 'C3', 'D4', 'B5', 'C6', 'D7', 'B8'):
2492+
assert not cell1.font.bold
2493+
assert cell2.font.bold
2494+
else:
2495+
assert_equal_style(cell1, cell2)
2496+
2497+
assert cell1.value == cell2.value
2498+
n_cells += 1
2499+
2500+
assert n_cells == (10 + 1) * (3 + 1)

0 commit comments

Comments
 (0)