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

1# Copyright (c) 2010-2023 openpyxl 

2 

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 

15 

16 This class is used as part of constructing a rich text strings. 

17 """ 

18 font = Typed(expected_type=InlineFont) 

19 text = String() 

20 

21 def __init__(self, font, text): 

22 self.font = font 

23 self.text = text 

24 

25 

26 def __eq__(self, other): 

27 return self.text == other.text and self.font == other.font 

28 

29 

30 def __str__(self): 

31 """Just retun the text""" 

32 return self.text 

33 

34 

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}" 

38 

39 

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. 

49 

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 

54 

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 """ 

59 

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) 

71 

72 @classmethod 

73 def _check_element(cls, value): 

74 if hasattr(value, "__str__"): 

75 return 

76 raise TypeError(f"Illegal CellRichText element {value}") 

77 

78 @classmethod 

79 def _check_rich_text(cls, rich_text): 

80 for t in rich_text: 

81 CellRichText._check_element(t) 

82 

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) 

98 

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 

125 

126 

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() 

132 

133 

134 def __add__(self, arg): 

135 return CellRichText([copy(e) for e in list(self) + list(arg)])._opt() 

136 

137 

138 def __setitem__(self, indx, val): 

139 CellRichText._check_element(val) 

140 super().__setitem__(indx, val) 

141 self._opt() 

142 

143 

144 def append(self, arg): 

145 CellRichText._check_element(arg) 

146 super().append(arg) 

147 

148 

149 def extend(self, arg): 

150 CellRichText._check_rich_text(arg) 

151 super().extend(arg) 

152 

153 

154 def __repr__(self): 

155 return "CellRichText([{}])".format(', '.join((repr(s) for s in self))) 

156 

157 

158 def __str__(self): 

159 return ''.join([str(s) for s in self]) 

160 

161 

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]