diff options
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/workbook')
14 files changed, 1864 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/__init__.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/__init__.py new file mode 100644 index 00000000..8ae4d80d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) 2010-2024 openpyxl + + +from .workbook import Workbook diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/_writer.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/_writer.py new file mode 100644 index 00000000..1aa6aacf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/_writer.py @@ -0,0 +1,197 @@ +# Copyright (c) 2010-2024 openpyxl + +"""Write the workbook global settings to the archive.""" + +from openpyxl.utils import quote_sheetname +from openpyxl.xml.constants import ( + ARC_APP, + ARC_CORE, + ARC_CUSTOM, + ARC_WORKBOOK, + PKG_REL_NS, + CUSTOMUI_NS, + ARC_ROOT_RELS, +) +from openpyxl.xml.functions import tostring, fromstring + +from openpyxl.packaging.relationship import Relationship, RelationshipList +from openpyxl.workbook.defined_name import ( + DefinedName, + DefinedNameList, +) +from openpyxl.workbook.external_reference import ExternalReference +from openpyxl.packaging.workbook import ChildSheet, WorkbookPackage, PivotCache +from openpyxl.workbook.properties import WorkbookProperties +from openpyxl.utils.datetime import CALENDAR_MAC_1904 + + +def get_active_sheet(wb): + """ + Return the index of the active sheet. + If the sheet set to active is hidden return the next visible sheet or None + """ + visible_sheets = [idx for idx, sheet in enumerate(wb._sheets) if sheet.sheet_state == "visible"] + if not visible_sheets: + raise IndexError("At least one sheet must be visible") + + idx = wb._active_sheet_index + sheet = wb.active + if sheet and sheet.sheet_state == "visible": + return idx + + for idx in visible_sheets[idx:]: + wb.active = idx + return idx + + return None + + +class WorkbookWriter: + + def __init__(self, wb): + self.wb = wb + self.rels = RelationshipList() + self.package = WorkbookPackage() + self.package.workbookProtection = wb.security + self.package.calcPr = wb.calculation + + + def write_properties(self): + + props = WorkbookProperties() # needs a mapping to the workbook for preservation + if self.wb.code_name is not None: + props.codeName = self.wb.code_name + if self.wb.excel_base_date == CALENDAR_MAC_1904: + props.date1904 = True + self.package.workbookPr = props + + + def write_worksheets(self): + for idx, sheet in enumerate(self.wb._sheets, 1): + sheet_node = ChildSheet(name=sheet.title, sheetId=idx, id="rId{0}".format(idx)) + rel = Relationship(type=sheet._rel_type, Target=sheet.path) + self.rels.append(rel) + + if not sheet.sheet_state == 'visible': + if len(self.wb._sheets) == 1: + raise ValueError("The only worksheet of a workbook cannot be hidden") + sheet_node.state = sheet.sheet_state + self.package.sheets.append(sheet_node) + + + def write_refs(self): + for link in self.wb._external_links: + # need to match a counter with a workbook's relations + rId = len(self.wb.rels) + 1 + rel = Relationship(type=link._rel_type, Target=link.path) + self.rels.append(rel) + ext = ExternalReference(id=rel.id) + self.package.externalReferences.append(ext) + + + def write_names(self): + defined_names = list(self.wb.defined_names.values()) + + for idx, sheet in enumerate(self.wb.worksheets): + quoted = quote_sheetname(sheet.title) + + # local names + if sheet.defined_names: + names = sheet.defined_names.values() + for n in names: + n.localSheetId = idx + defined_names.extend(names) + + if sheet.auto_filter: + name = DefinedName(name='_FilterDatabase', localSheetId=idx, hidden=True) + name.value = f"{quoted}!{sheet.auto_filter}" + defined_names.append(name) + + if sheet.print_titles: + name = DefinedName(name="Print_Titles", localSheetId=idx) + name.value = sheet.print_titles + defined_names.append(name) + + if sheet.print_area: + name = DefinedName(name="Print_Area", localSheetId=idx) + name.value = sheet.print_area + defined_names.append(name) + + self.package.definedNames = DefinedNameList(definedName=defined_names) + + + def write_pivots(self): + pivot_caches = set() + for pivot in self.wb._pivots: + if pivot.cache not in pivot_caches: + pivot_caches.add(pivot.cache) + c = PivotCache(cacheId=pivot.cacheId) + self.package.pivotCaches.append(c) + rel = Relationship(Type=pivot.cache.rel_type, Target=pivot.cache.path) + self.rels.append(rel) + c.id = rel.id + #self.wb._pivots = [] # reset + + + def write_views(self): + active = get_active_sheet(self.wb) + if self.wb.views: + self.wb.views[0].activeTab = active + self.package.bookViews = self.wb.views + + + def write(self): + """Write the core workbook xml.""" + + self.write_properties() + self.write_worksheets() + self.write_names() + self.write_pivots() + self.write_views() + self.write_refs() + + return tostring(self.package.to_tree()) + + + def write_rels(self): + """Write the workbook relationships xml.""" + + styles = Relationship(type='styles', Target='styles.xml') + self.rels.append(styles) + + theme = Relationship(type='theme', Target='theme/theme1.xml') + self.rels.append(theme) + + if self.wb.vba_archive: + vba = Relationship(type='', Target='vbaProject.bin') + vba.Type ='http://schemas.microsoft.com/office/2006/relationships/vbaProject' + self.rels.append(vba) + + return tostring(self.rels.to_tree()) + + + def write_root_rels(self): + """Write the package relationships""" + + rels = RelationshipList() + + rel = Relationship(type="officeDocument", Target=ARC_WORKBOOK) + rels.append(rel) + rel = Relationship(Type=f"{PKG_REL_NS}/metadata/core-properties", Target=ARC_CORE) + rels.append(rel) + + rel = Relationship(type="extended-properties", Target=ARC_APP) + rels.append(rel) + + if len(self.wb.custom_doc_props) >= 1: + rel = Relationship(type="custom-properties", Target=ARC_CUSTOM) + rels.append(rel) + + if self.wb.vba_archive is not None: + # See if there was a customUI relation and reuse it + xml = fromstring(self.wb.vba_archive.read(ARC_ROOT_RELS)) + root_rels = RelationshipList.from_tree(xml) + for rel in root_rels.find(CUSTOMUI_NS): + rels.append(rel) + + return tostring(rels.to_tree()) diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/child.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/child.py new file mode 100644 index 00000000..19dd29fb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/child.py @@ -0,0 +1,166 @@ +# Copyright (c) 2010-2024 openpyxl + +import re +import warnings + +from openpyxl.worksheet.header_footer import HeaderFooter + +""" +Base class for worksheets, chartsheets, etc. that can be added to workbooks +""" + +INVALID_TITLE_REGEX = re.compile(r'[\\*?:/\[\]]') + + +def avoid_duplicate_name(names, value): + """ + Naive check to see whether name already exists. + If name does exist suggest a name using an incrementer + Duplicates are case insensitive + """ + # Check for an absolute match in which case we need to find an alternative + match = [n for n in names if n.lower() == value.lower()] + if match: + names = u",".join(names) + sheet_title_regex = re.compile(f'(?P<title>{re.escape(value)})(?P<count>\\d*),?', re.I) + matches = sheet_title_regex.findall(names) + if matches: + # use name, but append with the next highest integer + counts = [int(idx) for (t, idx) in matches if idx.isdigit()] + highest = 0 + if counts: + highest = max(counts) + value = u"{0}{1}".format(value, highest + 1) + return value + + +class _WorkbookChild: + + __title = "" + _id = None + _path = "{0}" + _parent = None + _default_title = "Sheet" + + def __init__(self, parent=None, title=None): + self._parent = parent + self.title = title or self._default_title + self.HeaderFooter = HeaderFooter() + + + def __repr__(self): + return '<{0} "{1}">'.format(self.__class__.__name__, self.title) + + + @property + def parent(self): + return self._parent + + + @property + def encoding(self): + return self._parent.encoding + + + @property + def title(self): + return self.__title + + + @title.setter + def title(self, value): + """ + Set a sheet title, ensuring it is valid. + Limited to 31 characters, no special characters. + Duplicate titles will be incremented numerically + """ + if not self._parent: + return + + if not value: + raise ValueError("Title must have at least one character") + + if hasattr(value, "decode"): + if not isinstance(value, str): + try: + value = value.decode("ascii") + except UnicodeDecodeError: + raise ValueError("Worksheet titles must be str") + + m = INVALID_TITLE_REGEX.search(value) + if m: + msg = "Invalid character {0} found in sheet title".format(m.group(0)) + raise ValueError(msg) + + if self.title is not None and self.title != value: + value = avoid_duplicate_name(self.parent.sheetnames, value) + + if len(value) > 31: + warnings.warn("Title is more than 31 characters. Some applications may not be able to read the file") + + self.__title = value + + + @property + def oddHeader(self): + return self.HeaderFooter.oddHeader + + + @oddHeader.setter + def oddHeader(self, value): + self.HeaderFooter.oddHeader = value + + + @property + def oddFooter(self): + return self.HeaderFooter.oddFooter + + + @oddFooter.setter + def oddFooter(self, value): + self.HeaderFooter.oddFooter = value + + + @property + def evenHeader(self): + return self.HeaderFooter.evenHeader + + + @evenHeader.setter + def evenHeader(self, value): + self.HeaderFooter.evenHeader = value + + + @property + def evenFooter(self): + return self.HeaderFooter.evenFooter + + + @evenFooter.setter + def evenFooter(self, value): + self.HeaderFooter.evenFooter = value + + + @property + def firstHeader(self): + return self.HeaderFooter.firstHeader + + + @firstHeader.setter + def firstHeader(self, value): + self.HeaderFooter.firstHeader = value + + + @property + def firstFooter(self): + return self.HeaderFooter.firstFooter + + + @firstFooter.setter + def firstFooter(self, value): + self.HeaderFooter.firstFooter = value + + + @property + def path(self): + return self._path.format(self._id) diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/defined_name.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/defined_name.py new file mode 100644 index 00000000..15f0bd30 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/defined_name.py @@ -0,0 +1,189 @@ +# Copyright (c) 2010-2024 openpyxl + +from collections import defaultdict +import re + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Alias, + String, + Integer, + Bool, + Sequence, + Descriptor, +) +from openpyxl.compat import safe_string +from openpyxl.formula import Tokenizer +from openpyxl.utils.cell import SHEETRANGE_RE + +RESERVED = frozenset(["Print_Area", "Print_Titles", "Criteria", + "_FilterDatabase", "Extract", "Consolidate_Area", + "Sheet_Title"]) + +_names = "|".join(RESERVED) +RESERVED_REGEX = re.compile(r"^_xlnm\.(?P<name>{0})".format(_names)) + + +class DefinedName(Serialisable): + + tagname = "definedName" + + name = String() # unique per workbook/worksheet + comment = String(allow_none=True) + customMenu = String(allow_none=True) + description = String(allow_none=True) + help = String(allow_none=True) + statusBar = String(allow_none=True) + localSheetId = Integer(allow_none=True) + hidden = Bool(allow_none=True) + function = Bool(allow_none=True) + vbProcedure = Bool(allow_none=True) + xlm = Bool(allow_none=True) + functionGroupId = Integer(allow_none=True) + shortcutKey = String(allow_none=True) + publishToServer = Bool(allow_none=True) + workbookParameter = Bool(allow_none=True) + attr_text = Descriptor() + value = Alias("attr_text") + + + def __init__(self, + name=None, + comment=None, + customMenu=None, + description=None, + help=None, + statusBar=None, + localSheetId=None, + hidden=None, + function=None, + vbProcedure=None, + xlm=None, + functionGroupId=None, + shortcutKey=None, + publishToServer=None, + workbookParameter=None, + attr_text=None + ): + self.name = name + self.comment = comment + self.customMenu = customMenu + self.description = description + self.help = help + self.statusBar = statusBar + self.localSheetId = localSheetId + self.hidden = hidden + self.function = function + self.vbProcedure = vbProcedure + self.xlm = xlm + self.functionGroupId = functionGroupId + self.shortcutKey = shortcutKey + self.publishToServer = publishToServer + self.workbookParameter = workbookParameter + self.attr_text = attr_text + + + @property + def type(self): + tok = Tokenizer("=" + self.value) + parsed = tok.items[0] + if parsed.type == "OPERAND": + return parsed.subtype + return parsed.type + + + @property + def destinations(self): + if self.type == "RANGE": + tok = Tokenizer("=" + self.value) + for part in tok.items: + if part.subtype == "RANGE": + m = SHEETRANGE_RE.match(part.value) + sheetname = m.group('notquoted') or m.group('quoted') + yield sheetname, m.group('cells') + + + @property + def is_reserved(self): + m = RESERVED_REGEX.match(self.name) + if m: + return m.group("name") + + + @property + def is_external(self): + return re.compile(r"^\[\d+\].*").match(self.value) is not None + + + def __iter__(self): + for key in self.__attrs__: + if key == "attr_text": + continue + v = getattr(self, key) + if v is not None: + if v in RESERVED: + v = "_xlnm." + v + yield key, safe_string(v) + + +class DefinedNameDict(dict): + + """ + Utility class for storing defined names. + Allows access by name and separation of global and scoped names + """ + + def __setitem__(self, key, value): + if not isinstance(value, DefinedName): + raise TypeError("Value must be a an instance of DefinedName") + elif value.name != key: + raise ValueError("Key must be the same as the name") + super().__setitem__(key, value) + + + def add(self, value): + """ + Add names without worrying about key and name matching. + """ + self[value.name] = value + + +class DefinedNameList(Serialisable): + + tagname = "definedNames" + + definedName = Sequence(expected_type=DefinedName) + + + def __init__(self, definedName=()): + self.definedName = definedName + + + def by_sheet(self): + """ + Break names down into sheet locals and globals + """ + names = defaultdict(DefinedNameDict) + for defn in self.definedName: + if defn.localSheetId is None: + if defn.name in ("_xlnm.Print_Titles", "_xlnm.Print_Area", "_xlnm._FilterDatabase"): + continue + names["global"][defn.name] = defn + else: + sheet = int(defn.localSheetId) + names[sheet][defn.name] = defn + return names + + + def _duplicate(self, defn): + """ + Check for whether DefinedName with the same name and scope already + exists + """ + for d in self.definedName: + if d.name == defn.name and d.localSheetId == defn.localSheetId: + return True + + + def __len__(self): + return len(self.definedName) diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/external_link/__init__.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/external_link/__init__.py new file mode 100644 index 00000000..c3cb6211 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/external_link/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) 2010-2024 openpyxl + +from .external import ExternalLink diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/external_link/external.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/external_link/external.py new file mode 100644 index 00000000..7e2e5b20 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/external_link/external.py @@ -0,0 +1,190 @@ +# Copyright (c) 2010-2024 openpyxl + + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Typed, + String, + Bool, + Integer, + NoneSet, + Sequence, +) +from openpyxl.descriptors.excel import Relation +from openpyxl.descriptors.nested import NestedText +from openpyxl.descriptors.sequence import NestedSequence, ValueSequence + +from openpyxl.packaging.relationship import ( + Relationship, + get_rels_path, + get_dependents + ) +from openpyxl.xml.constants import SHEET_MAIN_NS +from openpyxl.xml.functions import fromstring + + +"""Manage links to external Workbooks""" + + +class ExternalCell(Serialisable): + + r = String() + t = NoneSet(values=(['b', 'd', 'n', 'e', 's', 'str', 'inlineStr'])) + vm = Integer(allow_none=True) + v = NestedText(allow_none=True, expected_type=str) + + def __init__(self, + r=None, + t=None, + vm=None, + v=None, + ): + self.r = r + self.t = t + self.vm = vm + self.v = v + + +class ExternalRow(Serialisable): + + r = Integer() + cell = Sequence(expected_type=ExternalCell) + + __elements__ = ('cell',) + + def __init__(self, + r=(), + cell=None, + ): + self.r = r + self.cell = cell + + +class ExternalSheetData(Serialisable): + + sheetId = Integer() + refreshError = Bool(allow_none=True) + row = Sequence(expected_type=ExternalRow) + + __elements__ = ('row',) + + def __init__(self, + sheetId=None, + refreshError=None, + row=(), + ): + self.sheetId = sheetId + self.refreshError = refreshError + self.row = row + + +class ExternalSheetDataSet(Serialisable): + + sheetData = Sequence(expected_type=ExternalSheetData, ) + + __elements__ = ('sheetData',) + + def __init__(self, + sheetData=None, + ): + self.sheetData = sheetData + + +class ExternalSheetNames(Serialisable): + + sheetName = ValueSequence(expected_type=str) + + __elements__ = ('sheetName',) + + def __init__(self, + sheetName=(), + ): + self.sheetName = sheetName + + +class ExternalDefinedName(Serialisable): + + tagname = "definedName" + + name = String() + refersTo = String(allow_none=True) + sheetId = Integer(allow_none=True) + + def __init__(self, + name=None, + refersTo=None, + sheetId=None, + ): + self.name = name + self.refersTo = refersTo + self.sheetId = sheetId + + +class ExternalBook(Serialisable): + + tagname = "externalBook" + + sheetNames = Typed(expected_type=ExternalSheetNames, allow_none=True) + definedNames = NestedSequence(expected_type=ExternalDefinedName) + sheetDataSet = Typed(expected_type=ExternalSheetDataSet, allow_none=True) + id = Relation() + + __elements__ = ('sheetNames', 'definedNames', 'sheetDataSet') + + def __init__(self, + sheetNames=None, + definedNames=(), + sheetDataSet=None, + id=None, + ): + self.sheetNames = sheetNames + self.definedNames = definedNames + self.sheetDataSet = sheetDataSet + self.id = id + + +class ExternalLink(Serialisable): + + tagname = "externalLink" + + _id = None + _path = "/xl/externalLinks/externalLink{0}.xml" + _rel_type = "externalLink" + mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml" + + externalBook = Typed(expected_type=ExternalBook, allow_none=True) + file_link = Typed(expected_type=Relationship, allow_none=True) # link to external file + + __elements__ = ('externalBook', ) + + def __init__(self, + externalBook=None, + ddeLink=None, + oleLink=None, + extLst=None, + ): + self.externalBook = externalBook + # ignore other items for the moment. + + + def to_tree(self): + node = super().to_tree() + node.set("xmlns", SHEET_MAIN_NS) + return node + + + @property + def path(self): + return self._path.format(self._id) + + +def read_external_link(archive, book_path): + src = archive.read(book_path) + node = fromstring(src) + book = ExternalLink.from_tree(node) + + link_path = get_rels_path(book_path) + deps = get_dependents(archive, link_path) + book.file_link = deps[0] + + return book diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/external_reference.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/external_reference.py new file mode 100644 index 00000000..f05802da --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/external_reference.py @@ -0,0 +1,18 @@ +# Copyright (c) 2010-2024 openpyxl + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Sequence +) +from openpyxl.descriptors.excel import ( + Relation, +) + +class ExternalReference(Serialisable): + + tagname = "externalReference" + + id = Relation() + + def __init__(self, id): + self.id = id diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/function_group.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/function_group.py new file mode 100644 index 00000000..5d7e8557 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/function_group.py @@ -0,0 +1,36 @@ +# Copyright (c) 2010-2024 openpyxl + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Sequence, + String, + Integer, +) + +class FunctionGroup(Serialisable): + + tagname = "functionGroup" + + name = String() + + def __init__(self, + name=None, + ): + self.name = name + + +class FunctionGroupList(Serialisable): + + tagname = "functionGroups" + + builtInGroupCount = Integer(allow_none=True) + functionGroup = Sequence(expected_type=FunctionGroup, allow_none=True) + + __elements__ = ('functionGroup',) + + def __init__(self, + builtInGroupCount=16, + functionGroup=(), + ): + self.builtInGroupCount = builtInGroupCount + self.functionGroup = functionGroup diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/properties.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/properties.py new file mode 100644 index 00000000..bdc9d614 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/properties.py @@ -0,0 +1,151 @@ +# Copyright (c) 2010-2024 openpyxl + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + String, + Float, + Integer, + Bool, + NoneSet, + Set, +) + +from openpyxl.descriptors.excel import Guid + + +class WorkbookProperties(Serialisable): + + tagname = "workbookPr" + + date1904 = Bool(allow_none=True) + dateCompatibility = Bool(allow_none=True) + showObjects = NoneSet(values=(['all', 'placeholders'])) + showBorderUnselectedTables = Bool(allow_none=True) + filterPrivacy = Bool(allow_none=True) + promptedSolutions = Bool(allow_none=True) + showInkAnnotation = Bool(allow_none=True) + backupFile = Bool(allow_none=True) + saveExternalLinkValues = Bool(allow_none=True) + updateLinks = NoneSet(values=(['userSet', 'never', 'always'])) + codeName = String(allow_none=True) + hidePivotFieldList = Bool(allow_none=True) + showPivotChartFilter = Bool(allow_none=True) + allowRefreshQuery = Bool(allow_none=True) + publishItems = Bool(allow_none=True) + checkCompatibility = Bool(allow_none=True) + autoCompressPictures = Bool(allow_none=True) + refreshAllConnections = Bool(allow_none=True) + defaultThemeVersion = Integer(allow_none=True) + + def __init__(self, + date1904=None, + dateCompatibility=None, + showObjects=None, + showBorderUnselectedTables=None, + filterPrivacy=None, + promptedSolutions=None, + showInkAnnotation=None, + backupFile=None, + saveExternalLinkValues=None, + updateLinks=None, + codeName=None, + hidePivotFieldList=None, + showPivotChartFilter=None, + allowRefreshQuery=None, + publishItems=None, + checkCompatibility=None, + autoCompressPictures=None, + refreshAllConnections=None, + defaultThemeVersion=None, + ): + self.date1904 = date1904 + self.dateCompatibility = dateCompatibility + self.showObjects = showObjects + self.showBorderUnselectedTables = showBorderUnselectedTables + self.filterPrivacy = filterPrivacy + self.promptedSolutions = promptedSolutions + self.showInkAnnotation = showInkAnnotation + self.backupFile = backupFile + self.saveExternalLinkValues = saveExternalLinkValues + self.updateLinks = updateLinks + self.codeName = codeName + self.hidePivotFieldList = hidePivotFieldList + self.showPivotChartFilter = showPivotChartFilter + self.allowRefreshQuery = allowRefreshQuery + self.publishItems = publishItems + self.checkCompatibility = checkCompatibility + self.autoCompressPictures = autoCompressPictures + self.refreshAllConnections = refreshAllConnections + self.defaultThemeVersion = defaultThemeVersion + + +class CalcProperties(Serialisable): + + tagname = "calcPr" + + calcId = Integer() + calcMode = NoneSet(values=(['manual', 'auto', 'autoNoTable'])) + fullCalcOnLoad = Bool(allow_none=True) + refMode = NoneSet(values=(['A1', 'R1C1'])) + iterate = Bool(allow_none=True) + iterateCount = Integer(allow_none=True) + iterateDelta = Float(allow_none=True) + fullPrecision = Bool(allow_none=True) + calcCompleted = Bool(allow_none=True) + calcOnSave = Bool(allow_none=True) + concurrentCalc = Bool(allow_none=True) + concurrentManualCount = Integer(allow_none=True) + forceFullCalc = Bool(allow_none=True) + + def __init__(self, + calcId=124519, + calcMode=None, + fullCalcOnLoad=True, + refMode=None, + iterate=None, + iterateCount=None, + iterateDelta=None, + fullPrecision=None, + calcCompleted=None, + calcOnSave=None, + concurrentCalc=None, + concurrentManualCount=None, + forceFullCalc=None, + ): + self.calcId = calcId + self.calcMode = calcMode + self.fullCalcOnLoad = fullCalcOnLoad + self.refMode = refMode + self.iterate = iterate + self.iterateCount = iterateCount + self.iterateDelta = iterateDelta + self.fullPrecision = fullPrecision + self.calcCompleted = calcCompleted + self.calcOnSave = calcOnSave + self.concurrentCalc = concurrentCalc + self.concurrentManualCount = concurrentManualCount + self.forceFullCalc = forceFullCalc + + +class FileVersion(Serialisable): + + tagname = "fileVersion" + + appName = String(allow_none=True) + lastEdited = String(allow_none=True) + lowestEdited = String(allow_none=True) + rupBuild = String(allow_none=True) + codeName = Guid(allow_none=True) + + def __init__(self, + appName=None, + lastEdited=None, + lowestEdited=None, + rupBuild=None, + codeName=None, + ): + self.appName = appName + self.lastEdited = lastEdited + self.lowestEdited = lowestEdited + self.rupBuild = rupBuild + self.codeName = codeName diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/protection.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/protection.py new file mode 100644 index 00000000..d77d64bb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/protection.py @@ -0,0 +1,163 @@ +# Copyright (c) 2010-2024 openpyxl + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Alias, + Typed, + String, + Float, + Integer, + Bool, + NoneSet, + Set, +) +from openpyxl.descriptors.excel import ( + ExtensionList, + HexBinary, + Guid, + Relation, + Base64Binary, +) +from openpyxl.utils.protection import hash_password + + +class WorkbookProtection(Serialisable): + + _workbook_password, _revisions_password = None, None + + tagname = "workbookPr" + + workbook_password = Alias("workbookPassword") + workbookPasswordCharacterSet = String(allow_none=True) + revision_password = Alias("revisionsPassword") + revisionsPasswordCharacterSet = String(allow_none=True) + lockStructure = Bool(allow_none=True) + lock_structure = Alias("lockStructure") + lockWindows = Bool(allow_none=True) + lock_windows = Alias("lockWindows") + lockRevision = Bool(allow_none=True) + lock_revision = Alias("lockRevision") + revisionsAlgorithmName = String(allow_none=True) + revisionsHashValue = Base64Binary(allow_none=True) + revisionsSaltValue = Base64Binary(allow_none=True) + revisionsSpinCount = Integer(allow_none=True) + workbookAlgorithmName = String(allow_none=True) + workbookHashValue = Base64Binary(allow_none=True) + workbookSaltValue = Base64Binary(allow_none=True) + workbookSpinCount = Integer(allow_none=True) + + __attrs__ = ('workbookPassword', 'workbookPasswordCharacterSet', 'revisionsPassword', + 'revisionsPasswordCharacterSet', 'lockStructure', 'lockWindows', 'lockRevision', + 'revisionsAlgorithmName', 'revisionsHashValue', 'revisionsSaltValue', + 'revisionsSpinCount', 'workbookAlgorithmName', 'workbookHashValue', + 'workbookSaltValue', 'workbookSpinCount') + + def __init__(self, + workbookPassword=None, + workbookPasswordCharacterSet=None, + revisionsPassword=None, + revisionsPasswordCharacterSet=None, + lockStructure=None, + lockWindows=None, + lockRevision=None, + revisionsAlgorithmName=None, + revisionsHashValue=None, + revisionsSaltValue=None, + revisionsSpinCount=None, + workbookAlgorithmName=None, + workbookHashValue=None, + workbookSaltValue=None, + workbookSpinCount=None, + ): + if workbookPassword is not None: + self.workbookPassword = workbookPassword + self.workbookPasswordCharacterSet = workbookPasswordCharacterSet + if revisionsPassword is not None: + self.revisionsPassword = revisionsPassword + self.revisionsPasswordCharacterSet = revisionsPasswordCharacterSet + self.lockStructure = lockStructure + self.lockWindows = lockWindows + self.lockRevision = lockRevision + self.revisionsAlgorithmName = revisionsAlgorithmName + self.revisionsHashValue = revisionsHashValue + self.revisionsSaltValue = revisionsSaltValue + self.revisionsSpinCount = revisionsSpinCount + self.workbookAlgorithmName = workbookAlgorithmName + self.workbookHashValue = workbookHashValue + self.workbookSaltValue = workbookSaltValue + self.workbookSpinCount = workbookSpinCount + + def set_workbook_password(self, value='', already_hashed=False): + """Set a password on this workbook.""" + if not already_hashed: + value = hash_password(value) + self._workbook_password = value + + @property + def workbookPassword(self): + """Return the workbook password value, regardless of hash.""" + return self._workbook_password + + @workbookPassword.setter + def workbookPassword(self, value): + """Set a workbook password directly, forcing a hash step.""" + self.set_workbook_password(value) + + def set_revisions_password(self, value='', already_hashed=False): + """Set a revision password on this workbook.""" + if not already_hashed: + value = hash_password(value) + self._revisions_password = value + + @property + def revisionsPassword(self): + """Return the revisions password value, regardless of hash.""" + return self._revisions_password + + @revisionsPassword.setter + def revisionsPassword(self, value): + """Set a revisions password directly, forcing a hash step.""" + self.set_revisions_password(value) + + @classmethod + def from_tree(cls, node): + """Don't hash passwords when deserialising from XML""" + self = super().from_tree(node) + if self.workbookPassword: + self.set_workbook_password(node.get('workbookPassword'), already_hashed=True) + if self.revisionsPassword: + self.set_revisions_password(node.get('revisionsPassword'), already_hashed=True) + return self + +# Backwards compatibility +DocumentSecurity = WorkbookProtection + + +class FileSharing(Serialisable): + + tagname = "fileSharing" + + readOnlyRecommended = Bool(allow_none=True) + userName = String(allow_none=True) + reservationPassword = HexBinary(allow_none=True) + algorithmName = String(allow_none=True) + hashValue = Base64Binary(allow_none=True) + saltValue = Base64Binary(allow_none=True) + spinCount = Integer(allow_none=True) + + def __init__(self, + readOnlyRecommended=None, + userName=None, + reservationPassword=None, + algorithmName=None, + hashValue=None, + saltValue=None, + spinCount=None, + ): + self.readOnlyRecommended = readOnlyRecommended + self.userName = userName + self.reservationPassword = reservationPassword + self.algorithmName = algorithmName + self.hashValue = hashValue + self.saltValue = saltValue + self.spinCount = spinCount diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/smart_tags.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/smart_tags.py new file mode 100644 index 00000000..873e98bf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/smart_tags.py @@ -0,0 +1,56 @@ +# Copyright (c) 2010-2024 openpyxl + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Sequence, + String, + Bool, + NoneSet, + +) + +class SmartTag(Serialisable): + + tagname = "smartTagType" + + namespaceUri = String(allow_none=True) + name = String(allow_none=True) + url = String(allow_none=True) + + def __init__(self, + namespaceUri=None, + name=None, + url=None, + ): + self.namespaceUri = namespaceUri + self.name = name + self.url = url + + +class SmartTagList(Serialisable): + + tagname = "smartTagTypes" + + smartTagType = Sequence(expected_type=SmartTag, allow_none=True) + + __elements__ = ('smartTagType',) + + def __init__(self, + smartTagType=(), + ): + self.smartTagType = smartTagType + + +class SmartTagProperties(Serialisable): + + tagname = "smartTagPr" + + embed = Bool(allow_none=True) + show = NoneSet(values=(['all', 'noIndicator'])) + + def __init__(self, + embed=None, + show=None, + ): + self.embed = embed + self.show = show diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/views.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/views.py new file mode 100644 index 00000000..bcbf0267 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/views.py @@ -0,0 +1,155 @@ +# Copyright (c) 2010-2024 openpyxl + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Typed, + Sequence, + String, + Float, + Integer, + Bool, + NoneSet, + Set, +) +from openpyxl.descriptors.excel import ( + ExtensionList, + Guid, +) + + +class BookView(Serialisable): + + tagname = "workbookView" + + visibility = NoneSet(values=(['visible', 'hidden', 'veryHidden'])) + minimized = Bool(allow_none=True) + showHorizontalScroll = Bool(allow_none=True) + showVerticalScroll = Bool(allow_none=True) + showSheetTabs = Bool(allow_none=True) + xWindow = Integer(allow_none=True) + yWindow = Integer(allow_none=True) + windowWidth = Integer(allow_none=True) + windowHeight = Integer(allow_none=True) + tabRatio = Integer(allow_none=True) + firstSheet = Integer(allow_none=True) + activeTab = Integer(allow_none=True) + autoFilterDateGrouping = Bool(allow_none=True) + extLst = Typed(expected_type=ExtensionList, allow_none=True) + + __elements__ = () + + def __init__(self, + visibility="visible", + minimized=False, + showHorizontalScroll=True, + showVerticalScroll=True, + showSheetTabs=True, + xWindow=None, + yWindow=None, + windowWidth=None, + windowHeight=None, + tabRatio=600, + firstSheet=0, + activeTab=0, + autoFilterDateGrouping=True, + extLst=None, + ): + self.visibility = visibility + self.minimized = minimized + self.showHorizontalScroll = showHorizontalScroll + self.showVerticalScroll = showVerticalScroll + self.showSheetTabs = showSheetTabs + self.xWindow = xWindow + self.yWindow = yWindow + self.windowWidth = windowWidth + self.windowHeight = windowHeight + self.tabRatio = tabRatio + self.firstSheet = firstSheet + self.activeTab = activeTab + self.autoFilterDateGrouping = autoFilterDateGrouping + + +class CustomWorkbookView(Serialisable): + + tagname = "customWorkbookView" + + name = String() + guid = Guid() + autoUpdate = Bool(allow_none=True) + mergeInterval = Integer(allow_none=True) + changesSavedWin = Bool(allow_none=True) + onlySync = Bool(allow_none=True) + personalView = Bool(allow_none=True) + includePrintSettings = Bool(allow_none=True) + includeHiddenRowCol = Bool(allow_none=True) + maximized = Bool(allow_none=True) + minimized = Bool(allow_none=True) + showHorizontalScroll = Bool(allow_none=True) + showVerticalScroll = Bool(allow_none=True) + showSheetTabs = Bool(allow_none=True) + xWindow = Integer(allow_none=True) + yWindow = Integer(allow_none=True) + windowWidth = Integer() + windowHeight = Integer() + tabRatio = Integer(allow_none=True) + activeSheetId = Integer() + showFormulaBar = Bool(allow_none=True) + showStatusbar = Bool(allow_none=True) + showComments = NoneSet(values=(['commNone', 'commIndicator', + 'commIndAndComment'])) + showObjects = NoneSet(values=(['all', 'placeholders'])) + extLst = Typed(expected_type=ExtensionList, allow_none=True) + + __elements__ = () + + def __init__(self, + name=None, + guid=None, + autoUpdate=None, + mergeInterval=None, + changesSavedWin=None, + onlySync=None, + personalView=None, + includePrintSettings=None, + includeHiddenRowCol=None, + maximized=None, + minimized=None, + showHorizontalScroll=None, + showVerticalScroll=None, + showSheetTabs=None, + xWindow=None, + yWindow=None, + windowWidth=None, + windowHeight=None, + tabRatio=None, + activeSheetId=None, + showFormulaBar=None, + showStatusbar=None, + showComments="commIndicator", + showObjects="all", + extLst=None, + ): + self.name = name + self.guid = guid + self.autoUpdate = autoUpdate + self.mergeInterval = mergeInterval + self.changesSavedWin = changesSavedWin + self.onlySync = onlySync + self.personalView = personalView + self.includePrintSettings = includePrintSettings + self.includeHiddenRowCol = includeHiddenRowCol + self.maximized = maximized + self.minimized = minimized + self.showHorizontalScroll = showHorizontalScroll + self.showVerticalScroll = showVerticalScroll + self.showSheetTabs = showSheetTabs + self.xWindow = xWindow + self.yWindow = yWindow + self.windowWidth = windowWidth + self.windowHeight = windowHeight + self.tabRatio = tabRatio + self.activeSheetId = activeSheetId + self.showFormulaBar = showFormulaBar + self.showStatusbar = showStatusbar + self.showComments = showComments + self.showObjects = showObjects diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/web.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/web.py new file mode 100644 index 00000000..e30e761a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/web.py @@ -0,0 +1,98 @@ +# Copyright (c) 2010-2024 openpyxl + +from openpyxl.descriptors.serialisable import Serialisable +from openpyxl.descriptors import ( + Typed, + Sequence, + String, + Float, + Integer, + Bool, + NoneSet, +) + + +class WebPublishObject(Serialisable): + + tagname = "webPublishingObject" + + id = Integer() + divId = String() + sourceObject = String(allow_none=True) + destinationFile = String() + title = String(allow_none=True) + autoRepublish = Bool(allow_none=True) + + def __init__(self, + id=None, + divId=None, + sourceObject=None, + destinationFile=None, + title=None, + autoRepublish=None, + ): + self.id = id + self.divId = divId + self.sourceObject = sourceObject + self.destinationFile = destinationFile + self.title = title + self.autoRepublish = autoRepublish + + +class WebPublishObjectList(Serialisable): + + tagname ="webPublishingObjects" + + count = Integer(allow_none=True) + webPublishObject = Sequence(expected_type=WebPublishObject) + + __elements__ = ('webPublishObject',) + + def __init__(self, + count=None, + webPublishObject=(), + ): + self.webPublishObject = webPublishObject + + + @property + def count(self): + return len(self.webPublishObject) + + +class WebPublishing(Serialisable): + + tagname = "webPublishing" + + css = Bool(allow_none=True) + thicket = Bool(allow_none=True) + longFileNames = Bool(allow_none=True) + vml = Bool(allow_none=True) + allowPng = Bool(allow_none=True) + targetScreenSize = NoneSet(values=(['544x376', '640x480', '720x512', '800x600', + '1024x768', '1152x882', '1152x900', '1280x1024', '1600x1200', + '1800x1440', '1920x1200'])) + dpi = Integer(allow_none=True) + codePage = Integer(allow_none=True) + characterSet = String(allow_none=True) + + def __init__(self, + css=None, + thicket=None, + longFileNames=None, + vml=None, + allowPng=None, + targetScreenSize='800x600', + dpi=None, + codePage=None, + characterSet=None, + ): + self.css = css + self.thicket = thicket + self.longFileNames = longFileNames + self.vml = vml + self.allowPng = allowPng + self.targetScreenSize = targetScreenSize + self.dpi = dpi + self.codePage = codePage + self.characterSet = characterSet diff --git a/.venv/lib/python3.12/site-packages/openpyxl/workbook/workbook.py b/.venv/lib/python3.12/site-packages/openpyxl/workbook/workbook.py new file mode 100644 index 00000000..b83ac442 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/workbook/workbook.py @@ -0,0 +1,438 @@ +# Copyright (c) 2010-2024 openpyxl + +"""Workbook is the top-level container for all document information.""" +from copy import copy + +from openpyxl.compat import deprecated +from openpyxl.worksheet.worksheet import Worksheet +from openpyxl.worksheet._read_only import ReadOnlyWorksheet +from openpyxl.worksheet._write_only import WriteOnlyWorksheet +from openpyxl.worksheet.copier import WorksheetCopy + +from openpyxl.utils import quote_sheetname +from openpyxl.utils.indexed_list import IndexedList +from openpyxl.utils.datetime import WINDOWS_EPOCH, MAC_EPOCH +from openpyxl.utils.exceptions import ReadOnlyWorkbookException + +from openpyxl.writer.excel import save_workbook + +from openpyxl.styles.cell_style import StyleArray +from openpyxl.styles.named_styles import NamedStyle +from openpyxl.styles.differential import DifferentialStyleList +from openpyxl.styles.alignment import Alignment +from openpyxl.styles.borders import DEFAULT_BORDER +from openpyxl.styles.fills import DEFAULT_EMPTY_FILL, DEFAULT_GRAY_FILL +from openpyxl.styles.fonts import DEFAULT_FONT +from openpyxl.styles.protection import Protection +from openpyxl.styles.colors import COLOR_INDEX +from openpyxl.styles.named_styles import NamedStyleList +from openpyxl.styles.table import TableStyleList + +from openpyxl.chartsheet import Chartsheet +from .defined_name import DefinedName, DefinedNameDict +from openpyxl.packaging.core import DocumentProperties +from openpyxl.packaging.custom import CustomPropertyList +from openpyxl.packaging.relationship import RelationshipList +from .child import _WorkbookChild +from .protection import DocumentSecurity +from .properties import CalcProperties +from .views import BookView + + +from openpyxl.xml.constants import ( + XLSM, + XLSX, + XLTM, + XLTX +) + +INTEGER_TYPES = (int,) + +class Workbook: + """Workbook is the container for all other parts of the document.""" + + _read_only = False + _data_only = False + template = False + path = "/xl/workbook.xml" + + def __init__(self, + write_only=False, + iso_dates=False, + ): + self._sheets = [] + self._pivots = [] + self._active_sheet_index = 0 + self.defined_names = DefinedNameDict() + self._external_links = [] + self.properties = DocumentProperties() + self.custom_doc_props = CustomPropertyList() + self.security = DocumentSecurity() + self.__write_only = write_only + self.shared_strings = IndexedList() + + self._setup_styles() + + self.loaded_theme = None + self.vba_archive = None + self.is_template = False + self.code_name = None + self.epoch = WINDOWS_EPOCH + self.encoding = "utf-8" + self.iso_dates = iso_dates + + if not self.write_only: + self._sheets.append(Worksheet(self)) + + self.rels = RelationshipList() + self.calculation = CalcProperties() + self.views = [BookView()] + + + def _setup_styles(self): + """Bootstrap styles""" + + self._fonts = IndexedList() + self._fonts.add(DEFAULT_FONT) + + self._alignments = IndexedList([Alignment()]) + + self._borders = IndexedList() + self._borders.add(DEFAULT_BORDER) + + self._fills = IndexedList() + self._fills.add(DEFAULT_EMPTY_FILL) + self._fills.add(DEFAULT_GRAY_FILL) + + self._number_formats = IndexedList() + self._date_formats = {} + self._timedelta_formats = {} + + self._protections = IndexedList([Protection()]) + + self._colors = COLOR_INDEX + self._cell_styles = IndexedList([StyleArray()]) + self._named_styles = NamedStyleList() + self.add_named_style(NamedStyle(font=copy(DEFAULT_FONT), border=copy(DEFAULT_BORDER), builtinId=0)) + self._table_styles = TableStyleList() + self._differential_styles = DifferentialStyleList() + + + @property + def epoch(self): + if self._epoch == WINDOWS_EPOCH: + return WINDOWS_EPOCH + return MAC_EPOCH + + + @epoch.setter + def epoch(self, value): + if value not in (WINDOWS_EPOCH, MAC_EPOCH): + raise ValueError("The epoch must be either 1900 or 1904") + self._epoch = value + + + @property + def read_only(self): + return self._read_only + + @property + def data_only(self): + return self._data_only + + @property + def write_only(self): + return self.__write_only + + + @property + def excel_base_date(self): + return self.epoch + + @property + def active(self): + """Get the currently active sheet or None + + :type: :class:`openpyxl.worksheet.worksheet.Worksheet` + """ + try: + return self._sheets[self._active_sheet_index] + except IndexError: + pass + + @active.setter + def active(self, value): + """Set the active sheet""" + if not isinstance(value, (_WorkbookChild, INTEGER_TYPES)): + raise TypeError("Value must be either a worksheet, chartsheet or numerical index") + if isinstance(value, INTEGER_TYPES): + self._active_sheet_index = value + return + #if self._sheets and 0 <= value < len(self._sheets): + #value = self._sheets[value] + #else: + #raise ValueError("Sheet index is outside the range of possible values", value) + if value not in self._sheets: + raise ValueError("Worksheet is not in the workbook") + if value.sheet_state != "visible": + raise ValueError("Only visible sheets can be made active") + + idx = self._sheets.index(value) + self._active_sheet_index = idx + + + def create_sheet(self, title=None, index=None): + """Create a worksheet (at an optional index). + + :param title: optional title of the sheet + :type title: str + :param index: optional position at which the sheet will be inserted + :type index: int + + """ + if self.read_only: + raise ReadOnlyWorkbookException('Cannot create new sheet in a read-only workbook') + + if self.write_only : + new_ws = WriteOnlyWorksheet(parent=self, title=title) + else: + new_ws = Worksheet(parent=self, title=title) + + self._add_sheet(sheet=new_ws, index=index) + return new_ws + + + def _add_sheet(self, sheet, index=None): + """Add an worksheet (at an optional index).""" + + if not isinstance(sheet, (Worksheet, WriteOnlyWorksheet, Chartsheet)): + raise TypeError("Cannot be added to a workbook") + + if sheet.parent != self: + raise ValueError("You cannot add worksheets from another workbook.") + + if index is None: + self._sheets.append(sheet) + else: + self._sheets.insert(index, sheet) + + + def move_sheet(self, sheet, offset=0): + """ + Move a sheet or sheetname + """ + if not isinstance(sheet, Worksheet): + sheet = self[sheet] + idx = self._sheets.index(sheet) + del self._sheets[idx] + new_pos = idx + offset + self._sheets.insert(new_pos, sheet) + + + def remove(self, worksheet): + """Remove `worksheet` from this workbook.""" + idx = self._sheets.index(worksheet) + self._sheets.remove(worksheet) + + + @deprecated("Use wb.remove(worksheet) or del wb[sheetname]") + def remove_sheet(self, worksheet): + """Remove `worksheet` from this workbook.""" + self.remove(worksheet) + + + def create_chartsheet(self, title=None, index=None): + if self.read_only: + raise ReadOnlyWorkbookException("Cannot create new sheet in a read-only workbook") + cs = Chartsheet(parent=self, title=title) + + self._add_sheet(cs, index) + return cs + + + @deprecated("Use wb[sheetname]") + def get_sheet_by_name(self, name): + """Returns a worksheet by its name. + + :param name: the name of the worksheet to look for + :type name: string + + """ + return self[name] + + def __contains__(self, key): + return key in self.sheetnames + + + def index(self, worksheet): + """Return the index of a worksheet.""" + return self.worksheets.index(worksheet) + + + @deprecated("Use wb.index(worksheet)") + def get_index(self, worksheet): + """Return the index of the worksheet.""" + return self.index(worksheet) + + def __getitem__(self, key): + """Returns a worksheet by its name. + + :param name: the name of the worksheet to look for + :type name: string + + """ + for sheet in self.worksheets + self.chartsheets: + if sheet.title == key: + return sheet + raise KeyError("Worksheet {0} does not exist.".format(key)) + + def __delitem__(self, key): + sheet = self[key] + self.remove(sheet) + + def __iter__(self): + return iter(self.worksheets) + + + @deprecated("Use wb.sheetnames") + def get_sheet_names(self): + return self.sheetnames + + @property + def worksheets(self): + """A list of sheets in this workbook + + :type: list of :class:`openpyxl.worksheet.worksheet.Worksheet` + """ + return [s for s in self._sheets if isinstance(s, (Worksheet, ReadOnlyWorksheet, WriteOnlyWorksheet))] + + @property + def chartsheets(self): + """A list of Chartsheets in this workbook + + :type: list of :class:`openpyxl.chartsheet.chartsheet.Chartsheet` + """ + return [s for s in self._sheets if isinstance(s, Chartsheet)] + + @property + def sheetnames(self): + """Returns the list of the names of worksheets in this workbook. + + Names are returned in the worksheets order. + + :type: list of strings + + """ + return [s.title for s in self._sheets] + + + @deprecated("Assign scoped named ranges directly to worksheets or global ones to the workbook. Deprecated in 3.1") + def create_named_range(self, name, worksheet=None, value=None, scope=None): + """Create a new named_range on a worksheet + + """ + defn = DefinedName(name=name) + if worksheet is not None: + defn.value = "{0}!{1}".format(quote_sheetname(worksheet.title), value) + else: + defn.value = value + + self.defined_names[name] = defn + + + def add_named_style(self, style): + """ + Add a named style + """ + self._named_styles.append(style) + style.bind(self) + + + @property + def named_styles(self): + """ + List available named styles + """ + return self._named_styles.names + + + @property + def mime_type(self): + """ + The mime type is determined by whether a workbook is a template or + not and whether it contains macros or not. Excel requires the file + extension to match but openpyxl does not enforce this. + + """ + ct = self.template and XLTX or XLSX + if self.vba_archive: + ct = self.template and XLTM or XLSM + return ct + + + def save(self, filename): + """Save the current workbook under the given `filename`. + Use this function instead of using an `ExcelWriter`. + + .. warning:: + When creating your workbook using `write_only` set to True, + you will only be able to call this function once. Subsequent attempts to + modify or save the file will raise an :class:`openpyxl.shared.exc.WorkbookAlreadySaved` exception. + """ + if self.read_only: + raise TypeError("""Workbook is read-only""") + if self.write_only and not self.worksheets: + self.create_sheet() + save_workbook(self, filename) + + + @property + def style_names(self): + """ + List of named styles + """ + return [s.name for s in self._named_styles] + + + def copy_worksheet(self, from_worksheet): + """Copy an existing worksheet in the current workbook + + .. warning:: + This function cannot copy worksheets between workbooks. + worksheets can only be copied within the workbook that they belong + + :param from_worksheet: the worksheet to be copied from + :return: copy of the initial worksheet + """ + if self.__write_only or self._read_only: + raise ValueError("Cannot copy worksheets in read-only or write-only mode") + + new_title = u"{0} Copy".format(from_worksheet.title) + to_worksheet = self.create_sheet(title=new_title) + cp = WorksheetCopy(source_worksheet=from_worksheet, target_worksheet=to_worksheet) + cp.copy_worksheet() + return to_worksheet + + + def close(self): + """ + Close workbook file if open. Only affects read-only and write-only modes. + """ + if hasattr(self, '_archive'): + self._archive.close() + + + def _duplicate_name(self, name): + """ + Check for duplicate name in defined name list and table list of each worksheet. + Names are not case sensitive. + """ + name = name.lower() + for sheet in self.worksheets: + for t in sheet.tables: + if name == t.lower(): + return True + + if name in self.defined_names: + return True + |