Version 0.1

Added sidebar, Dashboard, Line Graph
This commit is contained in:
Ayxan
2022-05-23 04:12:37 +04:00
parent d660f2a4ca
commit 9e90b4a150
204 changed files with 29218 additions and 109 deletions

View File

@ -0,0 +1,3 @@
"""
Stuff related to Office OpenXML packaging: relationships, archive, content types.
"""

View File

@ -0,0 +1,112 @@
# Copyright (c) 2010-2022 openpyxl
import datetime
from openpyxl.compat import safe_string
from openpyxl.descriptors import (
String,
DateTime,
Alias,
)
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors.nested import NestedText
from openpyxl.xml.functions import (Element, QName, tostring)
from openpyxl.xml.constants import (
COREPROPS_NS,
DCORE_NS,
XSI_NS,
DCTERMS_NS,
DCTERMS_PREFIX
)
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:
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(QualifiedDateTime, self).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)
modified = QualifiedDateTime(allow_none=True, namespace=DCTERMS_NS)
__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=datetime.datetime.utcnow(),
creator="openpyxl",
description=None,
identifier=None,
language=None,
modified=datetime.datetime.utcnow(),
subject=None,
title=None,
):
self.contentStatus = contentStatus
self.lastPrinted = lastPrinted
self.revision = revision
self.version = version
self.creator = creator
self.lastModifiedBy = lastModifiedBy
self.modified = modified
self.created = created
self.title = title
self.subject = subject
self.description = description
self.identifier = identifier
self.language = language
self.keywords = keywords
self.category = category

View File

@ -0,0 +1,141 @@
# Copyright (c) 2010-2022 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
def get_version():
from openpyxl import __version__
VERSION = ".".join(__version__.split(".")[:2])
return 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
"""
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="Microsoft Excel",
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 = Application
if AppVersion is None:
AppVersion = get_version()
self.AppVersion = AppVersion
self.DocSecurity = DocSecurity
def to_tree(self):
tree = super(ExtendedProperties, self).to_tree()
tree.set("xmlns", XPROPS_NS)
return tree

View File

@ -0,0 +1,56 @@
# Copyright (c) 2010-2022 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
"""

View File

@ -0,0 +1,210 @@
# Copyright (c) 2010-2022 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_CORE,
ARC_CONTENT_TYPES,
ARC_WORKBOOK,
ARC_APP,
ARC_THEME,
ARC_STYLE,
ARC_SHARED_STRINGS,
EXTERNAL_LINK,
THEME_TYPE,
STYLES_TYPE,
XLSX,
XLSM,
XLTM,
XLTX,
WORKSHEET_TYPE,
COMMENTS_TYPE,
SHARED_STRINGS,
DRAWING_TYPE,
CHART_TYPE,
CHARTSHAPE_TYPE,
CHARTSHEET_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(Manifest, self).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)

View File

@ -0,0 +1,176 @@
# Copyright (c) 2010-2022 openpyxl
import posixpath
from openpyxl.descriptors import (
String,
Set,
NoneSet,
Alias,
Sequence,
)
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.xml.constants import REL_NS, PKG_REL_NS
from openpyxl.xml.functions import (
Element,
fromstring,
tostring
)
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(Serialisable):
tagname = "Relationships"
Relationship = Sequence(expected_type=Relationship)
def __init__(self, Relationship=()):
self.Relationship = Relationship
def append(self, value):
values = self.Relationship[:]
values.append(value)
if not value.Id:
value.Id = "rId{0}".format((len(values)))
self.Relationship = values
def __len__(self):
return len(self.Relationship)
def __bool__(self):
return bool(self.Relationship)
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.Relationship:
if r.Type == content_type:
yield r
def __getitem__(self, key):
for r in self.Relationship:
if r.Id == key:
return r
raise KeyError("Unknown relationship: {0}".format(key))
def to_tree(self):
tree = Element("Relationships", xmlns=PKG_REL_NS)
for idx, rel in enumerate(self.Relationship, 1):
if not rel.Id:
rel.Id = "rId{0}".format(idx)
tree.append(rel.to_tree())
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
from warnings import warn
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.Relationship:
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[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

View File

@ -0,0 +1,204 @@
# Copyright (c) 2010-2022 openpyxl
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors import (
Alias,
Typed,
String,
Integer,
Bool,
NoneSet,
Set,
Sequence,
)
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 DefinedName, 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(WorkbookPackage, self).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
@property
def pivot_caches(self):
"""
Get PivotCache objects
"""
d = {}
for c in self.caches:
cache = get_rel(self.archive, self.rels, id=c.id, cls=CacheDefinition)
if cache.deps:
records = get_rel(self.archive, cache.deps, cache.id, RecordList)
else:
records = None
cache.records = records
d[c.cacheId] = cache
return d