Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/openpyxl/writer/excel.py: 15%

185 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1# Copyright (c) 2010-2022 openpyxl 

2 

3"""Write a .xlsx file.""" 

4 

5# Python stdlib imports 

6import re 

7from tempfile import TemporaryFile 

8from zipfile import ZipFile, ZIP_DEFLATED 

9 

10# package imports 

11from openpyxl.compat import deprecated 

12from openpyxl.utils.exceptions import InvalidFileException 

13from openpyxl.xml.constants import ( 

14 ARC_SHARED_STRINGS, 

15 ARC_CONTENT_TYPES, 

16 ARC_ROOT_RELS, 

17 ARC_WORKBOOK_RELS, 

18 ARC_APP, ARC_CORE, 

19 ARC_THEME, 

20 ARC_STYLE, 

21 ARC_WORKBOOK, 

22 PACKAGE_WORKSHEETS, 

23 PACKAGE_CHARTSHEETS, 

24 PACKAGE_DRAWINGS, 

25 PACKAGE_CHARTS, 

26 PACKAGE_IMAGES, 

27 PACKAGE_XL 

28 ) 

29from openpyxl.drawing.spreadsheet_drawing import SpreadsheetDrawing 

30from openpyxl.xml.functions import tostring, fromstring, Element 

31from openpyxl.packaging.manifest import Manifest 

32from openpyxl.packaging.relationship import ( 

33 get_rels_path, 

34 RelationshipList, 

35 Relationship, 

36) 

37from openpyxl.comments.comment_sheet import CommentSheet 

38from openpyxl.packaging.extended import ExtendedProperties 

39from openpyxl.styles.stylesheet import write_stylesheet 

40from openpyxl.worksheet._writer import WorksheetWriter 

41from openpyxl.workbook._writer import WorkbookWriter 

42from .theme import theme_xml 

43 

44 

45class ExcelWriter(object): 

46 """Write a workbook object to an Excel file.""" 

47 

48 def __init__(self, workbook, archive): 

49 self._archive = archive 

50 self.workbook = workbook 

51 self.manifest = Manifest() 

52 self.vba_modified = set() 

53 self._tables = [] 

54 self._charts = [] 

55 self._images = [] 

56 self._drawings = [] 

57 self._comments = [] 

58 self._pivots = [] 

59 

60 

61 def write_data(self): 

62 """Write the various xml files into the zip archive.""" 

63 # cleanup all worksheets 

64 archive = self._archive 

65 

66 props = ExtendedProperties() 

67 archive.writestr(ARC_APP, tostring(props.to_tree())) 

68 

69 archive.writestr(ARC_CORE, tostring(self.workbook.properties.to_tree())) 

70 if self.workbook.loaded_theme: 

71 archive.writestr(ARC_THEME, self.workbook.loaded_theme) 

72 else: 

73 archive.writestr(ARC_THEME, theme_xml) 

74 

75 self._write_worksheets() 

76 self._write_chartsheets() 

77 self._write_images() 

78 self._write_charts() 

79 

80 #self._archive.writestr(ARC_SHARED_STRINGS, 

81 #write_string_table(self.workbook.shared_strings)) 

82 self._write_external_links() 

83 

84 stylesheet = write_stylesheet(self.workbook) 

85 archive.writestr(ARC_STYLE, tostring(stylesheet)) 

86 

87 writer = WorkbookWriter(self.workbook) 

88 archive.writestr(ARC_ROOT_RELS, writer.write_root_rels()) 

89 archive.writestr(ARC_WORKBOOK, writer.write()) 

90 archive.writestr(ARC_WORKBOOK_RELS, writer.write_rels()) 

91 

92 self._merge_vba() 

93 

94 self.manifest._write(archive, self.workbook) 

95 

96 def _merge_vba(self): 

97 """ 

98 If workbook contains macros then extract associated files from cache 

99 of old file and add to archive 

100 """ 

101 ARC_VBA = re.compile("|".join( 

102 ('xl/vba', r'xl/drawings/.*vmlDrawing\d\.vml', 

103 'xl/ctrlProps', 'customUI', 'xl/activeX', r'xl/media/.*\.emf') 

104 ) 

105 ) 

106 

107 if self.workbook.vba_archive: 

108 for name in set(self.workbook.vba_archive.namelist()) - self.vba_modified: 

109 if ARC_VBA.match(name): 

110 self._archive.writestr(name, self.workbook.vba_archive.read(name)) 

111 

112 

113 def _write_images(self): 

114 # delegate to object 

115 for img in self._images: 

116 self._archive.writestr(img.path[1:], img._data()) 

117 

118 

119 def _write_charts(self): 

120 # delegate to object 

121 if len(self._charts) != len(set(self._charts)): 

122 raise InvalidFileException("The same chart cannot be used in more than one worksheet") 

123 for chart in self._charts: 

124 self._archive.writestr(chart.path[1:], tostring(chart._write())) 

125 self.manifest.append(chart) 

126 

127 

128 def _write_drawing(self, drawing): 

129 """ 

130 Write a drawing 

131 """ 

132 self._drawings.append(drawing) 

133 drawing._id = len(self._drawings) 

134 for chart in drawing.charts: 

135 self._charts.append(chart) 

136 chart._id = len(self._charts) 

137 for img in drawing.images: 

138 self._images.append(img) 

139 img._id = len(self._images) 

140 rels_path = get_rels_path(drawing.path)[1:] 

141 self._archive.writestr(drawing.path[1:], tostring(drawing._write())) 

142 self._archive.writestr(rels_path, tostring(drawing._write_rels())) 

143 self.manifest.append(drawing) 

144 

145 

146 def _write_chartsheets(self): 

147 for idx, sheet in enumerate(self.workbook.chartsheets, 1): 

