Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/xlsxwriter/styles.py: 56%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

382 statements  

1############################################################################### 

2# 

3# Styles - A class for writing the Excel XLSX Worksheet file. 

4# 

5# SPDX-License-Identifier: BSD-2-Clause 

6# 

7# Copyright (c) 2013-2025, John McNamara, jmcnamara@cpan.org 

8# 

9 

10from enum import Enum 

11 

12# Package imports. 

13from xlsxwriter import xmlwriter 

14 

15 

16class XFormatType(Enum): 

17 """ 

18 Enum to distinguish the type of cell xf format since style and the default 

19 (the first format) are handled slightly differently. 

20 

21 """ 

22 

23 USER = 1 

24 STYLE = 2 

25 DEFAULT = 3 

26 

27 

28class Styles(xmlwriter.XMLwriter): 

29 """ 

30 A class for writing the Excel XLSX Styles file. 

31 

32 

33 """ 

34 

35 ########################################################################### 

36 # 

37 # Public API. 

38 # 

39 ########################################################################### 

40 

41 def __init__(self) -> None: 

42 """ 

43 Constructor. 

44 

45 """ 

46 

47 super().__init__() 

48 

49 self.xf_formats = [] 

50 self.palette = [] 

51 self.font_count = 0 

52 self.num_formats = [] 

53 self.border_count = 0 

54 self.fill_count = 0 

55 self.custom_colors = [] 

56 self.dxf_formats = [] 

57 self.has_hyperlink = False 

58 self.hyperlink_font_id = 0 

59 self.has_comments = False 

60 

61 ########################################################################### 

62 # 

63 # Private API. 

64 # 

65 ########################################################################### 

66 

67 def _assemble_xml_file(self) -> None: 

68 # Assemble and write the XML file. 

69 

70 # Write the XML declaration. 

71 self._xml_declaration() 

72 

73 # Add the style sheet. 

74 self._write_style_sheet() 

75 

76 # Write the number formats. 

77 self._write_num_fmts() 

78 

79 # Write the fonts. 

80 self._write_fonts() 

81 

82 # Write the fills. 

83 self._write_fills() 

84 

85 # Write the borders element. 

86 self._write_borders() 

87 

88 # Write the cellStyleXfs element. 

89 self._write_cell_style_xfs() 

90 

91 # Write the cellXfs element. 

92 self._write_cell_xfs() 

93 

94 # Write the cellStyles element. 

95 self._write_cell_styles() 

96 

97 # Write the dxfs element. 

98 self._write_dxfs() 

99 

100 # Write the tableStyles element. 

101 self._write_table_styles() 

102 

103 # Write the colors element. 

104 self._write_colors() 

105 

106 # Close the style sheet tag. 

107 self._xml_end_tag("styleSheet") 

108 

109 # Close the file. 

110 self._xml_close() 

111 

112 def _set_style_properties(self, properties) -> None: 

113 # Pass in the Format objects and other properties used in the styles. 

114 

115 self.xf_formats = properties[0] 

116 self.palette = properties[1] 

117 self.font_count = properties[2] 

118 self.num_formats = properties[3] 

119 self.border_count = properties[4] 

120 self.fill_count = properties[5] 

121 self.custom_colors = properties[6] 

122 self.dxf_formats = properties[7] 

123 self.has_comments = properties[8] 

124 

125 ########################################################################### 

126 # 

127 # XML methods. 

128 # 

129 ########################################################################### 

130 

131 def _write_style_sheet(self) -> None: 

132 # Write the <styleSheet> element. 

133 xmlns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" 

134 

135 attributes = [("xmlns", xmlns)] 

136 self._xml_start_tag("styleSheet", attributes) 

137 

138 def _write_num_fmts(self) -> None: 

139 # Write the <numFmts> element. 

140 if not self.num_formats: 

141 return 

142 

143 attributes = [("count", len(self.num_formats))] 

144 self._xml_start_tag("numFmts", attributes) 

