Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/openpyxl/descriptors/sequence.py: 93%
68 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
3from openpyxl.compat import safe_string
4from openpyxl.xml.functions import Element
5from openpyxl.utils.indexed_list import IndexedList
7from .base import Descriptor, Alias, _convert
8from .namespace import namespaced
11class Sequence(Descriptor):
12 """
13 A sequence (list or tuple) that may only contain objects of the declared
14 type
15 """
17 expected_type = type(None)
18 seq_types = (list, tuple)
19 idx_base = 0
20 unique = False
21 container = list
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)
31 super().__set__(instance, seq)
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
48class UniqueSequence(Sequence):
49 """
50 Use a set to keep values unique
51 """
52 seq_types = (list, tuple, set)
53 container = set
56class ValueSequence(Sequence):
57 """
58 A sequence of primitive types that are stored as a single attribute.
59 "val" is the default attribute
60 """
62 attribute = "val"
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)})
71 def from_tree(self, node):
73 return node.get(self.attribute)
76class NestedSequence(Sequence):
77 """
78 Wrap a sequence in an containing object
79 """
81 count = False
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
93 def from_tree(self, node):
94 return [self.expected_type.from_tree(el) for el in node]
97class MultiSequence(Sequence):
98 """
99 Sequences can contain objects with different tags
100 """
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)
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
118class MultiSequencePart(Alias):
119 """
120 Allow a multisequence to be built up from parts
122 Excluded from the instance __elements__ or __attrs__ as is effectively an Alias
123 """
125 def __init__(self, expected_type, store):
126 self.expected_type = expected_type
127 self.store = store
130 def __set__(self, instance, value):
131 value = _convert(self.expected_type, value)
132 instance.__dict__[self.store].append(value)
135 def __get__(self, instance, cls):
136 return self