Ticket #9764: idn_support_02.diff

File idn_support_02.diff, 7.6 KB (added by Ulrich Petri, 14 years ago)

Updated IDN patch to trunk (r12454); Added docs

  • django/db/models/fields/__init__.py

     
    807807        return super(DecimalField, self).formfield(**defaults)
    808808
    809809class EmailField(CharField):
    810     default_validators = [validators.validate_email]
     810    default_validators = [validators.EmailValidator()]
    811811    description = _("E-mail address")
    812812
    813813    def __init__(self, *args, **kwargs):
  • django/forms/fields.py

     
    413413    default_error_messages = {
    414414        'invalid': _(u'Enter a valid e-mail address.'),
    415415    }
    416     default_validators = [validators.validate_email]
     416    default_validators = [validators.EmailValidator()]
    417417
    418418class FileField(Field):
    419419    widget = FileInput
  • django/core/validators.py

     
    11import re
     2import urlparse
    23
    34from django.core.exceptions import ValidationError
    45from django.utils.translation import ugettext_lazy as _
     
    5253        self.user_agent = validator_user_agent
    5354
    5455    def __call__(self, value):
    55         super(URLValidator, self).__call__(value)
     56        try:
     57            super(URLValidator, self).__call__(value)
     58        except ValidationError, e:
     59            # Trivial case failed. Try for possible IDN domain
     60            if value:
     61                original = value
     62                value = smart_unicode(value)
     63                splitted = urlparse.urlsplit(value)
     64                try:
     65                    netloc_ace = splitted[1].encode('idna') # IDN -> ACE
     66                except UnicodeError: # invalid domain part
     67                    raise e
     68                value = value.replace(splitted[1], netloc_ace)
     69                # If no URL path given, assume /
     70                if not splitted[2]:
     71                    value += u'/'
     72                super(URLValidator, self).__call__(value)
     73                # After validation revert ACE encoded domain-part to
     74                # original (IDN) value as suggested by RFC 3490
     75                value = original
     76            else:
     77                raise
     78           
    5679        if self.verify_exists:
    5780            import urllib2
    5881            headers = {
     
    77100    except (ValueError, TypeError), e:
    78101        raise ValidationError('')
    79102
     103class EmailValidator(RegexValidator):
     104    regex = re.compile(
     105        r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
     106        r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
     107        r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)  # domain
     108    message = _(u'Enter a valid e-mail address.')
    80109
    81 email_re = re.compile(
    82     r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
    83     r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
    84     r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)  # domain
    85 validate_email = RegexValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid')
     110    def __call__(self, value):
     111        try:
     112            super(EmailValidator, self).__call__(value)
     113        except ValidationError, e:
     114            # Trivial case failed. Try for possible IDN domain-part
     115            if value and u'@' in value:
     116                parts = value.split(u'@')
     117                domain_part = parts[-1]
     118                try:
     119                    parts[-1] = parts[-1].encode('idna')
     120                except UnicodeError:
     121                    raise e
     122                super(EmailValidator, self).__call__(u'@'.join(parts))
     123            else:
     124                raise
    86125
     126validate_email = EmailValidator()
     127
    87128slug_re = re.compile(r'^[-\w]+$')
    88129validate_slug = RegexValidator(slug_re, _(u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
    89130
  • tests/regressiontests/forms/fields.py

     
    408408        self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid e-mail address.']", f.clean, 'example@inv-.-alid.com')
    409409        self.assertEqual(u'example@valid-----hyphens.com', f.clean('example@valid-----hyphens.com'))
    410410        self.assertEqual(u'example@valid-with-hyphens.com', f.clean('example@valid-with-hyphens.com'))
     411        self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid e-mail address.']", f.clean, 'example@.com')
     412        self.assertEqual(u'local@domain.with.idn.xyz\xe4\xf6\xfc\xdfabc.part.com', f.clean('local@domain.with.idn.xyzäöüßabc.part.com'))
    411413
    412414    def test_email_regexp_for_performance(self):
    413415        f = EmailField()
     
    489491        self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://inv-.alid-.com')
    490492        self.assertRaisesErrorWithMessage(ValidationError, "[u'Enter a valid URL.']", f.clean, 'http://inv-.-alid.com')
    491493        self.assertEqual(u'http://valid-----hyphens.com/', f.clean('http://valid-----hyphens.com'))
     494        self.assertEqual(u'http://some.idn.xyz\xe4\xf6\xfc\xdfabc.domain.com:123/blah', f.clean('http://some.idn.xyzäöüßabc.domain.com:123/blah'))
    492495
    493496    def test_url_regex_ticket11198(self):
    494497        f = URLField()
  • docs/ref/forms/fields.txt

     
    482482If provided, these arguments ensure that the string is at most or at least the
    483483given length.
    484484
     485.. versionchanged:: 1.2
     486   The EmailField previously did not recognize e-mail addresses as valid that
     487   contained an IDN (Internationalized Domain Name; a domain containing
     488   unicode characters) domain part. This has now been corrected.
     489
    485490``FileField``
    486491~~~~~~~~~~~~~
    487492
     
    707712    String used as the user-agent used when checking for a URL's existence.
    708713    Defaults to the value of the ``URL_VALIDATOR_USER_AGENT`` setting.
    709714
     715.. versionchanged:: 1.2
     716   The URLField previously did not recognize URLs as valid that contained an IDN
     717   (Internationalized Domain Name; a domain name containing unicode characters)
     718   domain name. This has now been corrected.
     719
     720
    710721Slightly complex built-in ``Field`` classes
    711722-------------------------------------------
    712723
  • docs/ref/forms/validation.txt

     
    186186        default_error_messages = {
    187187            'invalid': _(u'Enter a valid e-mail address.'),
    188188        }
    189         default_validators = [validators.validate_email]
     189        default_validators = [validators.EMailValidator()]
    190190
    191191As you can see, ``EmailField`` is just a ``CharField`` with customized error
    192192message and a validator that validates e-mail addresses. This can also be done
     
    196196
    197197is equivalent to::
    198198
    199     email = forms.CharField(validators=[validators.validate_email],
     199    email = forms.CharField(validators=[validators.EMailValidator()],
    200200            error_messages={'invalid': _(u'Enter a valid e-mail address.')})
    201201
    202202
Back to Top