@@ -115,6 +115,12 @@ def test_styler_to_excel_unstyled(engine):
115115 ["border" , "left" , "color" , "rgb" ],
116116 {"xlsxwriter" : "FF111222" , "openpyxl" : "00111222" },
117117 ),
118+ # Border styles
119+ (
120+ "border-left-style: hair; border-left-color: black" ,
121+ ["border" , "left" , "style" ],
122+ "hair" ,
123+ ),
118124]
119125
120126
@@ -196,6 +202,62 @@ def test_styler_to_excel_basic_indexes(engine, css, attrs, expected):
196202 assert sc_cell == expected
197203
198204
205+ # From https://openpyxl.readthedocs.io/en/stable/api/openpyxl.styles.borders.html
206+ # Note: Leaving behavior of "width"-type styles undefined; user should use border-width
207+ # instead
208+ excel_border_styles = [
209+ # "thin",
210+ "dashed" ,
211+ "mediumDashDot" ,
212+ "dashDotDot" ,
213+ "hair" ,
214+ "dotted" ,
215+ "mediumDashDotDot" ,
216+ # "medium",
217+ "double" ,
218+ "dashDot" ,
219+ "slantDashDot" ,
220+ # "thick",
221+ "mediumDashed" ,
222+ ]
223+
224+
225+ @pytest .mark .parametrize (
226+ "engine" ,
227+ ["xlsxwriter" , "openpyxl" ],
228+ )
229+ @pytest .mark .parametrize ("border_style" , excel_border_styles )
230+ def test_styler_to_excel_border_style (engine , border_style ):
231+ css = f"border-left: { border_style } black thin"
232+ attrs = ["border" , "left" , "style" ]
233+ expected = border_style
234+
235+ pytest .importorskip (engine )
236+ df = DataFrame (np .random .randn (1 , 1 ))
237+ styler = df .style .applymap (lambda x : css )
238+
239+ with tm .ensure_clean (".xlsx" ) as path :
240+ with ExcelWriter (path , engine = engine ) as writer :
241+ df .to_excel (writer , sheet_name = "dataframe" )
242+ styler .to_excel (writer , sheet_name = "styled" )
243+
244+ openpyxl = pytest .importorskip ("openpyxl" ) # test loading only with openpyxl
245+ with contextlib .closing (openpyxl .load_workbook (path )) as wb :
246+
247+ # test unstyled data cell does not have expected styles
248+ # test styled cell has expected styles
249+ u_cell , s_cell = wb ["dataframe" ].cell (2 , 2 ), wb ["styled" ].cell (2 , 2 )
250+ for attr in attrs :
251+ u_cell , s_cell = getattr (u_cell , attr , None ), getattr (s_cell , attr )
252+
253+ if isinstance (expected , dict ):
254+ assert u_cell is None or u_cell != expected [engine ]
255+ assert s_cell == expected [engine ]
256+ else :
257+ assert u_cell is None or u_cell != expected
258+ assert s_cell == expected
259+
260+
199261def test_styler_custom_converter ():
200262 openpyxl = pytest .importorskip ("openpyxl" )
201263
0 commit comments