148 

149 sheet._id = idx 

150 xml = tostring(sheet.to_tree()) 

151 

152 self._archive.writestr(sheet.path[1:], xml) 

153 self.manifest.append(sheet) 

154 

155 if sheet._drawing: 

156 self._write_drawing(sheet._drawing) 

157 

158 rel = Relationship(type="drawing", Target=sheet._drawing.path) 

159 rels = RelationshipList() 

160 rels.append(rel) 

161 tree = rels.to_tree() 

162 

163 rels_path = get_rels_path(sheet.path[1:]) 

164 self._archive.writestr(rels_path, tostring(tree)) 

165 

166 

167 def _write_comment(self, ws): 

168 

169 cs = CommentSheet.from_comments(ws._comments) 

170 self._comments.append(cs) 

171 cs._id = len(self._comments) 

172 self._archive.writestr(cs.path[1:], tostring(cs.to_tree())) 

173 self.manifest.append(cs) 

174 

175 if ws.legacy_drawing is None or self.workbook.vba_archive is None: 

176 ws.legacy_drawing = 'xl/drawings/commentsDrawing{0}.vml'.format(cs._id) 

177 vml = None 

178 else: 

179 vml = fromstring(self.workbook.vba_archive.read(ws.legacy_drawing)) 

180 

181 vml = cs.write_shapes(vml) 

182 

183 self._archive.writestr(ws.legacy_drawing, vml) 

184 self.vba_modified.add(ws.legacy_drawing) 

185 

186 comment_rel = Relationship(Id="comments", type=cs._rel_type, Target=cs.path) 

187 ws._rels.append(comment_rel) 

188 

189 

190 def write_worksheet(self, ws): 

191 ws._drawing = SpreadsheetDrawing() 

192 ws._drawing.charts = ws._charts 

193 ws._drawing.images = ws._images 

194 if self.workbook.write_only: 

195 if not ws.closed: 

196 ws.close() 

197 writer = ws._writer 

198 else: 

199 writer = WorksheetWriter(ws) 

200 writer.write() 

201 

202 ws._rels = writer._rels 

203 self._archive.write(writer.out, ws.path[1:]) 

204 self.manifest.append(ws) 

205 writer.cleanup() 

206 

207 

208 def _write_worksheets(self): 

209 

210 pivot_caches = set() 

211 

212 for idx, ws in enumerate(self.workbook.worksheets, 1): 

213 

214 ws._id = idx 

215 self.write_worksheet(ws) 

216 

217 if ws._drawing: 

218 self._write_drawing(ws._drawing) 

219 

220 for r in ws._rels.Relationship: 

221 if "drawing" in r.Type: 

222 r.Target = ws._drawing.path 

223 

224 if ws._comments: 

225 self._write_comment(ws) 

226 

227 if ws.legacy_drawing is not None: 

228 shape_rel = Relationship(type="vmlDrawing", Id="anysvml", 

229 Target="/" + ws.legacy_drawing) 

230 ws._rels.append(shape_rel) 

231 

232 for t in ws._tables.values(): 

233 self._tables.append(t) 

234 t.id = len(self._tables) 

235 t._write(self._archive) 

236 self.manifest.append(t) 

237 ws._rels[t._rel_id].Target = t.path 

238 

239 for p in ws._pivots: 

240 if p.cache not in pivot_caches: 

241 pivot_caches.add(p.cache) 

242 p.cache._id = len(pivot_caches) 

243 

244 self._pivots.append(p) 

245 p._id = len(self._pivots) 

246 p._write(self._archive, self.manifest) 

247 self.workbook._pivots.append(p) 

248 r = Relationship(Type=p.rel_type, Target=p.path) 

249 ws._rels.append(r) 

250 

251 if ws._rels: 

252 tree = ws._rels.to_tree() 

253 rels_path = get_rels_path(ws.path)[1:] 

254 self._archive.writestr(rels_path, tostring(tree)) 

255 

256 

257 def _write_external_links(self): 

258 # delegate to object 

259 """Write links to external workbooks""" 

260 wb = self.workbook 

261 for idx, link in enumerate(wb._external_links, 1): 

262 link._id = idx 

263 rels_path = get_rels_path(link.path[1:]) 

264 

265 xml = link.to_tree() 

266 self._archive.writestr(link.path[1:], tostring(xml)) 

267 rels = RelationshipList() 

268 rels.append(link.file_link) 

269 self._archive.writestr(rels_path, tostring(rels.to_tree())) 

270 self.manifest.append(link) 

271 

272 

273 def save(self): 

274 """Write data into the archive.""" 

275 self.write_data() 

276 self._archive.close() 

277 

278 

279def save_workbook(workbook, filename): 

280 """Save the given workbook on the filesystem under the name filename. 

281 

282 :param workbook: the workbook to save 

283 :type workbook: :class:`openpyxl.workbook.Workbook` 

284 

285 :param filename: the path to which save the workbook 

286 :type filename: string 

287 

288 :rtype: bool 

289 

290 """ 

291 archive = ZipFile(filename, 'w', ZIP_DEFLATED, allowZip64=True) 

292 writer = ExcelWriter(workbook, archive) 

293 writer.save() 

294 return True 

295 

296 

297@deprecated("Use a NamedTemporaryFile") 

298def save_virtual_workbook(workbook): 

299 """Return an in-memory workbook, suitable for a Django response.""" 

300 tmp = TemporaryFile() 

301 archive = ZipFile(tmp, 'w', ZIP_DEFLATED, allowZip64=True) 

302 

303 writer = ExcelWriter(workbook, archive) 

304 writer.save() 

305 

306 tmp.seek(0) 

307 virtual_workbook = tmp.read() 

308 tmp.close() 

309 

310 return virtual_workbook