145 

146 # Write the numFmts elements. 

147 for index, num_format in enumerate(self.num_formats, 164): 

148 self._write_num_fmt(index, num_format) 

149 

150 self._xml_end_tag("numFmts") 

151 

152 def _write_num_fmt(self, num_fmt_id, format_code) -> None: 

153 # Write the <numFmt> element. 

154 format_codes = { 

155 0: "General", 

156 1: "0", 

157 2: "0.00", 

158 3: "#,##0", 

159 4: "#,##0.00", 

160 5: "($#,##0_);($#,##0)", 

161 6: "($#,##0_);[Red]($#,##0)", 

162 7: "($#,##0.00_);($#,##0.00)", 

163 8: "($#,##0.00_);[Red]($#,##0.00)", 

164 9: "0%", 

165 10: "0.00%", 

166 11: "0.00E+00", 

167 12: "# ?/?", 

168 13: "# ??/??", 

169 14: "m/d/yy", 

170 15: "d-mmm-yy", 

171 16: "d-mmm", 

172 17: "mmm-yy", 

173 18: "h:mm AM/PM", 

174 19: "h:mm:ss AM/PM", 

175 20: "h:mm", 

176 21: "h:mm:ss", 

177 22: "m/d/yy h:mm", 

178 37: "(#,##0_);(#,##0)", 

179 38: "(#,##0_);[Red](#,##0)", 

180 39: "(#,##0.00_);(#,##0.00)", 

181 40: "(#,##0.00_);[Red](#,##0.00)", 

182 41: '_(* #,##0_);_(* (#,##0);_(* "-"_);_(_)', 

183 42: '_($* #,##0_);_($* (#,##0);_($* "-"_);_(_)', 

184 43: '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(_)', 

185 44: '_($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(_)', 

186 45: "mm:ss", 

187 46: "[h]:mm:ss", 

188 47: "mm:ss.0", 

189 48: "##0.0E+0", 

190 49: "@", 

191 } 

192 

193 # Set the format code for built-in number formats. 

194 if num_fmt_id < 164: 

195 format_code = format_codes.get(num_fmt_id, "General") 

196 

197 attributes = [ 

198 ("numFmtId", num_fmt_id), 

199 ("formatCode", format_code), 

200 ] 

201 

202 self._xml_empty_tag("numFmt", attributes) 

203 

204 def _write_fonts(self) -> None: 

205 # Write the <fonts> element. 

206 if self.has_comments: 

207 # Add extra font for comments. 

208 attributes = [("count", self.font_count + 1)] 

209 else: 

210 attributes = [("count", self.font_count)] 

211 

212 self._xml_start_tag("fonts", attributes) 

213 

214 # Write the font elements for xf_format objects that have them. 

215 for xf_format in self.xf_formats: 

216 if xf_format.has_font: 

217 self._write_font(xf_format) 

218 

219 if self.has_comments: 

220 self._write_comment_font() 

221 

222 self._xml_end_tag("fonts") 

223 

224 def _write_font(self, xf_format, is_dxf_format=False) -> None: 

225 # Write the <font> element. 

226 self._xml_start_tag("font") 

227 

228 # The condense and extend elements are mainly used in dxf formats. 

229 if xf_format.font_condense: 

230 self._write_condense() 

231 

232 if xf_format.font_extend: 

233 self._write_extend() 

234 

235 if xf_format.bold: 

236 self._xml_empty_tag("b") 

237 

238 if xf_format.italic: 

239 self._xml_empty_tag("i") 

240 

241 if xf_format.font_strikeout: 

242 self._xml_empty_tag("strike") 

243 

244 if xf_format.font_outline: 

245 self._xml_empty_tag("outline") 

246 

247 if xf_format.font_shadow: 

248 self._xml_empty_tag("shadow") 

249 

250 # Handle the underline variants. 

251 if xf_format.underline: 

252 self._write_underline(xf_format.underline) 

253 

