Skip to content

Commit

Permalink
Merge pull request formencode#16 from 2nd/bugfix.7
Browse files Browse the repository at this point in the history
Fix for formencode#7, will be included in the 1.3 release
  • Loading branch information
lambacck committed Dec 15, 2012
2 parents 04f6d2a + b001b27 commit 85a71cc
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 26 deletions.
56 changes: 33 additions & 23 deletions formencode/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
::
Expand Down Expand Up @@ -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):
...
Expand Down Expand Up @@ -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:
Expand All @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
if not '2.3' <= sys.version < '3.0':
raise ImportError('Python version not supported')

tests_require = ['nose', 'pycountry', 'pyDNS']
tests_require = ['nose', 'pycountry', 'dnspython']
if sys.version < '2.5':
tests_require.append('elementtree')

Expand Down
13 changes: 13 additions & 0 deletions tests/test_email.py
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
Expand Down Expand Up @@ -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@письмо.рф')
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ envlist=py24,py25,py26,py27

[testenv]
deps=nose
pyDNS
dnspython
pycountry
commands=nosetests

[testenv:py24]
deps=ElementTree
nose
pyDNS
dnspython
pycountry

0 comments on commit 85a71cc

Please sign in to comment.