about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/openpyxl/pivot/table.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/pivot/table.py')
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/pivot/table.py1261
1 files changed, 1261 insertions, 0 deletions
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)}"