aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/openpyxl/worksheet/table.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/worksheet/table.py')
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/worksheet/table.py385
1 files changed, 385 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/worksheet/table.py b/.venv/lib/python3.12/site-packages/openpyxl/worksheet/table.py
new file mode 100644
index 00000000..756345f9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/openpyxl/worksheet/table.py
@@ -0,0 +1,385 @@
+# Copyright (c) 2010-2024 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+ Descriptor,
+ Alias,
+ Typed,
+ Bool,
+ Integer,
+ NoneSet,
+ String,
+ Sequence,
+)
+from openpyxl.descriptors.excel import ExtensionList, CellRange
+from openpyxl.descriptors.sequence import NestedSequence
+from openpyxl.xml.constants import SHEET_MAIN_NS, REL_NS
+from openpyxl.xml.functions import tostring
+from openpyxl.utils import range_boundaries
+from openpyxl.utils.escape import escape, unescape
+
+from .related import Related
+
+from .filters import (
+ AutoFilter,
+ SortState,
+)
+
+TABLESTYLES = tuple(
+ ["TableStyleMedium{0}".format(i) for i in range(1, 29)]
+ + ["TableStyleLight{0}".format(i) for i in range(1, 22)]
+ + ["TableStyleDark{0}".format(i) for i in range(1, 12)]
+)
+
+PIVOTSTYLES = tuple(
+ ["PivotStyleMedium{0}".format(i) for i in range(1, 29)]
+ + ["PivotStyleLight{0}".format(i) for i in range(1, 29)]
+ + ["PivotStyleDark{0}".format(i) for i in range(1, 29)]
+)
+
+
+class TableStyleInfo(Serialisable):
+
+ tagname = "tableStyleInfo"
+
+ name = String(allow_none=True)
+ showFirstColumn = Bool(allow_none=True)
+ showLastColumn = Bool(allow_none=True)
+ showRowStripes = Bool(allow_none=True)
+ showColumnStripes = Bool(allow_none=True)
+
+ def __init__(self,
+ name=None,
+ showFirstColumn=None,
+ showLastColumn=None,
+ showRowStripes=None,
+ showColumnStripes=None,
+ ):
+ self.name = name
+ self.showFirstColumn = showFirstColumn
+ self.showLastColumn = showLastColumn
+ self.showRowStripes = showRowStripes
+ self.showColumnStripes = showColumnStripes
+
+
+class XMLColumnProps(Serialisable):
+
+ tagname = "xmlColumnPr"
+
+ mapId = Integer()
+ xpath = String()
+ denormalized = Bool(allow_none=True)
+ xmlDataType = String()
+ extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+ __elements__ = ()
+
+ def __init__(self,
+ mapId=None,
+ xpath=None,
+ denormalized=None,
+ xmlDataType=None,
+ extLst=None,
+ ):
+ self.mapId = mapId
+ self.xpath = xpath
+ self.denormalized = denormalized
+ self.xmlDataType = xmlDataType
+
+
+class TableFormula(Serialisable):
+
+ tagname = "tableFormula"
+
+ ## Note formula is stored as the text value
+
+ array = Bool(allow_none=True)
+ attr_text = Descriptor()
+ text = Alias('attr_text')
+
+
+ def __init__(self,
+ array=None,
+ attr_text=None,
+ ):
+ self.array = array
+ self.attr_text = attr_text
+
+
+class TableColumn(Serialisable):
+
+ tagname = "tableColumn"
+
+ id = Integer()
+ uniqueName = String(allow_none=True)
+ name = String()
+ totalsRowFunction = NoneSet(values=(['sum', 'min', 'max', 'average',
+ 'count', 'countNums', 'stdDev', 'var', 'custom']))
+ totalsRowLabel = String(allow_none=True)
+ queryTableFieldId = Integer(allow_none=True)
+ headerRowDxfId = Integer(allow_none=True)
+ dataDxfId = Integer(allow_none=True)
+ totalsRowDxfId = Integer(allow_none=True)
+ headerRowCellStyle = String(allow_none=True)
+ dataCellStyle = String(allow_none=True)
+ totalsRowCellStyle = String(allow_none=True)
+ calculatedColumnFormula = Typed(expected_type=TableFormula, allow_none=True)
+ totalsRowFormula = Typed(expected_type=TableFormula, allow_none=True)
+ xmlColumnPr = Typed(expected_type=XMLColumnProps, allow_none=True)
+ extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+ __elements__ = ('calculatedColumnFormula', 'totalsRowFormula',
+ 'xmlColumnPr', 'extLst')
+
+ def __init__(self,
+ id=None,
+ uniqueName=None,
+ name=None,
+ totalsRowFunction=None,
+ totalsRowLabel=None,
+ queryTableFieldId=None,
+ headerRowDxfId=None,
+ dataDxfId=None,
+ totalsRowDxfId=None,
+ headerRowCellStyle=None,
+ dataCellStyle=None,
+ totalsRowCellStyle=None,
+ calculatedColumnFormula=None,
+ totalsRowFormula=None,
+ xmlColumnPr=None,
+ extLst=None,
+ ):
+ self.id = id
+ self.uniqueName = uniqueName
+ self.name = name
+ self.totalsRowFunction = totalsRowFunction
+ self.totalsRowLabel = totalsRowLabel
+ self.queryTableFieldId = queryTableFieldId
+ self.headerRowDxfId = headerRowDxfId
+ self.dataDxfId = dataDxfId
+ self.totalsRowDxfId = totalsRowDxfId
+ self.headerRowCellStyle = headerRowCellStyle
+ self.dataCellStyle = dataCellStyle
+ self.totalsRowCellStyle = totalsRowCellStyle
+ self.calculatedColumnFormula = calculatedColumnFormula
+ self.totalsRowFormula = totalsRowFormula
+ self.xmlColumnPr = xmlColumnPr
+ self.extLst = extLst
+
+
+ def __iter__(self):
+ for k, v in super().__iter__():
+ if k == 'name':
+ v = escape(v)
+ yield k, v
+
+
+ @classmethod
+ def from_tree(cls, node):
+ self = super().from_tree(node)
+ self.name = unescape(self.name)
+ return self
+
+
+class TableNameDescriptor(String):
+
+ """
+ Table names cannot have spaces in them
+ """
+
+ def __set__(self, instance, value):
+ if value is not None and " " in value:
+ raise ValueError("Table names cannot have spaces")
+ super().__set__(instance, value)
+
+
+class Table(Serialisable):
+
+ _path = "/tables/table{0}.xml"
+ mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
+ _rel_type = REL_NS + "/table"
+ _rel_id = None
+
+ tagname = "table"
+
+ id = Integer()
+ name = String(allow_none=True)
+ displayName = TableNameDescriptor()
+ comment = String(allow_none=True)
+ ref = CellRange()
+ tableType = NoneSet(values=(['worksheet', 'xml', 'queryTable']))
+ headerRowCount = Integer(allow_none=True)
+ insertRow = Bool(allow_none=True)
+ insertRowShift = Bool(allow_none=True)
+ totalsRowCount = Integer(allow_none=True)
+ totalsRowShown = Bool(allow_none=True)
+ published = Bool(allow_none=True)
+ headerRowDxfId = Integer(allow_none=True)
+ dataDxfId = Integer(allow_none=True)
+ totalsRowDxfId = Integer(allow_none=True)
+ headerRowBorderDxfId = Integer(allow_none=True)
+ tableBorderDxfId = Integer(allow_none=True)
+ totalsRowBorderDxfId = Integer(allow_none=True)
+ headerRowCellStyle = String(allow_none=True)
+ dataCellStyle = String(allow_none=True)
+ totalsRowCellStyle = String(allow_none=True)
+ connectionId = Integer(allow_none=True)
+ autoFilter = Typed(expected_type=AutoFilter, allow_none=True)
+ sortState = Typed(expected_type=SortState, allow_none=True)
+ tableColumns = NestedSequence(expected_type=TableColumn, count=True)
+ tableStyleInfo = Typed(expected_type=TableStyleInfo, allow_none=True)
+ extLst = Typed(expected_type=ExtensionList, allow_none=True)
+
+ __elements__ = ('autoFilter', 'sortState', 'tableColumns',
+ 'tableStyleInfo')
+
+ def __init__(self,
+ id=1,
+ displayName=None,
+ ref=None,
+ name=None,
+ comment=None,
+ tableType=None,
+ headerRowCount=1,
+ insertRow=None,
+ insertRowShift=None,
+ totalsRowCount=None,
+ totalsRowShown=None,
+ published=None,
+ headerRowDxfId=None,
+ dataDxfId=None,
+ totalsRowDxfId=None,
+ headerRowBorderDxfId=None,
+ tableBorderDxfId=None,
+ totalsRowBorderDxfId=None,
+ headerRowCellStyle=None,
+ dataCellStyle=None,
+ totalsRowCellStyle=None,
+ connectionId=None,
+ autoFilter=None,
+ sortState=None,
+ tableColumns=(),
+ tableStyleInfo=None,
+ extLst=None,
+ ):
+ self.id = id
+ self.displayName = displayName
+ if name is None:
+ name = displayName
+ self.name = name
+ self.comment = comment
+ self.ref = ref
+ self.tableType = tableType
+ self.headerRowCount = headerRowCount
+ self.insertRow = insertRow
+ self.insertRowShift = insertRowShift
+ self.totalsRowCount = totalsRowCount
+ self.totalsRowShown = totalsRowShown
+ self.published = published
+ self.headerRowDxfId = headerRowDxfId
+ self.dataDxfId = dataDxfId
+ self.totalsRowDxfId = totalsRowDxfId
+ self.headerRowBorderDxfId = headerRowBorderDxfId
+ self.tableBorderDxfId = tableBorderDxfId
+ self.totalsRowBorderDxfId = totalsRowBorderDxfId
+ self.headerRowCellStyle = headerRowCellStyle
+ self.dataCellStyle = dataCellStyle
+ self.totalsRowCellStyle = totalsRowCellStyle
+ self.connectionId = connectionId
+ self.autoFilter = autoFilter
+ self.sortState = sortState
+ self.tableColumns = tableColumns
+ self.tableStyleInfo = tableStyleInfo
+
+
+ def to_tree(self):
+ tree = super().to_tree()
+ tree.set("xmlns", SHEET_MAIN_NS)
+ return tree
+
+
+ @property
+ def path(self):
+ """
+ Return path within the archive
+ """
+ return "/xl" + self._path.format(self.id)
+
+
+ def _write(self, archive):
+ """
+ Serialise to XML and write to archive
+ """
+ xml = self.to_tree()
+ archive.writestr(self.path[1:], tostring(xml))
+
+
+ def _initialise_columns(self):
+ """
+ Create a list of table columns from a cell range
+ Always set a ref if we have headers (the default)
+ Column headings must be strings and must match cells in the worksheet.
+ """
+
+ min_col, min_row, max_col, max_row = range_boundaries(self.ref)
+ for idx in range(min_col, max_col+1):
+ col = TableColumn(id=idx, name="Column{0}".format(idx))
+ self.tableColumns.append(col)
+ if self.headerRowCount and not self.autoFilter:
+ self.autoFilter = AutoFilter(ref=self.ref)
+
+
+ @property
+ def column_names(self):
+ return [column.name for column in self.tableColumns]
+
+
+class TablePartList(Serialisable):
+
+ tagname = "tableParts"
+
+ count = Integer(allow_none=True)
+ tablePart = Sequence(expected_type=Related)
+
+ __elements__ = ('tablePart',)
+ __attrs__ = ('count',)
+
+ def __init__(self,
+ count=None,
+ tablePart=(),
+ ):
+ self.tablePart = tablePart
+
+
+ def append(self, part):
+ self.tablePart.append(part)
+
+
+ @property
+ def count(self):
+ return len(self.tablePart)
+
+
+ def __bool__(self):
+ return bool(self.tablePart)
+
+
+class TableList(dict):
+
+
+ def add(self, table):
+ if not isinstance(table, Table):
+ raise TypeError("You can only add tables")
+ self[table.name] = table
+
+
+ def get(self, name=None, table_range=None):
+ if name is not None:
+ return super().get(name)
+ for table in self.values():
+ if table_range == table.ref:
+ return table
+
+
+ def items(self):
+ return [(name, table.ref) for name, table in super().items()]