about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/openpyxl/pivot
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/pivot')
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/pivot/__init__.py1
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/pivot/cache.py965
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/pivot/fields.py326
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/pivot/record.py111
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/pivot/table.py1261
5 files changed, 2664 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/pivot/__init__.py b/.venv/lib/python3.12/site-packages/openpyxl/pivot/__init__.py
new file mode 100644
index 00000000..ab6cdead
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/openpyxl/pivot/__init__.py
@@ -0,0 +1 @@
+# Copyright (c) 2010-2024 openpyxl
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/pivot/cache.py b/.venv/lib/python3.12/site-packages/openpyxl/pivot/cache.py
new file mode 100644
index 00000000..7ae2b4dd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/openpyxl/pivot/cache.py
@@ -0,0 +1,965 @@
+# 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)
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/pivot/fields.py b/.venv/lib/python3.12/site-packages/openpyxl/pivot/fields.py
new file mode 100644
index 00000000..cd6bcb28
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/openpyxl/pivot/fields.py
@@ -0,0 +1,326 @@
+# Copyright (c) 2010-2024 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    DateTime,
+    Bool,
+    Float,
+    String,
+    Integer,
+    Sequence,
+)
+from openpyxl.descriptors.excel import HexBinary
+
+class Index(Serialisable):
+
+    tagname = "x"
+
+    v = Integer(allow_none=True)
+
+    def __init__(self,
+                 v=0,
+                ):
+        self.v = v
+
+
+class Tuple(Serialisable):
+
+    tagname = "tpl"
+
+    fld = Integer(allow_none=True)
+    hier = Integer(allow_none=True)
+    item = Integer()
+
+    def __init__(self,
+                 fld=None,
+                 hier=None,
+                 item=None,
+                ):
+        self.fld = fld
+        self.hier = hier
+        self.item = item
+
+
+class TupleList(Serialisable):
+
+    tagname = "tpls"
+
+    c = Integer(allow_none=True)
+    tpl = Typed(expected_type=Tuple, )
+
+    __elements__ = ('tpl',)
+
+    def __init__(self,
+                 c=None,
+                 tpl=None,
+                ):
+        self.c = c
+        self.tpl = tpl
+
+
+class Missing(Serialisable):
+
+    tagname = "m"
+
+    tpls = Sequence(expected_type=TupleList)
+    x = Sequence(expected_type=Index)
+    u = Bool(allow_none=True)
+    f = Bool(allow_none=True)
+    c = String(allow_none=True)
+    cp = Integer(allow_none=True)
+    _in = Integer(allow_none=True)
+    bc = HexBinary(allow_none=True)
+    fc = HexBinary(allow_none=True)
+    i = Bool(allow_none=True)
+    un = Bool(allow_none=True)
+    st = Bool(allow_none=True)
+    b = Bool(allow_none=True)
+
+    __elements__ = ('tpls', 'x')
+
+    def __init__(self,
+                 tpls=(),
+                 x=(),
+                 u=None,
+                 f=None,
+                 c=None,
+                 cp=None,
+                 _in=None,
+                 bc=None,
+                 fc=None,
+                 i=None,
+                 un=None,
+                 st=None,
+                 b=None,
+                ):
+        self.tpls = tpls
+        self.x = x
+        self.u = u
+        self.f = f
+        self.c = c
+        self.cp = cp
+        self._in = _in
+        self.bc = bc
+        self.fc = fc
+        self.i = i
+        self.un = un
+        self.st = st
+        self.b = b
+
+
+class Number(Serialisable):
+
+    tagname = "n"
+
+    tpls = Sequence(expected_type=TupleList)
+    x = Sequence(expected_type=Index)
+    v = Float()
+    u = Bool(allow_none=True)
+    f = Bool(allow_none=True)
+    c = String(allow_none=True)
+    cp = Integer(allow_none=True)
+    _in = Integer(allow_none=True)
+    bc = HexBinary(allow_none=True)
+    fc = HexBinary(allow_none=True)
+    i = Bool(allow_none=True)
+    un = Bool(allow_none=True)
+    st = Bool(allow_none=True)
+    b = Bool(allow_none=True)
+
+    __elements__ = ('tpls', 'x')
+
+    def __init__(self,
+                 tpls=(),
+                 x=(),
+                 v=None,
+                 u=None,
+                 f=None,
+                 c=None,
+                 cp=None,
+                 _in=None,
+                 bc=None,
+                 fc=None,
+                 i=None,
+                 un=None,
+                 st=None,
+                 b=None,
+                ):
+        self.tpls = tpls
+        self.x = x
+        self.v = v
+        self.u = u
+        self.f = f
+        self.c = c
+        self.cp = cp
+        self._in = _in
+        self.bc = bc
+        self.fc = fc
+        self.i = i
+        self.un = un
+        self.st = st
+        self.b = b
+
+
+class Error(Serialisable):
+
+    tagname = "e"
+
+    tpls = Typed(expected_type=TupleList, allow_none=True)
+    x = Sequence(expected_type=Index)
+    v = String()
+    u = Bool(allow_none=True)
+    f = Bool(allow_none=True)
+    c = String(allow_none=True)
+    cp = Integer(allow_none=True)
+    _in = Integer(allow_none=True)
+    bc = HexBinary(allow_none=True)
+    fc = HexBinary(allow_none=True)
+    i = Bool(allow_none=True)
+    un = Bool(allow_none=True)
+    st = Bool(allow_none=True)
+    b = Bool(allow_none=True)
+
+    __elements__ = ('tpls', 'x')
+
+    def __init__(self,
+                 tpls=None,
+                 x=(),
+                 v=None,
+                 u=None,
+                 f=None,
+                 c=None,
+                 cp=None,
+                 _in=None,
+                 bc=None,
+                 fc=None,
+                 i=None,
+                 un=None,
+                 st=None,
+                 b=None,
+                ):
+        self.tpls = tpls
+        self.x = x
+        self.v = v
+        self.u = u
+        self.f = f
+        self.c = c
+        self.cp = cp
+        self._in = _in
+        self.bc = bc
+        self.fc = fc
+        self.i = i
+        self.un = un
+        self.st = st
+        self.b = b
+
+
+class Boolean(Serialisable):
+
+    tagname = "b"
+
+    x = Sequence(expected_type=Index)
+    v = Bool()
+    u = Bool(allow_none=True)
+    f = Bool(allow_none=True)
+    c = String(allow_none=True)
+    cp = Integer(allow_none=True)
+
+    __elements__ = ('x',)
+
+    def __init__(self,
+                 x=(),
+                 v=None,
+                 u=None,
+                 f=None,
+                 c=None,
+                 cp=None,
+                ):
+        self.x = x
+        self.v = v
+        self.u = u
+        self.f = f
+        self.c = c
+        self.cp = cp
+
+
+class Text(Serialisable):
+
+    tagname = "s"
+
+    tpls = Sequence(expected_type=TupleList)
+    x = Sequence(expected_type=Index)
+    v = String()
+    u = Bool(allow_none=True)
+    f = Bool(allow_none=True)
+    c = String(allow_none=True)
+    cp = Integer(allow_none=True)
+    _in = Integer(allow_none=True)
+    bc = HexBinary(allow_none=True)
+    fc = HexBinary(allow_none=True)
+    i = Bool(allow_none=True)
+    un = Bool(allow_none=True)
+    st = Bool(allow_none=True)
+    b = Bool(allow_none=True)
+
+    __elements__ = ('tpls', 'x')
+
+    def __init__(self,
+                 tpls=(),
+                 x=(),
+                 v=None,
+                 u=None,
+                 f=None,
+                 c=None,
+                 cp=None,
+                 _in=None,
+                 bc=None,
+                 fc=None,
+                 i=None,
+                 un=None,
+                 st=None,
+                 b=None,
+                 ):
+        self.tpls = tpls
+        self.x = x
+        self.v = v
+        self.u = u
+        self.f = f
+        self.c = c
+        self.cp = cp
+        self._in = _in
+        self.bc = bc
+        self.fc = fc
+        self.i = i
+        self.un = un
+        self.st = st
+        self.b = b
+
+
+class DateTimeField(Serialisable):
+
+    tagname = "d"
+
+    x = Sequence(expected_type=Index)
+    v = DateTime()
+    u = Bool(allow_none=True)
+    f = Bool(allow_none=True)
+    c = String(allow_none=True)
+    cp = Integer(allow_none=True)
+
+    __elements__ = ('x',)
+
+    def __init__(self,
+                 x=(),
+                 v=None,
+                 u=None,
+                 f=None,
+                 c=None,
+                 cp=None,
+                 ):
+        self.x = x
+        self.v = v
+        self.u = u
+        self.f = f
+        self.c = c
+        self.cp = cp
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/pivot/record.py b/.venv/lib/python3.12/site-packages/openpyxl/pivot/record.py
new file mode 100644
index 00000000..42603770
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/openpyxl/pivot/record.py
@@ -0,0 +1,111 @@
+# Copyright (c) 2010-2024 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Integer,
+    Sequence,
+)
+from openpyxl.descriptors.sequence import (
+    MultiSequence,
+    MultiSequencePart,
+)
+from openpyxl.descriptors.excel import ExtensionList
+from openpyxl.descriptors.nested import (
+    NestedInteger,
+    NestedBool,
+)
+
+from openpyxl.xml.constants import SHEET_MAIN_NS
+from openpyxl.xml.functions import tostring
+
+from .fields import (
+    Boolean,
+    Error,
+    Missing,
+    Number,
+    Text,
+    TupleList,
+    DateTimeField,
+    Index,
+)
+
+
+class Record(Serialisable):
+
+    tagname = "r"
+
+    _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")
+    x = MultiSequencePart(expected_type=Index, store="_fields")
+
+
+    def __init__(self,
+                 _fields=(),
+                 m=None,
+                 n=None,
+                 b=None,
+                 e=None,
+                 s=None,
+                 d=None,
+                 x=None,
+                ):
+        self._fields = _fields
+
+
+class RecordList(Serialisable):
+
+    mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"
+    rel_type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheRecords"
+    _id = 1
+    _path = "/xl/pivotCache/pivotCacheRecords{0}.xml"
+
+    tagname ="pivotCacheRecords"
+
+    r = Sequence(expected_type=Record, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('r', )
+    __attrs__ = ('count', )
+
+    def __init__(self,
+                 count=None,
+                 r=(),
+                 extLst=None,
+                ):
+        self.r = r
+        self.extLst = extLst
+
+
+    @property
+    def count(self):
+        return len(self.r)
+
+
+    def to_tree(self):
+        tree = super().to_tree()
+        tree.set("xmlns", SHEET_MAIN_NS)
+        return tree
+
+
+    @property
+    def path(self):
+        return self._path.format(self._id)
+
+
+    def _write(self, archive, manifest):
+        """
+        Write to zipfile and update manifest
+        """
+        xml = tostring(self.to_tree())
+        archive.writestr(self.path[1:], xml)
+        manifest.append(self)
+
+
+    def _write_rels(self, archive, manifest):
+        pass
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/pivot/table.py b/.venv/lib/python3.12/site-packages/openpyxl/pivot/table.py
new file mode 100644
index 00000000..cc3548b1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/openpyxl/pivot/table.py
@@ -0,0 +1,1261 @@
+# Copyright (c) 2010-2024 openpyxl
+
+
+from collections import defaultdict
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Integer,
+    NoneSet,
+    Set,
+    Bool,
+    String,
+    Bool,
+    Sequence,
+)
+
+from openpyxl.descriptors.excel import ExtensionList, Relation
+from openpyxl.descriptors.sequence import NestedSequence
+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 .fields import Index
+
+from openpyxl.worksheet.filters import (
+    AutoFilter,
+)
+
+
+class HierarchyUsage(Serialisable):
+
+    tagname = "hierarchyUsage"
+
+    hierarchyUsage = Integer()
+
+    def __init__(self,
+                 hierarchyUsage=None,
+                ):
+        self.hierarchyUsage = hierarchyUsage
+
+
+class ColHierarchiesUsage(Serialisable):
+
+    tagname = "colHierarchiesUsage"
+
+    colHierarchyUsage = Sequence(expected_type=HierarchyUsage, )
+
+    __elements__ = ('colHierarchyUsage',)
+    __attrs__ = ('count', )
+
+    def __init__(self,
+                 count=None,
+                 colHierarchyUsage=(),
+                ):
+        self.colHierarchyUsage = colHierarchyUsage
+
+
+    @property
+    def count(self):
+        return len(self.colHierarchyUsage)
+
+
+class RowHierarchiesUsage(Serialisable):
+
+    tagname = "rowHierarchiesUsage"
+
+    rowHierarchyUsage = Sequence(expected_type=HierarchyUsage, )
+
+    __elements__ = ('rowHierarchyUsage',)
+    __attrs__ = ('count', )
+
+    def __init__(self,
+                 count=None,
+                 rowHierarchyUsage=(),
+                ):
+        self.rowHierarchyUsage = rowHierarchyUsage
+
+    @property
+    def count(self):
+        return len(self.rowHierarchyUsage)
+
+
+class PivotFilter(Serialisable):
+
+    tagname = "filter"
+
+    fld = Integer()
+    mpFld = Integer(allow_none=True)
+    type = Set(values=(['unknown', 'count', 'percent', 'sum', 'captionEqual',
+                        'captionNotEqual', 'captionBeginsWith', 'captionNotBeginsWith',
+                        'captionEndsWith', 'captionNotEndsWith', 'captionContains',
+                        'captionNotContains', 'captionGreaterThan', 'captionGreaterThanOrEqual',
+                        'captionLessThan', 'captionLessThanOrEqual', 'captionBetween',
+                        'captionNotBetween', 'valueEqual', 'valueNotEqual', 'valueGreaterThan',
+                        'valueGreaterThanOrEqual', 'valueLessThan', 'valueLessThanOrEqual',
+                        'valueBetween', 'valueNotBetween', 'dateEqual', 'dateNotEqual',
+                        'dateOlderThan', 'dateOlderThanOrEqual', 'dateNewerThan',
+                        'dateNewerThanOrEqual', 'dateBetween', 'dateNotBetween', 'tomorrow',
+                        'today', 'yesterday', 'nextWeek', 'thisWeek', 'lastWeek', 'nextMonth',
+                        'thisMonth', 'lastMonth', 'nextQuarter', 'thisQuarter', 'lastQuarter',
+                        'nextYear', 'thisYear', 'lastYear', 'yearToDate', 'Q1', 'Q2', 'Q3', 'Q4',
+                        'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7', 'M8', 'M9', 'M10', 'M11',
+                        'M12']))
+    evalOrder = Integer(allow_none=True)
+    id = Integer()
+    iMeasureHier = Integer(allow_none=True)
+    iMeasureFld = Integer(allow_none=True)
+    name = String(allow_none=True)
+    description = String(allow_none=True)
+    stringValue1 = String(allow_none=True)
+    stringValue2 = String(allow_none=True)
+    autoFilter = Typed(expected_type=AutoFilter, )
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('autoFilter',)
+
+    def __init__(self,
+                 fld=None,
+                 mpFld=None,
+                 type=None,
+                 evalOrder=None,
+                 id=None,
+                 iMeasureHier=None,
+                 iMeasureFld=None,
+                 name=None,
+                 description=None,
+                 stringValue1=None,
+                 stringValue2=None,
+                 autoFilter=None,
+                 extLst=None,
+                ):
+        self.fld = fld
+        self.mpFld = mpFld
+        self.type = type
+        self.evalOrder = evalOrder
+        self.id = id
+        self.iMeasureHier = iMeasureHier
+        self.iMeasureFld = iMeasureFld
+        self.name = name
+        self.description = description
+        self.stringValue1 = stringValue1
+        self.stringValue2 = stringValue2
+        self.autoFilter = autoFilter
+
+
+class PivotFilters(Serialisable):
+
+    count = Integer()
+    filter = Typed(expected_type=PivotFilter, allow_none=True)
+
+    __elements__ = ('filter',)
+
+    def __init__(self,
+                 count=None,
+                 filter=None,
+                ):
+        self.filter = filter
+
+
+class PivotTableStyle(Serialisable):
+
+    tagname = "pivotTableStyleInfo"
+
+    name = String(allow_none=True)
+    showRowHeaders = Bool()
+    showColHeaders = Bool()
+    showRowStripes = Bool()
+    showColStripes = Bool()
+    showLastColumn = Bool()
+
+    def __init__(self,
+                 name=None,
+                 showRowHeaders=None,
+                 showColHeaders=None,
+                 showRowStripes=None,
+                 showColStripes=None,
+                 showLastColumn=None,
+                ):
+        self.name = name
+        self.showRowHeaders = showRowHeaders
+        self.showColHeaders = showColHeaders
+        self.showRowStripes = showRowStripes
+        self.showColStripes = showColStripes
+        self.showLastColumn = showLastColumn
+
+
+class MemberList(Serialisable):
+
+    tagname = "members"
+
+    level = Integer(allow_none=True)
+    member = NestedSequence(expected_type=String, attribute="name")
+
+    __elements__ = ('member',)
+
+    def __init__(self,
+                 count=None,
+                 level=None,
+                 member=(),
+                ):
+        self.level = level
+        self.member = member
+
+    @property
+    def count(self):
+        return len(self.member)
+
+
+class MemberProperty(Serialisable):
+
+    tagname = "mps"
+
+    name = String(allow_none=True)
+    showCell = Bool(allow_none=True)
+    showTip = Bool(allow_none=True)
+    showAsCaption = Bool(allow_none=True)
+    nameLen = Integer(allow_none=True)
+    pPos = Integer(allow_none=True)
+    pLen = Integer(allow_none=True)
+    level = Integer(allow_none=True)
+    field = Integer()
+
+    def __init__(self,
+                 name=None,
+                 showCell=None,
+                 showTip=None,
+                 showAsCaption=None,
+                 nameLen=None,
+                 pPos=None,
+                 pLen=None,
+                 level=None,
+                 field=None,
+                ):
+        self.name = name
+        self.showCell = showCell
+        self.showTip = showTip
+        self.showAsCaption = showAsCaption
+        self.nameLen = nameLen
+        self.pPos = pPos
+        self.pLen = pLen
+        self.level = level
+        self.field = field
+
+
+class PivotHierarchy(Serialisable):
+
+    tagname = "pivotHierarchy"
+
+    outline = Bool()
+    multipleItemSelectionAllowed = Bool()
+    subtotalTop = Bool()
+    showInFieldList = Bool()
+    dragToRow = Bool()
+    dragToCol = Bool()
+    dragToPage = Bool()
+    dragToData = Bool()
+    dragOff = Bool()
+    includeNewItemsInFilter = Bool()
+    caption = String(allow_none=True)
+    mps = NestedSequence(expected_type=MemberProperty, count=True)
+    members = Typed(expected_type=MemberList, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('mps', 'members',)
+
+    def __init__(self,
+                 outline=None,
+                 multipleItemSelectionAllowed=None,
+                 subtotalTop=None,
+                 showInFieldList=None,
+                 dragToRow=None,
+                 dragToCol=None,
+                 dragToPage=None,
+                 dragToData=None,
+                 dragOff=None,
+                 includeNewItemsInFilter=None,
+                 caption=None,
+                 mps=(),
+                 members=None,
+                 extLst=None,
+                ):
+        self.outline = outline
+        self.multipleItemSelectionAllowed = multipleItemSelectionAllowed
+        self.subtotalTop = subtotalTop
+        self.showInFieldList = showInFieldList
+        self.dragToRow = dragToRow
+        self.dragToCol = dragToCol
+        self.dragToPage = dragToPage
+        self.dragToData = dragToData
+        self.dragOff = dragOff
+        self.includeNewItemsInFilter = includeNewItemsInFilter
+        self.caption = caption
+        self.mps = mps
+        self.members = members
+        self.extLst = extLst
+
+
+class Reference(Serialisable):
+
+    tagname = "reference"
+
+    field = Integer(allow_none=True)
+    selected = Bool(allow_none=True)
+    byPosition = Bool(allow_none=True)
+    relative = Bool(allow_none=True)
+    defaultSubtotal = Bool(allow_none=True)
+    sumSubtotal = Bool(allow_none=True)
+    countASubtotal = Bool(allow_none=True)
+    avgSubtotal = Bool(allow_none=True)
+    maxSubtotal = Bool(allow_none=True)
+    minSubtotal = Bool(allow_none=True)
+    productSubtotal = Bool(allow_none=True)
+    countSubtotal = Bool(allow_none=True)
+    stdDevSubtotal = Bool(allow_none=True)
+    stdDevPSubtotal = Bool(allow_none=True)
+    varSubtotal = Bool(allow_none=True)
+    varPSubtotal = Bool(allow_none=True)
+    x = Sequence(expected_type=Index)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('x',)
+
+    def __init__(self,
+                 field=None,
+                 count=None,
+                 selected=None,
+                 byPosition=None,
+                 relative=None,
+                 defaultSubtotal=None,
+                 sumSubtotal=None,
+                 countASubtotal=None,
+                 avgSubtotal=None,
+                 maxSubtotal=None,
+                 minSubtotal=None,
+                 productSubtotal=None,
+                 countSubtotal=None,
+                 stdDevSubtotal=None,
+                 stdDevPSubtotal=None,
+                 varSubtotal=None,
+                 varPSubtotal=None,
+                 x=(),
+                 extLst=None,
+                ):
+        self.field = field
+        self.selected = selected
+        self.byPosition = byPosition
+        self.relative = relative
+        self.defaultSubtotal = defaultSubtotal
+        self.sumSubtotal = sumSubtotal
+        self.countASubtotal = countASubtotal
+        self.avgSubtotal = avgSubtotal
+        self.maxSubtotal = maxSubtotal
+        self.minSubtotal = minSubtotal
+        self.productSubtotal = productSubtotal
+        self.countSubtotal = countSubtotal
+        self.stdDevSubtotal = stdDevSubtotal
+        self.stdDevPSubtotal = stdDevPSubtotal
+        self.varSubtotal = varSubtotal
+        self.varPSubtotal = varPSubtotal
+        self.x = x
+
+
+    @property
+    def count(self):
+        return len(self.field)
+
+
+class PivotArea(Serialisable):
+
+    tagname = "pivotArea"
+
+    references = NestedSequence(expected_type=Reference, count=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+    field = Integer(allow_none=True)
+    type = NoneSet(values=(['normal', 'data', 'all', 'origin', 'button',
+                            'topEnd', 'topRight']))
+    dataOnly = Bool(allow_none=True)
+    labelOnly = Bool(allow_none=True)
+    grandRow = Bool(allow_none=True)
+    grandCol = Bool(allow_none=True)
+    cacheIndex = Bool(allow_none=True)
+    outline = Bool(allow_none=True)
+    offset = String(allow_none=True)
+    collapsedLevelsAreSubtotals = Bool(allow_none=True)
+    axis = NoneSet(values=(['axisRow', 'axisCol', 'axisPage', 'axisValues']))
+    fieldPosition = Integer(allow_none=True)
+
+    __elements__ = ('references',)
+
+    def __init__(self,
+                 references=(),
+                 extLst=None,
+                 field=None,
+                 type="normal",
+                 dataOnly=True,
+                 labelOnly=None,
+                 grandRow=None,
+                 grandCol=None,
+                 cacheIndex=None,
+                 outline=True,
+                 offset=None,
+                 collapsedLevelsAreSubtotals=None,
+                 axis=None,
+                 fieldPosition=None,
+                ):
+        self.references = references
+        self.extLst = extLst
+        self.field = field
+        self.type = type
+        self.dataOnly = dataOnly
+        self.labelOnly = labelOnly
+        self.grandRow = grandRow
+        self.grandCol = grandCol
+        self.cacheIndex = cacheIndex
+        self.outline = outline
+        self.offset = offset
+        self.collapsedLevelsAreSubtotals = collapsedLevelsAreSubtotals
+        self.axis = axis
+        self.fieldPosition = fieldPosition
+
+
+class ChartFormat(Serialisable):
+
+    tagname = "chartFormat"
+
+    chart = Integer()
+    format = Integer()
+    series = Bool()
+    pivotArea = Typed(expected_type=PivotArea, )
+
+    __elements__ = ('pivotArea',)
+
+    def __init__(self,
+                 chart=None,
+                 format=None,
+                 series=None,
+                 pivotArea=None,
+                ):
+        self.chart = chart
+        self.format = format
+        self.series = series
+        self.pivotArea = pivotArea
+
+
+class ConditionalFormat(Serialisable):
+
+    tagname = "conditionalFormat"
+
+    scope = Set(values=(['selection', 'data', 'field']))
+    type = NoneSet(values=(['all', 'row', 'column']))
+    priority = Integer()
+    pivotAreas = NestedSequence(expected_type=PivotArea)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('pivotAreas',)
+
+    def __init__(self,
+                 scope="selection",
+                 type=None,
+                 priority=None,
+                 pivotAreas=(),
+                 extLst=None,
+                ):
+        self.scope = scope
+        self.type = type
+        self.priority = priority
+        self.pivotAreas = pivotAreas
+        self.extLst = extLst
+
+
+class ConditionalFormatList(Serialisable):
+
+    tagname = "conditionalFormats"
+
+    conditionalFormat = Sequence(expected_type=ConditionalFormat)
+
+    __attrs__ = ("count",)
+
+    def __init__(self, conditionalFormat=(), count=None):
+        self.conditionalFormat = conditionalFormat
+
+
+    def by_priority(self):
+        """
+        Return a dictionary of format objects keyed by (field id and format property).
+        This can be used to map the formats to field but also to dedupe to match
+        worksheet definitions which are grouped by cell range
+        """
+
+        fmts = {}
+        for fmt in self.conditionalFormat:
+            for area in fmt.pivotAreas:
+                for ref in area.references:
+                    for field in ref.x:
+                        key = (field.v, fmt.priority)
+                        fmts[key] = fmt
+
+        return fmts
+
+
+    def _dedupe(self):
+        """
+        Group formats by field index and priority.
+        Sorted to match sorting and grouping for corresponding worksheet formats
+
+        The implemtenters notes contain significant deviance from the OOXML
+        specification, in particular how conditional formats in tables relate to
+        those defined in corresponding worksheets and how to determine which
+        format applies to which fields.
+
+        There are some magical interdependencies:
+
+        * Every pivot table fmt must have a worksheet cxf with the same priority.
+
+        * In the reference part the field 4294967294 refers to a data field, the
+        spec says -2
+
+        * Data fields are referenced by the 0-index reference.x.v value
+
+        Things are made more complicated by the fact that field items behave
+        diffently if the parent is a reference or shared item: "In Office if the
+        parent is the reference element, then restrictions of this value are
+        defined by reference@field. If the parent is the tables element, then
+        this value specifies the index into the table tag position in @url."
+        Yeah, right!
+        """
+        fmts = self.by_priority()
+        # sort by priority in order, keeping the highest numerical priority, least when
+        # actually applied
+        # this is not documented but it's what Excel is happy with
+        fmts = {field:fmt for (field, priority), fmt in sorted(fmts.items(), reverse=True)}
+        #fmts = {field:fmt for (field, priority), fmt in fmts.items()}
+        if fmts:
+            self.conditionalFormat = list(fmts.values())
+
+
+    @property
+    def count(self):
+        return len(self.conditionalFormat)
+
+
+    def to_tree(self, tagname=None):
+        self._dedupe()
+        return super().to_tree(tagname)
+
+
+class Format(Serialisable):
+
+    tagname = "format"
+
+    action = NoneSet(values=(['blank', 'formatting', 'drill', 'formula']))
+    dxfId = Integer(allow_none=True)
+    pivotArea = Typed(expected_type=PivotArea, )
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ('pivotArea',)
+
+    def __init__(self,
+                 action="formatting",
+                 dxfId=None,
+                 pivotArea=None,
+                 extLst=None,
+                ):
+        self.action = action
+        self.dxfId = dxfId
+        self.pivotArea = pivotArea
+        self.extLst = extLst
+
+
+class DataField(Serialisable):
+
+    tagname = "dataField"
+
+    name = String(allow_none=True)
+    fld = Integer()
+    subtotal = Set(values=(['average', 'count', 'countNums', 'max', 'min',
+                            'product', 'stdDev', 'stdDevp', 'sum', 'var', 'varp']))
+    showDataAs = Set(values=(['normal', 'difference', 'percent',
+                              'percentDiff', 'runTotal', 'percentOfRow', 'percentOfCol',
+                              'percentOfTotal', 'index']))
+    baseField = Integer()
+    baseItem = Integer()
+    numFmtId = Integer(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ()
+
+
+    def __init__(self,
+                 name=None,
+                 fld=None,
+                 subtotal="sum",
+                 showDataAs="normal",
+                 baseField=-1,
+                 baseItem=1048832,
+                 numFmtId=None,
+                 extLst=None,
+                ):
+        self.name = name
+        self.fld = fld
+        self.subtotal = subtotal
+        self.showDataAs = showDataAs
+        self.baseField = baseField
+        self.baseItem = baseItem
+        self.numFmtId = numFmtId
+        self.extLst = extLst
+
+
+class PageField(Serialisable):
+
+    tagname = "pageField"
+
+    fld = Integer()
+    item = Integer(allow_none=True)
+    hier = Integer(allow_none=True)
+    name = String(allow_none=True)
+    cap = String(allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+    __elements__ = ()
+
+    def __init__(self,
+                 fld=None,
+                 item=None,
+                 hier=None,
+                 name=None,
+                 cap=None,
+                 extLst=None,
+                ):
+        self.fld = fld
+        self.item = item
+        self.hier = hier
+        self.name = name
+        self.cap = cap
+        self.extLst = extLst
+
+
+class RowColItem(Serialisable):
+
+    tagname = "i"
+
+    t = Set(values=(['data', 'default', 'sum', 'countA', 'avg', 'max', 'min',
+                     'product', 'count', 'stdDev', 'stdDevP', 'var', 'varP', 'grand',
+                     'blank']))
+    r = Integer()
+    i = Integer()
+    x = Sequence(expected_type=Index, attribute="v")
+
+    __elements__ = ('x',)
+
+    def __init__(self,
+                 t="data",
+                 r=0,
+                 i=0,
+                 x=(),
+                ):
+        self.t = t
+        self.r = r
+        self.i = i
+        self.x = x
+
+
+class RowColField(Serialisable):
+
+    tagname = "field"
+
+    x = Integer()
+
+    def __init__(self,
+                 x=None,
+                ):
+        self.x = x
+
+
+class AutoSortScope(Serialisable):
+
+    pivotArea = Typed(expected_type=PivotArea, )
+
+    __elements__ = ('pivotArea',)
+
+    def __init__(self,
+                 pivotArea=None,
+                ):
+        self.pivotArea = pivotArea
+
+
+class FieldItem(Serialisable):
+
+    tagname = "item"
+
+    n = String(allow_none=True)
+    t = Set(values=(['data', 'default', 'sum', 'countA', 'avg', 'max', 'min',
+                     'product', 'count', 'stdDev', 'stdDevP', 'var', 'varP', 'grand',
+                     'blank']))
+    h = Bool(allow_none=True)
+    s = Bool(allow_none=True)
+    sd = Bool(allow_none=True)
+    f = Bool(allow_none=True)
+    m = Bool(allow_none=True)
+    c = Bool(allow_none=True)
+    x = Integer(allow_none=True)
+    d = Bool(allow_none=True)
+    e = Bool(allow_none=True)
+
+    def __init__(self,
+                 n=None,
+                 t="data",
+                 h=None,
+                 s=None,
+                 sd=True,
+                 f=None,
+                 m=None,
+                 c=None,
+                 x=None,
+                 d=None,
+                 e=None,
+                ):
+        self.n = n
+        self.t = t
+        self.h = h
+        self.s = s
+        self.sd = sd
+        self.f = f
+        self.m = m
+        self.c = c
+        self.x = x
+        self.d = d
+        self.e = e
+
+
+class PivotField(Serialisable):
+
+    tagname = "pivotField"
+
+    items = NestedSequence(expected_type=FieldItem, count=True)
+    autoSortScope = Typed(expected_type=AutoSortScope, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+    name = String(allow_none=True)
+    axis = NoneSet(values=(['axisRow', 'axisCol', 'axisPage', 'axisValues']))
+    dataField = Bool(allow_none=True)
+    subtotalCaption = String(allow_none=True)
+    showDropDowns = Bool(allow_none=True)
+    hiddenLevel = Bool(allow_none=True)
+    uniqueMemberProperty = String(allow_none=True)
+    compact = Bool(allow_none=True)
+    allDrilled = Bool(allow_none=True)
+    numFmtId = Integer(allow_none=True)
+    outline = Bool(allow_none=True)
+    subtotalTop = Bool(allow_none=True)
+    dragToRow = Bool(allow_none=True)
+    dragToCol = Bool(allow_none=True)
+    multipleItemSelectionAllowed = Bool(allow_none=True)
+    dragToPage = Bool(allow_none=True)
+    dragToData = Bool(allow_none=True)
+    dragOff = Bool(allow_none=True)
+    showAll = Bool(allow_none=True)
+    insertBlankRow = Bool(allow_none=True)
+    serverField = Bool(allow_none=True)
+    insertPageBreak = Bool(allow_none=True)
+    autoShow = Bool(allow_none=True)
+    topAutoShow = Bool(allow_none=True)
+    hideNewItems = Bool(allow_none=True)
+    measureFilter = Bool(allow_none=True)
+    includeNewItemsInFilter = Bool(allow_none=True)
+    itemPageCount = Integer(allow_none=True)
+    sortType = Set(values=(['manual', 'ascending', 'descending']))
+    dataSourceSort = Bool(allow_none=True)
+    nonAutoSortDefault = Bool(allow_none=True)
+    rankBy = Integer(allow_none=True)
+    defaultSubtotal = Bool(allow_none=True)
+    sumSubtotal = Bool(allow_none=True)
+    countASubtotal = Bool(allow_none=True)
+    avgSubtotal = Bool(allow_none=True)
+    maxSubtotal = Bool(allow_none=True)
+    minSubtotal = Bool(allow_none=True)
+    productSubtotal = Bool(allow_none=True)
+    countSubtotal = Bool(allow_none=True)
+    stdDevSubtotal = Bool(allow_none=True)
+    stdDevPSubtotal = Bool(allow_none=True)
+    varSubtotal = Bool(allow_none=True)
+    varPSubtotal = Bool(allow_none=True)
+    showPropCell = Bool(allow_none=True)
+    showPropTip = Bool(allow_none=True)
+    showPropAsCaption = Bool(allow_none=True)
+    defaultAttributeDrillState = Bool(allow_none=True)
+
+    __elements__ = ('items', 'autoSortScope',)
+
+    def __init__(self,
+                 items=(),
+                 autoSortScope=None,
+                 name=None,
+                 axis=None,
+                 dataField=None,
+                 subtotalCaption=None,
+                 showDropDowns=True,
+                 hiddenLevel=None,
+                 uniqueMemberProperty=None,
+                 compact=True,
+                 allDrilled=None,
+                 numFmtId=None,
+                 outline=True,
+                 subtotalTop=True,
+                 dragToRow=True,
+                 dragToCol=True,
+                 multipleItemSelectionAllowed=None,
+                 dragToPage=True,
+                 dragToData=True,
+                 dragOff=True,
+                 showAll=True,
+                 insertBlankRow=None,
+                 serverField=None,
+                 insertPageBreak=None,
+                 autoShow=None,
+                 topAutoShow=True,
+                 hideNewItems=None,
+                 measureFilter=None,
+                 includeNewItemsInFilter=None,
+                 itemPageCount=10,
+                 sortType="manual",
+                 dataSourceSort=None,
+                 nonAutoSortDefault=None,
+                 rankBy=None,
+                 defaultSubtotal=True,
+                 sumSubtotal=None,
+                 countASubtotal=None,
+                 avgSubtotal=None,
+                 maxSubtotal=None,
+                 minSubtotal=None,
+                 productSubtotal=None,
+                 countSubtotal=None,
+                 stdDevSubtotal=None,
+                 stdDevPSubtotal=None,
+                 varSubtotal=None,
+                 varPSubtotal=None,
+                 showPropCell=None,
+                 showPropTip=None,
+                 showPropAsCaption=None,
+                 defaultAttributeDrillState=None,
+                 extLst=None,
+                ):
+        self.items = items
+        self.autoSortScope = autoSortScope
+        self.name = name
+        self.axis = axis
+        self.dataField = dataField
+        self.subtotalCaption = subtotalCaption
+        self.showDropDowns = showDropDowns
+        self.hiddenLevel = hiddenLevel
+        self.uniqueMemberProperty = uniqueMemberProperty
+        self.compact = compact
+        self.allDrilled = allDrilled
+        self.numFmtId = numFmtId
+        self.outline = outline
+        self.subtotalTop = subtotalTop
+        self.dragToRow = dragToRow
+        self.dragToCol = dragToCol
+        self.multipleItemSelectionAllowed = multipleItemSelectionAllowed
+        self.dragToPage = dragToPage
+        self.dragToData = dragToData
+        self.dragOff = dragOff
+        self.showAll = showAll
+        self.insertBlankRow = insertBlankRow
+        self.serverField = serverField
+        self.insertPageBreak = insertPageBreak
+        self.autoShow = autoShow
+        self.topAutoShow = topAutoShow
+        self.hideNewItems = hideNewItems
+        self.measureFilter = measureFilter
+        self.includeNewItemsInFilter = includeNewItemsInFilter
+        self.itemPageCount = itemPageCount
+        self.sortType = sortType
+        self.dataSourceSort = dataSourceSort
+        self.nonAutoSortDefault = nonAutoSortDefault
+        self.rankBy = rankBy
+        self.defaultSubtotal = defaultSubtotal
+        self.sumSubtotal = sumSubtotal
+        self.countASubtotal = countASubtotal
+        self.avgSubtotal = avgSubtotal
+        self.maxSubtotal = maxSubtotal
+        self.minSubtotal = minSubtotal
+        self.productSubtotal = productSubtotal
+        self.countSubtotal = countSubtotal
+        self.stdDevSubtotal = stdDevSubtotal
+        self.stdDevPSubtotal = stdDevPSubtotal
+        self.varSubtotal = varSubtotal
+        self.varPSubtotal = varPSubtotal
+        self.showPropCell = showPropCell
+        self.showPropTip = showPropTip
+        self.showPropAsCaption = showPropAsCaption
+        self.defaultAttributeDrillState = defaultAttributeDrillState
+
+
+class Location(Serialisable):
+
+    tagname = "location"
+
+    ref = String()
+    firstHeaderRow = Integer()
+    firstDataRow = Integer()
+    firstDataCol = Integer()
+    rowPageCount = Integer(allow_none=True)
+    colPageCount = Integer(allow_none=True)
+
+    def __init__(self,
+                 ref=None,
+                 firstHeaderRow=None,
+                 firstDataRow=None,
+                 firstDataCol=None,
+                 rowPageCount=None,
+                 colPageCount=None,
+                ):
+        self.ref = ref
+        self.firstHeaderRow = firstHeaderRow
+        self.firstDataRow = firstDataRow
+        self.firstDataCol = firstDataCol
+        self.rowPageCount = rowPageCount
+        self.colPageCount = colPageCount
+
+
+class TableDefinition(Serialisable):
+
+    mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"
+    rel_type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
+    _id = 1
+    _path = "/xl/pivotTables/pivotTable{0}.xml"
+
+    tagname = "pivotTableDefinition"
+    cache = None
+
+    name = String()
+    cacheId = Integer()
+    dataOnRows = Bool()
+    dataPosition = Integer(allow_none=True)
+    dataCaption = String()
+    grandTotalCaption = String(allow_none=True)
+    errorCaption = String(allow_none=True)
+    showError = Bool()
+    missingCaption = String(allow_none=True)
+    showMissing = Bool()
+    pageStyle = String(allow_none=True)
+    pivotTableStyle = String(allow_none=True)
+    vacatedStyle = String(allow_none=True)
+    tag = String(allow_none=True)
+    updatedVersion = Integer()
+    minRefreshableVersion = Integer()
+    asteriskTotals = Bool()
+    showItems = Bool()
+    editData = Bool()
+    disableFieldList = Bool()
+    showCalcMbrs = Bool()
+    visualTotals = Bool()
+    showMultipleLabel = Bool()
+    showDataDropDown = Bool()
+    showDrill = Bool()
+    printDrill = Bool()
+    showMemberPropertyTips = Bool()
+    showDataTips = Bool()
+    enableWizard = Bool()
+    enableDrill = Bool()
+    enableFieldProperties = Bool()
+    preserveFormatting = Bool()
+    useAutoFormatting = Bool()
+    pageWrap = Integer()
+    pageOverThenDown = Bool()
+    subtotalHiddenItems = Bool()
+    rowGrandTotals = Bool()
+    colGrandTotals = Bool()
+    fieldPrintTitles = Bool()
+    itemPrintTitles = Bool()
+    mergeItem = Bool()
+    showDropZones = Bool()
+    createdVersion = Integer()
+    indent = Integer()
+    showEmptyRow = Bool()
+    showEmptyCol = Bool()
+    showHeaders = Bool()
+    compact = Bool()
+    outline = Bool()
+    outlineData = Bool()
+    compactData = Bool()
+    published = Bool()
+    gridDropZones = Bool()
+    immersive = Bool()
+    multipleFieldFilters = Bool()
+    chartFormat = Integer()
+    rowHeaderCaption = String(allow_none=True)
+    colHeaderCaption = String(allow_none=True)
+    fieldListSortAscending = Bool()
+    mdxSubqueries = Bool()
+    customListSort = Bool(allow_none=True)
+    autoFormatId = Integer(allow_none=True)
+    applyNumberFormats = Bool()
+    applyBorderFormats = Bool()
+    applyFontFormats = Bool()
+    applyPatternFormats = Bool()
+    applyAlignmentFormats = Bool()
+    applyWidthHeightFormats = Bool()
+    location = Typed(expected_type=Location, )
+    pivotFields = NestedSequence(expected_type=PivotField, count=True)
+    rowFields = NestedSequence(expected_type=RowColField, count=True)
+    rowItems = NestedSequence(expected_type=RowColItem, count=True)
+    colFields = NestedSequence(expected_type=RowColField, count=True)
+    colItems = NestedSequence(expected_type=RowColItem, count=True)
+    pageFields = NestedSequence(expected_type=PageField, count=True)
+    dataFields = NestedSequence(expected_type=DataField, count=True)
+    formats = NestedSequence(expected_type=Format, count=True)
+    conditionalFormats = Typed(expected_type=ConditionalFormatList, allow_none=True)
+    chartFormats = NestedSequence(expected_type=ChartFormat, count=True)
+    pivotHierarchies = NestedSequence(expected_type=PivotHierarchy, count=True)
+    pivotTableStyleInfo = Typed(expected_type=PivotTableStyle, allow_none=True)
+    filters = NestedSequence(expected_type=PivotFilter, count=True)
+    rowHierarchiesUsage = Typed(expected_type=RowHierarchiesUsage, allow_none=True)
+    colHierarchiesUsage = Typed(expected_type=ColHierarchiesUsage, allow_none=True)
+    extLst = Typed(expected_type=ExtensionList, allow_none=True)
+    id = Relation()
+
+    __elements__ = ('location', 'pivotFields', 'rowFields', 'rowItems',
+                    'colFields', 'colItems', 'pageFields', 'dataFields', 'formats',
+                    'conditionalFormats', 'chartFormats', 'pivotHierarchies',
+                    'pivotTableStyleInfo', 'filters', 'rowHierarchiesUsage',
+                    'colHierarchiesUsage',)
+
+    def __init__(self,
+                 name=None,
+                 cacheId=None,
+                 dataOnRows=False,
+                 dataPosition=None,
+                 dataCaption=None,
+                 grandTotalCaption=None,
+                 errorCaption=None,
+                 showError=False,
+                 missingCaption=None,
+                 showMissing=True,
+                 pageStyle=None,
+                 pivotTableStyle=None,
+                 vacatedStyle=None,
+                 tag=None,
+                 updatedVersion=0,
+                 minRefreshableVersion=0,
+                 asteriskTotals=False,
+                 showItems=True,
+                 editData=False,
+                 disableFieldList=False,
+                 showCalcMbrs=True,
+                 visualTotals=True,
+                 showMultipleLabel=True,
+                 showDataDropDown=True,
+                 showDrill=True,
+                 printDrill=False,
+                 showMemberPropertyTips=True,
+                 showDataTips=True,
+                 enableWizard=True,
+                 enableDrill=True,
+                 enableFieldProperties=True,
+                 preserveFormatting=True,
+                 useAutoFormatting=False,
+                 pageWrap=0,
+                 pageOverThenDown=False,
+                 subtotalHiddenItems=False,
+                 rowGrandTotals=True,
+                 colGrandTotals=True,
+                 fieldPrintTitles=False,
+                 itemPrintTitles=False,
+                 mergeItem=False,
+                 showDropZones=True,
+                 createdVersion=0,
+                 indent=1,
+                 showEmptyRow=False,
+                 showEmptyCol=False,
+                 showHeaders=True,
+                 compact=True,
+                 outline=False,
+                 outlineData=False,
+                 compactData=True,
+                 published=False,
+                 gridDropZones=False,
+                 immersive=True,
+                 multipleFieldFilters=None,
+                 chartFormat=0,
+                 rowHeaderCaption=None,
+                 colHeaderCaption=None,
+                 fieldListSortAscending=None,
+                 mdxSubqueries=None,
+                 customListSort=None,
+                 autoFormatId=None,
+                 applyNumberFormats=False,
+                 applyBorderFormats=False,
+                 applyFontFormats=False,
+                 applyPatternFormats=False,
+                 applyAlignmentFormats=False,
+                 applyWidthHeightFormats=False,
+                 location=None,
+                 pivotFields=(),
+                 rowFields=(),
+                 rowItems=(),
+                 colFields=(),
+                 colItems=(),
+                 pageFields=(),
+                 dataFields=(),
+                 formats=(),
+                 conditionalFormats=None,
+                 chartFormats=(),
+                 pivotHierarchies=(),
+                 pivotTableStyleInfo=None,
+                 filters=(),
+                 rowHierarchiesUsage=None,
+                 colHierarchiesUsage=None,
+                 extLst=None,
+                 id=None,
+                ):
+        self.name = name
+        self.cacheId = cacheId
+        self.dataOnRows = dataOnRows
+        self.dataPosition = dataPosition
+        self.dataCaption = dataCaption
+        self.grandTotalCaption = grandTotalCaption
+        self.errorCaption = errorCaption
+        self.showError = showError
+        self.missingCaption = missingCaption
+        self.showMissing = showMissing
+        self.pageStyle = pageStyle
+        self.pivotTableStyle = pivotTableStyle
+        self.vacatedStyle = vacatedStyle
+        self.tag = tag
+        self.updatedVersion = updatedVersion
+        self.minRefreshableVersion = minRefreshableVersion
+        self.asteriskTotals = asteriskTotals
+        self.showItems = showItems
+        self.editData = editData
+        self.disableFieldList = disableFieldList
+        self.showCalcMbrs = showCalcMbrs
+        self.visualTotals = visualTotals
+        self.showMultipleLabel = showMultipleLabel
+        self.showDataDropDown = showDataDropDown
+        self.showDrill = showDrill
+        self.printDrill = printDrill
+        self.showMemberPropertyTips = showMemberPropertyTips
+        self.showDataTips = showDataTips
+        self.enableWizard = enableWizard
+        self.enableDrill = enableDrill
+        self.enableFieldProperties = enableFieldProperties
+        self.preserveFormatting = preserveFormatting
+        self.useAutoFormatting = useAutoFormatting
+        self.pageWrap = pageWrap
+        self.pageOverThenDown = pageOverThenDown
+        self.subtotalHiddenItems = subtotalHiddenItems
+        self.rowGrandTotals = rowGrandTotals
+        self.colGrandTotals = colGrandTotals
+        self.fieldPrintTitles = fieldPrintTitles
+        self.itemPrintTitles = itemPrintTitles
+        self.mergeItem = mergeItem
+        self.showDropZones = showDropZones
+        self.createdVersion = createdVersion
+        self.indent = indent
+        self.showEmptyRow = showEmptyRow
+        self.showEmptyCol = showEmptyCol
+        self.showHeaders = showHeaders
+        self.compact = compact
+        self.outline = outline
+        self.outlineData = outlineData
+        self.compactData = compactData
+        self.published = published
+        self.gridDropZones = gridDropZones
+        self.immersive = immersive
+        self.multipleFieldFilters = multipleFieldFilters
+        self.chartFormat = chartFormat
+        self.rowHeaderCaption = rowHeaderCaption
+        self.colHeaderCaption = colHeaderCaption
+        self.fieldListSortAscending = fieldListSortAscending
+        self.mdxSubqueries = mdxSubqueries
+        self.customListSort = customListSort
+        self.autoFormatId = autoFormatId
+        self.applyNumberFormats = applyNumberFormats
+        self.applyBorderFormats = applyBorderFormats
+        self.applyFontFormats = applyFontFormats
+        self.applyPatternFormats = applyPatternFormats
+        self.applyAlignmentFormats = applyAlignmentFormats
+        self.applyWidthHeightFormats = applyWidthHeightFormats
+        self.location = location
+        self.pivotFields = pivotFields
+        self.rowFields = rowFields
+        self.rowItems = rowItems
+        self.colFields = colFields
+        self.colItems = colItems
+        self.pageFields = pageFields
+        self.dataFields = dataFields
+        self.formats = formats
+        self.conditionalFormats = conditionalFormats
+        self.conditionalFormats = None
+        self.chartFormats = chartFormats
+        self.pivotHierarchies = pivotHierarchies
+        self.pivotTableStyleInfo = pivotTableStyleInfo
+        self.filters = filters
+        self.rowHierarchiesUsage = rowHierarchiesUsage
+        self.colHierarchiesUsage = colHierarchiesUsage
+        self.extLst = extLst
+        self.id = id
+
+
+    def to_tree(self):
+        tree = super().to_tree()
+        tree.set("xmlns", SHEET_MAIN_NS)
+        return tree
+
+
+    @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.cache is None:
+            return
+
+        rels = RelationshipList()
+        r = Relationship(Type=self.cache.rel_type, Target=self.cache.path)
+        rels.append(r)
+        self.id = r.id
+        if self.cache.path[1:] not in archive.namelist():
+            self.cache._write(archive, manifest)
+
+        path = get_rels_path(self.path)
+        xml = tostring(rels.to_tree())
+        archive.writestr(path[1:], xml)
+
+
+    def formatted_fields(self):
+        """Map fields to associated conditional formats by priority"""
+        if not self.conditionalFormats:
+            return {}
+        fields = defaultdict(list)
+        for idx, prio in self.conditionalFormats.by_priority():
+            name = self.dataFields[idx].name
+            fields[name].append(prio)
+        return fields
+
+
+    @property
+    def summary(self):
+        """
+        Provide a simplified summary of the table
+        """
+
+        return f"{self.name} {dict(self.location)}"