base.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. from __future__ import absolute_import
  2. # Copyright (c) 2010-2019 openpyxl
  3. """
  4. Based on Python Cookbook 3rd Edition, 8.13
  5. http://chimera.labs.oreilly.com/books/1230000000393/ch08.html#_discussion_130
  6. """
  7. import datetime
  8. import re
  9. from openpyxl.compat import basestring, bytes, long
  10. from openpyxl.utils.datetime import from_ISO8601
  11. from .namespace import namespaced
  12. class Descriptor(object):
  13. def __init__(self, name=None, **kw):
  14. self.name = name
  15. for k, v in kw.items():
  16. setattr(self, k, v)
  17. def __set__(self, instance, value):
  18. instance.__dict__[self.name] = value
  19. class Typed(Descriptor):
  20. """Values must of a particular type"""
  21. expected_type = type(None)
  22. allow_none = False
  23. nested = False
  24. def __init__(self, *args, **kw):
  25. super(Typed, self).__init__(*args, **kw)
  26. self.__doc__ = "Values must be of type {0}".format(self.expected_type)
  27. def __set__(self, instance, value):
  28. if not isinstance(value, self.expected_type):
  29. if (not self.allow_none
  30. or (self.allow_none and value is not None)):
  31. raise TypeError('expected ' + str(self.expected_type))
  32. super(Typed, self).__set__(instance, value)
  33. def __repr__(self):
  34. return self.__doc__
  35. def _convert(expected_type, value):
  36. """
  37. Check value is of or can be converted to expected type.
  38. """
  39. if not isinstance(value, expected_type):
  40. try:
  41. value = expected_type(value)
  42. except:
  43. raise TypeError('expected ' + str(expected_type))
  44. return value
  45. class Convertible(Typed):
  46. """Values must be convertible to a particular type"""
  47. def __set__(self, instance, value):
  48. if ((self.allow_none and value is not None)
  49. or not self.allow_none):
  50. value = _convert(self.expected_type, value)
  51. super(Convertible, self).__set__(instance, value)
  52. class Max(Convertible):
  53. """Values must be less than a `max` value"""
  54. expected_type = float
  55. allow_none = False
  56. def __init__(self, **kw):
  57. if 'max' not in kw and not hasattr(self, 'max'):
  58. raise TypeError('missing max value')
  59. super(Max, self).__init__(**kw)
  60. def __set__(self, instance, value):
  61. if ((self.allow_none and value is not None)
  62. or not self.allow_none):
  63. value = _convert(self.expected_type, value)
  64. if value > self.max:
  65. raise ValueError('Max value is {0}'.format(self.max))
  66. super(Max, self).__set__(instance, value)
  67. class Min(Convertible):
  68. """Values must be greater than a `min` value"""
  69. expected_type = float
  70. allow_none = False
  71. def __init__(self, **kw):
  72. if 'min' not in kw and not hasattr(self, 'min'):
  73. raise TypeError('missing min value')
  74. super(Min, self).__init__(**kw)
  75. def __set__(self, instance, value):
  76. if ((self.allow_none and value is not None)
  77. or not self.allow_none):
  78. value = _convert(self.expected_type, value)
  79. if value < self.min:
  80. raise ValueError('Min value is {0}'.format(self.min))
  81. super(Min, self).__set__(instance, value)
  82. class MinMax(Min, Max):
  83. """Values must be greater than `min` value and less than a `max` one"""
  84. pass
  85. class Set(Descriptor):
  86. """Value can only be from a set of know values"""
  87. def __init__(self, name=None, **kw):
  88. if not 'values' in kw:
  89. raise TypeError("missing set of values")
  90. kw['values'] = set(kw['values'])
  91. super(Set, self).__init__(name, **kw)
  92. self.__doc__ = "Value must be one of {0}".format(self.values)
  93. def __set__(self, instance, value):
  94. if value not in self.values:
  95. raise ValueError(self.__doc__)
  96. super(Set, self).__set__(instance, value)
  97. class NoneSet(Set):
  98. """'none' will be treated as None"""
  99. def __init__(self, name=None, **kw):
  100. super(NoneSet, self).__init__(name, **kw)
  101. self.values.add(None)
  102. def __set__(self, instance, value):
  103. if value == 'none':
  104. value = None
  105. super(NoneSet, self).__set__(instance, value)
  106. class Integer(Convertible):
  107. expected_type = long
  108. class Float(Convertible):
  109. expected_type = float
  110. class Bool(Convertible):
  111. expected_type = bool
  112. def __set__(self, instance, value):
  113. if isinstance(value, str):
  114. if value in ('false', 'f', '0'):
  115. value = False
  116. super(Bool, self).__set__(instance, value)
  117. class String(Typed):
  118. expected_type = basestring
  119. class Text(String, Convertible):
  120. pass
  121. class ASCII(Typed):
  122. expected_type = bytes
  123. class Tuple(Typed):
  124. expected_type = tuple
  125. class Length(Descriptor):
  126. def __init__(self, name=None, **kw):
  127. if "length" not in kw:
  128. raise TypeError("value length must be supplied")
  129. super(Length, self).__init__(**kw)
  130. def __set__(self, instance, value):
  131. if len(value) != self.length:
  132. raise ValueError("Value must be length {0}".format(self.length))
  133. super(Length, self).__set__(instance, value)
  134. class Default(Typed):
  135. """
  136. When called returns an instance of the expected type.
  137. Additional default values can be passed in to the descriptor
  138. """
  139. def __init__(self, name=None, **kw):
  140. if "defaults" not in kw:
  141. kw['defaults'] = {}
  142. super(Default, self).__init__(**kw)
  143. def __call__(self):
  144. return self.expected_type()
  145. class Alias(Descriptor):
  146. """
  147. Aliases can be used when either the desired attribute name is not allowed
  148. or confusing in Python (eg. "type") or a more descriptve name is desired
  149. (eg. "underline" for "u")
  150. """
  151. def __init__(self, alias):
  152. self.alias = alias
  153. def __set__(self, instance, value):
  154. setattr(instance, self.alias, value)
  155. def __get__(self, instance, cls):
  156. return getattr(instance, self.alias)
  157. class MatchPattern(Descriptor):
  158. """Values must match a regex pattern """
  159. allow_none = False
  160. def __init__(self, name=None, **kw):
  161. if 'pattern' not in kw and not hasattr(self, 'pattern'):
  162. raise TypeError('missing pattern value')
  163. super(MatchPattern, self).__init__(name, **kw)
  164. self.test_pattern = re.compile(self.pattern, re.VERBOSE)
  165. def __set__(self, instance, value):
  166. if value is None and not self.allow_none:
  167. raise ValueError("Value must not be none")
  168. if ((self.allow_none and value is not None)
  169. or not self.allow_none):
  170. if not self.test_pattern.match(value):
  171. raise ValueError('Value does not match pattern {0}'.format(self.pattern))
  172. super(MatchPattern, self).__set__(instance, value)
  173. class DateTime(Typed):
  174. expected_type = datetime.datetime
  175. def __set__(self, instance, value):
  176. if value is not None and isinstance(value, basestring):
  177. try:
  178. value = from_ISO8601(value)
  179. except ValueError:
  180. raise ValueError("Value must be ISO datetime format")
  181. super(DateTime, self).__set__(instance, value)