Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/openpyxl/workbook/workbook.py: 33%
249 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1# Copyright (c) 2010-2022 openpyxl
3"""Workbook is the top-level container for all document information."""
4from copy import copy
6from openpyxl.compat import deprecated
7from openpyxl.worksheet.worksheet import Worksheet
8from openpyxl.worksheet._read_only import ReadOnlyWorksheet
9from openpyxl.worksheet._write_only import WriteOnlyWorksheet
10from openpyxl.worksheet.copier import WorksheetCopy
12from openpyxl.utils import quote_sheetname
13from openpyxl.utils.indexed_list import IndexedList
14from openpyxl.utils.datetime import WINDOWS_EPOCH, MAC_EPOCH
15from openpyxl.utils.exceptions import ReadOnlyWorkbookException
17from openpyxl.writer.excel import save_workbook
19from openpyxl.styles.cell_style import StyleArray
20from openpyxl.styles.named_styles import NamedStyle
21from openpyxl.styles.differential import DifferentialStyleList
22from openpyxl.styles.alignment import Alignment
23from openpyxl.styles.borders import DEFAULT_BORDER
24from openpyxl.styles.fills import DEFAULT_EMPTY_FILL, DEFAULT_GRAY_FILL
25from openpyxl.styles.fonts import DEFAULT_FONT
26from openpyxl.styles.protection import Protection
27from openpyxl.styles.colors import COLOR_INDEX
28from openpyxl.styles.named_styles import NamedStyleList
29from openpyxl.styles.table import TableStyleList
31from openpyxl.chartsheet import Chartsheet
32from .defined_name import DefinedName, DefinedNameList
33from openpyxl.packaging.core import DocumentProperties
34from openpyxl.packaging.relationship import RelationshipList
35from .child import _WorkbookChild
36from .protection import DocumentSecurity
37from .properties import CalcProperties
38from .views import BookView
41from openpyxl.xml.constants import (
42 XLSM,
43 XLSX,
44 XLTM,
45 XLTX
46)
48INTEGER_TYPES = (int,)
50class Workbook(object):
51 """Workbook is the container for all other parts of the document."""
53 _read_only = False
54 _data_only = False
55 template = False
56 path = "/xl/workbook.xml"
58 def __init__(self,
59 write_only=False,
60 iso_dates=False,
61 ):
62 self._sheets = []
63 self._pivots = []
64 self._active_sheet_index = 0
65 self.defined_names = DefinedNameList()
66 self._external_links = []
67 self.properties = DocumentProperties()
68 self.security = DocumentSecurity()
69 self.__write_only = write_only
70 self.shared_strings = IndexedList()
72 self._setup_styles()
74 self.loaded_theme = None
75 self.vba_archive = None
76 self.is_template = False
77 self.code_name = None
78 self.epoch = WINDOWS_EPOCH
79 self.encoding = "utf-8"
80 self.iso_dates = iso_dates
82 if not self.write_only:
83 self._sheets.append(Worksheet(self))
85 self.rels = RelationshipList()
86 self.calculation = CalcProperties()
87 self.views = [BookView()]
90 def _setup_styles(self):
91 """Bootstrap styles"""
93 self._fonts = IndexedList()
94 self._fonts.add(DEFAULT_FONT)
96 self._alignments = IndexedList([Alignment()])
98 self._borders = IndexedList()
99 self._borders.add(DEFAULT_BORDER)
101 self._fills = IndexedList()
102 self._fills.add(DEFAULT_EMPTY_FILL)
103 self._fills.add(DEFAULT_GRAY_FILL)
105 self._number_formats = IndexedList()
106 self._date_formats = {}
107 self._timedelta_formats = {}
109 self._protections = IndexedList([Protection()])
111 self._colors = COLOR_INDEX
112 self._cell_styles = IndexedList([StyleArray()])
113 self._named_styles = NamedStyleList()
114 self.add_named_style(NamedStyle(font=copy(DEFAULT_FONT), border=copy(DEFAULT_BORDER), builtinId=0))
115 self._table_styles = TableStyleList()
116 self._differential_styles = DifferentialStyleList()
119 @property
120 def epoch(self):
121 if self._epoch == WINDOWS_EPOCH:
122 return WINDOWS_EPOCH
123 return MAC_EPOCH
126 @epoch.setter
127 def epoch(self, value):
128 if value not in (WINDOWS_EPOCH, MAC_EPOCH):
129 raise ValueError("The epoch must be either 1900 or 1904")
130 self._epoch = value
133 @property
134 def read_only(self):
135 return self._read_only
137 @property
138 def data_only(self):
139 return self._data_only
141 @property
142 def write_only(self):
143 return self.__write_only
146 @property
147 def excel_base_date(self):
148 return self.epoch
150 @property
151 def active(self):
152 """Get the currently active sheet or None
154 :type: :class:`openpyxl.worksheet.worksheet.Worksheet`
155 """
156 try:
157 return self._sheets[self._active_sheet_index]
158 except IndexError:
159 pass
161 @active.setter
162 def active(self, value):
163 """Set the active sheet"""
164 if not isinstance(value, (_WorkbookChild, INTEGER_TYPES)):
165 raise TypeError("Value must be either a worksheet, chartsheet or numerical index")
166 if isinstance(value, INTEGER_TYPES):
167 self._active_sheet_index = value
168 return
169 #if self._sheets and 0 <= value < len(self._sheets):
170 #value = self._sheets[value]
171 #else:
172 #raise ValueError("Sheet index is outside the range of possible values", value)
173 if value not in self._sheets:
174 raise ValueError("Worksheet is not in the workbook")
175 if value.sheet_state != "visible":
176 raise ValueError("Only visible sheets can be made active")
178 idx = self._sheets.index(value)
179 self._active_sheet_index = idx
182 def create_sheet(self, title=None, index=None):
183 """Create a worksheet (at an optional index).
185 :param title: optional title of the sheet
186 :type title: str
187 :param index: optional position at which the sheet will be inserted
188 :type index: int
190 """
191 if self.read_only:
192 raise ReadOnlyWorkbookException('Cannot create new sheet in a read-only workbook')
194 if self.write_only :
195 new_ws = WriteOnlyWorksheet(parent=self, title=title)
196 else:
197 new_ws = Worksheet(parent=self, title=title)
199 self._add_sheet(sheet=new_ws, index=index)
200 return new_ws
203 def _add_sheet(self, sheet, index=None):
204 """Add an worksheet (at an optional index)."""
206 if not isinstance(sheet, (Worksheet, WriteOnlyWorksheet, Chartsheet)):
207 raise TypeError("Cannot be added to a workbook")
209 if sheet.parent != self:
210 raise ValueError("You cannot add worksheets from another workbook.")
212 if index is None:
213 self._sheets.append(sheet)
214 else:
215 self._sheets.insert(index, sheet)
218 def move_sheet(self, sheet, offset=0):
219 """
220 Move a sheet or sheetname
221 """
222 if not isinstance(sheet, Worksheet):
223 sheet = self[sheet]
224 idx = self._sheets.index(sheet)
225 del self._sheets[idx]
226 new_pos = idx + offset
227 self._sheets.insert(new_pos, sheet)
230 def remove(self, worksheet):
231 """Remove `worksheet` from this workbook."""
232 idx = self._sheets.index(worksheet)
233 localnames = self.defined_names.localnames(scope=idx)
234 for name in localnames:
235 self.defined_names.delete(name, scope=idx)
236 self._sheets.remove(worksheet)
239 @deprecated("Use wb.remove(worksheet) or del wb[sheetname]")
240 def remove_sheet(self, worksheet):
241 """Remove `worksheet` from this workbook."""
242 self.remove(worksheet)
245 def create_chartsheet(self, title=None, index=None):
246 if self.read_only:
247 raise ReadOnlyWorkbookException("Cannot create new sheet in a read-only workbook")
248 cs = Chartsheet(parent=self, title=title)
250 self._add_sheet(cs, index)
251 return cs
254 @deprecated("Use wb[sheetname]")
255 def get_sheet_by_name(self, name):
256 """Returns a worksheet by its name.
258 :param name: the name of the worksheet to look for
259 :type name: string
261 """
262 return self[name]
264 def __contains__(self, key):
265 return key in self.sheetnames
268 def index(self, worksheet):
269 """Return the index of a worksheet."""
270 return self.worksheets.index(worksheet)
273 @deprecated("Use wb.index(worksheet)")
274 def get_index(self, worksheet):
275 """Return the index of the worksheet."""
276 return self.index(worksheet)
278 def __getitem__(self, key):
279 """Returns a worksheet by its name.
281 :param name: the name of the worksheet to look for
282 :type name: string
284 """
285 for sheet in self.worksheets + self.chartsheets:
286 if sheet.title == key:
287 return sheet
288 raise KeyError("Worksheet {0} does not exist.".format(key))
290 def __delitem__(self, key):
291 sheet = self[key]
292 self.remove(sheet)
294 def __iter__(self):
295 return iter(self.worksheets)
298 @deprecated("Use wb.sheetnames")
299 def get_sheet_names(self):
300 return self.sheetnames
302 @property
303 def worksheets(self):
304 """A list of sheets in this workbook
306 :type: list of :class:`openpyxl.worksheet.worksheet.Worksheet`
307 """
308 return [s for s in self._sheets if isinstance(s, (Worksheet, ReadOnlyWorksheet, WriteOnlyWorksheet))]
310 @property
311 def chartsheets(self):
312 """A list of Chartsheets in this workbook
314 :type: list of :class:`openpyxl.chartsheet.chartsheet.Chartsheet`
315 """
316 return [s for s in self._sheets if isinstance(s, Chartsheet)]
318 @property
319 def sheetnames(self):
320 """Returns the list of the names of worksheets in this workbook.
322 Names are returned in the worksheets order.
324 :type: list of strings
326 """
327 return [s.title for s in self._sheets]
329 def create_named_range(self, name, worksheet=None, value=None, scope=None):
330 """Create a new named_range on a worksheet"""
331 defn = DefinedName(name=name, localSheetId=scope)
332 if worksheet is not None:
333 defn.value = "{0}!{1}".format(quote_sheetname(worksheet.title), value)
334 else:
335 defn.value = value
337 self.defined_names.append(defn)
340 def add_named_style(self, style):
341 """
342 Add a named style
343 """
344 self._named_styles.append(style)
345 style.bind(self)
348 @property
349 def named_styles(self):
350 """
351 List available named styles
352 """
353 return self._named_styles.names
356 @deprecated("Use workbook.defined_names.definedName")
357 def get_named_ranges(self):
358 """Return all named ranges"""
359 return self.defined_names.definedName
362 @deprecated("Use workbook.defined_names.append")
363 def add_named_range(self, named_range):
364 """Add an existing named_range to the list of named_ranges."""
365 self.defined_names.append(named_range)
368 @deprecated("Use workbook.defined_names[name]")
369 def get_named_range(self, name):
370 """Return the range specified by name."""
371 return self.defined_names[name]
374 @deprecated("Use del workbook.defined_names[name]")
375 def remove_named_range(self, named_range):
376 """Remove a named_range from this workbook."""
377 del self.defined_names[named_range]
380 @property
381 def mime_type(self):
382 """
383 The mime type is determined by whether a workbook is a template or
384 not and whether it contains macros or not. Excel requires the file
385 extension to match but openpyxl does not enforce this.
387 """
388 ct = self.template and XLTX or XLSX
389 if self.vba_archive:
390 ct = self.template and XLTM or XLSM
391 return ct
394 def save(self, filename):
395 """Save the current workbook under the given `filename`.
396 Use this function instead of using an `ExcelWriter`.
398 .. warning::
399 When creating your workbook using `write_only` set to True,
400 you will only be able to call this function once. Subsequents attempts to
401 modify or save the file will raise an :class:`openpyxl.shared.exc.WorkbookAlreadySaved` exception.
402 """
403 if self.read_only:
404 raise TypeError("""Workbook is read-only""")
405 if self.write_only and not self.worksheets:
406 self.create_sheet()
407 save_workbook(self, filename)
410 @property
411 def style_names(self):
412 """
413 List of named styles
414 """
415 return [s.name for s in self._named_styles]
418 def copy_worksheet(self, from_worksheet):
419 """Copy an existing worksheet in the current workbook
421 .. warning::
422 This function cannot copy worksheets between workbooks.
423 worksheets can only be copied within the workbook that they belong
425 :param from_worksheet: the worksheet to be copied from
426 :return: copy of the initial worksheet
427 """
428 if self.__write_only or self._read_only:
429 raise ValueError("Cannot copy worksheets in read-only or write-only mode")
431 new_title = u"{0} Copy".format(from_worksheet.title)
432 to_worksheet = self.create_sheet(title=new_title)
433 cp = WorksheetCopy(source_worksheet=from_worksheet, target_worksheet=to_worksheet)
434 cp.copy_worksheet()
435 return to_worksheet
438 def close(self):
439 """
440 Close workbook file if open. Only affects read-only and write-only modes.
441 """
442 if hasattr(self, '_archive'):
443 self._archive.close()
446 def _duplicate_name(self, name):
447 """
448 Check for duplicate name in defined name list and table list of each worksheet.
449 Names are not case sensitive.
450 """
451 name = name.lower()
452 for sheet in self.worksheets:
453 for t in sheet.tables:
454 if name == t.lower():
455 return True
457 if name in self.defined_names:
458 return True