Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/openpyxl/cell/rich_text.py: 29%
95 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"""
4RichText definition
5"""
6from copy import copy
7from openpyxl.cell.text import InlineFont, Text
8from openpyxl.descriptors import (
9 Strict,
10 String,
11 Typed
12)
13class TextBlock(Strict):
14 """ Represents text string in a specific format
16 This class is used as part of constructing a rich text strings.
17 """
18 font = Typed(expected_type=InlineFont)
19 text = String()
21 def __init__(self, font, text):
22 self.font = font
23 self.text = text
26 def __eq__(self, other):
27 return self.text == other.text and self.font == other.font
30 def __str__(self):
31 """Just retun the text"""
32 return self.text
35 def __repr__(self):
36 font = self.font != InlineFont() and self.font or "default"
37 return f"{self.__class__.__name__} text={self.text}, font={font}"
40#
41# Rich Text class.
42# This class behaves just like a list whose members are either simple strings, or TextBlock() instances.
43# In addition, it can be initialized in several ways:
44# t = CellRFichText([...]) # initialize with a list.
45# t = CellRFichText((...)) # initialize with a tuple.
46# t = CellRichText(node) # where node is an Element() from either lxml or xml.etree (has a 'tag' element)
47class CellRichText(list):
48 """Represents a rich text string.
50 Initialize with a list made of pure strings or :class:`TextBlock` elements
51 Can index object to access or modify individual rich text elements
52 it also supports the + and += operators between rich text strings
53 There are no user methods for this class
55 operations which modify the string will generally call an optimization pass afterwards,
56 that merges text blocks with identical formats, consecutive pure text strings,
57 and remove empty strings and empty text blocks
58 """
60 def __init__(self, *args):
61 if len(args) == 1:
62 args = args[0]
63 if isinstance(args, (list, tuple)):
64 CellRichText._check_rich_text(args)
65 else:
66 CellRichText._check_element(args)
67 args = [args]
68 else:
69 CellRichText._check_rich_text(args)
70 super().__init__(args)
72 @classmethod
73 def _check_element(cls, value):
74 if hasattr(value, "__str__"):
75 return
76 raise TypeError(f"Illegal CellRichText element {value}")
78 @classmethod
79 def _check_rich_text(cls, rich_text):
80 for t in rich_text:
81 CellRichText._check_element(t)
83 @classmethod
84 def from_tree(cls, node):
85 text = Text.from_tree(node)
86 if text.t:
87 return (text.t.replace('x005F_', ''),)
88 s = []
89 for r in text.r:
90 t = ""
91 if r.t:
92 t = r.t.replace('x005F_', '')
93 if r.rPr:
94 s.append(TextBlock(r.rPr, t))
95 else:
96 s.append(t)
97 return cls(s)
99 # Merge TextBlocks with identical formatting
100 # remove empty elements
101 def _opt(self):
102 last_t = None
103 l = CellRichText(tuple())
104 for t in self:
105 if isinstance(t, str):
106 if not t:
107 continue
108 elif not t.text:
109 continue
110 if type(last_t) == type(t):
111 if isinstance(t, str):
112 last_t += t
113 continue
114 elif last_t.font == t.font:
115 last_t.text += t.text
116 continue
117 if last_t:
118 l.append(last_t)
119 last_t = t
120 if last_t:
121 # Add remaining TextBlock at end of rich text
122 l.append(last_t)
123 super().__setitem__(slice(None), l)
124 return self
127 def __iadd__(self, arg):
128 # copy used here to create new TextBlock() so we don't modify the right hand side in _opt()
129 CellRichText._check_rich_text(arg)
130 super().__iadd__([copy(e) for e in list(arg)])
131 return self._opt()
134 def __add__(self, arg):
135 return CellRichText([copy(e) for e in list(self) + list(arg)])._opt()
138 def __setitem__(self, indx, val):
139 CellRichText._check_element(val)
140 super().__setitem__(indx, val)
141 self._opt()
144 def append(self, arg):
145 CellRichText._check_element(arg)
146 super().append(arg)
149 def extend(self, arg):
150 CellRichText._check_rich_text(arg)
151 super().extend(arg)
154 def __repr__(self):
155 return "CellRichText([{}])".format(', '.join((repr(s) for s in self)))
158 def __str__(self):
159 return ''.join([str(s) for s in self])
162 def as_list(self):
163 """
164 Returns a list of the strings contained.
165 The main reason for this is to make editing easier.
166 """
167 return [str(s) for s in self]