Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/openpyxl/packaging/manifest.py: 39%
98 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"""
4File manifest
5"""
6from mimetypes import MimeTypes
7import os.path
9from openpyxl.descriptors.serialisable import Serialisable
10from openpyxl.descriptors import String, Sequence
11from openpyxl.xml.functions import fromstring
12from openpyxl.xml.constants import (
13 ARC_CORE,
14 ARC_CONTENT_TYPES,
15 ARC_WORKBOOK,
16 ARC_APP,
17 ARC_THEME,
18 ARC_STYLE,
19 ARC_SHARED_STRINGS,
20 EXTERNAL_LINK,
21 THEME_TYPE,
22 STYLES_TYPE,
23 XLSX,
24 XLSM,
25 XLTM,
26 XLTX,
27 WORKSHEET_TYPE,
28 COMMENTS_TYPE,
29 SHARED_STRINGS,
30 DRAWING_TYPE,
31 CHART_TYPE,
32 CHARTSHAPE_TYPE,
33 CHARTSHEET_TYPE,
34 CONTYPES_NS,
35 ACTIVEX,
36 CTRL,
37 VBA,
38)
39from openpyxl.xml.functions import tostring
41# initialise mime-types
42mimetypes = MimeTypes()
43mimetypes.add_type('application/xml', ".xml")
44mimetypes.add_type('application/vnd.openxmlformats-package.relationships+xml', ".rels")
45mimetypes.add_type("application/vnd.ms-office.vbaProject", ".bin")
46mimetypes.add_type("application/vnd.openxmlformats-officedocument.vmlDrawing", ".vml")
47mimetypes.add_type("image/x-emf", ".emf")
50class FileExtension(Serialisable):
52 tagname = "Default"
54 Extension = String()
55 ContentType = String()
57 def __init__(self, Extension, ContentType):
58 self.Extension = Extension
59 self.ContentType = ContentType
62class Override(Serialisable):
64 tagname = "Override"
66 PartName = String()
67 ContentType = String()
69 def __init__(self, PartName, ContentType):
70 self.PartName = PartName
71 self.ContentType = ContentType
74DEFAULT_TYPES = [
75 FileExtension("rels", "application/vnd.openxmlformats-package.relationships+xml"),
76 FileExtension("xml", "application/xml"),
77]
79DEFAULT_OVERRIDE = [
80 Override("/" + ARC_STYLE, STYLES_TYPE), # Styles
81 Override("/" + ARC_THEME, THEME_TYPE), # Theme
82 Override("/docProps/core.xml", "application/vnd.openxmlformats-package.core-properties+xml"),
83 Override("/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml")
84]
87class Manifest(Serialisable):
89 tagname = "Types"
91 Default = Sequence(expected_type=FileExtension, unique=True)
92 Override = Sequence(expected_type=Override, unique=True)
93 path = "[Content_Types].xml"
95 __elements__ = ("Default", "Override")
97 def __init__(self,
98 Default=(),
99 Override=(),
100 ):
101 if not Default:
102 Default = DEFAULT_TYPES
103 self.Default = Default
104 if not Override:
105 Override = DEFAULT_OVERRIDE
106 self.Override = Override
109 @property
110 def filenames(self):
111 return [part.PartName for part in self.Override]
114 @property
115 def extensions(self):
116 """
117 Map content types to file extensions
118 Skip parts without extensions
119 """
120 exts = {os.path.splitext(part.PartName)[-1] for part in self.Override}
121 return [(ext[1:], mimetypes.types_map[True][ext]) for ext in sorted(exts) if ext]
124 def to_tree(self):
125 """
126 Custom serialisation method to allow setting a default namespace
127 """
128 defaults = [t.Extension for t in self.Default]
129 for ext, mime in self.extensions:
130 if ext not in defaults:
131 mime = FileExtension(ext, mime)
132 self.Default.append(mime)
133 tree = super(Manifest, self).to_tree()
134 tree.set("xmlns", CONTYPES_NS)
135 return tree
138 def __contains__(self, content_type):
139 """
140 Check whether a particular content type is contained
141 """
142 for t in self.Override:
143 if t.ContentType == content_type:
144 return True
147 def find(self, content_type):
148 """
149 Find specific content-type
150 """
151 try:
152 return next(self.findall(content_type))
153 except StopIteration:
154 return
157 def findall(self, content_type):
158 """
159 Find all elements of a specific content-type
160 """
161 for t in self.Override:
162 if t.ContentType == content_type:
163 yield t
166 def append(self, obj):
167 """
168 Add content object to the package manifest
169 # needs a contract...
170 """
171 ct = Override(PartName=obj.path, ContentType=obj.mime_type)
172 self.Override.append(ct)
175 def _write(self, archive, workbook):
176 """
177 Write manifest to the archive
178 """
179 self.append(workbook)
180 self._write_vba(workbook)
181 self._register_mimetypes(filenames=archive.namelist())
182 archive.writestr(self.path, tostring(self.to_tree()))
185 def _register_mimetypes(self, filenames):
186 """
187 Make sure that the mime type for all file extensions is registered
188 """
189 for fn in filenames:
190 ext = os.path.splitext(fn)[-1]
191 if not ext:
192 continue
193 mime = mimetypes.types_map[True][ext]
194 fe = FileExtension(ext[1:], mime)
195 self.Default.append(fe)
198 def _write_vba(self, workbook):
199 """
200 Add content types from cached workbook when keeping VBA
201 """
202 if workbook.vba_archive:
203 node = fromstring(workbook.vba_archive.read(ARC_CONTENT_TYPES))
204 mf = Manifest.from_tree(node)
205 filenames = self.filenames
206 for override in mf.Override:
207 if override.PartName not in (ACTIVEX, CTRL, VBA):
208 continue
209 if override.PartName not in filenames:
210 self.Override.append(override)