254 if xf_format.font_script == 1: 

255 self._write_vert_align("superscript") 

256 

257 if xf_format.font_script == 2: 

258 self._write_vert_align("subscript") 

259 

260 if not is_dxf_format: 

261 self._xml_empty_tag("sz", [("val", xf_format.font_size)]) 

262 

263 if xf_format.theme == -1: 

264 # Ignore for excel2003_style. 

265 pass 

266 elif xf_format.theme: 

267 self._write_color([("theme", xf_format.theme)]) 

268 elif xf_format.color_indexed: 

269 self._write_color([("indexed", xf_format.color_indexed)]) 

270 elif xf_format.font_color: 

271 color = xf_format.font_color 

272 if not color._is_automatic: 

273 self._write_color(color._attributes()) 

274 elif not is_dxf_format: 

275 self._write_color([("theme", 1)]) 

276 

277 if not is_dxf_format: 

278 self._xml_empty_tag("name", [("val", xf_format.font_name)]) 

279 

280 if xf_format.font_family: 

281 self._xml_empty_tag("family", [("val", xf_format.font_family)]) 

282 

283 if xf_format.font_charset: 

284 self._xml_empty_tag("charset", [("val", xf_format.font_charset)]) 

285 

286 if xf_format.font_scheme in ("major", "minor"): 

287 self._xml_empty_tag("scheme", [("val", xf_format.font_scheme)]) 

288 

289 if xf_format.hyperlink: 

290 self.has_hyperlink = True 

291 if self.hyperlink_font_id == 0: 

292 self.hyperlink_font_id = xf_format.font_index 

293 

294 self._xml_end_tag("font") 

295 

296 def _write_comment_font(self) -> None: 

297 # Write the <font> element for comments. 

298 self._xml_start_tag("font") 

299 

300 self._xml_empty_tag("sz", [("val", 8)]) 

301 self._write_color([("indexed", 81)]) 

302 self._xml_empty_tag("name", [("val", "Tahoma")]) 

303 self._xml_empty_tag("family", [("val", 2)]) 

304 

305 self._xml_end_tag("font") 

306 

307 def _write_underline(self, underline) -> None: 

308 # Write the underline font element. 

309 

310 if underline == 2: 

311 attributes = [("val", "double")] 

312 elif underline == 33: 

313 attributes = [("val", "singleAccounting")] 

314 elif underline == 34: 

315 attributes = [("val", "doubleAccounting")] 

316 else: 

317 # Default to single underline. 

318 attributes = [] 

319 

320 self._xml_empty_tag("u", attributes) 

321 

322 def _write_vert_align(self, val) -> None: 

323 # Write the <vertAlign> font sub-element. 

324 attributes = [("val", val)] 

325 

326 self._xml_empty_tag("vertAlign", attributes) 

327 

328 def _write_color(self, attributes) -> None: 

329 # Write the <color> element. 

330 self._xml_empty_tag("color", attributes) 

331 

332 def _write_fills(self) -> None: 

333 # Write the <fills> element. 

334 attributes = [("count", self.fill_count)] 

335 

336 self._xml_start_tag("fills", attributes) 

337 

338 # Write the default fill element. 

339 self._write_default_fill("none") 

340 self._write_default_fill("gray125") 

341 

342 # Write the fill elements for xf_format objects that have them. 

343 for xf_format in self.xf_formats: 

344 if xf_format.has_fill: 

345 self._write_fill(xf_format) 

346 

347 self._xml_end_tag("fills") 

348 

349 def _write_default_fill(self, pattern_type) -> None: 

350 # Write the <fill> element for the default fills. 

351 self._xml_start_tag("fill") 

352 self._xml_empty_tag("patternFill", [("patternType", pattern_type)]) 

353 self._xml_end_tag("fill") 

354 

355 def _write_fill(self, xf_format, is_dxf_format=False) -> None: 

356 # Write the <fill> element. 

357 pattern = xf_format.pattern 

358 bg_color = xf_format.bg_color 

