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
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1# Copyright (c) 2010-2022 openpyxl
3"""Write a .xlsx file."""
5# Python stdlib imports
6import re
7from tempfile import TemporaryFile
8from zipfile import ZipFile, ZIP_DEFLATED
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
45class ExcelWriter(object):
46 """Write a workbook object to an Excel file."""
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 = []
61 def write_data(self):
62 """Write the various xml files into the zip archive."""
63 # cleanup all worksheets
64 archive = self._archive
66 props = ExtendedProperties()
67 archive.writestr(ARC_APP, tostring(props.to_tree()))
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)
75 self._write_worksheets()
76 self._write_chartsheets()
77 self._write_images()
78 self._write_charts()
80 #self._archive.writestr(ARC_SHARED_STRINGS,
81 #write_string_table(self.workbook.shared_strings))
82 self._write_external_links()
84 stylesheet = write_stylesheet(self.workbook)
85 archive.writestr(ARC_STYLE, tostring(stylesheet))
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())
92 self._merge_vba()
94 self.manifest._write(archive, self.workbook)
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 )
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))
113 def _write_images(self):
114 # delegate to object
115 for img in self._images:
116 self._archive.writestr(img.path[1:], img._data())
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)
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)
146 def _write_chartsheets(self):
147 for idx, sheet in enumerate(self.workbook.chartsheets, 1):
149 sheet._id = idx
150 xml = tostring(sheet.to_tree())
152 self._archive.writestr(sheet.path[1:], xml)
153 self.manifest.append(sheet)
155 if sheet._drawing:
156 self._write_drawing(sheet._drawing)
158 rel = Relationship(type="drawing", Target=sheet._drawing.path)
159 rels = RelationshipList()
160 rels.append(rel)
161 tree = rels.to_tree()
163 rels_path = get_rels_path(sheet.path[1:])
164 self._archive.writestr(rels_path, tostring(tree))
167 def _write_comment(self, ws):
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)
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))
181 vml = cs.write_shapes(vml)
183 self._archive.writestr(ws.legacy_drawing, vml)
184 self.vba_modified.add(ws.legacy_drawing)
186 comment_rel = Relationship(Id="comments", type=cs._rel_type, Target=cs.path)
187 ws._rels.append(comment_rel)
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()
202 ws._rels = writer._rels
203 self._archive.write(writer.out, ws.path[1:])
204 self.manifest.append(ws)
205 writer.cleanup()
208 def _write_worksheets(self):
210 pivot_caches = set()
212 for idx, ws in enumerate(self.workbook.worksheets, 1):
214 ws._id = idx
215 self.write_worksheet(ws)
217 if ws._drawing:
218 self._write_drawing(ws._drawing)
220 for r in ws._rels.Relationship:
221 if "drawing" in r.Type:
222 r.Target = ws._drawing.path
224 if ws._comments:
225 self._write_comment(ws)
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)
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
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)
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)
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))
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:])
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)
273 def save(self):
274 """Write data into the archive."""
275 self.write_data()
276 self._archive.close()
279def save_workbook(workbook, filename):
280 """Save the given workbook on the filesystem under the name filename.
282 :param workbook: the workbook to save
283 :type workbook: :class:`openpyxl.workbook.Workbook`
285 :param filename: the path to which save the workbook
286 :type filename: string
288 :rtype: bool
290 """
291 archive = ZipFile(filename, 'w', ZIP_DEFLATED, allowZip64=True)
292 writer = ExcelWriter(workbook, archive)
293 writer.save()
294 return True
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)
303 writer = ExcelWriter(workbook, archive)
304 writer.save()
306 tmp.seek(0)
307 virtual_workbook = tmp.read()
308 tmp.close()
310 return virtual_workbook