Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/openpyxl/descriptors/sequence.py: 93%

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

68 statements  

1# Copyright (c) 2010-2024 openpyxl 

2 

3from openpyxl.compat import safe_string 

4from openpyxl.xml.functions import Element 

5from openpyxl.utils.indexed_list import IndexedList 

6 

7from .base import Descriptor, Alias, _convert 

8from .namespace import namespaced 

9 

10 

11class Sequence(Descriptor): 

12 """ 

13 A sequence (list or tuple) that may only contain objects of the declared 

14 type 

15 """ 

16 

17 expected_type = type(None) 

18 seq_types = (list, tuple) 

19 idx_base = 0 

20 unique = False 

21 container = list 

22 

23 

24 def __set__(self, instance, seq): 

25 if not isinstance(seq, self.seq_types): 

26 raise TypeError("Value must be a sequence") 

27 seq = self.container(_convert(self.expected_type, value) for value in seq) 

28 if self.unique: 

29 seq = IndexedList(seq) 

30 

31 super().__set__(instance, seq) 

32 

33 

34 def to_tree(self, tagname, obj, namespace=None): 

35 """ 

36 Convert the sequence represented by the descriptor to an XML element 

37 """ 

38 for idx, v in enumerate(obj, self.idx_base): 

39 if hasattr(v, "to_tree"): 

40 el = v.to_tree(tagname, idx) 

41 else: 

42 tagname = namespaced(obj, tagname, namespace) 

43 el = Element(tagname) 

44 el.text = safe_string(v) 

45 yield el 

46 

47 

48class UniqueSequence(Sequence): 

49 """ 

50 Use a set to keep values unique 

51 """ 

52 seq_types = (list, tuple, set) 

53 container = set 

54 

55 

56class ValueSequence(Sequence): 

57 """ 

58 A sequence of primitive types that are stored as a single attribute. 

59 "val" is the default attribute 

60 """ 

61 

62 attribute = "val" 

63 

64 

65 def to_tree(self, tagname, obj, namespace=None): 

66 tagname = namespaced(self, tagname, namespace) 

67 for v in obj: 

68 yield Element(tagname, {self.attribute:safe_string(v)}) 

69 

70 

71 def from_tree(self, node): 

72 

73 return node.get(self.attribute) 

74 

75 

76class NestedSequence(Sequence): 

77 """ 

78 Wrap a sequence in an containing object 

79 """ 

80 

81 count = False 

82 

83 def to_tree(self, tagname, obj, namespace=None): 

84 tagname = namespaced(self, tagname, namespace) 

85 container = Element(tagname) 

86 if self.count: 

87 container.set('count', str(len(obj))) 

88 for v in obj: 

89 container.append(v.to_tree()) 

90 return container 

91 

92 

93 def from_tree(self, node): 

94 return [self.expected_type.from_tree(el) for el in node] 

95 

96 

97class MultiSequence(Sequence): 

98 """ 

99 Sequences can contain objects with different tags 

100 """ 

101 

102 def __set__(self, instance, seq): 

103 if not isinstance(seq, (tuple, list)): 

104 raise ValueError("Value must be a sequence") 

105 seq = list(seq) 

106 Descriptor.__set__(self, instance, seq) 

107 

108 

109 def to_tree(self, tagname, obj, namespace=None): 

110 """ 

111 Convert the sequence represented by the descriptor to an XML element 

112 """ 

113 for v in obj: 

114 el = v.to_tree(namespace=namespace) 

115 yield el 

116 

117 

118class MultiSequencePart(Alias): 

119 """ 

120 Allow a multisequence to be built up from parts 

121 

122 Excluded from the instance __elements__ or __attrs__ as is effectively an Alias 

123 """ 

124 

125 def __init__(self, expected_type, store): 

126 self.expected_type = expected_type 

127 self.store = store 

128 

129 

130 def __set__(self, instance, value): 

131 value = _convert(self.expected_type, value) 

132 instance.__dict__[self.store].append(value) 

133 

134 

135 def __get__(self, instance, cls): 

136 return self