1
1
from collections import defaultdict
2
2
import datetime
3
3
4
- # import pandas._libs.json as json
4
+ import pandas ._libs .json as json
5
5
6
6
from pandas .io .excel ._base import ExcelWriter
7
7
8
8
# from pandas.io.excel._util import _validate_freeze_panes
9
9
10
10
from odf .opendocument import OpenDocumentSpreadsheet
11
+ from odf .style import Style , TextProperties , TableCellProperties , ParagraphProperties
11
12
from odf .table import Table , TableRow , TableCell
12
13
from odf .text import P
13
14
@@ -24,12 +25,8 @@ def __init__(self, path, engine=None, encoding=None, mode="w", **engine_kwargs):
24
25
25
26
super ().__init__ (path , mode = mode , ** engine_kwargs )
26
27
27
- if encoding is None :
28
- encoding = "ascii"
29
28
self .book = OpenDocumentSpreadsheet ()
30
-
31
- # self.fm_datetime = xlwt.easyxf(num_format_str=self.datetime_format)
32
- # self.fm_date = xlwt.easyxf(num_format_str=self.date_format)
29
+ self .style_dict = {}
33
30
34
31
def save (self ):
35
32
"""
@@ -57,25 +54,25 @@ def write_cells(
57
54
# wks.set_horz_split_pos(freeze_panes[0])
58
55
# wks.set_vert_split_pos(freeze_panes[1])
59
56
60
- style_dict = {}
61
57
62
58
rows = defaultdict (TableRow )
63
59
col_count = defaultdict (int )
64
60
65
61
for cell in sorted (cells , key = lambda cell : (cell .row , cell .col )):
66
62
attributes = {}
63
+ style_name = self ._process_style (cell .style )
64
+ if style_name is not None :
65
+ attributes ["stylename" ] = style_name
67
66
print (cell .row , cell .col , cell .val , cell .mergestart , cell .mergeend )
68
67
if cell .mergestart is not None and cell .mergeend is not None :
69
- attributes = {
70
- "numberrowsspanned" : max (1 , cell .mergestart ),
71
- "numbercolumnsspanned" : cell .mergeend ,
72
- }
68
+ attributes ["numberrowsspanned" ] = max (1 , cell .mergestart )
69
+ attributes ["numbercolumnsspanned" ] = cell .mergeend
73
70
# fill with empty cells if needed
74
71
for _ in range (cell .col - col_count [cell .row ]):
75
72
rows [cell .row ].addElement (TableCell ())
76
73
col_count [cell .row ] += 1
77
74
val , fmt = self ._value_with_fmt (cell .val )
78
- print ("type" , type (val ), "value" , val )
75
+ # print("type", type(val), "value", val)
79
76
pvalue = value = val
80
77
if isinstance (val , bool ):
81
78
value = str (val ).lower ()
@@ -108,78 +105,38 @@ def write_cells(
108
105
col_count [cell .row ] += 1
109
106
p = P (text = pvalue )
110
107
tc .addElement (p )
111
- """
112
- stylekey = json.dumps(cell.style)
113
- if fmt:
114
- stylekey += fmt
115
-
116
- if stylekey in style_dict:
117
- style = style_dict[stylekey]
118
- else:
119
- style = self._convert_to_style(cell.style, fmt)
120
- style_dict[stylekey] = style
121
- """
122
108
for row_nr in range (max (rows .keys ()) + 1 ):
123
109
wks .addElement (rows [row_nr ])
124
110
125
- @classmethod
126
- def _style_to_xlwt (
127
- cls , item , firstlevel : bool = True , field_sep = "," , line_sep = ";"
128
- ) -> str :
129
- """
130
- helper which recursively generate an xlwt easy style string
131
- for example:
132
-
133
- hstyle = {"font": {"bold": True},
134
- "border": {"top": "thin",
135
- "right": "thin",
136
- "bottom": "thin",
137
- "left": "thin"},
138
- "align": {"horiz": "center"}}
139
- will be converted to
140
- font: bold on; \
141
- border: top thin, right thin, bottom thin, left thin; \
142
- align: horiz center;
143
- """
144
- if hasattr (item , "items" ):
145
- if firstlevel :
146
- it = [
147
- f"{ key } : { cls ._style_to_xlwt (value , False )} "
148
- for key , value in item .items ()
149
- ]
150
- out = f"{ (line_sep ).join (it )} "
151
- return out
152
- else :
153
- it = [
154
- f"{ key } { cls ._style_to_xlwt (value , False )} "
155
- for key , value in item .items ()
156
- ]
157
- out = f"{ (field_sep ).join (it )} "
158
- return out
159
- else :
160
- item = f"{ item } "
161
- item = item .replace ("True" , "on" )
162
- item = item .replace ("False" , "off" )
163
- return item
164
-
165
- @classmethod
166
- def _convert_to_style (cls , style_dict , num_format_str = None ):
167
- """
168
- converts a style_dict to an xlwt style object
169
-
170
- Parameters
171
- ----------
172
- style_dict : style dictionary to convert
173
- num_format_str : optional number format string
174
- """
175
- import xlwt
176
-
177
- if style_dict :
178
- xlwt_stylestr = cls ._style_to_xlwt (style_dict )
179
- style = xlwt .easyxf (xlwt_stylestr , field_sep = "," , line_sep = ";" )
180
- else :
181
- style = xlwt .XFStyle ()
182
- if num_format_str is not None :
183
- style .num_format_str = num_format_str
184
-
185
- return style
111
+ def _process_style (self , style ):
112
+ if style is None :
113
+ return None
114
+ style_key = json .dumps (style )
115
+ if style_key in self .style_dict :
116
+ return self .style_dict [style_key ]
117
+ name = f"pd{ len (self .style_dict )+ 1 } "
118
+ self .style_dict [style_key ] = name
119
+ odf_style = Style (name = name , family = "table-cell" )
120
+ if "font" in style :
121
+ font = style ["font" ]
122
+ if font .get ("bold" , False ):
123
+ odf_style .addElement (TextProperties (fontweight = "bold" ))
124
+ if "borders" in style :
125
+ borders = style ["borders" ]
126
+ for side , thickness in borders .items ():
127
+ thickness_translation = {
128
+ "thin" : "0.75pt solid #000000"
129
+ }
130
+ odf_style .addElement (
131
+ TableCellProperties (
132
+ attributes = {f"border{ side } " : thickness_translation [thickness ]}))
133
+ if "alignment" in style :
134
+ alignment = style ["alignment" ]
135
+ horizontal = alignment .get ("horizontal" )
136
+ if horizontal :
137
+ odf_style .addElement (ParagraphProperties (textalign = horizontal ))
138
+ vertical = alignment .get ("vertical" )
139
+ if vertical :
140
+ odf_style .addElement (TableCellProperties (verticalalign = vertical ))
141
+ self .book .styles .addElement (odf_style )
142
+ return name
0 commit comments