359 fg_color = xf_format.fg_color 

360 

361 # Colors for dxf formats are handled differently from normal formats 

362 # since the normal xf_format reverses the meaning of BG and FG for 

363 # solid fills. 

364 if is_dxf_format: 

365 bg_color = xf_format.dxf_bg_color 

366 fg_color = xf_format.dxf_fg_color 

367 

368 patterns = ( 

369 "none", 

370 "solid", 

371 "mediumGray", 

372 "darkGray", 

373 "lightGray", 

374 "darkHorizontal", 

375 "darkVertical", 

376 "darkDown", 

377 "darkUp", 

378 "darkGrid", 

379 "darkTrellis", 

380 "lightHorizontal", 

381 "lightVertical", 

382 "lightDown", 

383 "lightUp", 

384 "lightGrid", 

385 "lightTrellis", 

386 "gray125", 

387 "gray0625", 

388 ) 

389 

390 # Special handling for pattern only case. 

391 if not fg_color and not bg_color and patterns[pattern]: 

392 self._write_default_fill(patterns[pattern]) 

393 return 

394 

395 self._xml_start_tag("fill") 

396 

397 # The "none" pattern is handled differently for dxf formats. 

398 if is_dxf_format and pattern <= 1: 

399 self._xml_start_tag("patternFill") 

400 else: 

401 self._xml_start_tag("patternFill", [("patternType", patterns[pattern])]) 

402 

403 if fg_color: 

404 if not fg_color._is_automatic: 

405 self._xml_empty_tag("fgColor", fg_color._attributes()) 

406 

407 if bg_color: 

408 if not bg_color._is_automatic: 

409 self._xml_empty_tag("bgColor", bg_color._attributes()) 

410 else: 

411 if not is_dxf_format and pattern <= 1: 

412 self._xml_empty_tag("bgColor", [("indexed", 64)]) 

413 

414 self._xml_end_tag("patternFill") 

415 self._xml_end_tag("fill") 

416 

417 def _write_borders(self) -> None: 

418 # Write the <borders> element. 

419 attributes = [("count", self.border_count)] 

420 

421 self._xml_start_tag("borders", attributes) 

422 

423 # Write the border elements for xf_format objects that have them. 

424 for xf_format in self.xf_formats: 

425 if xf_format.has_border: 

426 self._write_border(xf_format) 

427 

428 self._xml_end_tag("borders") 

429 

430 def _write_border(self, xf_format, is_dxf_format=False) -> None: 

431 # Write the <border> element. 

432 attributes = [] 

433 

434 # Diagonal borders add attributes to the <border> element. 

435 if xf_format.diag_type == 1: 

436 attributes.append(("diagonalUp", 1)) 

437 elif xf_format.diag_type == 2: 

438 attributes.append(("diagonalDown", 1)) 

439 elif xf_format.diag_type == 3: 

440 attributes.append(("diagonalUp", 1)) 

441 attributes.append(("diagonalDown", 1)) 

442 

443 # Ensure that a default diag border is set if the diag type is set. 

444 if xf_format.diag_type and not xf_format.diag_border: 

445 xf_format.diag_border = 1 

446 

447 # Write the start border tag. 

448 self._xml_start_tag("border", attributes) 

449 

450 # Write the <border> sub elements. 

451 self._write_sub_border("left", xf_format.left, xf_format.left_color) 

452 

453 self._write_sub_border("right", xf_format.right, xf_format.right_color) 

454 

455 self._write_sub_border("top", xf_format.top, xf_format.top_color) 

456 

457 self._write_sub_border("bottom", xf_format.bottom, xf_format.bottom_color) 

458 

459 # Condition DXF formats don't allow diagonal borders. 

460 if not is_dxf_format: 

461 self._write_sub_border( 

462 "diagonal", xf_format.diag_border, xf_format.diag_color 

463 ) 

464 

465 if is_dxf_format: 

466 self._write_sub_border("vertical", None, None) 

