forked from Alsan/Post_finder
venv
This commit is contained in:
385
venv/lib/python3.12/site-packages/openpyxl/worksheet/table.py
Normal file
385
venv/lib/python3.12/site-packages/openpyxl/worksheet/table.py
Normal file
@ -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()]
|
Reference in New Issue
Block a user