Updated script that can be controled by Nodejs web app
This commit is contained in:
@ -0,0 +1,4 @@
|
||||
# Copyright (c) 2010-2024 openpyxl
|
||||
|
||||
|
||||
from .workbook import Workbook
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
197
lib/python3.13/site-packages/openpyxl/workbook/_writer.py
Normal file
197
lib/python3.13/site-packages/openpyxl/workbook/_writer.py
Normal file
@ -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())
|
166
lib/python3.13/site-packages/openpyxl/workbook/child.py
Normal file
166
lib/python3.13/site-packages/openpyxl/workbook/child.py
Normal file
@ -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)
|
189
lib/python3.13/site-packages/openpyxl/workbook/defined_name.py
Normal file
189
lib/python3.13/site-packages/openpyxl/workbook/defined_name.py
Normal file
@ -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)
|
@ -0,0 +1,3 @@
|
||||
# Copyright (c) 2010-2024 openpyxl
|
||||
|
||||
from .external import ExternalLink
|
Binary file not shown.
Binary file not shown.
@ -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
|
@ -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
|
@ -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
|
151
lib/python3.13/site-packages/openpyxl/workbook/properties.py
Normal file
151
lib/python3.13/site-packages/openpyxl/workbook/properties.py
Normal file
@ -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
|
163
lib/python3.13/site-packages/openpyxl/workbook/protection.py
Normal file
163
lib/python3.13/site-packages/openpyxl/workbook/protection.py
Normal file
@ -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
|
56
lib/python3.13/site-packages/openpyxl/workbook/smart_tags.py
Normal file
56
lib/python3.13/site-packages/openpyxl/workbook/smart_tags.py
Normal file
@ -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
|
155
lib/python3.13/site-packages/openpyxl/workbook/views.py
Normal file
155
lib/python3.13/site-packages/openpyxl/workbook/views.py
Normal file
@ -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
|
98
lib/python3.13/site-packages/openpyxl/workbook/web.py
Normal file
98
lib/python3.13/site-packages/openpyxl/workbook/web.py
Normal file
@ -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
|
438
lib/python3.13/site-packages/openpyxl/workbook/workbook.py
Normal file
438
lib/python3.13/site-packages/openpyxl/workbook/workbook.py
Normal file
@ -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
|
||||
|
Reference in New Issue
Block a user