Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/openpyxl/descriptors/base.py: 75%
150 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1# Copyright (c) 2010-2022 openpyxl
4"""
5Based on Python Cookbook 3rd Edition, 8.13
6http://chimera.labs.oreilly.com/books/1230000000393/ch08.html#_discussiuncion_130
7"""
9import datetime
10import re
12from openpyxl.utils.datetime import from_ISO8601
14from .namespace import namespaced
16class Descriptor(object):
18 def __init__(self, name=None, **kw):
19 self.name = name
20 for k, v in kw.items():
21 setattr(self, k, v)
23 def __set__(self, instance, value):
24 instance.__dict__[self.name] = value
27class Typed(Descriptor):
28 """Values must of a particular type"""
30 expected_type = type(None)
31 allow_none = False
32 nested = False
34 def __init__(self, *args, **kw):
35 super(Typed, self).__init__(*args, **kw)
36 self.__doc__ = "Values must be of type {0}".format(self.expected_type)
38 def __set__(self, instance, value):
39 if not isinstance(value, self.expected_type):
40 if (not self.allow_none 40 ↛ 42line 40 didn't jump to line 42, because the condition on line 40 was never true
41 or (self.allow_none and value is not None)):
42 raise TypeError('expected ' + str(self.expected_type))
43 super(Typed, self).__set__(instance, value)
45 def __repr__(self):
46 return self.__doc__
49def _convert(expected_type, value):
50 """
51 Check value is of or can be converted to expected type.
52 """
53 if not isinstance(value, expected_type):
54 try:
55 value = expected_type(value)
56 except:
57 raise TypeError('expected ' + str(expected_type))
58 return value
61class Convertible(Typed):
62 """Values must be convertible to a particular type"""
64 def __set__(self, instance, value):
65 if ((self.allow_none and value is not None)
66 or not self.allow_none):
67 value = _convert(self.expected_type, value)
68 super(Convertible, self).__set__(instance, value)
71class Max(Convertible):
72 """Values must be less than a `max` value"""
74 expected_type = float
75 allow_none = False
77 def __init__(self, **kw):
78 if 'max' not in kw and not hasattr(self, 'max'): 78 ↛ 79line 78 didn't jump to line 79, because the condition on line 78 was never true
79 raise TypeError('missing max value')
80 super(Max, self).__init__(**kw)
82 def __set__(self, instance, value):
83 if ((self.allow_none and value is not None)
84 or not self.allow_none):
85 value = _convert(self.expected_type, value)
86 if value > self.max: 86 ↛ 87line 86 didn't jump to line 87, because the condition on line 86 was never true
87 raise ValueError('Max value is {0}'.format(self.max))
88 super(Max, self).__set__(instance, value)
91class Min(Convertible):
92 """Values must be greater than a `min` value"""
94 expected_type = float
95 allow_none = False
97 def __init__(self, **kw):
98 if 'min' not in kw and not hasattr(self, 'min'): 98 ↛ 99line 98 didn't jump to line 99, because the condition on line 98 was never true
99 raise TypeError('missing min value')
100 super(Min, self).__init__(**kw)
102 def __set__(self, instance, value):
103 if ((self.allow_none and value is not None)
104 or not self.allow_none):
105 value = _convert(self.expected_type, value)
106 if value < self.min: 106 ↛ 107line 106 didn't jump to line 107, because the condition on line 106 was never true
107 raise ValueError('Min value is {0}'.format(self.min))
108 super(Min, self).__set__(instance, value)
111class MinMax(Min, Max):
112 """Values must be greater than `min` value and less than a `max` one"""
113 pass
116class Set(Descriptor):
117 """Value can only be from a set of know values"""
119 def __init__(self, name=None, **kw):
120 if not 'values' in kw: 120 ↛ 121line 120 didn't jump to line 121, because the condition on line 120 was never true
121 raise TypeError("missing set of values")
122 kw['values'] = set(kw['values'])
123 super(Set, self).__init__(name, **kw)
124 self.__doc__ = "Value must be one of {0}".format(self.values)
126 def __set__(self, instance, value):
127 if value not in self.values: 127 ↛ 128line 127 didn't jump to line 128, because the condition on line 127 was never true
128 raise ValueError(self.__doc__)
129 super(Set, self).__set__(instance, value)
132class NoneSet(Set):
134 """'none' will be treated as None"""
136 def __init__(self, name=None, **kw):
137 super(NoneSet, self).__init__(name, **kw)
138 self.values.add(None)
140 def __set__(self, instance, value):
141 if value == 'none': 141 ↛ 142line 141 didn't jump to line 142, because the condition on line 141 was never true
142 value = None
143 super(NoneSet, self).__set__(instance, value)
146class Integer(Convertible):
148 expected_type = int
151class Float(Convertible):
153 expected_type = float
156class Bool(Convertible):
158 expected_type = bool
160 def __set__(self, instance, value):
161 if isinstance(value, str):
162 if value in ('false', 'f', '0'):
163 value = False
164 super(Bool, self).__set__(instance, value)
167class String(Typed):
169 expected_type = str
172class Text(String, Convertible):
174 pass
177class ASCII(Typed):
179 expected_type = bytes
182class Tuple(Typed):
184 expected_type = tuple
187class Length(Descriptor):
189 def __init__(self, name=None, **kw):
190 if "length" not in kw:
191 raise TypeError("value length must be supplied")
192 super(Length, self).__init__(**kw)
195 def __set__(self, instance, value):
196 if len(value) != self.length:
197 raise ValueError("Value must be length {0}".format(self.length))
198 super(Length, self).__set__(instance, value)
201class Default(Typed):
202 """
203 When called returns an instance of the expected type.
204 Additional default values can be passed in to the descriptor
205 """
207 def __init__(self, name=None, **kw):
208 if "defaults" not in kw:
209 kw['defaults'] = {}
210 super(Default, self).__init__(**kw)
212 def __call__(self):
213 return self.expected_type()
216class Alias(Descriptor):
217 """
218 Aliases can be used when either the desired attribute name is not allowed
219 or confusing in Python (eg. "type") or a more descriptve name is desired
220 (eg. "underline" for "u")
221 """
223 def __init__(self, alias):
224 self.alias = alias
226 def __set__(self, instance, value):
227 setattr(instance, self.alias, value)
229 def __get__(self, instance, cls):
230 return getattr(instance, self.alias)
233class MatchPattern(Descriptor):
234 """Values must match a regex pattern """
235 allow_none = False
237 def __init__(self, name=None, **kw):
238 if 'pattern' not in kw and not hasattr(self, 'pattern'): 238 ↛ 239line 238 didn't jump to line 239, because the condition on line 238 was never true
239 raise TypeError('missing pattern value')
241 super(MatchPattern, self).__init__(name, **kw)
242 self.test_pattern = re.compile(self.pattern, re.VERBOSE)
245 def __set__(self, instance, value):
247 if value is None and not self.allow_none:
248 raise ValueError("Value must not be none")
250 if ((self.allow_none and value is not None)
251 or not self.allow_none):
252 if not self.test_pattern.match(value):
253 raise ValueError('Value does not match pattern {0}'.format(self.pattern))
255 super(MatchPattern, self).__set__(instance, value)
258class DateTime(Typed):
260 expected_type = datetime.datetime
262 def __set__(self, instance, value):
263 if value is not None and isinstance(value, str):
264 try:
265 value = from_ISO8601(value)
266 except ValueError:
267 raise ValueError("Value must be ISO datetime format")
268 super(DateTime, self).__set__(instance, value)