467 self._write_sub_border("horizontal", None, None) 

468 

469 self._xml_end_tag("border") 

470 

471 def _write_sub_border(self, border_type, style, color) -> None: 

472 # Write the <border> sub elements such as <right>, <top>, etc. 

473 attributes = [] 

474 

475 if not style: 

476 self._xml_empty_tag(border_type) 

477 return 

478 

479 border_styles = ( 

480 "none", 

481 "thin", 

482 "medium", 

483 "dashed", 

484 "dotted", 

485 "thick", 

486 "double", 

487 "hair", 

488 "mediumDashed", 

489 "dashDot", 

490 "mediumDashDot", 

491 "dashDotDot", 

492 "mediumDashDotDot", 

493 "slantDashDot", 

494 ) 

495 

496 attributes.append(("style", border_styles[style])) 

497 

498 self._xml_start_tag(border_type, attributes) 

499 

500 if color and not color._is_automatic: 

501 self._xml_empty_tag("color", color._attributes()) 

502 else: 

503 self._xml_empty_tag("color", [("auto", 1)]) 

504 

505 self._xml_end_tag(border_type) 

506 

507 def _write_cell_style_xfs(self) -> None: 

508 # Write the <cellStyleXfs> element. 

509 count = 1 

510 

511 if self.has_hyperlink: 

512 count = 2 

513 

514 attributes = [("count", count)] 

515 

516 self._xml_start_tag("cellStyleXfs", attributes) 

517 style_format = self.xf_formats[0] 

518 self._write_xf(style_format, XFormatType.STYLE) 

519 

520 if self.has_hyperlink: 

521 self._write_style_xf(True, self.hyperlink_font_id) 

522 

523 self._xml_end_tag("cellStyleXfs") 

524 

525 def _write_cell_xfs(self) -> None: 

526 # Write the <cellXfs> element. 

527 formats = self.xf_formats 

528 

529 # Workaround for when the last xf_format is used for the comment font 

530 # and shouldn't be used for cellXfs. 

531 last_format = formats[-1] 

532 if last_format.font_only: 

533 formats.pop() 

534 

535 attributes = [("count", len(formats))] 

536 self._xml_start_tag("cellXfs", attributes) 

537 

538 # Write the xf elements. 

539 cell_type = XFormatType.DEFAULT 

540 for xf_format in formats: 

541 self._write_xf(xf_format, cell_type) 

542 cell_type = XFormatType.USER 

543 

544 self._xml_end_tag("cellXfs") 

545 

546 def _write_style_xf(self, has_hyperlink=False, font_id=0) -> None: 

547 # Write the style <xf> element. 

548 num_fmt_id = 0 

549 fill_id = 0 

550 border_id = 0 

551 

552 attributes = [ 

553 ("numFmtId", num_fmt_id), 

554 ("fontId", font_id), 

555 ("fillId", fill_id), 

556 ("borderId", border_id), 

557 ] 

558 

559 if has_hyperlink: 

560 attributes.append(("applyNumberFormat", 0)) 

561 attributes.append(("applyFill", 0)) 

562 attributes.append(("applyBorder", 0)) 

563 attributes.append(("applyAlignment", 0)) 

564 attributes.append(("applyProtection", 0)) 

565 

566 self._xml_start_tag("xf", attributes) 

567 self._xml_empty_tag("alignment", [("vertical", "top")]) 

568 self._xml_empty_tag("protection", [("locked", 0)]) 

569 self._xml_end_tag("xf") 

570 

571 else: 

572 self._xml_empty_tag("xf", attributes) 

573 

574 def _write_xf(self, xf_format, xf_type: XFormatType) -> None: 

575 # Write the <xf> element. 

576 xf_id = xf_format.xf_id 

577 font_id = xf_format.font_index 

578 fill_id = xf_format.fill_index 

579 border_id = xf_format.border_index 

580 num_fmt_id = xf_format.num_format_index 

581 

