Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/openpyxl/worksheet/_read_only.py: 23%

112 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1# Copyright (c) 2010-2022 openpyxl 

2 

3""" Read worksheets on-demand 

4""" 

5 

6from .worksheet import Worksheet 

7from openpyxl.cell.read_only import ReadOnlyCell, EMPTY_CELL 

8from openpyxl.utils import get_column_letter 

9 

10from ._reader import WorkSheetParser 

11 

12 

13def read_dimension(source): 

14 parser = WorkSheetParser(source, []) 

15 return parser.parse_dimensions() 

16 

17 

18class ReadOnlyWorksheet(object): 

19 

20 _min_column = 1 

21 _min_row = 1 

22 _max_column = _max_row = None 

23 

24 # from Standard Worksheet 

25 # Methods from Worksheet 

26 cell = Worksheet.cell 

27 iter_rows = Worksheet.iter_rows 

28 values = Worksheet.values 

29 rows = Worksheet.rows 

30 __getitem__ = Worksheet.__getitem__ 

31 __iter__ = Worksheet.__iter__ 

32 

33 

34 def __init__(self, parent_workbook, title, worksheet_path, shared_strings): 

35 self.parent = parent_workbook 

36 self.title = title 

37 self.sheet_state = 'visible' 

38 self._current_row = None 

39 self._worksheet_path = worksheet_path 

40 self._shared_strings = shared_strings 

41 self._get_size() 

42 

43 

44 def _get_size(self): 

45 src = self._get_source() 

46 parser = WorkSheetParser(src, []) 

47 dimensions = parser.parse_dimensions() 

48 src.close() 

49 if dimensions is not None: 

50 self._min_column, self._min_row, self._max_column, self._max_row = dimensions 

51 

52 

53 def _get_source(self): 

54 """Parse xml source on demand, must close after use""" 

55 return self.parent._archive.open(self._worksheet_path) 

56 

57 

58 def _cells_by_row(self, min_col, min_row, max_col, max_row, values_only=False): 

59 """ 

60 The source worksheet file may have columns or rows missing. 

61 Missing cells will be created. 

62 """ 

63 filler = EMPTY_CELL 

64 if values_only: 

65 filler = None 

66 

67 max_col = max_col or self.max_column 

68 max_row = max_row or self.max_row 

69 empty_row = [] 

70 if max_col is not None: 

71 empty_row = (filler,) * (max_col + 1 - min_col) 

72 

73 counter = min_row 

74 idx = 1 

75 src = self._get_source() 

76 parser = WorkSheetParser(src, self._shared_strings, 

77 data_only=self.parent.data_only, epoch=self.parent.epoch, 

78 date_formats=self.parent._date_formats) 

79 for idx, row in parser.parse(): 

80 if max_row is not None and idx > max_row: 

81 break 

82 

83 # some rows are missing 

84 for _ in range(counter, idx): 

85 counter += 1 

86 yield empty_row 

87 

88 # return cells from a row 

89 if counter <= idx: 

90 row = self._get_row(row, min_col, max_col, values_only) 

91 counter += 1 

92 yield row 

93 

94 src.close() # make sure source is always closed 

95 

96 if max_row is not None and max_row < idx: 

97 for _ in range(counter, max_row+1): 

98 yield empty_row 

99 

100 

101 def _get_row(self, row, min_col=1, max_col=None, values_only=False): 

102 """ 

103 Make sure a row contains always the same number of cells or values 

104 """ 

105 if not row and not max_col: # in case someone wants to force rows where there aren't any 

106 return () 

107 

108 max_col = max_col or row[-1]['column'] 

109 row_width = max_col + 1 - min_col 

110 

111 new_row = [EMPTY_CELL] * row_width 

112 if values_only: 

113 new_row = [None] * row_width 

114 

115 for cell in row: 

116 counter = cell['column'] 

117 if min_col <= counter <= max_col: 

118 idx = counter - min_col # position in list of cells returned 

119 new_row[idx] = cell['value'] 

120 if not values_only: 

121 new_row[idx] = ReadOnlyCell(self, **cell) 

122 

123 return tuple(new_row) 

124 

125 

126 def _get_cell(self, row, column): 

127 """Cells are returned by a generator which can be empty""" 

128 for row in self._cells_by_row(column, row, column, row): 

129 if row: 

130 return row[0] 

131 return EMPTY_CELL 

132 

133 

134 def calculate_dimension(self, force=False): 

135 if not all([self.max_column, self.max_row]): 

136 if force: 

137 self._calculate_dimension() 

138 else: 

139 raise ValueError("Worksheet is unsized, use calculate_dimension(force=True)") 

140 return f"{get_column_letter(self.min_column)}{self.min_row}:{get_column_letter(self.max_column)}{self.max_row}" 

141 

142 

143 def _calculate_dimension(self): 

144 """ 

145 Loop through all the cells to get the size of a worksheet. 

146 Do this only if it is explicitly requested. 

147 """ 

148 

149 max_col = 0 

150 for r in self.rows: 

151 if not r: 

152 continue 

153 cell = r[-1] 

154 max_col = max(max_col, cell.column) 

155 

156 self._max_row = cell.row 

157 self._max_column = max_col 

158 

159 

160 def reset_dimensions(self): 

161 """ 

162 Remove worksheet dimensions if these are incorrect in the worksheet source. 

163 NB. This probably indicates a bug in the library or application that created 

164 the workbook. 

165 """ 

166 self._max_row = self._max_column = None 

167 

168 

169 @property 

170 def min_row(self): 

171 return self._min_row 

172 

173 

174 @property 

175 def max_row(self): 

176 return self._max_row 

177 

178 

179 @property 

180 def min_column(self): 

181 return self._min_column 

182 

183 

184 @property 

185 def max_column(self): 

186 return self._max_column