about summary refs log tree commit diff
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()]