582 has_checkbox = xf_format.checkbox 

583 has_alignment = False 

584 has_protection = False 

585 

586 attributes = [ 

587 ("numFmtId", num_fmt_id), 

588 ("fontId", font_id), 

589 ("fillId", fill_id), 

590 ("borderId", border_id), 

591 ] 

592 

593 if xf_type != XFormatType.STYLE: 

594 attributes.append(("xfId", xf_id)) 

595 

596 if xf_format.quote_prefix: 

597 attributes.append(("quotePrefix", 1)) 

598 

599 if xf_format.num_format_index > 0: 

600 attributes.append(("applyNumberFormat", 1)) 

601 

602 # Add applyFont attribute if XF format uses a font element. 

603 if xf_format.font_index > 0 and not xf_format.hyperlink: 

604 attributes.append(("applyFont", 1)) 

605 

606 # Add applyFill attribute if XF format uses a fill element. 

607 if xf_format.fill_index > 0: 

608 attributes.append(("applyFill", 1)) 

609 

610 # Add applyBorder attribute if XF format uses a border element. 

611 if xf_format.border_index > 0: 

612 attributes.append(("applyBorder", 1)) 

613 

614 # Check if XF format has alignment properties set. 

615 (apply_align, align) = xf_format._get_align_properties() 

616 

617 # Check if an alignment sub-element should be written. 

618 if apply_align and align: 

619 has_alignment = True 

620 

621 # We can also have applyAlignment without a sub-element. 

622 if (apply_align or xf_format.hyperlink) and xf_type == XFormatType.USER: 

623 attributes.append(("applyAlignment", 1)) 

624 

625 # Check for cell protection properties. 

626 protection = xf_format._get_protection_properties() 

627 

628 if protection or xf_format.hyperlink: 

629 attributes.append(("applyProtection", 1)) 

630 

631 if not xf_format.hyperlink: 

632 has_protection = True 

633 

634 # Write XF with sub-elements if required. 

635 if has_alignment or has_protection or has_checkbox: 

636 self._xml_start_tag("xf", attributes) 

637 

638 if has_alignment: 

639 self._xml_empty_tag("alignment", align) 

640 

641 if has_protection: 

642 self._xml_empty_tag("protection", protection) 

643 

644 if has_checkbox: 

645 self._write_xf_format_extensions() 

646 

647 self._xml_end_tag("xf") 

648 else: 

649 self._xml_empty_tag("xf", attributes) 

650 

651 def _write_cell_styles(self) -> None: 

652 # Write the <cellStyles> element. 

653 count = 1 

654 

655 if self.has_hyperlink: 

656 count = 2 

657 

658 attributes = [("count", count)] 

659 

660 self._xml_start_tag("cellStyles", attributes) 

661 

662 if self.has_hyperlink: 

663 self._write_cell_style("Hyperlink", 1, 8) 

664 

665 self._write_cell_style() 

666 

667 self._xml_end_tag("cellStyles") 

668 

669 def _write_cell_style(self, name="Normal", xf_id=0, builtin_id=0) -> None: 

670 # Write the <cellStyle> element. 

671 attributes = [ 

672 ("name", name), 

673 ("xfId", xf_id), 

674 ("builtinId", builtin_id), 

675 ] 

676 

677 self._xml_empty_tag("cellStyle", attributes) 

678 

679 def _write_dxfs(self) -> None: 

680 # Write the <dxfs> element. 

681 formats = self.dxf_formats 

682 count = len(formats) 

683 

684 attributes = [("count", len(formats))] 

685 

686 if count: 

687 self._xml_start_tag("dxfs", attributes) 

688 

689 # Write the font elements for xf_format objects that have them. 

690 for dxf_format in self.dxf_formats: 

691 self._xml_start_tag("dxf") 

692 if dxf_format.has_dxf_font: 

693 self._write_font(dxf_format, True) 

694 

695 if dxf_format.num_format_index: 

