diff options
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/packaging')
8 files changed, 1137 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/packaging/__init__.py b/.venv/lib/python3.12/site-packages/openpyxl/packaging/__init__.py new file mode 100644 index 00000000..c3085ee5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/packaging/__init__.py @@ -0,0 +1,3 @@ +""" +Stuff related to Office OpenXML packaging: relationships, archive, content types. +""" diff --git a/.venv/lib/python3.12/site-packages/openpyxl/packaging/core.py b/.venv/lib/python3.12/site-packages/openpyxl/packaging/core.py new file mode 100644 index 00000000..45153732 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/packaging/core.py @@ -0,0 +1,115 @@ +# Copyright (c) 2010-2024 openpyxl + +import datetime + +from openpyxl.descriptors import ( + DateTime, + Alias, +) +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors.nested import NestedText +from openpyxl.xml.functions import ( + Element, + QName, +) +from openpyxl.xml.constants import ( + COREPROPS_NS, + DCORE_NS, + XSI_NS, + DCTERMS_NS, +) + + +class NestedDateTime(DateTime, NestedText): + + expected_type = datetime.datetime + + def to_tree(self, tagname=None, value=None, namespace=None): + namespace = getattr(self, "namespace", namespace) + if namespace is not None: + tagname = "{%s}%s" % (namespace, tagname) + el = Element(tagname) + if value is not None: + value = value.replace(tzinfo=None) + el.text = value.isoformat(timespec="seconds") + 'Z' + return el + + +class QualifiedDateTime(NestedDateTime): + + """In certain situations Excel will complain if the additional type + attribute isn't set""" + + def to_tree(self, tagname=None, value=None, namespace=None): + el = super().to_tree(tagname, value, namespace) + el.set("{%s}type" % XSI_NS, QName(DCTERMS_NS, "W3CDTF")) + return el + + +class DocumentProperties(Serialisable): + """High-level properties of the document. + Defined in ECMA-376 Par2 Annex D + """ + + tagname = "coreProperties" + namespace = COREPROPS_NS + + category = NestedText(expected_type=str, allow_none=True) + contentStatus = NestedText(expected_type=str, allow_none=True) + keywords = NestedText(expected_type=str, allow_none=True) + lastModifiedBy = NestedText(expected_type=str, allow_none=True) + lastPrinted = NestedDateTime(allow_none=True) + revision = NestedText(expected_type=str, allow_none=True) + version = NestedText(expected_type=str, allow_none=True) + last_modified_by = Alias("lastModifiedBy") + + # Dublin Core Properties + subject = NestedText(expected_type=str, allow_none=True, namespace=DCORE_NS) + title = NestedText(expected_type=str, allow_none=True, namespace=DCORE_NS) + creator = NestedText(expected_type=str, allow_none=True, namespace=DCORE_NS) + description = NestedText(expected_type=str, allow_none=True, namespace=DCORE_NS) + identifier = NestedText(expected_type=str, allow_none=True, namespace=DCORE_NS) + language = NestedText(expected_type=str, allow_none=True, namespace=DCORE_NS) + # Dublin Core Terms + created = QualifiedDateTime(allow_none=True, namespace=DCTERMS_NS) # assumed to be UTC + modified = QualifiedDateTime(allow_none=True, namespace=DCTERMS_NS) # assumed to be UTC + + __elements__ = ("creator", "title", "description", "subject","identifier", + "language", "created", "modified", "lastModifiedBy", "category", + "contentStatus", "version", "revision", "keywords", "lastPrinted", + ) + + + def __init__(self, + category=None, + contentStatus=None, + keywords=None, + lastModifiedBy=None, + lastPrinted=None, + revision=None, + version=None, + created=None, + creator="openpyxl", + description=None, + identifier=None, + language=None, + modified=None, + subject=None, + title=None, + ): + now = datetime.datetime.now(tz=datetime.timezone.utc).replace(tzinfo=None) + self.contentStatus = contentStatus + self.lastPrinted = lastPrinted + self.revision = revision + self.version = version + self.creator = creator + self.lastModifiedBy = lastModifiedBy + self.modified = modified or now + self.created = created or now + self.title = title + self.subject = subject + self.description = description + self.identifier = identifier + self.language = language + self.keywords = keywords + self.category = category diff --git a/.venv/lib/python3.12/site-packages/openpyxl/packaging/custom.py b/.venv/lib/python3.12/site-packages/openpyxl/packaging/custom.py new file mode 100644 index 00000000..7e253d78 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/packaging/custom.py @@ -0,0 +1,289 @@ +# Copyright (c) 2010-2024 openpyxl + +"""Implementation of custom properties see ยง 22.3 in the specification""" + + +from warnings import warn + +from openpyxl.descriptors import Strict +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors.sequence import Sequence +from openpyxl.descriptors import ( + Alias, + String, + Integer, + Float, + DateTime, + Bool, +) +from openpyxl.descriptors.nested import ( + NestedText, +) + +from openpyxl.xml.constants import ( + CUSTPROPS_NS, + VTYPES_NS, + CPROPS_FMTID, +) + +from .core import NestedDateTime + + +class NestedBoolText(Bool, NestedText): + """ + Descriptor for handling nested elements with the value stored in the text part + """ + + pass + + +class _CustomDocumentProperty(Serialisable): + + """ + Low-level representation of a Custom Document Property. + Not used directly + Must always contain a child element, even if this is empty + """ + + tagname = "property" + _typ = None + + name = String(allow_none=True) + lpwstr = NestedText(expected_type=str, allow_none=True, namespace=VTYPES_NS) + i4 = NestedText(expected_type=int, allow_none=True, namespace=VTYPES_NS) + r8 = NestedText(expected_type=float, allow_none=True, namespace=VTYPES_NS) + filetime = NestedDateTime(allow_none=True, namespace=VTYPES_NS) + bool = NestedBoolText(expected_type=bool, allow_none=True, namespace=VTYPES_NS) + linkTarget = String(expected_type=str, allow_none=True) + fmtid = String() + pid = Integer() + + def __init__(self, + name=None, + pid=0, + fmtid=CPROPS_FMTID, + linkTarget=None, + **kw): + self.fmtid = fmtid + self.pid = pid + self.name = name + self._typ = None + self.linkTarget = linkTarget + + for k, v in kw.items(): + setattr(self, k, v) + setattr(self, "_typ", k) # ugh! + for e in self.__elements__: + if e not in kw: + setattr(self, e, None) + + + @property + def type(self): + if self._typ is not None: + return self._typ + for a in self.__elements__: + if getattr(self, a) is not None: + return a + if self.linkTarget is not None: + return "linkTarget" + + + def to_tree(self, tagname=None, idx=None, namespace=None): + child = getattr(self, self._typ, None) + if child is None: + setattr(self, self._typ, "") + + return super().to_tree(tagname=None, idx=None, namespace=None) + + +class _CustomDocumentPropertyList(Serialisable): + + """ + Parses and seriliases property lists but is not used directly + """ + + tagname = "Properties" + + property = Sequence(expected_type=_CustomDocumentProperty, namespace=CUSTPROPS_NS) + customProps = Alias("property") + + + def __init__(self, property=()): + self.property = property + + + def __len__(self): + return len(self.property) + + + def to_tree(self, tagname=None, idx=None, namespace=None): + for idx, p in enumerate(self.property, 2): + p.pid = idx + tree = super().to_tree(tagname, idx, namespace) + tree.set("xmlns", CUSTPROPS_NS) + + return tree + + +class _TypedProperty(Strict): + + name = String() + + def __init__(self, + name, + value): + self.name = name + self.value = value + + + def __eq__(self, other): + return self.name == other.name and self.value == other.value + + + def __repr__(self): + return f"{self.__class__.__name__}, name={self.name}, value={self.value}" + + +class IntProperty(_TypedProperty): + + value = Integer() + + +class FloatProperty(_TypedProperty): + + value = Float() + + +class StringProperty(_TypedProperty): + + value = String(allow_none=True) + + +class DateTimeProperty(_TypedProperty): + + value = DateTime() + + +class BoolProperty(_TypedProperty): + + value = Bool() + + +class LinkProperty(_TypedProperty): + + value = String() + + +# from Python +CLASS_MAPPING = { + StringProperty: "lpwstr", + IntProperty: "i4", + FloatProperty: "r8", + DateTimeProperty: "filetime", + BoolProperty: "bool", + LinkProperty: "linkTarget" +} + +XML_MAPPING = {v:k for k,v in CLASS_MAPPING.items()} + + +class CustomPropertyList(Strict): + + + props = Sequence(expected_type=_TypedProperty) + + def __init__(self): + self.props = [] + + + @classmethod + def from_tree(cls, tree): + """ + Create list from OOXML element + """ + prop_list = _CustomDocumentPropertyList.from_tree(tree) + props = [] + + for prop in prop_list.property: + attr = prop.type + + typ = XML_MAPPING.get(attr, None) + if not typ: + warn(f"Unknown type for {prop.name}") + continue + value = getattr(prop, attr) + link = prop.linkTarget + if link is not None: + typ = LinkProperty + value = prop.linkTarget + + new_prop = typ(name=prop.name, value=value) + props.append(new_prop) + + new_prop_list = cls() + new_prop_list.props = props + return new_prop_list + + + def append(self, prop): + if prop.name in self.names: + raise ValueError(f"Property with name {prop.name} already exists") + + self.props.append(prop) + + + def to_tree(self): + props = [] + + for p in self.props: + attr = CLASS_MAPPING.get(p.__class__, None) + if not attr: + raise TypeError("Unknown adapter for {p}") + np = _CustomDocumentProperty(name=p.name, **{attr:p.value}) + if isinstance(p, LinkProperty): + np._typ = "lpwstr" + #np.lpwstr = "" + props.append(np) + + prop_list = _CustomDocumentPropertyList(property=props) + return prop_list.to_tree() + + + def __len__(self): + return len(self.props) + + + @property + def names(self): + """List of property names""" + return [p.name for p in self.props] + + + def __getitem__(self, name): + """ + Get property by name + """ + for p in self.props: + if p.name == name: + return p + raise KeyError(f"Property with name {name} not found") + + + def __delitem__(self, name): + """ + Delete a propery by name + """ + for idx, p in enumerate(self.props): + if p.name == name: + self.props.pop(idx) + return + raise KeyError(f"Property with name {name} not found") + + + def __repr__(self): + return f"{self.__class__.__name__} containing {self.props}" + + + def __iter__(self): + return iter(self.props) diff --git a/.venv/lib/python3.12/site-packages/openpyxl/packaging/extended.py b/.venv/lib/python3.12/site-packages/openpyxl/packaging/extended.py new file mode 100644 index 00000000..fbd794af --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/packaging/extended.py @@ -0,0 +1,137 @@ +# Copyright (c) 2010-2024 openpyxl + + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Typed, +) +from openpyxl.descriptors.nested import ( + NestedText, +) + +from openpyxl.xml.constants import XPROPS_NS +from openpyxl import __version__ + + +class DigSigBlob(Serialisable): + + __elements__ = __attrs__ = () + + +class VectorLpstr(Serialisable): + + __elements__ = __attrs__ = () + + +class VectorVariant(Serialisable): + + __elements__ = __attrs__ = () + + +class ExtendedProperties(Serialisable): + + """ + See 22.2 + + Most of this is irrelevant but Excel is very picky about the version number + + It uses XX.YYYY (Version.Build) and expects everyone else to + + We provide Major.Minor and the full version in the application name + """ + + tagname = "Properties" + + Template = NestedText(expected_type=str, allow_none=True) + Manager = NestedText(expected_type=str, allow_none=True) + Company = NestedText(expected_type=str, allow_none=True) + Pages = NestedText(expected_type=int, allow_none=True) + Words = NestedText(expected_type=int,allow_none=True) + Characters = NestedText(expected_type=int, allow_none=True) + PresentationFormat = NestedText(expected_type=str, allow_none=True) + Lines = NestedText(expected_type=int, allow_none=True) + Paragraphs = NestedText(expected_type=int, allow_none=True) + Slides = NestedText(expected_type=int, allow_none=True) + Notes = NestedText(expected_type=int, allow_none=True) + TotalTime = NestedText(expected_type=int, allow_none=True) + HiddenSlides = NestedText(expected_type=int, allow_none=True) + MMClips = NestedText(expected_type=int, allow_none=True) + ScaleCrop = NestedText(expected_type=bool, allow_none=True) + HeadingPairs = Typed(expected_type=VectorVariant, allow_none=True) + TitlesOfParts = Typed(expected_type=VectorLpstr, allow_none=True) + LinksUpToDate = NestedText(expected_type=bool, allow_none=True) + CharactersWithSpaces = NestedText(expected_type=int, allow_none=True) + SharedDoc = NestedText(expected_type=bool, allow_none=True) + HyperlinkBase = NestedText(expected_type=str, allow_none=True) + HLinks = Typed(expected_type=VectorVariant, allow_none=True) + HyperlinksChanged = NestedText(expected_type=bool, allow_none=True) + DigSig = Typed(expected_type=DigSigBlob, allow_none=True) + Application = NestedText(expected_type=str, allow_none=True) + AppVersion = NestedText(expected_type=str, allow_none=True) + DocSecurity = NestedText(expected_type=int, allow_none=True) + + __elements__ = ('Application', 'AppVersion', 'DocSecurity', 'ScaleCrop', + 'LinksUpToDate', 'SharedDoc', 'HyperlinksChanged') + + def __init__(self, + Template=None, + Manager=None, + Company=None, + Pages=None, + Words=None, + Characters=None, + PresentationFormat=None, + Lines=None, + Paragraphs=None, + Slides=None, + Notes=None, + TotalTime=None, + HiddenSlides=None, + MMClips=None, + ScaleCrop=None, + HeadingPairs=None, + TitlesOfParts=None, + LinksUpToDate=None, + CharactersWithSpaces=None, + SharedDoc=None, + HyperlinkBase=None, + HLinks=None, + HyperlinksChanged=None, + DigSig=None, + Application=None, + AppVersion=None, + DocSecurity=None, + ): + self.Template = Template + self.Manager = Manager + self.Company = Company + self.Pages = Pages + self.Words = Words + self.Characters = Characters + self.PresentationFormat = PresentationFormat + self.Lines = Lines + self.Paragraphs = Paragraphs + self.Slides = Slides + self.Notes = Notes + self.TotalTime = TotalTime + self.HiddenSlides = HiddenSlides + self.MMClips = MMClips + self.ScaleCrop = ScaleCrop + self.HeadingPairs = None + self.TitlesOfParts = None + self.LinksUpToDate = LinksUpToDate + self.CharactersWithSpaces = CharactersWithSpaces + self.SharedDoc = SharedDoc + self.HyperlinkBase = HyperlinkBase + self.HLinks = None + self.HyperlinksChanged = HyperlinksChanged + self.DigSig = None + self.Application = f"Microsoft Excel Compatible / Openpyxl {__version__}" + self.AppVersion = ".".join(__version__.split(".")[:-1]) + self.DocSecurity = DocSecurity + + + def to_tree(self): + tree = super().to_tree() + tree.set("xmlns", XPROPS_NS) + return tree diff --git a/.venv/lib/python3.12/site-packages/openpyxl/packaging/interface.py b/.venv/lib/python3.12/site-packages/openpyxl/packaging/interface.py new file mode 100644 index 00000000..cacc0462 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/packaging/interface.py @@ -0,0 +1,56 @@ +# Copyright (c) 2010-2024 openpyxl + +from abc import abstractproperty +from openpyxl.compat.abc import ABC + + +class ISerialisableFile(ABC): + + """ + Interface for Serialisable classes that represent files in the archive + """ + + + @abstractproperty + def id(self): + """ + Object id making it unique + """ + pass + + + @abstractproperty + def _path(self): + """ + File path in the archive + """ + pass + + + @abstractproperty + def _namespace(self): + """ + Qualified namespace when serialised + """ + pass + + + @abstractproperty + def _type(self): + """ + The content type for the manifest + """ + + + @abstractproperty + def _rel_type(self): + """ + The content type for relationships + """ + + + @abstractproperty + def _rel_id(self): + """ + Links object with parent + """ diff --git a/.venv/lib/python3.12/site-packages/openpyxl/packaging/manifest.py b/.venv/lib/python3.12/site-packages/openpyxl/packaging/manifest.py new file mode 100644 index 00000000..41da07f4 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/packaging/manifest.py @@ -0,0 +1,194 @@ +# Copyright (c) 2010-2024 openpyxl + +""" +File manifest +""" +from mimetypes import MimeTypes +import os.path + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import String, Sequence +from openpyxl.xml.functions import fromstring +from openpyxl.xml.constants import ( + ARC_CONTENT_TYPES, + ARC_THEME, + ARC_STYLE, + THEME_TYPE, + STYLES_TYPE, + CONTYPES_NS, + ACTIVEX, + CTRL, + VBA, +) +from openpyxl.xml.functions import tostring + +# initialise mime-types +mimetypes = MimeTypes() +mimetypes.add_type('application/xml', ".xml") +mimetypes.add_type('application/vnd.openxmlformats-package.relationships+xml', ".rels") +mimetypes.add_type("application/vnd.ms-office.vbaProject", ".bin") +mimetypes.add_type("application/vnd.openxmlformats-officedocument.vmlDrawing", ".vml") +mimetypes.add_type("image/x-emf", ".emf") + + +class FileExtension(Serialisable): + + tagname = "Default" + + Extension = String() + ContentType = String() + + def __init__(self, Extension, ContentType): + self.Extension = Extension + self.ContentType = ContentType + + +class Override(Serialisable): + + tagname = "Override" + + PartName = String() + ContentType = String() + + def __init__(self, PartName, ContentType): + self.PartName = PartName + self.ContentType = ContentType + + +DEFAULT_TYPES = [ + FileExtension("rels", "application/vnd.openxmlformats-package.relationships+xml"), + FileExtension("xml", "application/xml"), +] + +DEFAULT_OVERRIDE = [ + Override("/" + ARC_STYLE, STYLES_TYPE), # Styles + Override("/" + ARC_THEME, THEME_TYPE), # Theme + Override("/docProps/core.xml", "application/vnd.openxmlformats-package.core-properties+xml"), + Override("/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml") +] + + +class Manifest(Serialisable): + + tagname = "Types" + + Default = Sequence(expected_type=FileExtension, unique=True) + Override = Sequence(expected_type=Override, unique=True) + path = "[Content_Types].xml" + + __elements__ = ("Default", "Override") + + def __init__(self, + Default=(), + Override=(), + ): + if not Default: + Default = DEFAULT_TYPES + self.Default = Default + if not Override: + Override = DEFAULT_OVERRIDE + self.Override = Override + + + @property + def filenames(self): + return [part.PartName for part in self.Override] + + + @property + def extensions(self): + """ + Map content types to file extensions + Skip parts without extensions + """ + exts = {os.path.splitext(part.PartName)[-1] for part in self.Override} + return [(ext[1:], mimetypes.types_map[True][ext]) for ext in sorted(exts) if ext] + + + def to_tree(self): + """ + Custom serialisation method to allow setting a default namespace + """ + defaults = [t.Extension for t in self.Default] + for ext, mime in self.extensions: + if ext not in defaults: + mime = FileExtension(ext, mime) + self.Default.append(mime) + tree = super().to_tree() + tree.set("xmlns", CONTYPES_NS) + return tree + + + def __contains__(self, content_type): + """ + Check whether a particular content type is contained + """ + for t in self.Override: + if t.ContentType == content_type: + return True + + + def find(self, content_type): + """ + Find specific content-type + """ + try: + return next(self.findall(content_type)) + except StopIteration: + return + + + def findall(self, content_type): + """ + Find all elements of a specific content-type + """ + for t in self.Override: + if t.ContentType == content_type: + yield t + + + def append(self, obj): + """ + Add content object to the package manifest + # needs a contract... + """ + ct = Override(PartName=obj.path, ContentType=obj.mime_type) + self.Override.append(ct) + + + def _write(self, archive, workbook): + """ + Write manifest to the archive + """ + self.append(workbook) + self._write_vba(workbook) + self._register_mimetypes(filenames=archive.namelist()) + archive.writestr(self.path, tostring(self.to_tree())) + + + def _register_mimetypes(self, filenames): + """ + Make sure that the mime type for all file extensions is registered + """ + for fn in filenames: + ext = os.path.splitext(fn)[-1] + if not ext: + continue + mime = mimetypes.types_map[True][ext] + fe = FileExtension(ext[1:], mime) + self.Default.append(fe) + + + def _write_vba(self, workbook): + """ + Add content types from cached workbook when keeping VBA + """ + if workbook.vba_archive: + node = fromstring(workbook.vba_archive.read(ARC_CONTENT_TYPES)) + mf = Manifest.from_tree(node) + filenames = self.filenames + for override in mf.Override: + if override.PartName not in (ACTIVEX, CTRL, VBA): + continue + if override.PartName not in filenames: + self.Override.append(override) diff --git a/.venv/lib/python3.12/site-packages/openpyxl/packaging/relationship.py b/.venv/lib/python3.12/site-packages/openpyxl/packaging/relationship.py new file mode 100644 index 00000000..4318282d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/packaging/relationship.py @@ -0,0 +1,158 @@ +# Copyright (c) 2010-2024 openpyxl + +import posixpath +from warnings import warn + +from openpyxl.descriptors import ( + String, + Alias, + Sequence, +) +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors.container import ElementList + +from openpyxl.xml.constants import REL_NS, PKG_REL_NS +from openpyxl.xml.functions import ( + Element, + fromstring, +) + + +class Relationship(Serialisable): + """Represents many kinds of relationships.""" + + tagname = "Relationship" + + Type = String() + Target = String() + target = Alias("Target") + TargetMode = String(allow_none=True) + Id = String(allow_none=True) + id = Alias("Id") + + + def __init__(self, + Id=None, + Type=None, + type=None, + Target=None, + TargetMode=None + ): + """ + `type` can be used as a shorthand with the default relationships namespace + otherwise the `Type` must be a fully qualified URL + """ + if type is not None: + Type = "{0}/{1}".format(REL_NS, type) + self.Type = Type + self.Target = Target + self.TargetMode = TargetMode + self.Id = Id + + +class RelationshipList(ElementList): + + tagname = "Relationships" + expected_type = Relationship + + + def append(self, value): + super().append(value) + if not value.Id: + value.Id = f"rId{len(self)}" + + + def find(self, content_type): + """ + Find relationships by content-type + NB. these content-types namespaced objects and different to the MIME-types + in the package manifest :-( + """ + for r in self: + if r.Type == content_type: + yield r + + + def get(self, key): + for r in self: + if r.Id == key: + return r + raise KeyError("Unknown relationship: {0}".format(key)) + + + def to_dict(self): + """Return a dictionary of relations keyed by id""" + return {r.id:r for r in self} + + + def to_tree(self): + tree = super().to_tree() + tree.set("xmlns", PKG_REL_NS) + return tree + + +def get_rels_path(path): + """ + Convert relative path to absolutes that can be loaded from a zip + archive. + The path to be passed in is that of containing object (workbook, + worksheet, etc.) + """ + folder, obj = posixpath.split(path) + filename = posixpath.join(folder, '_rels', '{0}.rels'.format(obj)) + return filename + + +def get_dependents(archive, filename): + """ + Normalise dependency file paths to absolute ones + + Relative paths are relative to parent object + """ + src = archive.read(filename) + node = fromstring(src) + try: + rels = RelationshipList.from_tree(node) + except TypeError: + msg = "{0} contains invalid dependency definitions".format(filename) + warn(msg) + rels = RelationshipList() + folder = posixpath.dirname(filename) + parent = posixpath.split(folder)[0] + for r in rels: + if r.TargetMode == "External": + continue + elif r.target.startswith("/"): + r.target = r.target[1:] + else: + pth = posixpath.join(parent, r.target) + r.target = posixpath.normpath(pth) + return rels + + +def get_rel(archive, deps, id=None, cls=None): + """ + Get related object based on id or rel_type + """ + if not any([id, cls]): + raise ValueError("Either the id or the content type are required") + if id is not None: + rel = deps.get(id) + else: + try: + rel = next(deps.find(cls.rel_type)) + except StopIteration: # no known dependency + return + + path = rel.target + src = archive.read(path) + tree = fromstring(src) + obj = cls.from_tree(tree) + + rels_path = get_rels_path(path) + try: + obj.deps = get_dependents(archive, rels_path) + except KeyError: + obj.deps = [] + + return obj diff --git a/.venv/lib/python3.12/site-packages/openpyxl/packaging/workbook.py b/.venv/lib/python3.12/site-packages/openpyxl/packaging/workbook.py new file mode 100644 index 00000000..a6413cdc --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/packaging/workbook.py @@ -0,0 +1,185 @@ +# Copyright (c) 2010-2024 openpyxl + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Alias, + Typed, + String, + Integer, + Bool, + NoneSet, +) +from openpyxl.descriptors.excel import ExtensionList, Relation +from openpyxl.descriptors.sequence import NestedSequence +from openpyxl.descriptors.nested import NestedString + +from openpyxl.xml.constants import SHEET_MAIN_NS + +from openpyxl.workbook.defined_name import DefinedNameList +from openpyxl.workbook.external_reference import ExternalReference +from openpyxl.workbook.function_group import FunctionGroupList +from openpyxl.workbook.properties import WorkbookProperties, CalcProperties, FileVersion +from openpyxl.workbook.protection import WorkbookProtection, FileSharing +from openpyxl.workbook.smart_tags import SmartTagList, SmartTagProperties +from openpyxl.workbook.views import CustomWorkbookView, BookView +from openpyxl.workbook.web import WebPublishing, WebPublishObjectList + + +class FileRecoveryProperties(Serialisable): + + tagname = "fileRecoveryPr" + + autoRecover = Bool(allow_none=True) + crashSave = Bool(allow_none=True) + dataExtractLoad = Bool(allow_none=True) + repairLoad = Bool(allow_none=True) + + def __init__(self, + autoRecover=None, + crashSave=None, + dataExtractLoad=None, + repairLoad=None, + ): + self.autoRecover = autoRecover + self.crashSave = crashSave + self.dataExtractLoad = dataExtractLoad + self.repairLoad = repairLoad + + +class ChildSheet(Serialisable): + """ + Represents a reference to a worksheet or chartsheet in workbook.xml + + It contains the title, order and state but only an indirect reference to + the objects themselves. + """ + + tagname = "sheet" + + name = String() + sheetId = Integer() + state = NoneSet(values=(['visible', 'hidden', 'veryHidden'])) + id = Relation() + + def __init__(self, + name=None, + sheetId=None, + state="visible", + id=None, + ): + self.name = name + self.sheetId = sheetId + self.state = state + self.id = id + + +class PivotCache(Serialisable): + + tagname = "pivotCache" + + cacheId = Integer() + id = Relation() + + def __init__(self, + cacheId=None, + id=None + ): + self.cacheId = cacheId + self.id = id + + +class WorkbookPackage(Serialisable): + + """ + Represent the workbook file in the archive + """ + + tagname = "workbook" + + conformance = NoneSet(values=['strict', 'transitional']) + fileVersion = Typed(expected_type=FileVersion, allow_none=True) + fileSharing = Typed(expected_type=FileSharing, allow_none=True) + workbookPr = Typed(expected_type=WorkbookProperties, allow_none=True) + properties = Alias("workbookPr") + workbookProtection = Typed(expected_type=WorkbookProtection, allow_none=True) + bookViews = NestedSequence(expected_type=BookView) + sheets = NestedSequence(expected_type=ChildSheet) + functionGroups = Typed(expected_type=FunctionGroupList, allow_none=True) + externalReferences = NestedSequence(expected_type=ExternalReference) + definedNames = Typed(expected_type=DefinedNameList, allow_none=True) + calcPr = Typed(expected_type=CalcProperties, allow_none=True) + oleSize = NestedString(allow_none=True, attribute="ref") + customWorkbookViews = NestedSequence(expected_type=CustomWorkbookView) + pivotCaches = NestedSequence(expected_type=PivotCache, allow_none=True) + smartTagPr = Typed(expected_type=SmartTagProperties, allow_none=True) + smartTagTypes = Typed(expected_type=SmartTagList, allow_none=True) + webPublishing = Typed(expected_type=WebPublishing, allow_none=True) + fileRecoveryPr = Typed(expected_type=FileRecoveryProperties, allow_none=True) + webPublishObjects = Typed(expected_type=WebPublishObjectList, allow_none=True) + extLst = Typed(expected_type=ExtensionList, allow_none=True) + Ignorable = NestedString(namespace="http://schemas.openxmlformats.org/markup-compatibility/2006", allow_none=True) + + __elements__ = ('fileVersion', 'fileSharing', 'workbookPr', + 'workbookProtection', 'bookViews', 'sheets', 'functionGroups', + 'externalReferences', 'definedNames', 'calcPr', 'oleSize', + 'customWorkbookViews', 'pivotCaches', 'smartTagPr', 'smartTagTypes', + 'webPublishing', 'fileRecoveryPr', 'webPublishObjects') + + def __init__(self, + conformance=None, + fileVersion=None, + fileSharing=None, + workbookPr=None, + workbookProtection=None, + bookViews=(), + sheets=(), + functionGroups=None, + externalReferences=(), + definedNames=None, + calcPr=None, + oleSize=None, + customWorkbookViews=(), + pivotCaches=(), + smartTagPr=None, + smartTagTypes=None, + webPublishing=None, + fileRecoveryPr=None, + webPublishObjects=None, + extLst=None, + Ignorable=None, + ): + self.conformance = conformance + self.fileVersion = fileVersion + self.fileSharing = fileSharing + if workbookPr is None: + workbookPr = WorkbookProperties() + self.workbookPr = workbookPr + self.workbookProtection = workbookProtection + self.bookViews = bookViews + self.sheets = sheets + self.functionGroups = functionGroups + self.externalReferences = externalReferences + self.definedNames = definedNames + self.calcPr = calcPr + self.oleSize = oleSize + self.customWorkbookViews = customWorkbookViews + self.pivotCaches = pivotCaches + self.smartTagPr = smartTagPr + self.smartTagTypes = smartTagTypes + self.webPublishing = webPublishing + self.fileRecoveryPr = fileRecoveryPr + self.webPublishObjects = webPublishObjects + + + def to_tree(self): + tree = super().to_tree() + tree.set("xmlns", SHEET_MAIN_NS) + return tree + + + @property + def active(self): + for view in self.bookViews: + if view.activeTab is not None: + return view.activeTab + return 0 |