2024-12-04 13:35:57 +05:00

966 lines
27 KiB
Python

# Copyright (c) 2010-2024 openpyxl
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors import (
Typed,
Bool,
Float,
Set,
NoneSet,
String,
Integer,
DateTime,
Sequence,
)
from openpyxl.descriptors.excel import (
HexBinary,
ExtensionList,
Relation,
)
from openpyxl.descriptors.nested import NestedInteger
from openpyxl.descriptors.sequence import (
NestedSequence,
MultiSequence,
MultiSequencePart,
)
from openpyxl.xml.constants import SHEET_MAIN_NS
from openpyxl.xml.functions import tostring
from openpyxl.packaging.relationship import (
RelationshipList,
Relationship,
get_rels_path
)
from .table import (
PivotArea,
Reference,
)
from .fields import (
Boolean,
Error,
Missing,
Number,
Text,
TupleList,
DateTimeField,
)
class MeasureDimensionMap(Serialisable):
tagname = "map"
measureGroup = Integer(allow_none=True)
dimension = Integer(allow_none=True)
def __init__(self,
measureGroup=None,
dimension=None,
):
self.measureGroup = measureGroup
self.dimension = dimension
class MeasureGroup(Serialisable):
tagname = "measureGroup"
name = String()
caption = String()
def __init__(self,
name=None,
caption=None,
):
self.name = name
self.caption = caption
class PivotDimension(Serialisable):
tagname = "dimension"
measure = Bool()
name = String()
uniqueName = String()
caption = String()
def __init__(self,
measure=None,
name=None,
uniqueName=None,
caption=None,
):
self.measure = measure
self.name = name
self.uniqueName = uniqueName
self.caption = caption
class CalculatedMember(Serialisable):
tagname = "calculatedMember"
name = String()
mdx = String()
memberName = String(allow_none=True)
hierarchy = String(allow_none=True)
parent = String(allow_none=True)
solveOrder = Integer(allow_none=True)
set = Bool()
extLst = Typed(expected_type=ExtensionList, allow_none=True)
__elements__ = ()
def __init__(self,
name=None,
mdx=None,
memberName=None,
hierarchy=None,
parent=None,
solveOrder=None,
set=None,
extLst=None,
):
self.name = name
self.mdx = mdx
self.memberName = memberName
self.hierarchy = hierarchy
self.parent = parent
self.solveOrder = solveOrder
self.set = set
#self.extLst = extLst
class CalculatedItem(Serialisable):
tagname = "calculatedItem"
field = Integer(allow_none=True)
formula = String()
pivotArea = Typed(expected_type=PivotArea, )
extLst = Typed(expected_type=ExtensionList, allow_none=True)
__elements__ = ('pivotArea', 'extLst')
def __init__(self,
field=None,
formula=None,
pivotArea=None,
extLst=None,
):
self.field = field
self.formula = formula
self.pivotArea = pivotArea
self.extLst = extLst
class ServerFormat(Serialisable):
tagname = "serverFormat"
culture = String(allow_none=True)
format = String(allow_none=True)
def __init__(self,
culture=None,
format=None,
):
self.culture = culture
self.format = format
class Query(Serialisable):
tagname = "query"
mdx = String()
tpls = Typed(expected_type=TupleList, allow_none=True)
__elements__ = ('tpls',)
def __init__(self,
mdx=None,
tpls=None,
):
self.mdx = mdx
self.tpls = tpls
class OLAPSet(Serialisable):
tagname = "set"
count = Integer()
maxRank = Integer()
setDefinition = String()
sortType = NoneSet(values=(['ascending', 'descending', 'ascendingAlpha',
'descendingAlpha', 'ascendingNatural', 'descendingNatural']))
queryFailed = Bool()
tpls = Typed(expected_type=TupleList, allow_none=True)
sortByTuple = Typed(expected_type=TupleList, allow_none=True)
__elements__ = ('tpls', 'sortByTuple')
def __init__(self,
count=None,
maxRank=None,
setDefinition=None,
sortType=None,
queryFailed=None,
tpls=None,
sortByTuple=None,
):
self.count = count
self.maxRank = maxRank
self.setDefinition = setDefinition
self.sortType = sortType
self.queryFailed = queryFailed
self.tpls = tpls
self.sortByTuple = sortByTuple
class PCDSDTCEntries(Serialisable):
# Implements CT_PCDSDTCEntries
tagname = "entries"
count = Integer(allow_none=True)
# elements are choice
m = Typed(expected_type=Missing, allow_none=True)
n = Typed(expected_type=Number, allow_none=True)
e = Typed(expected_type=Error, allow_none=True)
s = Typed(expected_type=Text, allow_none=True)
__elements__ = ('m', 'n', 'e', 's')
def __init__(self,
count=None,
m=None,
n=None,
e=None,
s=None,
):
self.count = count
self.m = m
self.n = n
self.e = e
self.s = s
class TupleCache(Serialisable):
tagname = "tupleCache"
entries = Typed(expected_type=PCDSDTCEntries, allow_none=True)
sets = NestedSequence(expected_type=OLAPSet, count=True)
queryCache = NestedSequence(expected_type=Query, count=True)
serverFormats = NestedSequence(expected_type=ServerFormat, count=True)
extLst = Typed(expected_type=ExtensionList, allow_none=True)
__elements__ = ('entries', 'sets', 'queryCache', 'serverFormats', 'extLst')
def __init__(self,
entries=None,
sets=(),
queryCache=(),
serverFormats=(),
extLst=None,
):
self.entries = entries
self.sets = sets
self.queryCache = queryCache
self.serverFormats = serverFormats
self.extLst = extLst
class OLAPKPI(Serialisable):
tagname = "kpi"
uniqueName = String()
caption = String(allow_none=True)
displayFolder = String(allow_none=True)
measureGroup = String(allow_none=True)
parent = String(allow_none=True)
value = String()
goal = String(allow_none=True)
status = String(allow_none=True)
trend = String(allow_none=True)
weight = String(allow_none=True)
time = String(allow_none=True)
def __init__(self,
uniqueName=None,
caption=None,
displayFolder=None,
measureGroup=None,
parent=None,
value=None,
goal=None,
status=None,
trend=None,
weight=None,
time=None,
):
self.uniqueName = uniqueName
self.caption = caption
self.displayFolder = displayFolder
self.measureGroup = measureGroup
self.parent = parent
self.value = value
self.goal = goal
self.status = status
self.trend = trend
self.weight = weight
self.time = time
class GroupMember(Serialisable):
tagname = "groupMember"
uniqueName = String()
group = Bool()
def __init__(self,
uniqueName=None,
group=None,
):
self.uniqueName = uniqueName
self.group = group
class LevelGroup(Serialisable):
tagname = "group"
name = String()
uniqueName = String()
caption = String()
uniqueParent = String()
id = Integer()
groupMembers = NestedSequence(expected_type=GroupMember, count=True)
__elements__ = ('groupMembers',)
def __init__(self,
name=None,
uniqueName=None,
caption=None,
uniqueParent=None,
id=None,
groupMembers=(),
):
self.name = name
self.uniqueName = uniqueName
self.caption = caption
self.uniqueParent = uniqueParent
self.id = id
self.groupMembers = groupMembers
class GroupLevel(Serialisable):
tagname = "groupLevel"
uniqueName = String()
caption = String()
user = Bool()
customRollUp = Bool()
groups = NestedSequence(expected_type=LevelGroup, count=True)
extLst = Typed(expected_type=ExtensionList, allow_none=True)
__elements__ = ('groups', 'extLst')
def __init__(self,
uniqueName=None,
caption=None,
user=None,
customRollUp=None,
groups=(),
extLst=None,
):
self.uniqueName = uniqueName
self.caption = caption
self.user = user
self.customRollUp = customRollUp
self.groups = groups
self.extLst = extLst
class FieldUsage(Serialisable):
tagname = "fieldUsage"
x = Integer()
def __init__(self,
x=None,
):
self.x = x
class CacheHierarchy(Serialisable):
tagname = "cacheHierarchy"
uniqueName = String()
caption = String(allow_none=True)
measure = Bool()
set = Bool()
parentSet = Integer(allow_none=True)
iconSet = Integer()
attribute = Bool()
time = Bool()
keyAttribute = Bool()
defaultMemberUniqueName = String(allow_none=True)
allUniqueName = String(allow_none=True)
allCaption = String(allow_none=True)
dimensionUniqueName = String(allow_none=True)
displayFolder = String(allow_none=True)
measureGroup = String(allow_none=True)
measures = Bool()
count = Integer()
oneField = Bool()
memberValueDatatype = Integer(allow_none=True)
unbalanced = Bool(allow_none=True)
unbalancedGroup = Bool(allow_none=True)
hidden = Bool()
fieldsUsage = NestedSequence(expected_type=FieldUsage, count=True)
groupLevels = NestedSequence(expected_type=GroupLevel, count=True)
extLst = Typed(expected_type=ExtensionList, allow_none=True)
__elements__ = ('fieldsUsage', 'groupLevels')
def __init__(self,
uniqueName="",
caption=None,
measure=None,
set=None,
parentSet=None,
iconSet=0,
attribute=None,
time=None,
keyAttribute=None,
defaultMemberUniqueName=None,
allUniqueName=None,
allCaption=None,
dimensionUniqueName=None,
displayFolder=None,
measureGroup=None,
measures=None,
count=None,
oneField=None,
memberValueDatatype=None,
unbalanced=None,
unbalancedGroup=None,
hidden=None,
fieldsUsage=(),
groupLevels=(),
extLst=None,
):
self.uniqueName = uniqueName
self.caption = caption
self.measure = measure
self.set = set
self.parentSet = parentSet
self.iconSet = iconSet
self.attribute = attribute
self.time = time
self.keyAttribute = keyAttribute
self.defaultMemberUniqueName = defaultMemberUniqueName
self.allUniqueName = allUniqueName
self.allCaption = allCaption
self.dimensionUniqueName = dimensionUniqueName
self.displayFolder = displayFolder
self.measureGroup = measureGroup
self.measures = measures
self.count = count
self.oneField = oneField
self.memberValueDatatype = memberValueDatatype
self.unbalanced = unbalanced
self.unbalancedGroup = unbalancedGroup
self.hidden = hidden
self.fieldsUsage = fieldsUsage
self.groupLevels = groupLevels
self.extLst = extLst
class GroupItems(Serialisable):
tagname = "groupItems"
m = Sequence(expected_type=Missing)
n = Sequence(expected_type=Number)
b = Sequence(expected_type=Boolean)
e = Sequence(expected_type=Error)
s = Sequence(expected_type=Text)
d = Sequence(expected_type=DateTimeField,)
__elements__ = ('m', 'n', 'b', 'e', 's', 'd')
__attrs__ = ("count", )
def __init__(self,
count=None,
m=(),
n=(),
b=(),
e=(),
s=(),
d=(),
):
self.m = m
self.n = n
self.b = b
self.e = e
self.s = s
self.d = d
@property
def count(self):
return len(self.m + self.n + self.b + self.e + self.s + self.d)
class RangePr(Serialisable):
tagname = "rangePr"
autoStart = Bool(allow_none=True)
autoEnd = Bool(allow_none=True)
groupBy = NoneSet(values=(['range', 'seconds', 'minutes', 'hours', 'days',
'months', 'quarters', 'years']))
startNum = Float(allow_none=True)
endNum = Float(allow_none=True)
startDate = DateTime(allow_none=True)
endDate = DateTime(allow_none=True)
groupInterval = Float(allow_none=True)
def __init__(self,
autoStart=True,
autoEnd=True,
groupBy="range",
startNum=None,
endNum=None,
startDate=None,
endDate=None,
groupInterval=1,
):
self.autoStart = autoStart
self.autoEnd = autoEnd
self.groupBy = groupBy
self.startNum = startNum
self.endNum = endNum
self.startDate = startDate
self.endDate = endDate
self.groupInterval = groupInterval
class FieldGroup(Serialisable):
tagname = "fieldGroup"
par = Integer(allow_none=True)
base = Integer(allow_none=True)
rangePr = Typed(expected_type=RangePr, allow_none=True)
discretePr = NestedSequence(expected_type=NestedInteger, count=True)
groupItems = Typed(expected_type=GroupItems, allow_none=True)
__elements__ = ('rangePr', 'discretePr', 'groupItems')
def __init__(self,
par=None,
base=None,
rangePr=None,
discretePr=(),
groupItems=None,
):
self.par = par
self.base = base
self.rangePr = rangePr
self.discretePr = discretePr
self.groupItems = groupItems
class SharedItems(Serialisable):
tagname = "sharedItems"
_fields = MultiSequence()
m = MultiSequencePart(expected_type=Missing, store="_fields")
n = MultiSequencePart(expected_type=Number, store="_fields")
b = MultiSequencePart(expected_type=Boolean, store="_fields")
e = MultiSequencePart(expected_type=Error, store="_fields")
s = MultiSequencePart(expected_type=Text, store="_fields")
d = MultiSequencePart(expected_type=DateTimeField, store="_fields")
# attributes are optional and must be derived from associated cache records
containsSemiMixedTypes = Bool(allow_none=True)
containsNonDate = Bool(allow_none=True)
containsDate = Bool(allow_none=True)
containsString = Bool(allow_none=True)
containsBlank = Bool(allow_none=True)
containsMixedTypes = Bool(allow_none=True)
containsNumber = Bool(allow_none=True)
containsInteger = Bool(allow_none=True)
minValue = Float(allow_none=True)
maxValue = Float(allow_none=True)
minDate = DateTime(allow_none=True)
maxDate = DateTime(allow_none=True)
longText = Bool(allow_none=True)
__attrs__ = ('count', 'containsBlank', 'containsDate', 'containsInteger',
'containsMixedTypes', 'containsNonDate', 'containsNumber',
'containsSemiMixedTypes', 'containsString', 'minValue', 'maxValue',
'minDate', 'maxDate', 'longText')
def __init__(self,
_fields=(),
containsSemiMixedTypes=None,
containsNonDate=None,
containsDate=None,
containsString=None,
containsBlank=None,
containsMixedTypes=None,
containsNumber=None,
containsInteger=None,
minValue=None,
maxValue=None,
minDate=None,
maxDate=None,
count=None,
longText=None,
):
self._fields = _fields
self.containsBlank = containsBlank
self.containsDate = containsDate
self.containsNonDate = containsNonDate
self.containsString = containsString
self.containsMixedTypes = containsMixedTypes
self.containsSemiMixedTypes = containsSemiMixedTypes
self.containsNumber = containsNumber
self.containsInteger = containsInteger
self.minValue = minValue
self.maxValue = maxValue
self.minDate = minDate
self.maxDate = maxDate
self.longText = longText
@property
def count(self):
return len(self._fields)
class CacheField(Serialisable):
tagname = "cacheField"
sharedItems = Typed(expected_type=SharedItems, allow_none=True)
fieldGroup = Typed(expected_type=FieldGroup, allow_none=True)
mpMap = NestedInteger(allow_none=True, attribute="v")
extLst = Typed(expected_type=ExtensionList, allow_none=True)
name = String()
caption = String(allow_none=True)
propertyName = String(allow_none=True)
serverField = Bool(allow_none=True)
uniqueList = Bool(allow_none=True)
numFmtId = Integer(allow_none=True)
formula = String(allow_none=True)
sqlType = Integer(allow_none=True)
hierarchy = Integer(allow_none=True)
level = Integer(allow_none=True)
databaseField = Bool(allow_none=True)
mappingCount = Integer(allow_none=True)
memberPropertyField = Bool(allow_none=True)
__elements__ = ('sharedItems', 'fieldGroup', 'mpMap')
def __init__(self,
sharedItems=None,
fieldGroup=None,
mpMap=None,
extLst=None,
name=None,
caption=None,
propertyName=None,
serverField=None,
uniqueList=True,
numFmtId=None,
formula=None,
sqlType=0,
hierarchy=0,
level=0,
databaseField=True,
mappingCount=None,
memberPropertyField=None,
):
self.sharedItems = sharedItems
self.fieldGroup = fieldGroup
self.mpMap = mpMap
self.extLst = extLst
self.name = name
self.caption = caption
self.propertyName = propertyName
self.serverField = serverField
self.uniqueList = uniqueList
self.numFmtId = numFmtId
self.formula = formula
self.sqlType = sqlType
self.hierarchy = hierarchy
self.level = level
self.databaseField = databaseField
self.mappingCount = mappingCount
self.memberPropertyField = memberPropertyField
class RangeSet(Serialisable):
tagname = "rangeSet"
i1 = Integer(allow_none=True)
i2 = Integer(allow_none=True)
i3 = Integer(allow_none=True)
i4 = Integer(allow_none=True)
ref = String()
name = String(allow_none=True)
sheet = String(allow_none=True)
def __init__(self,
i1=None,
i2=None,
i3=None,
i4=None,
ref=None,
name=None,
sheet=None,
):
self.i1 = i1
self.i2 = i2
self.i3 = i3
self.i4 = i4
self.ref = ref
self.name = name
self.sheet = sheet
class PageItem(Serialisable):
tagname = "pageItem"
name = String()
def __init__(self,
name=None,
):
self.name = name
class Consolidation(Serialisable):
tagname = "consolidation"
autoPage = Bool(allow_none=True)
pages = NestedSequence(expected_type=PageItem, count=True)
rangeSets = NestedSequence(expected_type=RangeSet, count=True)
__elements__ = ('pages', 'rangeSets')
def __init__(self,
autoPage=None,
pages=(),
rangeSets=(),
):
self.autoPage = autoPage
self.pages = pages
self.rangeSets = rangeSets
class WorksheetSource(Serialisable):
tagname = "worksheetSource"
ref = String(allow_none=True)
name = String(allow_none=True)
sheet = String(allow_none=True)
def __init__(self,
ref=None,
name=None,
sheet=None,
):
self.ref = ref
self.name = name
self.sheet = sheet
class CacheSource(Serialisable):
tagname = "cacheSource"
type = Set(values=(['worksheet', 'external', 'consolidation', 'scenario']))
connectionId = Integer(allow_none=True)
# some elements are choice
worksheetSource = Typed(expected_type=WorksheetSource, allow_none=True)
consolidation = Typed(expected_type=Consolidation, allow_none=True)
extLst = Typed(expected_type=ExtensionList, allow_none=True)
__elements__ = ('worksheetSource', 'consolidation',)
def __init__(self,
type=None,
connectionId=None,
worksheetSource=None,
consolidation=None,
extLst=None,
):
self.type = type
self.connectionId = connectionId
self.worksheetSource = worksheetSource
self.consolidation = consolidation
class CacheDefinition(Serialisable):
mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"
rel_type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
_id = 1
_path = "/xl/pivotCache/pivotCacheDefinition{0}.xml"
records = None
tagname = "pivotCacheDefinition"
invalid = Bool(allow_none=True)
saveData = Bool(allow_none=True)
refreshOnLoad = Bool(allow_none=True)
optimizeMemory = Bool(allow_none=True)
enableRefresh = Bool(allow_none=True)
refreshedBy = String(allow_none=True)
refreshedDate = Float(allow_none=True)
refreshedDateIso = DateTime(allow_none=True)
backgroundQuery = Bool(allow_none=True)
missingItemsLimit = Integer(allow_none=True)
createdVersion = Integer(allow_none=True)
refreshedVersion = Integer(allow_none=True)
minRefreshableVersion = Integer(allow_none=True)
recordCount = Integer(allow_none=True)
upgradeOnRefresh = Bool(allow_none=True)
supportSubquery = Bool(allow_none=True)
supportAdvancedDrill = Bool(allow_none=True)
cacheSource = Typed(expected_type=CacheSource)
cacheFields = NestedSequence(expected_type=CacheField, count=True)
cacheHierarchies = NestedSequence(expected_type=CacheHierarchy, allow_none=True)
kpis = NestedSequence(expected_type=OLAPKPI, count=True)
tupleCache = Typed(expected_type=TupleCache, allow_none=True)
calculatedItems = NestedSequence(expected_type=CalculatedItem, count=True)
calculatedMembers = NestedSequence(expected_type=CalculatedMember, count=True)
dimensions = NestedSequence(expected_type=PivotDimension, allow_none=True)
measureGroups = NestedSequence(expected_type=MeasureGroup, count=True)
maps = NestedSequence(expected_type=MeasureDimensionMap, count=True)
extLst = Typed(expected_type=ExtensionList, allow_none=True)
id = Relation()
__elements__ = ('cacheSource', 'cacheFields', 'cacheHierarchies', 'kpis',
'tupleCache', 'calculatedItems', 'calculatedMembers', 'dimensions',
'measureGroups', 'maps',)
def __init__(self,
invalid=None,
saveData=None,
refreshOnLoad=None,
optimizeMemory=None,
enableRefresh=None,
refreshedBy=None,
refreshedDate=None,
refreshedDateIso=None,
backgroundQuery=None,
missingItemsLimit=None,
createdVersion=None,
refreshedVersion=None,
minRefreshableVersion=None,
recordCount=None,
upgradeOnRefresh=None,
tupleCache=None,
supportSubquery=None,
supportAdvancedDrill=None,
cacheSource=None,
cacheFields=(),
cacheHierarchies=(),
kpis=(),
calculatedItems=(),
calculatedMembers=(),
dimensions=(),
measureGroups=(),
maps=(),
extLst=None,
id = None,
):
self.invalid = invalid
self.saveData = saveData
self.refreshOnLoad = refreshOnLoad
self.optimizeMemory = optimizeMemory
self.enableRefresh = enableRefresh
self.refreshedBy = refreshedBy
self.refreshedDate = refreshedDate
self.refreshedDateIso = refreshedDateIso
self.backgroundQuery = backgroundQuery
self.missingItemsLimit = missingItemsLimit
self.createdVersion = createdVersion
self.refreshedVersion = refreshedVersion
self.minRefreshableVersion = minRefreshableVersion
self.recordCount = recordCount
self.upgradeOnRefresh = upgradeOnRefresh
self.supportSubquery = supportSubquery
self.supportAdvancedDrill = supportAdvancedDrill
self.cacheSource = cacheSource
self.cacheFields = cacheFields
self.cacheHierarchies = cacheHierarchies
self.kpis = kpis
self.tupleCache = tupleCache
self.calculatedItems = calculatedItems
self.calculatedMembers = calculatedMembers
self.dimensions = dimensions
self.measureGroups = measureGroups
self.maps = maps
self.id = id
def to_tree(self):
node = super().to_tree()
node.set("xmlns", SHEET_MAIN_NS)
return node
@property
def path(self):
return self._path.format(self._id)
def _write(self, archive, manifest):
"""
Add to zipfile and update manifest
"""
self._write_rels(archive, manifest)
xml = tostring(self.to_tree())
archive.writestr(self.path[1:], xml)
manifest.append(self)
def _write_rels(self, archive, manifest):
"""
Write the relevant child objects and add links
"""
if self.records is None:
return
rels = RelationshipList()
r = Relationship(Type=self.records.rel_type, Target=self.records.path)
rels.append(r)
self.id = r.id
self.records._id = self._id
self.records._write(archive, manifest)
path = get_rels_path(self.path)
xml = tostring(rels.to_tree())
archive.writestr(path[1:], xml)