Skip to content

Commit

Permalink
change and better error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin committed Nov 10, 2019
1 parent 705b095 commit 85e9fb1
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 28 deletions.
3 changes: 3 additions & 0 deletions changes/988-samuelcolvin.md
@@ -0,0 +1,3 @@
Changes to email validation: whitespace is stripped from names, e.g. `' Fred Smith <fred@example.com>'`,
unicode NFC normalization is applied to the local part, the domain part is cleaned to the internationalized form
by round-tripping through IDNA ASCII, better error messages are provided when validation fails
5 changes: 4 additions & 1 deletion pydantic/errors.py
Expand Up @@ -152,7 +152,10 @@ class DictError(PydanticTypeError):


class EmailError(PydanticValueError):
msg_template = 'value is not a valid email address'
msg_template = 'value is not a valid email address: {reason}'

def __init__(self, reason: str):
super().__init__(reason=reason)


class UrlError(PydanticValueError):
Expand Down
2 changes: 1 addition & 1 deletion pydantic/networks.py
Expand Up @@ -378,6 +378,6 @@ def validate_email(value: str) -> Tuple[str, str]:
try:
parts = email_validator.validate_email(email, check_deliverability=False)
except email_validator.EmailNotValidError as e:
raise errors.EmailError() from e
raise errors.EmailError(*e.args) from e

return name or parts['local'], parts['email']
54 changes: 28 additions & 26 deletions tests/test_networks.py
@@ -1,6 +1,6 @@
import pytest

from pydantic import AnyUrl, BaseModel, HttpUrl, PostgresDsn, RedisDsn, ValidationError, stricturl
from pydantic import AnyUrl, BaseModel, EmailError, HttpUrl, PostgresDsn, RedisDsn, ValidationError, stricturl
from pydantic.networks import validate_email

try:
Expand Down Expand Up @@ -350,34 +350,36 @@ def test_address_valid(value, name, email):

@pytest.mark.skipif(not email_validator, reason='email_validator not installed')
@pytest.mark.parametrize(
'value',
'value,reason',
[
'f oo.bar@example.com ',
'foo.bar@exam\nple.com ',
'foobar',
'foobar <foobar@example.com',
'@example.com',
'foobar@.example.com',
'foobar@.com',
'foo bar@example.com',
'foo@bar@example.com',
'\n@example.com',
'\r@example.com',
'\f@example.com',
' @example.com',
'\u0020@example.com',
'\u001f@example.com',
'"@example.com',
'\"@example.com',
',@example.com',
'foobar <foobar<@example.com>',
'foobar <foobar@example.com>>',
'foobar <<foobar<@example.com>',
'foobar <>',
('@example.com', 'There must be something before the @-sign.'),
('f oo.bar@example.com', 'The email address contains invalid characters before the @-sign'),
('foobar', 'The email address is not valid. It must have exactly one @-sign.'),
('foobar@localhost', 'The domain name localhost is not valid. It should have a period.'),
('foobar@127.0.0.1', 'The domain name 127.0.0.1 is not valid. It is not within a valid top-level domain.'),
('foo.bar@exam\nple.com ', None),
('foobar <foobar@example.com', None),
('foobar@.example.com', None),
('foobar@.com', None),
('foo bar@example.com', None),
('foo@bar@example.com', None),
('\n@example.com', None),
('\r@example.com', None),
('\f@example.com', None),
(' @example.com', None),
('\u0020@example.com', None),
('\u001f@example.com', None),
('"@example.com', None),
('\"@example.com', None),
(',@example.com', None),
('foobar <foobar<@example.com>', None),
('foobar <foobar@example.com>>', None),
('foobar <<foobar<@example.com>', None),
('foobar <>', None),
],
)
def test_address_invalid(value):
with pytest.raises(ValueError):
def test_address_invalid(value, reason):
with pytest.raises(EmailError, match='value is not a valid email address: ' + (reason or '')):
validate_email(value)


Expand Down

0 comments on commit 85e9fb1

Please sign in to comment.