|
16 | 16 |
|
17 | 17 | import pandas as pd
|
18 | 18 | from pandas import DataFrame, Index, MultiIndex
|
| 19 | +from pandas.formats.excel import ExcelFormatter |
19 | 20 | from pandas.io.parsers import read_csv
|
20 | 21 | from pandas.io.excel import (
|
21 | 22 | ExcelFile, ExcelWriter, read_excel, _XlwtWriter, _Openpyxl1Writer,
|
|
27 | 28 | import pandas.util.testing as tm
|
28 | 29 |
|
29 | 30 |
|
30 |
| -# FIXME: run all/some tests with plain Styler instead of DataFrame |
31 |
| -# FIXME: run some tests with styled Styler |
32 |
| - |
33 |
| - |
34 | 31 | def _skip_if_no_xlrd():
|
35 | 32 | try:
|
36 | 33 | import xlrd
|
@@ -2153,6 +2150,126 @@ def test_write_cells_merge_styled(self):
|
2153 | 2150 | self.assertEqual(xcell_b1.font, openpyxl_sty_merged)
|
2154 | 2151 | self.assertEqual(xcell_a2.font, openpyxl_sty_merged)
|
2155 | 2152 |
|
| 2153 | + def test_styler_to_excel(self): |
| 2154 | + if not openpyxl_compat.is_compat(major_ver=2): |
| 2155 | + pytest.skip('incompatible openpyxl version') |
| 2156 | + |
| 2157 | + def style(df): |
| 2158 | + return DataFrame([['font-weight: bold', '', ''], |
| 2159 | + ['', 'color: blue', ''], |
| 2160 | + ['', '', 'text-decoration: underline'], |
| 2161 | + ['border-style: solid', '', ''], |
| 2162 | + ['', 'font-style: italic', ''], |
| 2163 | + ['', '', 'text-align: right'], |
| 2164 | + ['background-color: red', '', ''], |
| 2165 | + ['', '', ''], |
| 2166 | + ['', '', ''], |
| 2167 | + ['', '', '']], |
| 2168 | + index=df.index, columns=df.columns) |
| 2169 | + |
| 2170 | + def assert_equal_style(cell1, cell2): |
| 2171 | + # XXX: should find a better way to check equality |
| 2172 | + assert cell1.alignment.__dict__ == cell2.alignment.__dict__ |
| 2173 | + assert cell1.border.__dict__ == cell2.border.__dict__ |
| 2174 | + assert cell1.fill.__dict__ == cell2.fill.__dict__ |
| 2175 | + assert cell1.font.__dict__ == cell2.font.__dict__ |
| 2176 | + assert cell1.number_format == cell2.number_format |
| 2177 | + assert cell1.protection.__dict__ == cell2.protection.__dict__ |
| 2178 | + |
| 2179 | + def custom_converter(css): |
| 2180 | + # use bold iff there is custom style attached to the cell |
| 2181 | + if css.strip(' \n;'): |
| 2182 | + return {'font': {'bold': True}} |
| 2183 | + return {} |
| 2184 | + |
| 2185 | + # Prepare spreadsheets |
| 2186 | + |
| 2187 | + df = DataFrame(np.random.randn(10, 3)) |
| 2188 | + with ensure_clean('.xlsx') as path: |
| 2189 | + writer = _Openpyxl22Writer(path) |
| 2190 | + df.to_excel(writer, engine='openpyxl', sheet_name='frame') |
| 2191 | + df.style.to_excel(writer, engine='openpyxl', sheet_name='unstyled') |
| 2192 | + styled = df.style.apply(style, axis=None) |
| 2193 | + styled.to_excel(writer, engine='openpyxl', sheet_name='styled') |
| 2194 | + ExcelFormatter(styled, style_converter=custom_converter).write( |
| 2195 | + writer, engine='openpyxl', sheet_name='custom') |
| 2196 | + |
| 2197 | + # (1) compare DataFrame.to_excel and Styler.to_excel when unstyled |
| 2198 | + n_cells = 0 |
| 2199 | + for col1, col2 in zip(writer.sheets['frame'], |
| 2200 | + writer.sheets['unstyled']): |
| 2201 | + assert len(col1) == len(col2) |
| 2202 | + for cell1, cell2 in zip(col1, col2): |
| 2203 | + assert cell1.value == cell2.value |
| 2204 | + assert_equal_style(cell1, cell2) |
| 2205 | + n_cells += 1 |
| 2206 | + |
| 2207 | + # ensure iteration actually happened: |
| 2208 | + assert n_cells == (10 + 1) * (3 + 1) |
| 2209 | + |
| 2210 | + # (2) check styling with default converter |
| 2211 | + n_cells = 0 |
| 2212 | + for col1, col2 in zip(writer.sheets['frame'], |
| 2213 | + writer.sheets['styled']): |
| 2214 | + assert len(col1) == len(col2) |
| 2215 | + for cell1, cell2 in zip(col1, col2): |
| 2216 | + ref = '%s%d' % (cell2.column, cell2.row) |
| 2217 | + # XXX: this isn't as strong a test as ideal; we should |
| 2218 | + # differences are exclusive |
| 2219 | + if ref == 'B2': |
| 2220 | + assert not cell1.font.bold |
| 2221 | + assert cell2.font.bold |
| 2222 | + elif ref == 'C3': |
| 2223 | + assert cell1.font.color.rgb != cell2.font.color.rgb |
| 2224 | + assert cell2.font.color.rgb == '000000FF' |
| 2225 | + elif ref == 'D4': |
| 2226 | + assert cell1.font.underline != cell2.font.underline |
| 2227 | + assert cell2.font.underline == 'single' |
| 2228 | + elif ref == 'B5': |
| 2229 | + assert not cell1.border.left.style |
| 2230 | + assert (cell2.border.top.style == |
| 2231 | + cell2.border.right.style == |
| 2232 | + cell2.border.bottom.style == |
| 2233 | + cell2.border.left.style == |
| 2234 | + 'medium') |
| 2235 | + elif ref == 'C6': |
| 2236 | + assert not cell1.font.italic |
| 2237 | + assert cell2.font.italic |
| 2238 | + elif ref == 'D7': |
| 2239 | + assert (cell1.alignment.horizontal != |
| 2240 | + cell2.alignment.horizontal) |
| 2241 | + assert cell2.alignment.horizontal == 'right' |
| 2242 | + elif ref == 'B8': |
| 2243 | + assert cell1.fill.fgColor.rgb != cell2.fill.fgColor.rgb |
| 2244 | + assert cell1.fill.patternType != cell2.fill.patternType |
| 2245 | + assert cell2.fill.fgColor.rgb == '00FF0000' |
| 2246 | + assert cell2.fill.patternType == 'solid' |
| 2247 | + else: |
| 2248 | + assert_equal_style(cell1, cell2) |
| 2249 | + |
| 2250 | + assert cell1.value == cell2.value |
| 2251 | + n_cells += 1 |
| 2252 | + |
| 2253 | + assert n_cells == (10 + 1) * (3 + 1) |
| 2254 | + |
| 2255 | + # (3) check styling with custom converter |
| 2256 | + n_cells = 0 |
| 2257 | + for col1, col2 in zip(writer.sheets['frame'], |
| 2258 | + writer.sheets['custom']): |
| 2259 | + assert len(col1) == len(col2) |
| 2260 | + for cell1, cell2 in zip(col1, col2): |
| 2261 | + ref = '%s%d' % (cell2.column, cell2.row) |
| 2262 | + if ref in ('B2', 'C3', 'D4', 'B5', 'C6', 'D7', 'B8'): |
| 2263 | + assert not cell1.font.bold |
| 2264 | + assert cell2.font.bold |
| 2265 | + else: |
| 2266 | + assert_equal_style(cell1, cell2) |
| 2267 | + |
| 2268 | + assert cell1.value == cell2.value |
| 2269 | + n_cells += 1 |
| 2270 | + |
| 2271 | + assert n_cells == (10 + 1) * (3 + 1) |
| 2272 | + |
2156 | 2273 |
|
2157 | 2274 | class XlwtTests(ExcelWriterBase, tm.TestCase):
|
2158 | 2275 | ext = '.xls'
|
|
0 commit comments