diff options
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/worksheet/_read_only.py')
-rw-r--r-- | .venv/lib/python3.12/site-packages/openpyxl/worksheet/_read_only.py | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/worksheet/_read_only.py b/.venv/lib/python3.12/site-packages/openpyxl/worksheet/_read_only.py new file mode 100644 index 00000000..95852f21 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/openpyxl/worksheet/_read_only.py @@ -0,0 +1,190 @@ +# Copyright (c) 2010-2024 openpyxl + +""" Read worksheets on-demand +""" + +from .worksheet import Worksheet +from openpyxl.cell.read_only import ReadOnlyCell, EMPTY_CELL +from openpyxl.utils import get_column_letter + +from ._reader import WorkSheetParser +from openpyxl.workbook.defined_name import DefinedNameDict + + +def read_dimension(source): + parser = WorkSheetParser(source, []) + return parser.parse_dimensions() + + +class ReadOnlyWorksheet: + + _min_column = 1 + _min_row = 1 + _max_column = _max_row = None + + # from Standard Worksheet + # Methods from Worksheet + cell = Worksheet.cell + iter_rows = Worksheet.iter_rows + values = Worksheet.values + rows = Worksheet.rows + __getitem__ = Worksheet.__getitem__ + __iter__ = Worksheet.__iter__ + + + def __init__(self, parent_workbook, title, worksheet_path, shared_strings): + self.parent = parent_workbook + self.title = title + self.sheet_state = 'visible' + self._current_row = None + self._worksheet_path = worksheet_path + self._shared_strings = shared_strings + self._get_size() + self.defined_names = DefinedNameDict() + + + def _get_size(self): + src = self._get_source() + parser = WorkSheetParser(src, []) + dimensions = parser.parse_dimensions() + src.close() + if dimensions is not None: + self._min_column, self._min_row, self._max_column, self._max_row = dimensions + + + def _get_source(self): + """Parse xml source on demand, must close after use""" + return self.parent._archive.open(self._worksheet_path) + + + def _cells_by_row(self, min_col, min_row, max_col, max_row, values_only=False): + """ + The source worksheet file may have columns or rows missing. + Missing cells will be created. + """ + filler = EMPTY_CELL + if values_only: + filler = None + + max_col = max_col or self.max_column + max_row = max_row or self.max_row + empty_row = [] + if max_col is not None: + empty_row = (filler,) * (max_col + 1 - min_col) + + counter = min_row + idx = 1 + with self._get_source() as src: + parser = WorkSheetParser(src, + self._shared_strings, + data_only=self.parent.data_only, + epoch=self.parent.epoch, + date_formats=self.parent._date_formats, + timedelta_formats=self.parent._timedelta_formats) + + for idx, row in parser.parse(): + if max_row is not None and idx > max_row: + break + + # some rows are missing + for _ in range(counter, idx): + counter += 1 + yield empty_row + + # return cells from a row + if counter <= idx: + row = self._get_row(row, min_col, max_col, values_only) + counter += 1 + yield row + + if max_row is not None and max_row < idx: + for _ in range(counter, max_row+1): + yield empty_row + + + def _get_row(self, row, min_col=1, max_col=None, values_only=False): + """ + Make sure a row contains always the same number of cells or values + """ + if not row and not max_col: # in case someone wants to force rows where there aren't any + return () + + max_col = max_col or row[-1]['column'] + row_width = max_col + 1 - min_col + + new_row = [EMPTY_CELL] * row_width + if values_only: + new_row = [None] * row_width + + for cell in row: + counter = cell['column'] + if min_col <= counter <= max_col: + idx = counter - min_col # position in list of cells returned + new_row[idx] = cell['value'] + if not values_only: + new_row[idx] = ReadOnlyCell(self, **cell) + + return tuple(new_row) + + + def _get_cell(self, row, column): + """Cells are returned by a generator which can be empty""" + for row in self._cells_by_row(column, row, column, row): + if row: + return row[0] + return EMPTY_CELL + + + def calculate_dimension(self, force=False): + if not all([self.max_column, self.max_row]): + if force: + self._calculate_dimension() + else: + raise ValueError("Worksheet is unsized, use calculate_dimension(force=True)") + return f"{get_column_letter(self.min_column)}{self.min_row}:{get_column_letter(self.max_column)}{self.max_row}" + + + def _calculate_dimension(self): + """ + Loop through all the cells to get the size of a worksheet. + Do this only if it is explicitly requested. + """ + + max_col = 0 + for r in self.rows: + if not r: + continue + cell = r[-1] + max_col = max(max_col, cell.column) + + self._max_row = cell.row + self._max_column = max_col + + + def reset_dimensions(self): + """ + Remove worksheet dimensions if these are incorrect in the worksheet source. + NB. This probably indicates a bug in the library or application that created + the workbook. + """ + self._max_row = self._max_column = None + + + @property + def min_row(self): + return self._min_row + + + @property + def max_row(self): + return self._max_row + + + @property + def min_column(self): + return self._min_column + + + @property + def max_column(self): + return self._max_column |