diff options
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.py | 385 |
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()] |