696 self._write_num_fmt( 

697 dxf_format.num_format_index, dxf_format.num_format 

698 ) 

699 

700 if dxf_format.has_dxf_fill: 

701 self._write_fill(dxf_format, True) 

702 

703 if dxf_format.has_dxf_border: 

704 self._write_border(dxf_format, True) 

705 

706 if dxf_format.checkbox: 

707 self._write_dxf_format_extensions() 

708 

709 self._xml_end_tag("dxf") 

710 

711 self._xml_end_tag("dxfs") 

712 else: 

713 self._xml_empty_tag("dxfs", attributes) 

714 

715 def _write_table_styles(self) -> None: 

716 # Write the <tableStyles> element. 

717 count = 0 

718 default_table_style = "TableStyleMedium9" 

719 default_pivot_style = "PivotStyleLight16" 

720 

721 attributes = [ 

722 ("count", count), 

723 ("defaultTableStyle", default_table_style), 

724 ("defaultPivotStyle", default_pivot_style), 

725 ] 

726 

727 self._xml_empty_tag("tableStyles", attributes) 

728 

729 def _write_colors(self) -> None: 

730 # Write the <colors> element. 

731 custom_colors = self.custom_colors 

732 

733 if not custom_colors: 

734 return 

735 

736 self._xml_start_tag("colors") 

737 self._write_mru_colors(custom_colors) 

738 self._xml_end_tag("colors") 

739 

740 def _write_mru_colors(self, custom_colors) -> None: 

741 # Write the <mruColors> element for the most recently used colors. 

742 

743 # Write the custom custom_colors in reverse order. 

744 custom_colors.reverse() 

745 

746 # Limit the mruColors to the last 10. 

747 if len(custom_colors) > 10: 

748 custom_colors = custom_colors[0:10] 

749 

750 self._xml_start_tag("mruColors") 

751 

752 # Write the custom custom_colors in reverse order. 

753 for color in custom_colors: 

754 # For backwards compatibility convert possible 

755 self._write_color(color._attributes()) 

756 

757 self._xml_end_tag("mruColors") 

758 

759 def _write_condense(self) -> None: 

760 # Write the <condense> element. 

761 attributes = [("val", 0)] 

762 

763 self._xml_empty_tag("condense", attributes) 

764 

765 def _write_extend(self) -> None: 

766 # Write the <extend> element. 

767 attributes = [("val", 0)] 

768 

769 self._xml_empty_tag("extend", attributes) 

770 

771 def _write_xf_format_extensions(self) -> None: 

772 # Write the xfComplement <extLst> elements. 

773 schema = "http://schemas.microsoft.com/office/spreadsheetml" 

774 attributes = [ 

775 ("uri", "{C7286773-470A-42A8-94C5-96B5CB345126}"), 

776 ( 

777 "xmlns:xfpb", 

778 schema + "/2022/featurepropertybag", 

779 ), 

780 ] 

781 

782 self._xml_start_tag("extLst") 

783 self._xml_start_tag("ext", attributes) 

784 

785 self._xml_empty_tag("xfpb:xfComplement", [("i", "0")]) 

786 

787 self._xml_end_tag("ext") 

788 self._xml_end_tag("extLst") 

789 

790 def _write_dxf_format_extensions(self) -> None: 

791 # Write the DXFComplement <extLst> elements. 

792 schema = "http://schemas.microsoft.com/office/spreadsheetml" 

793 attributes = [ 

794 ("uri", "{0417FA29-78FA-4A13-93AC-8FF0FAFDF519}"), 

795 ( 

796 "xmlns:xfpb", 

797 schema + "/2022/featurepropertybag", 

798 ), 

799 ] 

800 

801 self._xml_start_tag("extLst") 

802 self._xml_start_tag("ext", attributes) 

803 

804 self._xml_empty_tag("xfpb:DXFComplement", [("i", "0")]) 

805 

806 self._xml_end_tag("ext") 

807 self._xml_end_tag("extLst")