Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport update to email-validator>=2.0.0.post2 #5627

Merged
merged 11 commits into from
Apr 30, 2023
1 change: 1 addition & 0 deletions changes/5627-adriangb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update email-validator dependency to >=2.0.0post2
36 changes: 19 additions & 17 deletions pydantic/networks.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,32 +706,34 @@ def validate(cls, value: NetworkType) -> Union[IPv4Network, IPv6Network]:

def validate_email(value: Union[str]) -> Tuple[str, str]:
"""
Brutally simple email address validation. Note unlike most email address validation
Email address validation using https://pypi.org/project/email-validator/
Notes:
* raw ip address (literal) domain parts are not allowed.
* "John Doe <local_part@domain.com>" style "pretty" email addresses are processed
* the local part check is extremely basic. This raises the possibility of unicode spoofing, but no better
solution is really possible.
* spaces are striped from the beginning and end of addresses but no error is raised

See RFC 5322 but treat it with suspicion, there seems to exist no universally acknowledged test for a valid email!
"""
if email_validator is None:
import_email_validator()

m = pretty_email_regex.fullmatch(value)
name: Optional[str] = None
name: Union[str, None] = None
if m:
name, value = m.groups()

email = value.strip()

try:
email_validator.validate_email(email, check_deliverability=False)
parts = email_validator.validate_email(email, check_deliverability=False)
except email_validator.EmailNotValidError as e:
raise errors.EmailError() from e

at_index = email.index('@')
local_part = email[:at_index] # RFC 5321, local part must be case-sensitive.
global_part = email[at_index:].lower()

return name or local_part, local_part + global_part
raise errors.EmailError from e

if hasattr(parts, 'normalized'):
# email-validator >= 2
email = parts.normalized
assert email is not None
name = name or parts.local_part
return name, email
else:
# email-validator >1, <2
at_index = email.index('@')
local_part = email[:at_index] # RFC 5321, local part must be case-sensitive.
global_part = email[at_index:].lower()

return name or local_part, local_part + global_part
Comment on lines +733 to +739
Copy link
Member Author

@adriangb adriangb Apr 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the exact same code we had previously. To avoid adding a whole CI run just to test this version of email-validator, we are going to leave it uncovered. I ran locally and all tests pass with email-validator <2. This is also being run via the FastAPI tests, it's just not counted towards coverage.

2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Cython==0.29.32;sys_platform!='win32'
devtools==0.9.0
email-validator==1.2.1
email-validator==2.0.0.post2
dataclasses==0.6; python_version < '3.7'
typing-extensions==4.3.0
python-dotenv==0.20.0
5 changes: 4 additions & 1 deletion tests/requirements-testing.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
coverage==6.4.4
hypothesis==6.54.4
# pin importlib-metadata as upper versions need typing-extensions to work if on Python < 3.8
importlib-metadata==3.1.0;python_version<"3.8"
importlib-metadata==3.6.0;python_version<"3.8"
mypy==0.971
pytest==7.2.1
pytest-cov==4.0.0
pytest-mock==3.10.0
pytest-sugar==0.9.6
# pin typing-extensions to minimum requirement - see #4885
typing-extensions==4.2.0
# used in FastAPI tests, pin to avoid warnings in newer version
# that FastAPI needs to fix
Flask==2.2.3