Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/openpyxl/worksheet/_read_only.py: 30%
114 statements
« prev ^ index » next coverage.py v7.3.3, created at 2023-12-20 06:34 +0000
« prev ^ index » next coverage.py v7.3.3, created at 2023-12-20 06:34 +0000
1# Copyright (c) 2010-2023 openpyxl
3""" Read worksheets on-demand
4"""
6from .worksheet import Worksheet
7from openpyxl.cell.read_only import ReadOnlyCell, EMPTY_CELL
8from openpyxl.utils import get_column_letter
10from ._reader import WorkSheetParser
11from openpyxl.workbook.defined_name import DefinedNameDict
14def read_dimension(source):
15 parser = WorkSheetParser(source, [])
16 return parser.parse_dimensions()
19class ReadOnlyWorksheet(object):
21 _min_column = 1
22 _min_row = 1
23 _max_column = _max_row = None
25 # from Standard Worksheet
26 # Methods from Worksheet
27 cell = Worksheet.cell
28 iter_rows = Worksheet.iter_rows
29 values = Worksheet.values
30 rows = Worksheet.rows
31 __getitem__ = Worksheet.__getitem__
32 __iter__ = Worksheet.__iter__
35 def __init__(self, parent_workbook, title, worksheet_path, shared_strings):
36 self.parent = parent_workbook
37 self.title = title
38 self.sheet_state = 'visible'
39 self._current_row = None
40 self._worksheet_path = worksheet_path
41 self._shared_strings = shared_strings
42 self._get_size()
43 self.defined_names = DefinedNameDict()
46 def _get_size(self):
47 src = self._get_source()
48 parser = WorkSheetParser(src, [])
49 dimensions = parser.parse_dimensions()
50 src.close()
51 if dimensions is not None:
52 self._min_column, self._min_row, self._max_column, self._max_row = dimensions
55 def _get_source(self):
56 """Parse xml source on demand, must close after use"""
57 return self.parent._archive.open(self._worksheet_path)
60 def _cells_by_row(self, min_col, min_row, max_col, max_row, values_only=False):
61 """
62 The source worksheet file may have columns or rows missing.
63 Missing cells will be created.
64 """
65 filler = EMPTY_CELL
66 if values_only:
67 filler = None
69 max_col = max_col or self.max_column
70 max_row = max_row or self.max_row
71 empty_row = []
72 if max_col is not None:
73 empty_row = (filler,) * (max_col + 1 - min_col)
75 counter = min_row
76 idx = 1
77 src = self._get_source()
78 parser = WorkSheetParser(src, self._shared_strings,
79 data_only=self.parent.data_only, epoch=self.parent.epoch,
80 date_formats=self.parent._date_formats)
81 for idx, row in parser.parse():
82 if max_row is not None and idx > max_row:
83 break
85 # some rows are missing
86 for _ in range(counter, idx):
87 counter += 1
88 yield empty_row
90 # return cells from a row
91 if counter <= idx:
92 row = self._get_row(row, min_col, max_col, values_only)
93 counter += 1
94 yield row
96 src.close() # make sure source is always closed
98 if max_row is not None and max_row < idx:
99 for _ in range(counter, max_row+1):
100 yield empty_row
103 def _get_row(self, row, min_col=1, max_col=None, values_only=False):
104 """
105 Make sure a row contains always the same number of cells or values
106 """
107 if not row and not max_col: # in case someone wants to force rows where there aren't any
108 return ()
110 max_col = max_col or row[-1]['column']
111 row_width = max_col + 1 - min_col
113 new_row = [EMPTY_CELL] * row_width
114 if values_only:
115 new_row = [None] * row_width
117 for cell in row:
118 counter = cell['column']
119 if min_col <= counter <= max_col:
120 idx = counter - min_col # position in list of cells returned
121 new_row[idx] = cell['value']
122 if not values_only:
123 new_row[idx] = ReadOnlyCell(self, **cell)
125 return tuple(new_row)
128 def _get_cell(self, row, column):
129 """Cells are returned by a generator which can be empty"""
130 for row in self._cells_by_row(column, row, column, row):
131 if row:
132 return row[0]
133 return EMPTY_CELL
136 def calculate_dimension(self, force=False):
137 if not all([self.max_column, self.max_row]):
138 if force:
139 self._calculate_dimension()
140 else:
141 raise ValueError("Worksheet is unsized, use calculate_dimension(force=True)")
142 return f"{get_column_letter(self.min_column)}{self.min_row}:{get_column_letter(self.max_column)}{self.max_row}"
145 def _calculate_dimension(self):
146 """
147 Loop through all the cells to get the size of a worksheet.
148 Do this only if it is explicitly requested.
149 """
151 max_col = 0
152 for r in self.rows:
153 if not r:
154 continue
155 cell = r[-1]
156 max_col = max(max_col, cell.column)
158 self._max_row = cell.row
159 self._max_column = max_col
162 def reset_dimensions(self):
163 """
164 Remove worksheet dimensions if these are incorrect in the worksheet source.
165 NB. This probably indicates a bug in the library or application that created
166 the workbook.
167 """
168 self._max_row = self._max_column = None
171 @property
172 def min_row(self):
173 return self._min_row
176 @property
177 def max_row(self):
178 return self._max_row
181 @property
182 def min_column(self):
183 return self._min_column
186 @property
187 def max_column(self):
188 return self._max_column