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

171 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"""Manage individual cells in a spreadsheet. 

4 

5The Cell class is required to know its value and type, display options, 

6and any other features of an Excel cell. Utilities for referencing 

7cells using Excel's 'A1' column/row nomenclature are also provided. 

8 

9""" 

10 

11__docformat__ = "restructuredtext en" 

12 

13# Python stdlib imports 

14from copy import copy 

15import datetime 

16import re 

17 

18 

19from openpyxl.compat import ( 

20 NUMERIC_TYPES, 

21 deprecated, 

22) 

23 

24from openpyxl.utils.exceptions import IllegalCharacterError 

25 

26from openpyxl.utils import get_column_letter 

27from openpyxl.styles import numbers, is_date_format 

28from openpyxl.styles.styleable import StyleableObject 

29from openpyxl.worksheet.hyperlink import Hyperlink 

30 

31# constants 

32 

33TIME_TYPES = (datetime.datetime, datetime.date, datetime.time, datetime.timedelta) 

34TIME_FORMATS = { 

35 datetime.datetime:numbers.FORMAT_DATE_DATETIME, 

36 datetime.date:numbers.FORMAT_DATE_YYYYMMDD2, 

37 datetime.time:numbers.FORMAT_DATE_TIME6, 

38 datetime.timedelta:numbers.FORMAT_DATE_TIMEDELTA, 

39 } 

40 

41STRING_TYPES = (str, bytes) 

42KNOWN_TYPES = NUMERIC_TYPES + TIME_TYPES + STRING_TYPES + (bool, type(None)) 

43 

44ILLEGAL_CHARACTERS_RE = re.compile(r'[\000-\010]|[\013-\014]|[\016-\037]') 

45ERROR_CODES = ('#NULL!', '#DIV/0!', '#VALUE!', '#REF!', '#NAME?', '#NUM!', 

46 '#N/A') 

47 

48TYPE_STRING = 's' 

49TYPE_FORMULA = 'f' 

50TYPE_NUMERIC = 'n' 

51TYPE_BOOL = 'b' 

52TYPE_NULL = 'n' 

53TYPE_INLINE = 'inlineStr' 

54TYPE_ERROR = 'e' 

55TYPE_FORMULA_CACHE_STRING = 'str' 

56 

57VALID_TYPES = (TYPE_STRING, TYPE_FORMULA, TYPE_NUMERIC, TYPE_BOOL, 

58 TYPE_NULL, TYPE_INLINE, TYPE_ERROR, TYPE_FORMULA_CACHE_STRING) 

59 

60 

61_TYPES = {int:'n', float:'n', str:'s', bool:'b'} 

62 

63 

64def get_type(t, value): 

65 if isinstance(value, NUMERIC_TYPES): 

66 dt = 'n' 

67 elif isinstance(value, STRING_TYPES): 

68 dt = 's' 

69 elif isinstance(value, TIME_TYPES): 

70 dt = 'd' 

71 else: 

72 return 

73 _TYPES[t] = dt 

74 return dt 

75 

76 

77def get_time_format(t): 

78 value = TIME_FORMATS.get(t) 

79 if value: 

80 return value 

81 for base in t.mro()[1:]: 

82 value = TIME_FORMATS.get(base) 

83 if value: 

84 TIME_FORMATS[t] = value 

85 return value 

86 raise ValueError("Could not get time format for {0!r}".format(value)) 

87 

88 

89class Cell(StyleableObject): 

90 """Describes cell associated properties. 

91 

92 Properties of interest include style, type, value, and address. 

93 

94 """ 

95 __slots__ = ( 

96 'row', 

97 'column', 

98 '_value', 

99 'data_type', 

100 'parent', 

101 '_hyperlink', 

102 '_comment', 

103 ) 

104 

105 def __init__(self, worksheet, row=None, column=None, value=None, style_array=None): 

106 super(Cell, self).__init__(worksheet, style_array) 

107 self.row = row 

108 """Row number of this cell (1-based)""" 

109 self.column = column 

110 """Column number of this cell (1-based)""" 

111 # _value is the stored value, while value is the displayed value 

112 self._value = None 

113 self._hyperlink = None 

114 self.data_type = 'n' 

115 if value is not None: 

116 self.value = value 

117 self._comment = None 

118 

119 

120 @property 

121 def coordinate(self): 

122 """This cell's coordinate (ex. 'A5')""" 

123 col = get_column_letter(self.column) 

124 return f"{col}{self.row}" 

125 

126 

127 @property 

128 def col_idx(self): 

129 """The numerical index of the column""" 

130 return self.column 

131 

132 

133 @property 

134 def column_letter(self): 

135 return get_column_letter(self.column) 

136 

137 

138 @property 

139 def encoding(self): 

140 return self.parent.encoding 

141 

142 @property 

143 def base_date(self): 

144 return self.parent.parent.epoch 

145 

146 

147 def __repr__(self): 

148 return "<Cell {0!r}.{1}>".format(self.parent.title, self.coordinate) 

149 

150 def check_string(self, value): 

