validate.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. # -*- coding: utf-8 -*-
  2. """Validation classes for various types of data."""
  3. from __future__ import unicode_literals
  4. import re
  5. from operator import attrgetter
  6. from marshmallow.compat import basestring, text_type, zip_longest
  7. from marshmallow.exceptions import ValidationError
  8. class Validator(object):
  9. """Base abstract class for validators.
  10. .. note::
  11. This class does not provide any behavior. It is only used to
  12. add a useful `__repr__` implementation for validators.
  13. """
  14. def __repr__(self):
  15. args = self._repr_args()
  16. args = '{0}, '.format(args) if args else ''
  17. return (
  18. '<{self.__class__.__name__}({args}error={self.error!r})>'
  19. .format(self=self, args=args)
  20. )
  21. def _repr_args(self):
  22. """A string representation of the args passed to this validator. Used by
  23. `__repr__`.
  24. """
  25. return ''
  26. class URL(Validator):
  27. """Validate a URL.
  28. :param bool relative: Whether to allow relative URLs.
  29. :param str error: Error message to raise in case of a validation error.
  30. Can be interpolated with `{input}`.
  31. :param set schemes: Valid schemes. By default, ``http``, ``https``,
  32. ``ftp``, and ``ftps`` are allowed.
  33. :param bool require_tld: Whether to reject non-FQDN hostnames
  34. """
  35. class RegexMemoizer(object):
  36. def __init__(self):
  37. self._memoized = {}
  38. def _regex_generator(self, relative, require_tld):
  39. return re.compile(
  40. r''.join((
  41. r'^',
  42. r'(' if relative else r'',
  43. r'(?:[a-z0-9\.\-\+]*)://', # scheme is validated separately
  44. r'(?:[^:@]+?(:[^:@]*?)?@|)', # basic auth
  45. r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+',
  46. r'(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|', # domain...
  47. r'localhost|', # localhost...
  48. (
  49. r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.?)|'
  50. if not require_tld else r''
  51. ), # allow dotless hostnames
  52. r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|', # ...or ipv4
  53. r'\[[A-F0-9]*:[A-F0-9:]+\])', # ...or ipv6
  54. r'(?::\d+)?', # optional port
  55. r')?' if relative else r'', # host is optional, allow for relative URLs
  56. r'(?:/?|[/?]\S+)$',
  57. )), re.IGNORECASE,
  58. )
  59. def __call__(self, relative, require_tld):
  60. key = (relative, require_tld)
  61. if key not in self._memoized:
  62. self._memoized[key] = self._regex_generator(relative, require_tld)
  63. return self._memoized[key]
  64. _regex = RegexMemoizer()
  65. default_message = 'Not a valid URL.'
  66. default_schemes = set(['http', 'https', 'ftp', 'ftps'])
  67. # TODO; Switch position of `error` and `schemes` in 3.0
  68. def __init__(self, relative=False, error=None, schemes=None, require_tld=True):
  69. self.relative = relative
  70. self.error = error or self.default_message
  71. self.schemes = schemes or self.default_schemes
  72. self.require_tld = require_tld
  73. def _repr_args(self):
  74. return 'relative={0!r}'.format(self.relative)
  75. def _format_error(self, value):
  76. return self.error.format(input=value)
  77. def __call__(self, value):
  78. message = self._format_error(value)
  79. if not value:
  80. raise ValidationError(message)
  81. # Check first if the scheme is valid
  82. if '://' in value:
  83. scheme = value.split('://')[0].lower()
  84. if scheme not in self.schemes:
  85. raise ValidationError(message)
  86. regex = self._regex(self.relative, self.require_tld)
  87. if not regex.search(value):
  88. raise ValidationError(message)
  89. return value
  90. class Email(Validator):
  91. """Validate an email address.
  92. :param str error: Error message to raise in case of a validation error. Can be
  93. interpolated with `{input}`.
  94. """
  95. USER_REGEX = re.compile(
  96. r"(^[-!#$%&'*+/=?^`{}|~\w]+(\.[-!#$%&'*+/=?^`{}|~\w]+)*$" # dot-atom
  97. # quoted-string
  98. r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]'
  99. r'|\\[\001-\011\013\014\016-\177])*"$)', re.IGNORECASE | re.UNICODE,
  100. )
  101. DOMAIN_REGEX = re.compile(
  102. # domain
  103. r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+'
  104. r'(?:[A-Z]{2,6}|[A-Z0-9-]{2,})$'
  105. # literal form, ipv4 address (SMTP 4.1.3)
  106. r'|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)'
  107. r'(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE | re.UNICODE,
  108. )
  109. DOMAIN_WHITELIST = ('localhost',)
  110. default_message = 'Not a valid email address.'
  111. def __init__(self, error=None):
  112. self.error = error or self.default_message
  113. def _format_error(self, value):
  114. return self.error.format(input=value)
  115. def __call__(self, value):
  116. message = self._format_error(value)
  117. if not value or '@' not in value:
  118. raise ValidationError(message)
  119. user_part, domain_part = value.rsplit('@', 1)
  120. if not self.USER_REGEX.match(user_part):
  121. raise ValidationError(message)
  122. if domain_part not in self.DOMAIN_WHITELIST:
  123. if not self.DOMAIN_REGEX.match(domain_part):
  124. try:
  125. domain_part = domain_part.encode('idna').decode('ascii')
  126. except UnicodeError:
  127. pass
  128. else:
  129. if self.DOMAIN_REGEX.match(domain_part):
  130. return value
  131. raise ValidationError(message)
  132. return value
  133. class Range(Validator):
  134. """Validator which succeeds if the value it is passed is greater
  135. or equal to ``min`` and less than or equal to ``max``. If ``min``
  136. is not specified, or is specified as `None`, no lower bound
  137. exists. If ``max`` is not specified, or is specified as `None`,
  138. no upper bound exists.
  139. :param min: The minimum value (lower bound). If not provided, minimum
  140. value will not be checked.
  141. :param max: The maximum value (upper bound). If not provided, maximum
  142. value will not be checked.
  143. :param str error: Error message to raise in case of a validation error.
  144. Can be interpolated with `{input}`, `{min}` and `{max}`.
  145. """
  146. message_min = 'Must be at least {min}.'
  147. message_max = 'Must be at most {max}.'
  148. message_all = 'Must be between {min} and {max}.'
  149. def __init__(self, min=None, max=None, error=None):
  150. self.min = min
  151. self.max = max
  152. self.error = error
  153. def _repr_args(self):
  154. return 'min={0!r}, max={1!r}'.format(self.min, self.max)
  155. def _format_error(self, value, message):
  156. return (self.error or message).format(input=value, min=self.min, max=self.max)
  157. def __call__(self, value):
  158. if self.min is not None and value < self.min:
  159. message = self.message_min if self.max is None else self.message_all
  160. raise ValidationError(self._format_error(value, message))
  161. if self.max is not None and value > self.max:
  162. message = self.message_max if self.min is None else self.message_all
  163. raise ValidationError(self._format_error(value, message))
  164. return value
  165. class Length(Validator):
  166. """Validator which succeeds if the value passed to it has a
  167. length between a minimum and maximum. Uses len(), so it
  168. can work for strings, lists, or anything with length.
  169. :param int min: The minimum length. If not provided, minimum length
  170. will not be checked.
  171. :param int max: The maximum length. If not provided, maximum length
  172. will not be checked.
  173. :param int equal: The exact length. If provided, maximum and minimum
  174. length will not be checked.
  175. :param str error: Error message to raise in case of a validation error.
  176. Can be interpolated with `{input}`, `{min}` and `{max}`.
  177. """
  178. message_min = 'Shorter than minimum length {min}.'
  179. message_max = 'Longer than maximum length {max}.'
  180. message_all = 'Length must be between {min} and {max}.'
  181. message_equal = 'Length must be {equal}.'
  182. def __init__(self, min=None, max=None, error=None, equal=None):
  183. if equal is not None and any([min, max]):
  184. raise ValueError(
  185. 'The `equal` parameter was provided, maximum or '
  186. 'minimum parameter must not be provided.',
  187. )
  188. self.min = min
  189. self.max = max
  190. self.error = error
  191. self.equal = equal
  192. def _repr_args(self):
  193. return 'min={0!r}, max={1!r}, equal={2!r}'.format(self.min, self.max, self.equal)
  194. def _format_error(self, value, message):
  195. return (self.error or message).format(
  196. input=value, min=self.min, max=self.max,
  197. equal=self.equal,
  198. )
  199. def __call__(self, value):
  200. length = len(value)
  201. if self.equal is not None:
  202. if length != self.equal:
  203. raise ValidationError(self._format_error(value, self.message_equal))
  204. return value
  205. if self.min is not None and length < self.min:
  206. message = self.message_min if self.max is None else self.message_all
  207. raise ValidationError(self._format_error(value, message))
  208. if self.max is not None and length > self.max:
  209. message = self.message_max if self.min is None else self.message_all
  210. raise ValidationError(self._format_error(value, message))
  211. return value
  212. class Equal(Validator):
  213. """Validator which succeeds if the ``value`` passed to it is
  214. equal to ``comparable``.
  215. :param comparable: The object to compare to.
  216. :param str error: Error message to raise in case of a validation error.
  217. Can be interpolated with `{input}` and `{other}`.
  218. """
  219. default_message = 'Must be equal to {other}.'
  220. def __init__(self, comparable, error=None):
  221. self.comparable = comparable
  222. self.error = error or self.default_message
  223. def _repr_args(self):
  224. return 'comparable={0!r}'.format(self.comparable)
  225. def _format_error(self, value):
  226. return self.error.format(input=value, other=self.comparable)
  227. def __call__(self, value):
  228. if value != self.comparable:
  229. raise ValidationError(self._format_error(value))
  230. return value
  231. class Regexp(Validator):
  232. """Validate ``value`` against the provided regex.
  233. :param regex: The regular expression string to use. Can also be a compiled
  234. regular expression pattern.
  235. :param flags: The regexp flags to use, for example re.IGNORECASE. Ignored
  236. if ``regex`` is not a string.
  237. :param str error: Error message to raise in case of a validation error.
  238. Can be interpolated with `{input}` and `{regex}`.
  239. """
  240. default_message = 'String does not match expected pattern.'
  241. def __init__(self, regex, flags=0, error=None):
  242. self.regex = re.compile(regex, flags) if isinstance(regex, basestring) else regex
  243. self.error = error or self.default_message
  244. def _repr_args(self):
  245. return 'regex={0!r}'.format(self.regex)
  246. def _format_error(self, value):
  247. return self.error.format(input=value, regex=self.regex.pattern)
  248. def __call__(self, value):
  249. if self.regex.match(value) is None:
  250. raise ValidationError(self._format_error(value))
  251. return value
  252. class Predicate(Validator):
  253. """Call the specified ``method`` of the ``value`` object. The
  254. validator succeeds if the invoked method returns an object that
  255. evaluates to True in a Boolean context. Any additional keyword
  256. argument will be passed to the method.
  257. :param str method: The name of the method to invoke.
  258. :param str error: Error message to raise in case of a validation error.
  259. Can be interpolated with `{input}` and `{method}`.
  260. :param kwargs: Additional keyword arguments to pass to the method.
  261. """
  262. default_message = 'Invalid input.'
  263. def __init__(self, method, error=None, **kwargs):
  264. self.method = method
  265. self.error = error or self.default_message
  266. self.kwargs = kwargs
  267. def _repr_args(self):
  268. return 'method={0!r}, kwargs={1!r}'.format(self.method, self.kwargs)
  269. def _format_error(self, value):
  270. return self.error.format(input=value, method=self.method)
  271. def __call__(self, value):
  272. method = getattr(value, self.method)
  273. if not method(**self.kwargs):
  274. raise ValidationError(self._format_error(value))
  275. return value
  276. class NoneOf(Validator):
  277. """Validator which fails if ``value`` is a member of ``iterable``.
  278. :param iterable iterable: A sequence of invalid values.
  279. :param str error: Error message to raise in case of a validation error. Can be
  280. interpolated using `{input}` and `{values}`.
  281. """
  282. default_message = 'Invalid input.'
  283. def __init__(self, iterable, error=None):
  284. self.iterable = iterable
  285. self.values_text = ', '.join(text_type(each) for each in self.iterable)
  286. self.error = error or self.default_message
  287. def _repr_args(self):
  288. return 'iterable={0!r}'.format(self.iterable)
  289. def _format_error(self, value):
  290. return self.error.format(
  291. input=value,
  292. values=self.values_text,
  293. )
  294. def __call__(self, value):
  295. try:
  296. if value in self.iterable:
  297. raise ValidationError(self._format_error(value))
  298. except TypeError:
  299. pass
  300. return value
  301. class OneOf(Validator):
  302. """Validator which succeeds if ``value`` is a member of ``choices``.
  303. :param iterable choices: A sequence of valid values.
  304. :param iterable labels: Optional sequence of labels to pair with the choices.
  305. :param str error: Error message to raise in case of a validation error. Can be
  306. interpolated with `{input}`, `{choices}` and `{labels}`.
  307. """
  308. default_message = 'Must be one of: {choices}.'
  309. def __init__(self, choices, labels=None, error=None):
  310. self.choices = choices
  311. self.choices_text = ', '.join(text_type(choice) for choice in self.choices)
  312. self.labels = labels if labels is not None else []
  313. self.labels_text = ', '.join(text_type(label) for label in self.labels)
  314. self.error = error or self.default_message
  315. def _repr_args(self):
  316. return 'choices={0!r}, labels={1!r}'.format(self.choices, self.labels)
  317. def _format_error(self, value):
  318. return self.error.format(
  319. input=value,
  320. choices=self.choices_text,
  321. labels=self.labels_text,
  322. )
  323. def __call__(self, value):
  324. try:
  325. if value not in self.choices:
  326. raise ValidationError(self._format_error(value))
  327. except TypeError:
  328. raise ValidationError(self._format_error(value))
  329. return value
  330. def options(self, valuegetter=text_type):
  331. """Return a generator over the (value, label) pairs, where value
  332. is a string associated with each choice. This convenience method
  333. is useful to populate, for instance, a form select field.
  334. :param valuegetter: Can be a callable or a string. In the former case, it must
  335. be a one-argument callable which returns the value of a
  336. choice. In the latter case, the string specifies the name
  337. of an attribute of the choice objects. Defaults to `str()`
  338. or `unicode()`.
  339. """
  340. valuegetter = valuegetter if callable(valuegetter) else attrgetter(valuegetter)
  341. pairs = zip_longest(self.choices, self.labels, fillvalue='')
  342. return ((valuegetter(choice), label) for choice, label in pairs)
  343. class ContainsOnly(OneOf):
  344. """Validator which succeeds if ``value`` is a sequence and each element
  345. in the sequence is also in the sequence passed as ``choices``. Empty input
  346. is considered valid.
  347. :param iterable choices: Same as :class:`OneOf`.
  348. :param iterable labels: Same as :class:`OneOf`.
  349. :param str error: Same as :class:`OneOf`.
  350. .. versionchanged:: 3.0.0b2
  351. Duplicate values are considered valid.
  352. .. versionchanged:: 3.0.0b2
  353. Empty input is considered valid. Use `validate.Length(min=1) <marshmallow.validate.Length>`
  354. to validate against empty inputs.
  355. """
  356. default_message = 'One or more of the choices you made was not in: {choices}.'
  357. def _format_error(self, value):
  358. value_text = ', '.join(text_type(val) for val in value)
  359. return super(ContainsOnly, self)._format_error(value_text)
  360. def __call__(self, value):
  361. # We can't use set.issubset because does not handle unhashable types
  362. for val in value:
  363. if val not in self.choices:
  364. raise ValidationError(self._format_error(value))
  365. return value