table.py 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. # Copyright (c) 2010-2024 openpyxl
  2. from collections import defaultdict
  3. from openpyxl.descriptors.serialisable import Serialisable
  4. from openpyxl.descriptors import (
  5. Typed,
  6. Integer,
  7. NoneSet,
  8. Set,
  9. Bool,
  10. String,
  11. Bool,
  12. Sequence,
  13. )
  14. from openpyxl.descriptors.excel import ExtensionList, Relation
  15. from openpyxl.descriptors.sequence import NestedSequence
  16. from openpyxl.xml.constants import SHEET_MAIN_NS
  17. from openpyxl.xml.functions import tostring
  18. from openpyxl.packaging.relationship import (
  19. RelationshipList,
  20. Relationship,
  21. get_rels_path
  22. )
  23. from .fields import Index
  24. from openpyxl.worksheet.filters import (
  25. AutoFilter,
  26. )
  27. class HierarchyUsage(Serialisable):
  28. tagname = "hierarchyUsage"
  29. hierarchyUsage = Integer()
  30. def __init__(self,
  31. hierarchyUsage=None,
  32. ):
  33. self.hierarchyUsage = hierarchyUsage
  34. class ColHierarchiesUsage(Serialisable):
  35. tagname = "colHierarchiesUsage"
  36. colHierarchyUsage = Sequence(expected_type=HierarchyUsage, )
  37. __elements__ = ('colHierarchyUsage',)
  38. __attrs__ = ('count', )
  39. def __init__(self,
  40. count=None,
  41. colHierarchyUsage=(),
  42. ):
  43. self.colHierarchyUsage = colHierarchyUsage
  44. @property
  45. def count(self):
  46. return len(self.colHierarchyUsage)
  47. class RowHierarchiesUsage(Serialisable):
  48. tagname = "rowHierarchiesUsage"
  49. rowHierarchyUsage = Sequence(expected_type=HierarchyUsage, )
  50. __elements__ = ('rowHierarchyUsage',)
  51. __attrs__ = ('count', )
  52. def __init__(self,
  53. count=None,
  54. rowHierarchyUsage=(),
  55. ):
  56. self.rowHierarchyUsage = rowHierarchyUsage
  57. @property
  58. def count(self):
  59. return len(self.rowHierarchyUsage)
  60. class PivotFilter(Serialisable):
  61. tagname = "filter"
  62. fld = Integer()
  63. mpFld = Integer(allow_none=True)
  64. type = Set(values=(['unknown', 'count', 'percent', 'sum', 'captionEqual',
  65. 'captionNotEqual', 'captionBeginsWith', 'captionNotBeginsWith',
  66. 'captionEndsWith', 'captionNotEndsWith', 'captionContains',
  67. 'captionNotContains', 'captionGreaterThan', 'captionGreaterThanOrEqual',
  68. 'captionLessThan', 'captionLessThanOrEqual', 'captionBetween',
  69. 'captionNotBetween', 'valueEqual', 'valueNotEqual', 'valueGreaterThan',
  70. 'valueGreaterThanOrEqual', 'valueLessThan', 'valueLessThanOrEqual',
  71. 'valueBetween', 'valueNotBetween', 'dateEqual', 'dateNotEqual',
  72. 'dateOlderThan', 'dateOlderThanOrEqual', 'dateNewerThan',
  73. 'dateNewerThanOrEqual', 'dateBetween', 'dateNotBetween', 'tomorrow',
  74. 'today', 'yesterday', 'nextWeek', 'thisWeek', 'lastWeek', 'nextMonth',
  75. 'thisMonth', 'lastMonth', 'nextQuarter', 'thisQuarter', 'lastQuarter',
  76. 'nextYear', 'thisYear', 'lastYear', 'yearToDate', 'Q1', 'Q2', 'Q3', 'Q4',
  77. 'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7', 'M8', 'M9', 'M10', 'M11',
  78. 'M12']))
  79. evalOrder = Integer(allow_none=True)
  80. id = Integer()
  81. iMeasureHier = Integer(allow_none=True)
  82. iMeasureFld = Integer(allow_none=True)
  83. name = String(allow_none=True)
  84. description = String(allow_none=True)
  85. stringValue1 = String(allow_none=True)
  86. stringValue2 = String(allow_none=True)
  87. autoFilter = Typed(expected_type=AutoFilter, )
  88. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  89. __elements__ = ('autoFilter',)
  90. def __init__(self,
  91. fld=None,
  92. mpFld=None,
  93. type=None,
  94. evalOrder=None,
  95. id=None,
  96. iMeasureHier=None,
  97. iMeasureFld=None,
  98. name=None,
  99. description=None,
  100. stringValue1=None,
  101. stringValue2=None,
  102. autoFilter=None,
  103. extLst=None,
  104. ):
  105. self.fld = fld
  106. self.mpFld = mpFld
  107. self.type = type
  108. self.evalOrder = evalOrder
  109. self.id = id
  110. self.iMeasureHier = iMeasureHier
  111. self.iMeasureFld = iMeasureFld
  112. self.name = name
  113. self.description = description
  114. self.stringValue1 = stringValue1
  115. self.stringValue2 = stringValue2
  116. self.autoFilter = autoFilter
  117. class PivotFilters(Serialisable):
  118. count = Integer()
  119. filter = Typed(expected_type=PivotFilter, allow_none=True)
  120. __elements__ = ('filter',)
  121. def __init__(self,
  122. count=None,
  123. filter=None,
  124. ):
  125. self.filter = filter
  126. class PivotTableStyle(Serialisable):
  127. tagname = "pivotTableStyleInfo"
  128. name = String(allow_none=True)
  129. showRowHeaders = Bool()
  130. showColHeaders = Bool()
  131. showRowStripes = Bool()
  132. showColStripes = Bool()
  133. showLastColumn = Bool()
  134. def __init__(self,
  135. name=None,
  136. showRowHeaders=None,
  137. showColHeaders=None,
  138. showRowStripes=None,
  139. showColStripes=None,
  140. showLastColumn=None,
  141. ):
  142. self.name = name
  143. self.showRowHeaders = showRowHeaders
  144. self.showColHeaders = showColHeaders
  145. self.showRowStripes = showRowStripes
  146. self.showColStripes = showColStripes
  147. self.showLastColumn = showLastColumn
  148. class MemberList(Serialisable):
  149. tagname = "members"
  150. level = Integer(allow_none=True)
  151. member = NestedSequence(expected_type=String, attribute="name")
  152. __elements__ = ('member',)
  153. def __init__(self,
  154. count=None,
  155. level=None,
  156. member=(),
  157. ):
  158. self.level = level
  159. self.member = member
  160. @property
  161. def count(self):
  162. return len(self.member)
  163. class MemberProperty(Serialisable):
  164. tagname = "mps"
  165. name = String(allow_none=True)
  166. showCell = Bool(allow_none=True)
  167. showTip = Bool(allow_none=True)
  168. showAsCaption = Bool(allow_none=True)
  169. nameLen = Integer(allow_none=True)
  170. pPos = Integer(allow_none=True)
  171. pLen = Integer(allow_none=True)
  172. level = Integer(allow_none=True)
  173. field = Integer()
  174. def __init__(self,
  175. name=None,
  176. showCell=None,
  177. showTip=None,
  178. showAsCaption=None,
  179. nameLen=None,
  180. pPos=None,
  181. pLen=None,
  182. level=None,
  183. field=None,
  184. ):
  185. self.name = name
  186. self.showCell = showCell
  187. self.showTip = showTip
  188. self.showAsCaption = showAsCaption
  189. self.nameLen = nameLen
  190. self.pPos = pPos
  191. self.pLen = pLen
  192. self.level = level
  193. self.field = field
  194. class PivotHierarchy(Serialisable):
  195. tagname = "pivotHierarchy"
  196. outline = Bool()
  197. multipleItemSelectionAllowed = Bool()
  198. subtotalTop = Bool()
  199. showInFieldList = Bool()
  200. dragToRow = Bool()
  201. dragToCol = Bool()
  202. dragToPage = Bool()
  203. dragToData = Bool()
  204. dragOff = Bool()
  205. includeNewItemsInFilter = Bool()
  206. caption = String(allow_none=True)
  207. mps = NestedSequence(expected_type=MemberProperty, count=True)
  208. members = Typed(expected_type=MemberList, allow_none=True)
  209. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  210. __elements__ = ('mps', 'members',)
  211. def __init__(self,
  212. outline=None,
  213. multipleItemSelectionAllowed=None,
  214. subtotalTop=None,
  215. showInFieldList=None,
  216. dragToRow=None,
  217. dragToCol=None,
  218. dragToPage=None,
  219. dragToData=None,
  220. dragOff=None,
  221. includeNewItemsInFilter=None,
  222. caption=None,
  223. mps=(),
  224. members=None,
  225. extLst=None,
  226. ):
  227. self.outline = outline
  228. self.multipleItemSelectionAllowed = multipleItemSelectionAllowed
  229. self.subtotalTop = subtotalTop
  230. self.showInFieldList = showInFieldList
  231. self.dragToRow = dragToRow
  232. self.dragToCol = dragToCol
  233. self.dragToPage = dragToPage
  234. self.dragToData = dragToData
  235. self.dragOff = dragOff
  236. self.includeNewItemsInFilter = includeNewItemsInFilter
  237. self.caption = caption
  238. self.mps = mps
  239. self.members = members
  240. self.extLst = extLst
  241. class Reference(Serialisable):
  242. tagname = "reference"
  243. field = Integer(allow_none=True)
  244. selected = Bool(allow_none=True)
  245. byPosition = Bool(allow_none=True)
  246. relative = Bool(allow_none=True)
  247. defaultSubtotal = Bool(allow_none=True)
  248. sumSubtotal = Bool(allow_none=True)
  249. countASubtotal = Bool(allow_none=True)
  250. avgSubtotal = Bool(allow_none=True)
  251. maxSubtotal = Bool(allow_none=True)
  252. minSubtotal = Bool(allow_none=True)
  253. productSubtotal = Bool(allow_none=True)
  254. countSubtotal = Bool(allow_none=True)
  255. stdDevSubtotal = Bool(allow_none=True)
  256. stdDevPSubtotal = Bool(allow_none=True)
  257. varSubtotal = Bool(allow_none=True)
  258. varPSubtotal = Bool(allow_none=True)
  259. x = Sequence(expected_type=Index)
  260. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  261. __elements__ = ('x',)
  262. def __init__(self,
  263. field=None,
  264. count=None,
  265. selected=None,
  266. byPosition=None,
  267. relative=None,
  268. defaultSubtotal=None,
  269. sumSubtotal=None,
  270. countASubtotal=None,
  271. avgSubtotal=None,
  272. maxSubtotal=None,
  273. minSubtotal=None,
  274. productSubtotal=None,
  275. countSubtotal=None,
  276. stdDevSubtotal=None,
  277. stdDevPSubtotal=None,
  278. varSubtotal=None,
  279. varPSubtotal=None,
  280. x=(),
  281. extLst=None,
  282. ):
  283. self.field = field
  284. self.selected = selected
  285. self.byPosition = byPosition
  286. self.relative = relative
  287. self.defaultSubtotal = defaultSubtotal
  288. self.sumSubtotal = sumSubtotal
  289. self.countASubtotal = countASubtotal
  290. self.avgSubtotal = avgSubtotal
  291. self.maxSubtotal = maxSubtotal
  292. self.minSubtotal = minSubtotal
  293. self.productSubtotal = productSubtotal
  294. self.countSubtotal = countSubtotal
  295. self.stdDevSubtotal = stdDevSubtotal
  296. self.stdDevPSubtotal = stdDevPSubtotal
  297. self.varSubtotal = varSubtotal
  298. self.varPSubtotal = varPSubtotal
  299. self.x = x
  300. @property
  301. def count(self):
  302. return len(self.field)
  303. class PivotArea(Serialisable):
  304. tagname = "pivotArea"
  305. references = NestedSequence(expected_type=Reference, count=True)
  306. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  307. field = Integer(allow_none=True)
  308. type = NoneSet(values=(['normal', 'data', 'all', 'origin', 'button',
  309. 'topEnd', 'topRight']))
  310. dataOnly = Bool(allow_none=True)
  311. labelOnly = Bool(allow_none=True)
  312. grandRow = Bool(allow_none=True)
  313. grandCol = Bool(allow_none=True)
  314. cacheIndex = Bool(allow_none=True)
  315. outline = Bool(allow_none=True)
  316. offset = String(allow_none=True)
  317. collapsedLevelsAreSubtotals = Bool(allow_none=True)
  318. axis = NoneSet(values=(['axisRow', 'axisCol', 'axisPage', 'axisValues']))
  319. fieldPosition = Integer(allow_none=True)
  320. __elements__ = ('references',)
  321. def __init__(self,
  322. references=(),
  323. extLst=None,
  324. field=None,
  325. type="normal",
  326. dataOnly=True,
  327. labelOnly=None,
  328. grandRow=None,
  329. grandCol=None,
  330. cacheIndex=None,
  331. outline=True,
  332. offset=None,
  333. collapsedLevelsAreSubtotals=None,
  334. axis=None,
  335. fieldPosition=None,
  336. ):
  337. self.references = references
  338. self.extLst = extLst
  339. self.field = field
  340. self.type = type
  341. self.dataOnly = dataOnly
  342. self.labelOnly = labelOnly
  343. self.grandRow = grandRow
  344. self.grandCol = grandCol
  345. self.cacheIndex = cacheIndex
  346. self.outline = outline
  347. self.offset = offset
  348. self.collapsedLevelsAreSubtotals = collapsedLevelsAreSubtotals
  349. self.axis = axis
  350. self.fieldPosition = fieldPosition
  351. class ChartFormat(Serialisable):
  352. tagname = "chartFormat"
  353. chart = Integer()
  354. format = Integer()
  355. series = Bool()
  356. pivotArea = Typed(expected_type=PivotArea, )
  357. __elements__ = ('pivotArea',)
  358. def __init__(self,
  359. chart=None,
  360. format=None,
  361. series=None,
  362. pivotArea=None,
  363. ):
  364. self.chart = chart
  365. self.format = format
  366. self.series = series
  367. self.pivotArea = pivotArea
  368. class ConditionalFormat(Serialisable):
  369. tagname = "conditionalFormat"
  370. scope = Set(values=(['selection', 'data', 'field']))
  371. type = NoneSet(values=(['all', 'row', 'column']))
  372. priority = Integer()
  373. pivotAreas = NestedSequence(expected_type=PivotArea)
  374. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  375. __elements__ = ('pivotAreas',)
  376. def __init__(self,
  377. scope="selection",
  378. type=None,
  379. priority=None,
  380. pivotAreas=(),
  381. extLst=None,
  382. ):
  383. self.scope = scope
  384. self.type = type
  385. self.priority = priority
  386. self.pivotAreas = pivotAreas
  387. self.extLst = extLst
  388. class ConditionalFormatList(Serialisable):
  389. tagname = "conditionalFormats"
  390. conditionalFormat = Sequence(expected_type=ConditionalFormat)
  391. __attrs__ = ("count",)
  392. def __init__(self, conditionalFormat=(), count=None):
  393. self.conditionalFormat = conditionalFormat
  394. def by_priority(self):
  395. """
  396. Return a dictionary of format objects keyed by (field id and format property).
  397. This can be used to map the formats to field but also to dedupe to match
  398. worksheet definitions which are grouped by cell range
  399. """
  400. fmts = {}
  401. for fmt in self.conditionalFormat:
  402. for area in fmt.pivotAreas:
  403. for ref in area.references:
  404. for field in ref.x:
  405. key = (field.v, fmt.priority)
  406. fmts[key] = fmt
  407. return fmts
  408. def _dedupe(self):
  409. """
  410. Group formats by field index and priority.
  411. Sorted to match sorting and grouping for corresponding worksheet formats
  412. The implemtenters notes contain significant deviance from the OOXML
  413. specification, in particular how conditional formats in tables relate to
  414. those defined in corresponding worksheets and how to determine which
  415. format applies to which fields.
  416. There are some magical interdependencies:
  417. * Every pivot table fmt must have a worksheet cxf with the same priority.
  418. * In the reference part the field 4294967294 refers to a data field, the
  419. spec says -2
  420. * Data fields are referenced by the 0-index reference.x.v value
  421. Things are made more complicated by the fact that field items behave
  422. diffently if the parent is a reference or shared item: "In Office if the
  423. parent is the reference element, then restrictions of this value are
  424. defined by reference@field. If the parent is the tables element, then
  425. this value specifies the index into the table tag position in @url."
  426. Yeah, right!
  427. """
  428. fmts = self.by_priority()
  429. # sort by priority in order, keeping the highest numerical priority, least when
  430. # actually applied
  431. # this is not documented but it's what Excel is happy with
  432. fmts = {field:fmt for (field, priority), fmt in sorted(fmts.items(), reverse=True)}
  433. #fmts = {field:fmt for (field, priority), fmt in fmts.items()}
  434. if fmts:
  435. self.conditionalFormat = list(fmts.values())
  436. @property
  437. def count(self):
  438. return len(self.conditionalFormat)
  439. def to_tree(self, tagname=None):
  440. self._dedupe()
  441. return super().to_tree(tagname)
  442. class Format(Serialisable):
  443. tagname = "format"
  444. action = NoneSet(values=(['blank', 'formatting', 'drill', 'formula']))
  445. dxfId = Integer(allow_none=True)
  446. pivotArea = Typed(expected_type=PivotArea, )
  447. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  448. __elements__ = ('pivotArea',)
  449. def __init__(self,
  450. action="formatting",
  451. dxfId=None,
  452. pivotArea=None,
  453. extLst=None,
  454. ):
  455. self.action = action
  456. self.dxfId = dxfId
  457. self.pivotArea = pivotArea
  458. self.extLst = extLst
  459. class DataField(Serialisable):
  460. tagname = "dataField"
  461. name = String(allow_none=True)
  462. fld = Integer()
  463. subtotal = Set(values=(['average', 'count', 'countNums', 'max', 'min',
  464. 'product', 'stdDev', 'stdDevp', 'sum', 'var', 'varp']))
  465. showDataAs = Set(values=(['normal', 'difference', 'percent',
  466. 'percentDiff', 'runTotal', 'percentOfRow', 'percentOfCol',
  467. 'percentOfTotal', 'index']))
  468. baseField = Integer()
  469. baseItem = Integer()
  470. numFmtId = Integer(allow_none=True)
  471. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  472. __elements__ = ()
  473. def __init__(self,
  474. name=None,
  475. fld=None,
  476. subtotal="sum",
  477. showDataAs="normal",
  478. baseField=-1,
  479. baseItem=1048832,
  480. numFmtId=None,
  481. extLst=None,
  482. ):
  483. self.name = name
  484. self.fld = fld
  485. self.subtotal = subtotal
  486. self.showDataAs = showDataAs
  487. self.baseField = baseField
  488. self.baseItem = baseItem
  489. self.numFmtId = numFmtId
  490. self.extLst = extLst
  491. class PageField(Serialisable):
  492. tagname = "pageField"
  493. fld = Integer()
  494. item = Integer(allow_none=True)
  495. hier = Integer(allow_none=True)
  496. name = String(allow_none=True)
  497. cap = String(allow_none=True)
  498. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  499. __elements__ = ()
  500. def __init__(self,
  501. fld=None,
  502. item=None,
  503. hier=None,
  504. name=None,
  505. cap=None,
  506. extLst=None,
  507. ):
  508. self.fld = fld
  509. self.item = item
  510. self.hier = hier
  511. self.name = name
  512. self.cap = cap
  513. self.extLst = extLst
  514. class RowColItem(Serialisable):
  515. tagname = "i"
  516. t = Set(values=(['data', 'default', 'sum', 'countA', 'avg', 'max', 'min',
  517. 'product', 'count', 'stdDev', 'stdDevP', 'var', 'varP', 'grand',
  518. 'blank']))
  519. r = Integer()
  520. i = Integer()
  521. x = Sequence(expected_type=Index, attribute="v")
  522. __elements__ = ('x',)
  523. def __init__(self,
  524. t="data",
  525. r=0,
  526. i=0,
  527. x=(),
  528. ):
  529. self.t = t
  530. self.r = r
  531. self.i = i
  532. self.x = x
  533. class RowColField(Serialisable):
  534. tagname = "field"
  535. x = Integer()
  536. def __init__(self,
  537. x=None,
  538. ):
  539. self.x = x
  540. class AutoSortScope(Serialisable):
  541. pivotArea = Typed(expected_type=PivotArea, )
  542. __elements__ = ('pivotArea',)
  543. def __init__(self,
  544. pivotArea=None,
  545. ):
  546. self.pivotArea = pivotArea
  547. class FieldItem(Serialisable):
  548. tagname = "item"
  549. n = String(allow_none=True)
  550. t = Set(values=(['data', 'default', 'sum', 'countA', 'avg', 'max', 'min',
  551. 'product', 'count', 'stdDev', 'stdDevP', 'var', 'varP', 'grand',
  552. 'blank']))
  553. h = Bool(allow_none=True)
  554. s = Bool(allow_none=True)
  555. sd = Bool(allow_none=True)
  556. f = Bool(allow_none=True)
  557. m = Bool(allow_none=True)
  558. c = Bool(allow_none=True)
  559. x = Integer(allow_none=True)
  560. d = Bool(allow_none=True)
  561. e = Bool(allow_none=True)
  562. def __init__(self,
  563. n=None,
  564. t="data",
  565. h=None,
  566. s=None,
  567. sd=True,
  568. f=None,
  569. m=None,
  570. c=None,
  571. x=None,
  572. d=None,
  573. e=None,
  574. ):
  575. self.n = n
  576. self.t = t
  577. self.h = h
  578. self.s = s
  579. self.sd = sd
  580. self.f = f
  581. self.m = m
  582. self.c = c
  583. self.x = x
  584. self.d = d
  585. self.e = e
  586. class PivotField(Serialisable):
  587. tagname = "pivotField"
  588. items = NestedSequence(expected_type=FieldItem, count=True)
  589. autoSortScope = Typed(expected_type=AutoSortScope, allow_none=True)
  590. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  591. name = String(allow_none=True)
  592. axis = NoneSet(values=(['axisRow', 'axisCol', 'axisPage', 'axisValues']))
  593. dataField = Bool(allow_none=True)
  594. subtotalCaption = String(allow_none=True)
  595. showDropDowns = Bool(allow_none=True)
  596. hiddenLevel = Bool(allow_none=True)
  597. uniqueMemberProperty = String(allow_none=True)
  598. compact = Bool(allow_none=True)
  599. allDrilled = Bool(allow_none=True)
  600. numFmtId = Integer(allow_none=True)
  601. outline = Bool(allow_none=True)
  602. subtotalTop = Bool(allow_none=True)
  603. dragToRow = Bool(allow_none=True)
  604. dragToCol = Bool(allow_none=True)
  605. multipleItemSelectionAllowed = Bool(allow_none=True)
  606. dragToPage = Bool(allow_none=True)
  607. dragToData = Bool(allow_none=True)
  608. dragOff = Bool(allow_none=True)
  609. showAll = Bool(allow_none=True)
  610. insertBlankRow = Bool(allow_none=True)
  611. serverField = Bool(allow_none=True)
  612. insertPageBreak = Bool(allow_none=True)
  613. autoShow = Bool(allow_none=True)
  614. topAutoShow = Bool(allow_none=True)
  615. hideNewItems = Bool(allow_none=True)
  616. measureFilter = Bool(allow_none=True)
  617. includeNewItemsInFilter = Bool(allow_none=True)
  618. itemPageCount = Integer(allow_none=True)
  619. sortType = Set(values=(['manual', 'ascending', 'descending']))
  620. dataSourceSort = Bool(allow_none=True)
  621. nonAutoSortDefault = Bool(allow_none=True)
  622. rankBy = Integer(allow_none=True)
  623. defaultSubtotal = Bool(allow_none=True)
  624. sumSubtotal = Bool(allow_none=True)
  625. countASubtotal = Bool(allow_none=True)
  626. avgSubtotal = Bool(allow_none=True)
  627. maxSubtotal = Bool(allow_none=True)
  628. minSubtotal = Bool(allow_none=True)
  629. productSubtotal = Bool(allow_none=True)
  630. countSubtotal = Bool(allow_none=True)
  631. stdDevSubtotal = Bool(allow_none=True)
  632. stdDevPSubtotal = Bool(allow_none=True)
  633. varSubtotal = Bool(allow_none=True)
  634. varPSubtotal = Bool(allow_none=True)
  635. showPropCell = Bool(allow_none=True)
  636. showPropTip = Bool(allow_none=True)
  637. showPropAsCaption = Bool(allow_none=True)
  638. defaultAttributeDrillState = Bool(allow_none=True)
  639. __elements__ = ('items', 'autoSortScope',)
  640. def __init__(self,
  641. items=(),
  642. autoSortScope=None,
  643. name=None,
  644. axis=None,
  645. dataField=None,
  646. subtotalCaption=None,
  647. showDropDowns=True,
  648. hiddenLevel=None,
  649. uniqueMemberProperty=None,
  650. compact=True,
  651. allDrilled=None,
  652. numFmtId=None,
  653. outline=True,
  654. subtotalTop=True,
  655. dragToRow=True,
  656. dragToCol=True,
  657. multipleItemSelectionAllowed=None,
  658. dragToPage=True,
  659. dragToData=True,
  660. dragOff=True,
  661. showAll=True,
  662. insertBlankRow=None,
  663. serverField=None,
  664. insertPageBreak=None,
  665. autoShow=None,
  666. topAutoShow=True,
  667. hideNewItems=None,
  668. measureFilter=None,
  669. includeNewItemsInFilter=None,
  670. itemPageCount=10,
  671. sortType="manual",
  672. dataSourceSort=None,
  673. nonAutoSortDefault=None,
  674. rankBy=None,
  675. defaultSubtotal=True,
  676. sumSubtotal=None,
  677. countASubtotal=None,
  678. avgSubtotal=None,
  679. maxSubtotal=None,
  680. minSubtotal=None,
  681. productSubtotal=None,
  682. countSubtotal=None,
  683. stdDevSubtotal=None,
  684. stdDevPSubtotal=None,
  685. varSubtotal=None,
  686. varPSubtotal=None,
  687. showPropCell=None,
  688. showPropTip=None,
  689. showPropAsCaption=None,
  690. defaultAttributeDrillState=None,
  691. extLst=None,
  692. ):
  693. self.items = items
  694. self.autoSortScope = autoSortScope
  695. self.name = name
  696. self.axis = axis
  697. self.dataField = dataField
  698. self.subtotalCaption = subtotalCaption
  699. self.showDropDowns = showDropDowns
  700. self.hiddenLevel = hiddenLevel
  701. self.uniqueMemberProperty = uniqueMemberProperty
  702. self.compact = compact
  703. self.allDrilled = allDrilled
  704. self.numFmtId = numFmtId
  705. self.outline = outline
  706. self.subtotalTop = subtotalTop
  707. self.dragToRow = dragToRow
  708. self.dragToCol = dragToCol
  709. self.multipleItemSelectionAllowed = multipleItemSelectionAllowed
  710. self.dragToPage = dragToPage
  711. self.dragToData = dragToData
  712. self.dragOff = dragOff
  713. self.showAll = showAll
  714. self.insertBlankRow = insertBlankRow
  715. self.serverField = serverField
  716. self.insertPageBreak = insertPageBreak
  717. self.autoShow = autoShow
  718. self.topAutoShow = topAutoShow
  719. self.hideNewItems = hideNewItems
  720. self.measureFilter = measureFilter
  721. self.includeNewItemsInFilter = includeNewItemsInFilter
  722. self.itemPageCount = itemPageCount
  723. self.sortType = sortType
  724. self.dataSourceSort = dataSourceSort
  725. self.nonAutoSortDefault = nonAutoSortDefault
  726. self.rankBy = rankBy
  727. self.defaultSubtotal = defaultSubtotal
  728. self.sumSubtotal = sumSubtotal
  729. self.countASubtotal = countASubtotal
  730. self.avgSubtotal = avgSubtotal
  731. self.maxSubtotal = maxSubtotal
  732. self.minSubtotal = minSubtotal
  733. self.productSubtotal = productSubtotal
  734. self.countSubtotal = countSubtotal
  735. self.stdDevSubtotal = stdDevSubtotal
  736. self.stdDevPSubtotal = stdDevPSubtotal
  737. self.varSubtotal = varSubtotal
  738. self.varPSubtotal = varPSubtotal
  739. self.showPropCell = showPropCell
  740. self.showPropTip = showPropTip
  741. self.showPropAsCaption = showPropAsCaption
  742. self.defaultAttributeDrillState = defaultAttributeDrillState
  743. class Location(Serialisable):
  744. tagname = "location"
  745. ref = String()
  746. firstHeaderRow = Integer()
  747. firstDataRow = Integer()
  748. firstDataCol = Integer()
  749. rowPageCount = Integer(allow_none=True)
  750. colPageCount = Integer(allow_none=True)
  751. def __init__(self,
  752. ref=None,
  753. firstHeaderRow=None,
  754. firstDataRow=None,
  755. firstDataCol=None,
  756. rowPageCount=None,
  757. colPageCount=None,
  758. ):
  759. self.ref = ref
  760. self.firstHeaderRow = firstHeaderRow
  761. self.firstDataRow = firstDataRow
  762. self.firstDataCol = firstDataCol
  763. self.rowPageCount = rowPageCount
  764. self.colPageCount = colPageCount
  765. class TableDefinition(Serialisable):
  766. mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"
  767. rel_type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
  768. _id = 1
  769. _path = "/xl/pivotTables/pivotTable{0}.xml"
  770. tagname = "pivotTableDefinition"
  771. cache = None
  772. name = String()
  773. cacheId = Integer()
  774. dataOnRows = Bool()
  775. dataPosition = Integer(allow_none=True)
  776. dataCaption = String()
  777. grandTotalCaption = String(allow_none=True)
  778. errorCaption = String(allow_none=True)
  779. showError = Bool()
  780. missingCaption = String(allow_none=True)
  781. showMissing = Bool()
  782. pageStyle = String(allow_none=True)
  783. pivotTableStyle = String(allow_none=True)
  784. vacatedStyle = String(allow_none=True)
  785. tag = String(allow_none=True)
  786. updatedVersion = Integer()
  787. minRefreshableVersion = Integer()
  788. asteriskTotals = Bool()
  789. showItems = Bool()
  790. editData = Bool()
  791. disableFieldList = Bool()
  792. showCalcMbrs = Bool()
  793. visualTotals = Bool()
  794. showMultipleLabel = Bool()
  795. showDataDropDown = Bool()
  796. showDrill = Bool()
  797. printDrill = Bool()
  798. showMemberPropertyTips = Bool()
  799. showDataTips = Bool()
  800. enableWizard = Bool()
  801. enableDrill = Bool()
  802. enableFieldProperties = Bool()
  803. preserveFormatting = Bool()
  804. useAutoFormatting = Bool()
  805. pageWrap = Integer()
  806. pageOverThenDown = Bool()
  807. subtotalHiddenItems = Bool()
  808. rowGrandTotals = Bool()
  809. colGrandTotals = Bool()
  810. fieldPrintTitles = Bool()
  811. itemPrintTitles = Bool()
  812. mergeItem = Bool()
  813. showDropZones = Bool()
  814. createdVersion = Integer()
  815. indent = Integer()
  816. showEmptyRow = Bool()
  817. showEmptyCol = Bool()
  818. showHeaders = Bool()
  819. compact = Bool()
  820. outline = Bool()
  821. outlineData = Bool()
  822. compactData = Bool()
  823. published = Bool()
  824. gridDropZones = Bool()
  825. immersive = Bool()
  826. multipleFieldFilters = Bool()
  827. chartFormat = Integer()
  828. rowHeaderCaption = String(allow_none=True)
  829. colHeaderCaption = String(allow_none=True)
  830. fieldListSortAscending = Bool()
  831. mdxSubqueries = Bool()
  832. customListSort = Bool(allow_none=True)
  833. autoFormatId = Integer(allow_none=True)
  834. applyNumberFormats = Bool()
  835. applyBorderFormats = Bool()
  836. applyFontFormats = Bool()
  837. applyPatternFormats = Bool()
  838. applyAlignmentFormats = Bool()
  839. applyWidthHeightFormats = Bool()
  840. location = Typed(expected_type=Location, )
  841. pivotFields = NestedSequence(expected_type=PivotField, count=True)
  842. rowFields = NestedSequence(expected_type=RowColField, count=True)
  843. rowItems = NestedSequence(expected_type=RowColItem, count=True)
  844. colFields = NestedSequence(expected_type=RowColField, count=True)
  845. colItems = NestedSequence(expected_type=RowColItem, count=True)
  846. pageFields = NestedSequence(expected_type=PageField, count=True)
  847. dataFields = NestedSequence(expected_type=DataField, count=True)
  848. formats = NestedSequence(expected_type=Format, count=True)
  849. conditionalFormats = Typed(expected_type=ConditionalFormatList, allow_none=True)
  850. chartFormats = NestedSequence(expected_type=ChartFormat, count=True)
  851. pivotHierarchies = NestedSequence(expected_type=PivotHierarchy, count=True)
  852. pivotTableStyleInfo = Typed(expected_type=PivotTableStyle, allow_none=True)
  853. filters = NestedSequence(expected_type=PivotFilter, count=True)
  854. rowHierarchiesUsage = Typed(expected_type=RowHierarchiesUsage, allow_none=True)
  855. colHierarchiesUsage = Typed(expected_type=ColHierarchiesUsage, allow_none=True)
  856. extLst = Typed(expected_type=ExtensionList, allow_none=True)
  857. id = Relation()
  858. __elements__ = ('location', 'pivotFields', 'rowFields', 'rowItems',
  859. 'colFields', 'colItems', 'pageFields', 'dataFields', 'formats',
  860. 'conditionalFormats', 'chartFormats', 'pivotHierarchies',
  861. 'pivotTableStyleInfo', 'filters', 'rowHierarchiesUsage',
  862. 'colHierarchiesUsage',)
  863. def __init__(self,
  864. name=None,
  865. cacheId=None,
  866. dataOnRows=False,
  867. dataPosition=None,
  868. dataCaption=None,
  869. grandTotalCaption=None,
  870. errorCaption=None,
  871. showError=False,
  872. missingCaption=None,
  873. showMissing=True,
  874. pageStyle=None,
  875. pivotTableStyle=None,
  876. vacatedStyle=None,
  877. tag=None,
  878. updatedVersion=0,
  879. minRefreshableVersion=0,
  880. asteriskTotals=False,
  881. showItems=True,
  882. editData=False,
  883. disableFieldList=False,
  884. showCalcMbrs=True,
  885. visualTotals=True,
  886. showMultipleLabel=True,
  887. showDataDropDown=True,
  888. showDrill=True,
  889. printDrill=False,
  890. showMemberPropertyTips=True,
  891. showDataTips=True,
  892. enableWizard=True,
  893. enableDrill=True,
  894. enableFieldProperties=True,
  895. preserveFormatting=True,
  896. useAutoFormatting=False,
  897. pageWrap=0,
  898. pageOverThenDown=False,
  899. subtotalHiddenItems=False,
  900. rowGrandTotals=True,
  901. colGrandTotals=True,
  902. fieldPrintTitles=False,
  903. itemPrintTitles=False,
  904. mergeItem=False,
  905. showDropZones=True,
  906. createdVersion=0,
  907. indent=1,
  908. showEmptyRow=False,
  909. showEmptyCol=False,
  910. showHeaders=True,
  911. compact=True,
  912. outline=False,
  913. outlineData=False,
  914. compactData=True,
  915. published=False,
  916. gridDropZones=False,
  917. immersive=True,
  918. multipleFieldFilters=None,
  919. chartFormat=0,
  920. rowHeaderCaption=None,
  921. colHeaderCaption=None,
  922. fieldListSortAscending=None,
  923. mdxSubqueries=None,
  924. customListSort=None,
  925. autoFormatId=None,
  926. applyNumberFormats=False,
  927. applyBorderFormats=False,
  928. applyFontFormats=False,
  929. applyPatternFormats=False,
  930. applyAlignmentFormats=False,
  931. applyWidthHeightFormats=False,
  932. location=None,
  933. pivotFields=(),
  934. rowFields=(),
  935. rowItems=(),
  936. colFields=(),
  937. colItems=(),
  938. pageFields=(),
  939. dataFields=(),
  940. formats=(),
  941. conditionalFormats=None,
  942. chartFormats=(),
  943. pivotHierarchies=(),
  944. pivotTableStyleInfo=None,
  945. filters=(),
  946. rowHierarchiesUsage=None,
  947. colHierarchiesUsage=None,
  948. extLst=None,
  949. id=None,
  950. ):
  951. self.name = name
  952. self.cacheId = cacheId
  953. self.dataOnRows = dataOnRows
  954. self.dataPosition = dataPosition
  955. self.dataCaption = dataCaption
  956. self.grandTotalCaption = grandTotalCaption
  957. self.errorCaption = errorCaption
  958. self.showError = showError
  959. self.missingCaption = missingCaption
  960. self.showMissing = showMissing
  961. self.pageStyle = pageStyle
  962. self.pivotTableStyle = pivotTableStyle
  963. self.vacatedStyle = vacatedStyle
  964. self.tag = tag
  965. self.updatedVersion = updatedVersion
  966. self.minRefreshableVersion = minRefreshableVersion
  967. self.asteriskTotals = asteriskTotals
  968. self.showItems = showItems
  969. self.editData = editData
  970. self.disableFieldList = disableFieldList
  971. self.showCalcMbrs = showCalcMbrs
  972. self.visualTotals = visualTotals
  973. self.showMultipleLabel = showMultipleLabel
  974. self.showDataDropDown = showDataDropDown
  975. self.showDrill = showDrill
  976. self.printDrill = printDrill
  977. self.showMemberPropertyTips = showMemberPropertyTips
  978. self.showDataTips = showDataTips
  979. self.enableWizard = enableWizard
  980. self.enableDrill = enableDrill
  981. self.enableFieldProperties = enableFieldProperties
  982. self.preserveFormatting = preserveFormatting
  983. self.useAutoFormatting = useAutoFormatting
  984. self.pageWrap = pageWrap
  985. self.pageOverThenDown = pageOverThenDown
  986. self.subtotalHiddenItems = subtotalHiddenItems
  987. self.rowGrandTotals = rowGrandTotals
  988. self.colGrandTotals = colGrandTotals
  989. self.fieldPrintTitles = fieldPrintTitles
  990. self.itemPrintTitles = itemPrintTitles
  991. self.mergeItem = mergeItem
  992. self.showDropZones = showDropZones
  993. self.createdVersion = createdVersion
  994. self.indent = indent
  995. self.showEmptyRow = showEmptyRow
  996. self.showEmptyCol = showEmptyCol
  997. self.showHeaders = showHeaders
  998. self.compact = compact
  999. self.outline = outline
  1000. self.outlineData = outlineData
  1001. self.compactData = compactData
  1002. self.published = published
  1003. self.gridDropZones = gridDropZones
  1004. self.immersive = immersive
  1005. self.multipleFieldFilters = multipleFieldFilters
  1006. self.chartFormat = chartFormat
  1007. self.rowHeaderCaption = rowHeaderCaption
  1008. self.colHeaderCaption = colHeaderCaption
  1009. self.fieldListSortAscending = fieldListSortAscending
  1010. self.mdxSubqueries = mdxSubqueries
  1011. self.customListSort = customListSort
  1012. self.autoFormatId = autoFormatId
  1013. self.applyNumberFormats = applyNumberFormats
  1014. self.applyBorderFormats = applyBorderFormats
  1015. self.applyFontFormats = applyFontFormats
  1016. self.applyPatternFormats = applyPatternFormats
  1017. self.applyAlignmentFormats = applyAlignmentFormats
  1018. self.applyWidthHeightFormats = applyWidthHeightFormats
  1019. self.location = location
  1020. self.pivotFields = pivotFields
  1021. self.rowFields = rowFields
  1022. self.rowItems = rowItems
  1023. self.colFields = colFields
  1024. self.colItems = colItems
  1025. self.pageFields = pageFields
  1026. self.dataFields = dataFields
  1027. self.formats = formats
  1028. self.conditionalFormats = conditionalFormats
  1029. self.conditionalFormats = None
  1030. self.chartFormats = chartFormats
  1031. self.pivotHierarchies = pivotHierarchies
  1032. self.pivotTableStyleInfo = pivotTableStyleInfo
  1033. self.filters = filters
  1034. self.rowHierarchiesUsage = rowHierarchiesUsage
  1035. self.colHierarchiesUsage = colHierarchiesUsage
  1036. self.extLst = extLst
  1037. self.id = id
  1038. def to_tree(self):
  1039. tree = super().to_tree()
  1040. tree.set("xmlns", SHEET_MAIN_NS)
  1041. return tree
  1042. @property
  1043. def path(self):
  1044. return self._path.format(self._id)
  1045. def _write(self, archive, manifest):
  1046. """
  1047. Add to zipfile and update manifest
  1048. """
  1049. self._write_rels(archive, manifest)
  1050. xml = tostring(self.to_tree())
  1051. archive.writestr(self.path[1:], xml)
  1052. manifest.append(self)
  1053. def _write_rels(self, archive, manifest):
  1054. """
  1055. Write the relevant child objects and add links
  1056. """
  1057. if self.cache is None:
  1058. return
  1059. rels = RelationshipList()
  1060. r = Relationship(Type=self.cache.rel_type, Target=self.cache.path)
  1061. rels.append(r)
  1062. self.id = r.id
  1063. if self.cache.path[1:] not in archive.namelist():
  1064. self.cache._write(archive, manifest)
  1065. path = get_rels_path(self.path)
  1066. xml = tostring(rels.to_tree())
  1067. archive.writestr(path[1:], xml)
  1068. def formatted_fields(self):
  1069. """Map fields to associated conditional formats by priority"""
  1070. if not self.conditionalFormats:
  1071. return {}
  1072. fields = defaultdict(list)
  1073. for idx, prio in self.conditionalFormats.by_priority():
  1074. name = self.dataFields[idx].name
  1075. fields[name].append(prio)
  1076. return fields
  1077. @property
  1078. def summary(self):
  1079. """
  1080. Provide a simplified summary of the table
  1081. """
  1082. return f"{self.name} {dict(self.location)}"