PageRenderTime 30ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/django-1.5/django/core/validators.py

https://github.com/theosp/google_appengine
Python | 197 lines | 164 code | 25 blank | 8 comment | 12 complexity | 0c4e250d1a4f72b52c1db2d34dfc55d0 MD5 | raw file
  1. from __future__ import unicode_literals
  2. import re
  3. try:
  4. from urllib.parse import urlsplit, urlunsplit
  5. except ImportError: # Python 2
  6. from urlparse import urlsplit, urlunsplit
  7. from django.core.exceptions import ValidationError
  8. from django.utils.translation import ugettext_lazy as _
  9. from django.utils.encoding import force_text
  10. from django.utils.ipv6 import is_valid_ipv6_address
  11. from django.utils import six
  12. # These values, if given to validate(), will trigger the self.required check.
  13. EMPTY_VALUES = (None, '', [], (), {})
  14. class RegexValidator(object):
  15. regex = ''
  16. message = _('Enter a valid value.')
  17. code = 'invalid'
  18. def __init__(self, regex=None, message=None, code=None):
  19. if regex is not None:
  20. self.regex = regex
  21. if message is not None:
  22. self.message = message
  23. if code is not None:
  24. self.code = code
  25. # Compile the regex if it was not passed pre-compiled.
  26. if isinstance(self.regex, six.string_types):
  27. self.regex = re.compile(self.regex)
  28. def __call__(self, value):
  29. """
  30. Validates that the input matches the regular expression.
  31. """
  32. if not self.regex.search(force_text(value)):
  33. raise ValidationError(self.message, code=self.code)
  34. class URLValidator(RegexValidator):
  35. regex = re.compile(
  36. r'^(?:http|ftp)s?://' # http:// or https://
  37. r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
  38. r'localhost|' # localhost...
  39. r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
  40. r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
  41. r'(?::\d+)?' # optional port
  42. r'(?:/?|[/?]\S+)$', re.IGNORECASE)
  43. def __call__(self, value):
  44. try:
  45. super(URLValidator, self).__call__(value)
  46. except ValidationError as e:
  47. # Trivial case failed. Try for possible IDN domain
  48. if value:
  49. value = force_text(value)
  50. scheme, netloc, path, query, fragment = urlsplit(value)
  51. try:
  52. netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
  53. except UnicodeError: # invalid domain part
  54. raise e
  55. url = urlunsplit((scheme, netloc, path, query, fragment))
  56. super(URLValidator, self).__call__(url)
  57. else:
  58. raise
  59. else:
  60. url = value
  61. def validate_integer(value):
  62. try:
  63. int(value)
  64. except (ValueError, TypeError):
  65. raise ValidationError('')
  66. class EmailValidator(RegexValidator):
  67. def __call__(self, value):
  68. try:
  69. super(EmailValidator, self).__call__(value)
  70. except ValidationError as e:
  71. # Trivial case failed. Try for possible IDN domain-part
  72. if value and '@' in value:
  73. parts = value.split('@')
  74. try:
  75. parts[-1] = parts[-1].encode('idna').decode('ascii')
  76. except UnicodeError:
  77. raise e
  78. super(EmailValidator, self).__call__('@'.join(parts))
  79. else:
  80. raise
  81. email_re = re.compile(
  82. r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
  83. # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5
  84. r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"'
  85. r')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)$)' # domain
  86. r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3)
  87. validate_email = EmailValidator(email_re, _('Enter a valid email address.'), 'invalid')
  88. slug_re = re.compile(r'^[-a-zA-Z0-9_]+$')
  89. validate_slug = RegexValidator(slug_re, _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
  90. ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
  91. validate_ipv4_address = RegexValidator(ipv4_re, _('Enter a valid IPv4 address.'), 'invalid')
  92. def validate_ipv6_address(value):
  93. if not is_valid_ipv6_address(value):
  94. raise ValidationError(_('Enter a valid IPv6 address.'), code='invalid')
  95. def validate_ipv46_address(value):
  96. try:
  97. validate_ipv4_address(value)
  98. except ValidationError:
  99. try:
  100. validate_ipv6_address(value)
  101. except ValidationError:
  102. raise ValidationError(_('Enter a valid IPv4 or IPv6 address.'), code='invalid')
  103. ip_address_validator_map = {
  104. 'both': ([validate_ipv46_address], _('Enter a valid IPv4 or IPv6 address.')),
  105. 'ipv4': ([validate_ipv4_address], _('Enter a valid IPv4 address.')),
  106. 'ipv6': ([validate_ipv6_address], _('Enter a valid IPv6 address.')),
  107. }
  108. def ip_address_validators(protocol, unpack_ipv4):
  109. """
  110. Depending on the given parameters returns the appropriate validators for
  111. the GenericIPAddressField.
  112. This code is here, because it is exactly the same for the model and the form field.
  113. """
  114. if protocol != 'both' and unpack_ipv4:
  115. raise ValueError(
  116. "You can only use `unpack_ipv4` if `protocol` is set to 'both'")
  117. try:
  118. return ip_address_validator_map[protocol.lower()]
  119. except KeyError:
  120. raise ValueError("The protocol '%s' is unknown. Supported: %s"
  121. % (protocol, list(ip_address_validator_map)))
  122. comma_separated_int_list_re = re.compile('^[\d,]+$')
  123. validate_comma_separated_integer_list = RegexValidator(comma_separated_int_list_re, _('Enter only digits separated by commas.'), 'invalid')
  124. class BaseValidator(object):
  125. compare = lambda self, a, b: a is not b
  126. clean = lambda self, x: x
  127. message = _('Ensure this value is %(limit_value)s (it is %(show_value)s).')
  128. code = 'limit_value'
  129. def __init__(self, limit_value):
  130. self.limit_value = limit_value
  131. def __call__(self, value):
  132. cleaned = self.clean(value)
  133. params = {'limit_value': self.limit_value, 'show_value': cleaned}
  134. if self.compare(cleaned, self.limit_value):
  135. raise ValidationError(
  136. self.message % params,
  137. code=self.code,
  138. params=params,
  139. )
  140. class MaxValueValidator(BaseValidator):
  141. compare = lambda self, a, b: a > b
  142. message = _('Ensure this value is less than or equal to %(limit_value)s.')
  143. code = 'max_value'
  144. class MinValueValidator(BaseValidator):
  145. compare = lambda self, a, b: a < b
  146. message = _('Ensure this value is greater than or equal to %(limit_value)s.')
  147. code = 'min_value'
  148. class MinLengthValidator(BaseValidator):
  149. compare = lambda self, a, b: a < b
  150. clean = lambda self, x: len(x)
  151. message = _('Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).')
  152. code = 'min_length'
  153. class MaxLengthValidator(BaseValidator):
  154. compare = lambda self, a, b: a > b
  155. clean = lambda self, x: len(x)
  156. message = _('Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).')
  157. code = 'max_length'