151 """Check string coding, length, and line break character""" 

152 if value is None: 

153 return 

154 # convert to str string 

155 if not isinstance(value, str): 

156 value = str(value, self.encoding) 

157 value = str(value) 

158 # string must never be longer than 32,767 characters 

159 # truncate if necessary 

160 value = value[:32767] 

161 if next(ILLEGAL_CHARACTERS_RE.finditer(value), None): 

162 raise IllegalCharacterError 

163 return value 

164 

165 def check_error(self, value): 

166 """Tries to convert Error" else N/A""" 

167 try: 

168 return str(value) 

169 except UnicodeDecodeError: 

170 return u'#N/A' 

171 

172 

173 def _bind_value(self, value): 

174 """Given a value, infer the correct data type""" 

175 

176 self.data_type = "n" 

177 t = type(value) 

178 try: 

179 dt = _TYPES[t] 

180 except KeyError: 

181 dt = get_type(t, value) 

182 

183 if dt is None and value is not None: 

184 raise ValueError("Cannot convert {0!r} to Excel".format(value)) 

185 

186 if dt: 

187 self.data_type = dt 

188 

189 if dt == 'd': 

190 if not is_date_format(self.number_format): 

191 self.number_format = get_time_format(t) 

192 

193 elif dt == "s": 

194 value = self.check_string(value) 

195 if len(value) > 1 and value.startswith("="): 

196 self.data_type = 'f' 

197 elif value in ERROR_CODES: 

198 self.data_type = 'e' 

199 

200 self._value = value 

201 

202 

203 @property 

204 def value(self): 

205 """Get or set the value held in the cell. 

206 

207 :type: depends on the value (string, float, int or 

208 :class:`datetime.datetime`) 

209 """ 

210 return self._value 

211 

212 @value.setter 

213 def value(self, value): 

214 """Set the value and infer type and display options.""" 

215 self._bind_value(value) 

216 

217 @property 

218 def internal_value(self): 

219 """Always returns the value for excel.""" 

220 return self._value 

221 

222 @property 

223 def hyperlink(self): 

224 """Return the hyperlink target or an empty string""" 

225 return self._hyperlink 

226 

227 

228 @hyperlink.setter 

229 def hyperlink(self, val): 

230 """Set value and display for hyperlinks in a cell. 

231 Automatically sets the `value` of the cell with link text, 

232 but you can modify it afterwards by setting the `value` 

233 property, and the hyperlink will remain. 

234 Hyperlink is removed if set to ``None``.""" 

235 if val is None: 

236 self._hyperlink = None 

237 else: 

238 if not isinstance(val, Hyperlink): 

239 val = Hyperlink(ref="", target=val) 

240 val.ref = self.coordinate 

241 self._hyperlink = val 

242 if self._value is None: 

243 self.value = val.target or val.location 

244 

245 

246 @property 

247 def is_date(self): 

248 """True if the value is formatted as a date 

249 

250 :type: bool 

251 """ 

252 return self.data_type == 'd' or ( 

253 self.data_type == 'n' and is_date_format(self.number_format) 

254 ) 

255 

256 

257 def offset(self, row=0, column=0): 

258 """Returns a cell location relative to this cell. 

259 

260 :param row: number of rows to offset 

261 :type row: int 

262 

263 :param column: number of columns to offset 

264 :type column: int 

265 

266 :rtype: :class:`openpyxl.cell.Cell` 

267 """ 

268 offset_column = self.col_idx + column 

269 offset_row = self.row + row 

270 return self.parent.cell(column=offset_column, row=offset_row) 

271 

272 

273 @property 

274 def comment(self): 

275 """ Returns the comment associated with this cell 

276 

277 :type: :class:`openpyxl.comments.Comment` 

278 """ 

279 return self._comment 

280 

281 

282 @comment.setter 

283 def comment(self, value): 

284 """ 

285 Assign a comment to a cell 

286 """ 

287 

288 if value is not None: 

289 if value.parent: 

290 value = copy(value) 

291 value.bind(self) 

292 elif value is None and self._comment: 

293 self._comment.unbind() 

294 self._comment = value 

295 

296 

297class MergedCell(StyleableObject): 

298 

299 """ 

300 Describes the properties of a cell in a merged cell and helps to 

301 display the borders of the merged cell. 

302 

303 The value of a MergedCell is always None. 

304 """ 

305 

306 __slots__ = ('row', 'column') 

307 

308 _value = None 

309 data_type = "n" 

310 comment = None 

311 hyperlink = None 

312 

313 

314 def __init__(self, worksheet, row=None, column=None): 

315 super(MergedCell, self).__init__(worksheet) 

316 self.row = row 

317 self.column = column 

318 

319 

320 def __repr__(self): 

321 return "<MergedCell {0!r}.{1}>".format(self.parent.title, self.coordinate) 

322 

323 coordinate = Cell.coordinate 

324 _comment = comment 

325 value = _value 

326 

327 

328def WriteOnlyCell(ws=None, value=None): 

329 return Cell(worksheet=ws, column=1, row=1, value=value)