validators.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #Copyright ReportLab Europe Ltd. 2000-2017
  2. #see license.txt for license details
  3. #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/validators.py
  4. __version__='3.5.33'
  5. __doc__="""Standard verifying functions used by attrmap."""
  6. import sys, codecs
  7. from reportlab.lib.utils import isSeq, isBytes, isStr
  8. from reportlab.lib import colors
  9. class Percentage(float):
  10. pass
  11. class Validator:
  12. "base validator class"
  13. def __call__(self,x):
  14. return self.test(x)
  15. def __str__(self):
  16. return getattr(self,'_str',self.__class__.__name__)
  17. def normalize(self,x):
  18. return x
  19. def normalizeTest(self,x):
  20. try:
  21. self.normalize(x)
  22. return True
  23. except:
  24. return False
  25. class _isAnything(Validator):
  26. def test(self,x):
  27. return True
  28. class _isNothing(Validator):
  29. def test(self,x):
  30. return False
  31. class _isBoolean(Validator):
  32. def test(self,x):
  33. if isinstance(int,bool): return x in (0,1)
  34. return self.normalizeTest(x)
  35. def normalize(self,x):
  36. if x in (0,1): return x
  37. try:
  38. S = x.upper()
  39. except:
  40. raise ValueError('Must be boolean not %s' % ascii(s))
  41. if S in ('YES','TRUE'): return True
  42. if S in ('NO','FALSE',None): return False
  43. raise ValueError('Must be boolean not %s' % ascii(s))
  44. class _isString(Validator):
  45. def test(self,x):
  46. return isStr(x)
  47. class _isCodec(Validator):
  48. def test(self,x):
  49. if not isStr(x):
  50. return False
  51. try:
  52. a,b,c,d = codecs.lookup(x)
  53. return True
  54. except LookupError:
  55. return False
  56. class _isNumber(Validator):
  57. def test(self,x):
  58. if isinstance(x,(float,int)): return True
  59. return self.normalizeTest(x)
  60. def normalize(self,x):
  61. try:
  62. return float(x)
  63. except:
  64. return int(x)
  65. class _isInt(Validator):
  66. def test(self,x):
  67. if not isinstance(x,int) and not isStr(x): return False
  68. return self.normalizeTest(x)
  69. def normalize(self,x):
  70. return int(x.decode('utf8') if isBytes(x) else x)
  71. class _isNumberOrNone(_isNumber):
  72. def test(self,x):
  73. return x is None or isNumber(x)
  74. def normalize(self,x):
  75. if x is None: return x
  76. return _isNumber.normalize(x)
  77. class _isListOfNumbersOrNone(Validator):
  78. "ListOfNumbersOrNone validator class."
  79. def test(self, x):
  80. if x is None: return True
  81. return isListOfNumbers(x)
  82. class isNumberInRange(_isNumber):
  83. def __init__(self, min, max):
  84. self.min = min
  85. self.max = max
  86. def test(self, x):
  87. try:
  88. n = self.normalize(x)
  89. if self.min <= n <= self.max:
  90. return True
  91. except ValueError:
  92. pass
  93. return False
  94. class _isListOfShapes(Validator):
  95. "ListOfShapes validator class."
  96. def test(self, x):
  97. from reportlab.graphics.shapes import Shape
  98. if isSeq(x):
  99. answer = 1
  100. for e in x:
  101. if not isinstance(e, Shape):
  102. answer = 0
  103. return answer
  104. else:
  105. return False
  106. class _isListOfStringsOrNone(Validator):
  107. "ListOfStringsOrNone validator class."
  108. def test(self, x):
  109. if x is None: return True
  110. return isListOfStrings(x)
  111. class _isTransform(Validator):
  112. "Transform validator class."
  113. def test(self, x):
  114. if isSeq(x):
  115. if len(x) == 6:
  116. for element in x:
  117. if not isNumber(element):
  118. return False
  119. return True
  120. else:
  121. return False
  122. else:
  123. return False
  124. class _isColor(Validator):
  125. "Color validator class."
  126. def test(self, x):
  127. return isinstance(x, colors.Color)
  128. class _isColorOrNone(Validator):
  129. "ColorOrNone validator class."
  130. def test(self, x):
  131. if x is None: return True
  132. return isColor(x)
  133. from reportlab.lib.normalDate import NormalDate
  134. class _isNormalDate(Validator):
  135. def test(self,x):
  136. if isinstance(x,NormalDate):
  137. return True
  138. return x is not None and self.normalizeTest(x)
  139. def normalize(self,x):
  140. return NormalDate(x)
  141. class _isValidChild(Validator):
  142. "ValidChild validator class."
  143. def test(self, x):
  144. """Is this child allowed in a drawing or group?
  145. I.e. does it descend from Shape or UserNode?
  146. """
  147. from reportlab.graphics.shapes import UserNode, Shape
  148. return isinstance(x, UserNode) or isinstance(x, Shape)
  149. class _isValidChildOrNone(_isValidChild):
  150. def test(self,x):
  151. return _isValidChild.test(self,x) or x is None
  152. class _isCallable(Validator):
  153. def test(self, x):
  154. return hasattr(x,'__call__')
  155. class OneOf(Validator):
  156. """Make validator functions for list of choices.
  157. Usage:
  158. f = reportlab.lib.validators.OneOf('happy','sad')
  159. or
  160. f = reportlab.lib.validators.OneOf(('happy','sad'))
  161. f('sad'),f('happy'), f('grumpy')
  162. (1,1,0)
  163. """
  164. def __init__(self, enum,*args):
  165. if isSeq(enum):
  166. if args!=():
  167. raise ValueError("Either all singleton args or a single sequence argument")
  168. self._enum = tuple(enum)+args
  169. else:
  170. self._enum = (enum,)+args
  171. def test(self, x):
  172. return x in self._enum
  173. class SequenceOf(Validator):
  174. def __init__(self,elemTest,name=None,emptyOK=1, NoneOK=0, lo=0,hi=0x7fffffff):
  175. self._elemTest = elemTest
  176. self._emptyOK = emptyOK
  177. self._NoneOK = NoneOK
  178. self._lo, self._hi = lo, hi
  179. if name: self._str = name
  180. def test(self, x):
  181. if not isSeq(x):
  182. if x is None: return self._NoneOK
  183. return False
  184. if x==[] or x==():
  185. return self._emptyOK
  186. elif not self._lo<=len(x)<=self._hi: return False
  187. for e in x:
  188. if not self._elemTest(e): return False
  189. return True
  190. class EitherOr(Validator):
  191. def __init__(self,tests,name=None):
  192. if not isSeq(tests): tests = (tests,)
  193. self._tests = tests
  194. if name: self._str = name
  195. def test(self, x):
  196. for t in self._tests:
  197. if t(x): return True
  198. return False
  199. class NoneOr(Validator):
  200. def __init__(self,elemTest,name=None):
  201. self._elemTest = elemTest
  202. if name: self._str = name
  203. def test(self, x):
  204. if x is None: return True
  205. return self._elemTest(x)
  206. class NotSetOr(NoneOr):
  207. _not_set = object()
  208. def test(self, x):
  209. if x is NotSetOr._not_set: return True
  210. return self._elemTest(x)
  211. @staticmethod
  212. def conditionalValue(v,a):
  213. return a if v is NotSetOr._not_set else v
  214. class _isNotSet(Validator):
  215. def test(self,x):
  216. return x is NotSetOr._not_set
  217. class Auto(Validator):
  218. def __init__(self,**kw):
  219. self.__dict__.update(kw)
  220. def test(self,x):
  221. return x is self.__class__ or isinstance(x,self.__class__)
  222. class AutoOr(NoneOr):
  223. def test(self,x):
  224. return isAuto(x) or self._elemTest(x)
  225. class isInstanceOf(Validator):
  226. def __init__(self,klass=None):
  227. self._klass = klass
  228. def test(self,x):
  229. return isinstance(x,self._klass)
  230. class isSubclassOf(Validator):
  231. def __init__(self,klass=None):
  232. self._klass = klass
  233. def test(self,x):
  234. return issubclass(x,self._klass)
  235. class matchesPattern(Validator):
  236. """Matches value, or its string representation, against regex"""
  237. def __init__(self, pattern):
  238. self._pattern = re.compile(pattern)
  239. def test(self,x):
  240. x = str(x)
  241. print('testing %s against %s' % (x, self._pattern))
  242. return (self._pattern.match(x) != None)
  243. class DerivedValue:
  244. """This is used for magic values which work themselves out.
  245. An example would be an "inherit" property, so that one can have
  246. drawing.chart.categoryAxis.labels.fontName = inherit
  247. and pick up the value from the top of the drawing.
  248. Validators will permit this provided that a value can be pulled
  249. in which satisfies it. And the renderer will have special
  250. knowledge of these so they can evaluate themselves.
  251. """
  252. def getValue(self, renderer, attr):
  253. """Override this. The renderers will pass the renderer,
  254. and the attribute name. Algorithms can then backtrack up
  255. through all the stuff the renderer provides, including
  256. a correct stack of parent nodes."""
  257. return None
  258. class Inherit(DerivedValue):
  259. def __repr__(self):
  260. return "inherit"
  261. def getValue(self, renderer, attr):
  262. return renderer.getStateValue(attr)
  263. inherit = Inherit()
  264. class NumericAlign(str):
  265. '''for creating the numeric string value for anchors etc etc
  266. dp is the character to align on (the last occurrence will be used)
  267. dpLen is the length of characters after the dp
  268. '''
  269. def __new__(cls,dp='.',dpLen=0):
  270. self = str.__new__(cls,'numeric')
  271. self._dp=dp
  272. self._dpLen = dpLen
  273. return self
  274. isAuto = Auto()
  275. isBoolean = _isBoolean()
  276. isString = _isString()
  277. isCodec = _isCodec()
  278. isNumber = _isNumber()
  279. isInt = _isInt()
  280. isNoneOrInt = NoneOr(isInt,'isNoneOrInt')
  281. isNumberOrNone = _isNumberOrNone()
  282. isTextAnchor = OneOf('start','middle','end','boxauto')
  283. isListOfNumbers = SequenceOf(isNumber,'isListOfNumbers')
  284. isListOfNoneOrNumber = SequenceOf(isNumberOrNone,'isListOfNoneOrNumber')
  285. isListOfListOfNoneOrNumber = SequenceOf(isListOfNoneOrNumber,'isListOfListOfNoneOrNumber')
  286. isListOfNumbersOrNone = _isListOfNumbersOrNone()
  287. isListOfShapes = _isListOfShapes()
  288. isListOfStrings = SequenceOf(isString,'isListOfStrings')
  289. isListOfStringsOrNone = _isListOfStringsOrNone()
  290. isTransform = _isTransform()
  291. isColor = _isColor()
  292. isListOfColors = SequenceOf(isColor,'isListOfColors')
  293. isColorOrNone = _isColorOrNone()
  294. isShape = isValidChild = _isValidChild()
  295. isNoneOrShape = isValidChildOrNone = _isValidChildOrNone()
  296. isAnything = _isAnything()
  297. isNothing = _isNothing()
  298. isXYCoord = SequenceOf(isNumber,lo=2,hi=2,emptyOK=0)
  299. isBoxAnchor = OneOf('nw','n','ne','w','c','e','sw','s','se', 'autox', 'autoy')
  300. isNoneOrString = NoneOr(isString,'NoneOrString')
  301. isNoneOrListOfNoneOrStrings=SequenceOf(isNoneOrString,'isNoneOrListOfNoneOrStrings',NoneOK=1)
  302. isListOfNoneOrString=SequenceOf(isNoneOrString,'isListOfNoneOrString',NoneOK=0)
  303. isNoneOrListOfNoneOrNumbers=SequenceOf(isNumberOrNone,'isNoneOrListOfNoneOrNumbers',NoneOK=1)
  304. isCallable = _isCallable()
  305. isNoneOrCallable = NoneOr(isCallable)
  306. isStringOrCallable=EitherOr((isString,isCallable),'isStringOrCallable')
  307. isStringOrCallableOrNone=NoneOr(isStringOrCallable,'isStringOrCallableNone')
  308. isStringOrNone=NoneOr(isString,'isStringOrNone')
  309. isNormalDate=_isNormalDate()
  310. isNotSet=_isNotSet()