11from __future__ import annotations
2-
32import json
43from typing import (
54 TYPE_CHECKING ,
65 Any ,
76)
8-
97from pandas .io .excel ._base import ExcelWriter
108from pandas .io .excel ._util import (
119 combine_kwargs ,
1210 validate_freeze_panes ,
1311)
14-
1512if TYPE_CHECKING :
1613 from pandas ._typing import (
1714 ExcelWriterIfSheetExists ,
1815 FilePath ,
1916 StorageOptions ,
2017 WriteExcelBuffer ,
2118 )
22-
23-
2419class _XlsxStyler :
2520 # Map from openpyxl-oriented styles to flatter xlsxwriter representation
2621 # Ordering necessary for both determinism and because some are keyed by
@@ -91,30 +86,24 @@ class _XlsxStyler:
9186 (("left" ,), "left" ),
9287 ],
9388 }
94-
9589 @classmethod
9690 def convert (cls , style_dict , num_format_str = None ) -> dict [str , Any ]:
9791 """
9892 converts a style_dict to an xlsxwriter format dict
99-
10093 Parameters
10194 ----------
10295 style_dict : style dictionary to convert
10396 num_format_str : optional number format string
10497 """
10598 # Create a XlsxWriter format object.
10699 props = {}
107-
108100 if num_format_str is not None :
109101 props ["num_format" ] = num_format_str
110-
111102 if style_dict is None :
112103 return props
113-
114104 if "borders" in style_dict :
115105 style_dict = style_dict .copy ()
116106 style_dict ["border" ] = style_dict .pop ("borders" )
117-
118107 for style_group_key , style_group in style_dict .items ():
119108 for src , dst in cls .STYLE_MAPPING .get (style_group_key , []):
120109 # src is a sequence of keys into a nested dict
@@ -129,11 +118,9 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]:
129118 break
130119 else :
131120 props [dst ] = v
132-
133121 if isinstance (props .get ("pattern" ), str ):
134122 # TODO: support other fill patterns
135123 props ["pattern" ] = 0 if props ["pattern" ] == "none" else 1
136-
137124 for k in ["border" , "top" , "right" , "bottom" , "left" ]:
138125 if isinstance (props .get (k ), str ):
139126 try :
@@ -155,12 +142,10 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]:
155142 ].index (props [k ])
156143 except ValueError :
157144 props [k ] = 2
158-
159145 if isinstance (props .get ("font_script" ), str ):
160146 props ["font_script" ] = ["baseline" , "superscript" , "subscript" ].index (
161147 props ["font_script" ]
162148 )
163-
164149 if isinstance (props .get ("underline" ), str ):
165150 props ["underline" ] = {
166151 "none" : 0 ,
@@ -169,18 +154,13 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]:
169154 "singleAccounting" : 33 ,
170155 "doubleAccounting" : 34 ,
171156 }[props ["underline" ]]
172-
173157 # GH 30107 - xlsxwriter uses different name
174158 if props .get ("valign" ) == "center" :
175159 props ["valign" ] = "vcenter"
176-
177160 return props
178-
179-
180161class XlsxWriter (ExcelWriter ):
181162 _engine = "xlsxwriter"
182163 _supported_extensions = (".xlsx" ,)
183-
184164 def __init__ ( # pyright: ignore[reportInconsistentConstructor]
185165 self ,
186166 path : FilePath | WriteExcelBuffer | ExcelWriter ,
@@ -195,12 +175,9 @@ def __init__( # pyright: ignore[reportInconsistentConstructor]
195175 ) -> None :
196176 # Use the xlsxwriter module as the Excel writer.
197177 from xlsxwriter import Workbook
198-
199178 engine_kwargs = combine_kwargs (engine_kwargs , kwargs )
200-
201179 if mode == "a" :
202180 raise ValueError ("Append mode is not supported with xlsxwriter!" )
203-
204181 super ().__init__ (
205182 path ,
206183 engine = engine ,
@@ -211,33 +188,27 @@ def __init__( # pyright: ignore[reportInconsistentConstructor]
211188 if_sheet_exists = if_sheet_exists ,
212189 engine_kwargs = engine_kwargs ,
213190 )
214-
215191 try :
216- self ._book = Workbook (self ._handles .handle , ** engine_kwargs ) # type: ignore[arg-type]
192+ self ._book = Workbook (self ._handles .handle , ** engine_kwargs )
217193 except TypeError :
218194 self ._handles .handle .close ()
219195 raise
220-
221196 @property
222197 def book (self ):
223198 """
224199 Book instance of class xlsxwriter.Workbook.
225-
226200 This attribute can be used to access engine-specific features.
227201 """
228202 return self ._book
229-
230203 @property
231204 def sheets (self ) -> dict [str , Any ]:
232205 result = self .book .sheetnames
233206 return result
234-
235207 def _save (self ) -> None :
236208 """
237209 Save workbook to disk.
238210 """
239211 self .book .close ()
240-
241212 def _write_cells (
242213 self ,
243214 cells ,
@@ -248,29 +219,22 @@ def _write_cells(
248219 ) -> None :
249220 # Write the frame cells using xlsxwriter.
250221 sheet_name = self ._get_sheet_name (sheet_name )
251-
252222 wks = self .book .get_worksheet_by_name (sheet_name )
253223 if wks is None :
254224 wks = self .book .add_worksheet (sheet_name )
255-
256225 style_dict = {"null" : None }
257-
258226 if validate_freeze_panes (freeze_panes ):
259227 wks .freeze_panes (* (freeze_panes ))
260-
261228 for cell in cells :
262229 val , fmt = self ._value_with_fmt (cell .val )
263-
264230 stylekey = json .dumps (cell .style )
265231 if fmt :
266232 stylekey += fmt
267-
268233 if stylekey in style_dict :
269234 style = style_dict [stylekey ]
270235 else :
271236 style = self .book .add_format (_XlsxStyler .convert (cell .style , fmt ))
272237 style_dict [stylekey ] = style
273-
274238 if cell .mergestart is not None and cell .mergeend is not None :
275239 wks .merge_range (
276240 startrow + cell .row ,
0 commit comments