forked from formencode/formencode
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request formencode#16 from 2nd/bugfix.7
Fix for formencode#7, will be included in the 1.3 release
- Loading branch information
Showing
4 changed files
with
49 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,10 +16,9 @@ | |
from sets import Set as set | ||
|
||
try: | ||
import DNS | ||
DNS.DiscoverNameServers() | ||
# DNS.DiscoverNameServers() raises IOError when network isn't available | ||
# on BSD/Mac OS X | ||
import dns.resolver | ||
import dns.exception | ||
from encodings import idna | ||
have_dns = True | ||
except (IOError, ImportError): | ||
have_dns = False | ||
|
@@ -1227,7 +1226,7 @@ class Email(FancyValidator): | |
If you pass ``resolve_domain=True``, then it will try to resolve | ||
the domain name to make sure it's valid. This takes longer, of | ||
course. You must have the `pyDNS <http://pydns.sf.net>`__ modules | ||
course. You must have the `dnspython <http://www.dnspython.org/>`__ modules | ||
installed to look up DNS (MX and A) records. | ||
:: | ||
|
@@ -1266,7 +1265,7 @@ class Email(FancyValidator): | |
'[email protected]' | ||
>>> e.to_python('[email protected]') | ||
'[email protected]' | ||
>>> # NOTE: If you do not have PyDNS installed this example won't work: | ||
>>> # NOTE: If you do not have dnspython installed this example won't work: | ||
>>> e.to_python('[email protected]') | ||
Traceback (most recent call last): | ||
... | ||
|
@@ -1304,10 +1303,10 @@ def __init__(self, *args, **kw): | |
if self.resolve_domain: | ||
if not have_dns: | ||
warnings.warn( | ||
"pyDNS <http://pydns.sf.net> is not installed on" | ||
" your system (or the DNS package cannot be found)." | ||
" I cannot resolve domain names in addresses") | ||
raise ImportError("no module named DNS") | ||
"dnspython <http://www.dnspython.org/> is not installed on" | ||
" your system (or the dns.resolver package cannot be found)." | ||
" I cannot resolve domain names in addresses") | ||
raise ImportError("no module named dns.resolver") | ||
|
||
def validate_python(self, value, state): | ||
if not value: | ||
|
@@ -1322,29 +1321,40 @@ def validate_python(self, value, state): | |
raise Invalid( | ||
self.message('badUsername', state, username=username), | ||
value, state) | ||
if not self.domainRE.search(domain): | ||
try: | ||
idna_domain = '.'.join([idna.ToASCII(l) for l in domain.split('.')]) | ||
except UnicodeError: | ||
# UnicodeError: label empty or too long | ||
# This exception might happen if we have an invalid domain name part | ||
# (for example [email protected]) | ||
raise Invalid( | ||
self.message('badDomain', state, domain=domain), | ||
value, state) | ||
if not self.domainRE.search(idna_domain): | ||
raise Invalid( | ||
self.message('badDomain', state, domain=domain), | ||
value, state) | ||
if self.resolve_domain: | ||
assert have_dns, "pyDNS should be available" | ||
assert have_dns, "dnspython should be available" | ||
global socket | ||
if socket is None: | ||
import socket | ||
try: | ||
answers = DNS.DnsRequest(domain, qtype='a', | ||
timeout=self.resolve_timeout).req().answers | ||
if answers: | ||
answers = DNS.DnsRequest(domain, qtype='mx', | ||
timeout=self.resolve_timeout).req().answers | ||
except (socket.error, DNS.DNSError), e: | ||
try: | ||
a = dns.resolver.query(domain, 'MX') | ||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer), e: | ||
try: | ||
a = dns.resolver.query(domain, 'A') | ||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer), e: | ||
raise Invalid( | ||
self.message('domainDoesNotExist', state, domain=domain), | ||
value, state | ||
) | ||
except (socket.error, dns.exception.DNSException), e: | ||
raise Invalid( | ||
self.message('socketError', state, error=e), | ||
value, state) | ||
if not answers: | ||
raise Invalid( | ||
self.message('domainDoesNotExist', state, domain=domain), | ||
value, state) | ||
value, state | ||
) | ||
|
||
def _to_python(self, value, state): | ||
return value.strip() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
# -*- coding: utf-8 -*- | ||
from unittest import TestCase | ||
from nose.tools import assert_equal | ||
from formencode.validators import Email, Invalid | ||
|
@@ -69,3 +70,15 @@ def expected_message(validator, message_name, username, domain): | |
|
||
for email, expected in valid_email_addresses: | ||
yield assert_equal, _validate(validator, email), expected | ||
|
||
|
||
class TestUnicodeEmailWithResolveDomain(TestCase): | ||
|
||
def setUp(self): | ||
self.validator = Email(resolve_domain=True) | ||
|
||
def test_unicode_ascii_subgroup(self): | ||
self.assertEqual(self.validator.to_python(u'[email protected]'), '[email protected]') | ||
|
||
def test_cyrillic_email(self): | ||
self.assertEqual(self.validator.to_python(u'me@письмо.рф'), u'me@письмо.рф') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters