summaryrefslogtreecommitdiff
path: root/django/core/validators.py
diff options
context:
space:
mode:
authorJustin Bronn <jbronn@gmail.com>2007-08-26 01:10:53 +0000
committerJustin Bronn <jbronn@gmail.com>2007-08-26 01:10:53 +0000
commit2052b508eb92c62fc0678efd4936c5ec1e0e735b (patch)
treee510109b74b28c8ccef5f6955727cb9dce3da655 /django/core/validators.py
parenta7297a255f4bb86f608ea251e00253d18c31d9d4 (diff)
gis: Made necessary modifications for unicode, manage refactor, backend refactor and merged 5584-6000 via svnmerge from [repos:django/trunk trunk].
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6018 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/core/validators.py')
-rw-r--r--django/core/validators.py144
1 files changed, 76 insertions, 68 deletions
diff --git a/django/core/validators.py b/django/core/validators.py
index 293f0e1a8c..8a93462b21 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -10,9 +10,14 @@ form field is required.
import urllib2
from django.conf import settings
-from django.utils.translation import gettext, gettext_lazy, ngettext
+from django.utils.translation import ugettext as _, ugettext_lazy, ungettext
from django.utils.functional import Promise, lazy
+from django.utils.encoding import force_unicode
import re
+try:
+ from decimal import Decimal, DecimalException
+except ImportError:
+ from django.utils._decimal import Decimal, DecimalException # Python 2.3
_datere = r'\d{4}-\d{1,2}-\d{1,2}'
_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?'
@@ -23,25 +28,25 @@ ansi_time_re = re.compile('^%s$' % _timere)
ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))
email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
- r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
+ r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
-decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
integer_re = re.compile(r'^-?\d+$')
ip4_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}$')
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
slug_re = re.compile(r'^[-\w]+$')
url_re = re.compile(r'^https?://\S+$')
-lazy_inter = lazy(lambda a,b: str(a) % b, str)
+lazy_inter = lazy(lambda a,b: force_unicode(a) % b, unicode)
class ValidationError(Exception):
def __init__(self, message):
"ValidationError can be passed a string or a list."
if isinstance(message, list):
- self.messages = message
+ self.messages = [force_unicode(msg) for msg in message]
else:
assert isinstance(message, (basestring, Promise)), ("%s should be a string" % repr(message))
- self.messages = [message]
+ self.messages = [force_unicode(message)]
+
def __str__(self):
# This is needed because, without a __str__(), printing an exception
# instance would result in this:
@@ -53,39 +58,40 @@ class CriticalValidationError(Exception):
def __init__(self, message):
"ValidationError can be passed a string or a list."
if isinstance(message, list):
- self.messages = message
+ self.messages = [force_unicode(msg) for msg in message]
else:
assert isinstance(message, (basestring, Promise)), ("'%s' should be a string" % message)
- self.messages = [message]
+ self.messages = [force_unicode(message)]
+
def __str__(self):
return str(self.messages)
def isAlphaNumeric(field_data, all_data):
if not alnum_re.search(field_data):
- raise ValidationError, gettext("This value must contain only letters, numbers and underscores.")
+ raise ValidationError, _("This value must contain only letters, numbers and underscores.")
def isAlphaNumericURL(field_data, all_data):
if not alnumurl_re.search(field_data):
- raise ValidationError, gettext("This value must contain only letters, numbers, underscores, dashes or slashes.")
+ raise ValidationError, _("This value must contain only letters, numbers, underscores, dashes or slashes.")
def isSlug(field_data, all_data):
if not slug_re.search(field_data):
- raise ValidationError, gettext("This value must contain only letters, numbers, underscores or hyphens.")
+ raise ValidationError, _("This value must contain only letters, numbers, underscores or hyphens.")
def isLowerCase(field_data, all_data):
if field_data.lower() != field_data:
- raise ValidationError, gettext("Uppercase letters are not allowed here.")
+ raise ValidationError, _("Uppercase letters are not allowed here.")
def isUpperCase(field_data, all_data):
if field_data.upper() != field_data:
- raise ValidationError, gettext("Lowercase letters are not allowed here.")
+ raise ValidationError, _("Lowercase letters are not allowed here.")
def isCommaSeparatedIntegerList(field_data, all_data):
for supposed_int in field_data.split(','):
try:
int(supposed_int)
except ValueError:
- raise ValidationError, gettext("Enter only digits separated by commas.")
+ raise ValidationError, _("Enter only digits separated by commas.")
def isCommaSeparatedEmailList(field_data, all_data):
"""
@@ -97,32 +103,32 @@ def isCommaSeparatedEmailList(field_data, all_data):
try:
isValidEmail(supposed_email.strip(), '')
except ValidationError:
- raise ValidationError, gettext("Enter valid e-mail addresses separated by commas.")
+ raise ValidationError, _("Enter valid e-mail addresses separated by commas.")
def isValidIPAddress4(field_data, all_data):
if not ip4_re.search(field_data):
- raise ValidationError, gettext("Please enter a valid IP address.")
+ raise ValidationError, _("Please enter a valid IP address.")
def isNotEmpty(field_data, all_data):
if field_data.strip() == '':
- raise ValidationError, gettext("Empty values are not allowed here.")
+ raise ValidationError, _("Empty values are not allowed here.")
def isOnlyDigits(field_data, all_data):
if not field_data.isdigit():
- raise ValidationError, gettext("Non-numeric characters aren't allowed here.")
+ raise ValidationError, _("Non-numeric characters aren't allowed here.")
def isNotOnlyDigits(field_data, all_data):
if field_data.isdigit():
- raise ValidationError, gettext("This value can't be comprised solely of digits.")
+ raise ValidationError, _("This value can't be comprised solely of digits.")
def isInteger(field_data, all_data):
# This differs from isOnlyDigits because this accepts the negative sign
if not integer_re.search(field_data):
- raise ValidationError, gettext("Enter a whole number.")
+ raise ValidationError, _("Enter a whole number.")
def isOnlyLetters(field_data, all_data):
if not field_data.isalpha():
- raise ValidationError, gettext("Only alphabetical characters are allowed here.")
+ raise ValidationError, _("Only alphabetical characters are allowed here.")
def _isValidDate(date_string):
"""
@@ -137,30 +143,30 @@ def _isValidDate(date_string):
# This check is needed because strftime is used when saving the date
# value to the database, and strftime requires that the year be >=1900.
if year < 1900:
- raise ValidationError, gettext('Year must be 1900 or later.')
+ raise ValidationError, _('Year must be 1900 or later.')
try:
date(year, month, day)
except ValueError, e:
- msg = gettext('Invalid date: %s') % gettext(str(e))
+ msg = _('Invalid date: %s') % _(str(e))
raise ValidationError, msg
def isValidANSIDate(field_data, all_data):
if not ansi_date_re.search(field_data):
- raise ValidationError, gettext('Enter a valid date in YYYY-MM-DD format.')
+ raise ValidationError, _('Enter a valid date in YYYY-MM-DD format.')
_isValidDate(field_data)
def isValidANSITime(field_data, all_data):
if not ansi_time_re.search(field_data):
- raise ValidationError, gettext('Enter a valid time in HH:MM format.')
+ raise ValidationError, _('Enter a valid time in HH:MM format.')
def isValidANSIDatetime(field_data, all_data):
if not ansi_datetime_re.search(field_data):
- raise ValidationError, gettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
+ raise ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
_isValidDate(field_data.split()[0])
def isValidEmail(field_data, all_data):
if not email_re.search(field_data):
- raise ValidationError, gettext('Enter a valid e-mail address.')
+ raise ValidationError, _('Enter a valid e-mail address.')
def isValidImage(field_data, all_data):
"""
@@ -172,22 +178,22 @@ def isValidImage(field_data, all_data):
try:
content = field_data['content']
except TypeError:
- raise ValidationError, gettext("No file was submitted. Check the encoding type on the form.")
+ raise ValidationError, _("No file was submitted. Check the encoding type on the form.")
try:
Image.open(StringIO(content))
except IOError: # Python Imaging Library doesn't recognize it as an image
- raise ValidationError, gettext("Upload a valid image. The file you uploaded was either not an image or a corrupted image.")
+ raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.")
def isValidImageURL(field_data, all_data):
uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png'))
try:
uc(field_data, all_data)
except URLMimeTypeCheck.InvalidContentType:
- raise ValidationError, gettext("The URL %s does not point to a valid image.") % field_data
+ raise ValidationError, _("The URL %s does not point to a valid image.") % field_data
def isValidPhone(field_data, all_data):
if not phone_re.search(field_data):
- raise ValidationError, gettext('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data
+ raise ValidationError, _('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data
def isValidQuicktimeVideoURL(field_data, all_data):
"Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)"
@@ -195,11 +201,11 @@ def isValidQuicktimeVideoURL(field_data, all_data):
try:
uc(field_data, all_data)
except URLMimeTypeCheck.InvalidContentType:
- raise ValidationError, gettext("The URL %s does not point to a valid QuickTime video.") % field_data
+ raise ValidationError, _("The URL %s does not point to a valid QuickTime video.") % field_data
def isValidURL(field_data, all_data):
if not url_re.search(field_data):
- raise ValidationError, gettext("A valid URL is required.")
+ raise ValidationError, _("A valid URL is required.")
def isValidHTML(field_data, all_data):
import urllib, urllib2
@@ -213,14 +219,14 @@ def isValidHTML(field_data, all_data):
return
from xml.dom.minidom import parseString
error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')]
- raise ValidationError, gettext("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages)
+ raise ValidationError, _("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages)
def isWellFormedXml(field_data, all_data):
from xml.dom.minidom import parseString
try:
parseString(field_data)
except Exception, e: # Naked except because we're not sure what will be thrown
- raise ValidationError, gettext("Badly formed XML: %s") % str(e)
+ raise ValidationError, _("Badly formed XML: %s") % str(e)
def isWellFormedXmlFragment(field_data, all_data):
isWellFormedXml('<root>%s</root>' % field_data, all_data)
@@ -250,7 +256,7 @@ def isValidUSState(field_data, all_data):
"Checks that the given string is a valid two-letter U.S. state abbreviation"
states = ['AA', 'AE', 'AK', 'AL', 'AP', 'AR', 'AS', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'FM', 'GA', 'GU', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MH', 'MI', 'MN', 'MO', 'MP', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'PR', 'PW', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VI', 'VT', 'WA', 'WI', 'WV', 'WY']
if field_data.upper() not in states:
- raise ValidationError, gettext("Enter a valid U.S. state abbreviation.")
+ raise ValidationError, _("Enter a valid U.S. state abbreviation.")
def hasNoProfanities(field_data, all_data):
"""
@@ -263,15 +269,15 @@ def hasNoProfanities(field_data, all_data):
words_seen = [w for w in settings.PROFANITIES_LIST if w in field_data]
if words_seen:
from django.utils.text import get_text_list
- plural = len(words_seen) > 1
- raise ValidationError, ngettext("Watch your mouth! The word %s is not allowed here.",
+ plural = len(words_seen)
+ raise ValidationError, ungettext("Watch your mouth! The word %s is not allowed here.",
"Watch your mouth! The words %s are not allowed here.", plural) % \
- get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], 'and')
+ get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], _('and'))
class AlwaysMatchesOtherField(object):
def __init__(self, other_field_name, error_message=None):
self.other = other_field_name
- self.error_message = error_message or lazy_inter(gettext_lazy("This field must match the '%s' field."), self.other)
+ self.error_message = error_message or lazy_inter(ugettext_lazy("This field must match the '%s' field."), self.other)
self.always_test = True
def __call__(self, field_data, all_data):
@@ -290,7 +296,7 @@ class ValidateIfOtherFieldEquals(object):
v(field_data, all_data)
class RequiredIfOtherFieldNotGiven(object):
- def __init__(self, other_field_name, error_message=gettext_lazy("Please enter something for at least one field.")):
+ def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter something for at least one field.")):
self.other, self.error_message = other_field_name, error_message
self.always_test = True
@@ -299,7 +305,7 @@ class RequiredIfOtherFieldNotGiven(object):
raise ValidationError, self.error_message
class RequiredIfOtherFieldsGiven(object):
- def __init__(self, other_field_names, error_message=gettext_lazy("Please enter both fields or leave them both empty.")):
+ def __init__(self, other_field_names, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")):
self.other, self.error_message = other_field_names, error_message
self.always_test = True
@@ -310,7 +316,7 @@ class RequiredIfOtherFieldsGiven(object):
class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven):
"Like RequiredIfOtherFieldsGiven, but takes a single field name instead of a list."
- def __init__(self, other_field_name, error_message=gettext_lazy("Please enter both fields or leave them both empty.")):
+ def __init__(self, other_field_name, error_message=ugettext_lazy("Please enter both fields or leave them both empty.")):
RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message)
class RequiredIfOtherFieldEquals(object):
@@ -318,7 +324,7 @@ class RequiredIfOtherFieldEquals(object):
self.other_field = other_field
self.other_value = other_value
other_label = other_label or other_value
- self.error_message = error_message or lazy_inter(gettext_lazy("This field must be given if %(field)s is %(value)s"), {
+ self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is %(value)s"), {
'field': other_field, 'value': other_label})
self.always_test = True
@@ -331,7 +337,7 @@ class RequiredIfOtherFieldDoesNotEqual(object):
self.other_field = other_field
self.other_value = other_value
other_label = other_label or other_value
- self.error_message = error_message or lazy_inter(gettext_lazy("This field must be given if %(field)s is not %(value)s"), {
+ self.error_message = error_message or lazy_inter(ugettext_lazy("This field must be given if %(field)s is not %(value)s"), {
'field': other_field, 'value': other_label})
self.always_test = True
@@ -350,7 +356,7 @@ class IsLessThanOtherField(object):
class UniqueAmongstFieldsWithPrefix(object):
def __init__(self, field_name, prefix, error_message):
self.field_name, self.prefix = field_name, prefix
- self.error_message = error_message or gettext_lazy("Duplicate values are not allowed.")
+ self.error_message = error_message or ugettext_lazy("Duplicate values are not allowed.")
def __call__(self, field_data, all_data):
for field_name, value in all_data.items():
@@ -365,11 +371,11 @@ class NumberIsInRange(object):
self.lower, self.upper = lower, upper
if not error_message:
if lower and upper:
- self.error_message = gettext("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper}
+ self.error_message = _("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper}
elif lower:
- self.error_message = gettext("This value must be at least %s.") % lower
+ self.error_message = _("This value must be at least %s.") % lower
elif upper:
- self.error_message = gettext("This value must be no more than %s.") % upper
+ self.error_message = _("This value must be no more than %s.") % upper
else:
self.error_message = error_message
@@ -405,28 +411,30 @@ class IsAPowerOf(object):
from math import log
val = log(int(field_data)) / log(self.power_of)
if val != int(val):
- raise ValidationError, gettext("This value must be a power of %s.") % self.power_of
+ raise ValidationError, _("This value must be a power of %s.") % self.power_of
class IsValidDecimal(object):
def __init__(self, max_digits, decimal_places):
self.max_digits, self.decimal_places = max_digits, decimal_places
def __call__(self, field_data, all_data):
- match = decimal_re.search(str(field_data))
- if not match:
- raise ValidationError, gettext("Please enter a valid decimal number.")
-
- digits = len(match.group('digits') or '')
- decimals = len(match.group('decimals') or '')
-
+ try:
+ val = Decimal(field_data)
+ except DecimalException:
+ raise ValidationError, _("Please enter a valid decimal number.")
+
+ pieces = str(val).split('.')
+ decimals = (len(pieces) == 2) and len(pieces[1]) or 0
+ digits = len(pieces[0])
+
if digits + decimals > self.max_digits:
- raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.",
+ raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.",
"Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits
if digits > (self.max_digits - self.decimal_places):
- raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
+ raise ValidationError, ungettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
"Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places)
if decimals > self.decimal_places:
- raise ValidationError, ngettext("Please enter a valid decimal number with at most %s decimal place.",
+ raise ValidationError, ungettext("Please enter a valid decimal number with at most %s decimal place.",
"Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places
def isValidFloat(field_data, all_data):
@@ -434,7 +442,7 @@ def isValidFloat(field_data, all_data):
try:
float(data)
except ValueError:
- raise ValidationError, gettext("Please enter a valid floating point number.")
+ raise ValidationError, _("Please enter a valid floating point number.")
class HasAllowableSize(object):
"""
@@ -443,14 +451,14 @@ class HasAllowableSize(object):
"""
def __init__(self, min_size=None, max_size=None, min_error_message=None, max_error_message=None):
self.min_size, self.max_size = min_size, max_size
- self.min_error_message = min_error_message or lazy_inter(gettext_lazy("Make sure your uploaded file is at least %s bytes big."), min_size)
- self.max_error_message = max_error_message or lazy_inter(gettext_lazy("Make sure your uploaded file is at most %s bytes big."), max_size)
+ self.min_error_message = min_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at least %s bytes big."), min_size)
+ self.max_error_message = max_error_message or lazy_inter(ugettext_lazy("Make sure your uploaded file is at most %s bytes big."), max_size)
def __call__(self, field_data, all_data):
try:
content = field_data['content']
except TypeError:
- raise ValidationError, gettext_lazy("No file was submitted. Check the encoding type on the form.")
+ raise ValidationError, ugettext_lazy("No file was submitted. Check the encoding type on the form.")
if self.min_size is not None and len(content) < self.min_size:
raise ValidationError, self.min_error_message
if self.max_size is not None and len(content) > self.max_size:
@@ -461,7 +469,7 @@ class MatchesRegularExpression(object):
Checks that the field matches the given regular-expression. The regex
should be in string format, not already compiled.
"""
- def __init__(self, regexp, error_message=gettext_lazy("The format for this field is wrong.")):
+ def __init__(self, regexp, error_message=ugettext_lazy("The format for this field is wrong.")):
self.regexp = re.compile(regexp)
self.error_message = error_message
@@ -476,7 +484,7 @@ class AnyValidator(object):
as a validation error. The message is rather unspecific, so it's best to
specify one on instantiation.
"""
- def __init__(self, validator_list=None, error_message=gettext_lazy("This field is invalid.")):
+ def __init__(self, validator_list=None, error_message=ugettext_lazy("This field is invalid.")):
if validator_list is None: validator_list = []
self.validator_list = validator_list
self.error_message = error_message
@@ -512,10 +520,10 @@ class URLMimeTypeCheck(object):
try:
info = urllib2.urlopen(field_data).info()
except (urllib2.HTTPError, urllib2.URLError):
- raise URLMimeTypeCheck.CouldNotRetrieve, gettext("Could not retrieve anything from %s.") % field_data
+ raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data
content_type = info['content-type']
if content_type not in self.mime_type_list:
- raise URLMimeTypeCheck.InvalidContentType, gettext("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % {
+ raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % {
'url': field_data, 'contenttype': content_type}
class RelaxNGCompact(object):