Skip to content

Commit

Permalink
Move setattr out of non-test code
Browse files Browse the repository at this point in the history
  • Loading branch information
tamird committed May 9, 2024
1 parent be42a70 commit c8bb812
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 35 deletions.
15 changes: 11 additions & 4 deletions email_validator/deliverability.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any, Dict, Optional
from typing import Any, List, Optional, Tuple, TypedDict
from typing_extensions import NotRequired

import ipaddress

Expand All @@ -18,7 +19,14 @@ def caching_resolver(*, timeout: Optional[int] = None, cache: Any = None, dns_re
return resolver


def validate_email_deliverability(domain: str, domain_i18n: str, timeout: Optional[int] = None, dns_resolver: Optional[dns.resolver.Resolver] = None) -> Dict[str, str]:
DeliverabilityInfo = TypedDict("DeliverabilityInfo", {
"mx": NotRequired[List[Tuple[int, str]]],
"mx_fallback_type": NotRequired[Optional[str]],
"unknown-deliverability": NotRequired[str],
})


def validate_email_deliverability(domain: str, domain_i18n: str, timeout: Optional[int] = None, dns_resolver: Optional[dns.resolver.Resolver] = None) -> DeliverabilityInfo:
# Check that the domain resolves to an MX record. If there is no MX record,
# try an A or AAAA record which is a deprecated fallback for deliverability.
# Raises an EmailUndeliverableError on failure. On success, returns a dict
Expand All @@ -36,7 +44,7 @@ def validate_email_deliverability(domain: str, domain_i18n: str, timeout: Option
elif timeout is not None:
raise ValueError("It's not valid to pass both timeout and dns_resolver.")

deliverability_info: Dict[str, Any] = {}
deliverability_info: DeliverabilityInfo = {}

try:
try:
Expand Down Expand Up @@ -115,7 +123,6 @@ def is_global_addr(address: Any) -> bool:
for rec in response:
value = b"".join(rec.strings)
if value.startswith(b"v=spf1 "):
deliverability_info["spf"] = value.decode("ascii", errors='replace')
if value == b"v=spf1 -all":
raise EmailUndeliverableError(f"The domain name {domain_i18n} does not send email.")
except dns.resolver.NoAnswer:
Expand Down
7 changes: 1 addition & 6 deletions email_validator/exceptions_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,11 @@ class ValidatedEmail:

"""If no MX records are actually specified in DNS and instead are inferred, through an obsolete
mechanism, from A or AAAA records, the value is the type of DNS record used instead (`A` or `AAAA`)."""
mx_fallback_type: str
mx_fallback_type: Optional[str]

"""The display name in the original input text, unquoted and unescaped, or None."""
display_name: Optional[str]

"""Tests use this constructor."""
def __init__(self, **kwargs: Any) -> None:
for k, v in kwargs.items():
setattr(self, k, v)

def __repr__(self) -> str:
return f"<ValidatedEmail {self.normalized}>"

Expand Down
6 changes: 4 additions & 2 deletions email_validator/validate_email.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ def validate_email(
deliverability_info = validate_email_deliverability(
ret.ascii_domain, ret.domain, timeout, dns_resolver
)
for key, value in deliverability_info.items():
setattr(ret, key, value)
mx = deliverability_info.get("mx")
if mx is not None:
ret.mx = mx
ret.mx_fallback_type = deliverability_info.get("mx_fallback_type")

return ret
55 changes: 32 additions & 23 deletions tests/test_syntax.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
from typing import Any

import pytest

from email_validator import EmailSyntaxError, \
validate_email, \
ValidatedEmail


def MakeValidatedEmail(**kwargs: Any) -> ValidatedEmail:
ret = ValidatedEmail()
for k, v in kwargs.items():
setattr(ret, k, v)
return ret


@pytest.mark.parametrize(
'email_input,output',
[
(
'[email protected]',
ValidatedEmail(
MakeValidatedEmail(
local_part='Abc',
ascii_local_part='Abc',
smtputf8=False,
Expand All @@ -22,7 +31,7 @@
),
(
'[email protected]',
ValidatedEmail(
MakeValidatedEmail(
local_part='Abc.123',
ascii_local_part='Abc.123',
smtputf8=False,
Expand All @@ -34,7 +43,7 @@
),
(
'user+mailbox/[email protected]',
ValidatedEmail(
MakeValidatedEmail(
local_part='user+mailbox/department=shipping',
ascii_local_part='user+mailbox/department=shipping',
smtputf8=False,
Expand All @@ -46,7 +55,7 @@
),
(
"!#$%&'*+-/=?^_`.{|}[email protected]",
ValidatedEmail(
MakeValidatedEmail(
local_part="!#$%&'*+-/=?^_`.{|}~",
ascii_local_part="!#$%&'*+-/=?^_`.{|}~",
smtputf8=False,
Expand All @@ -58,7 +67,7 @@
),
(
'jeff@臺網中心.tw',
ValidatedEmail(
MakeValidatedEmail(
local_part='jeff',
ascii_local_part='jeff',
smtputf8=False,
Expand All @@ -70,7 +79,7 @@
),
(
'"quoted local part"@example.org',
ValidatedEmail(
MakeValidatedEmail(
local_part='"quoted local part"',
ascii_local_part='"quoted local part"',
smtputf8=False,
Expand All @@ -82,7 +91,7 @@
),
(
'"de-quoted.local.part"@example.org',
ValidatedEmail(
MakeValidatedEmail(
local_part='de-quoted.local.part',
ascii_local_part='de-quoted.local.part',
smtputf8=False,
Expand All @@ -94,7 +103,7 @@
),
(
'MyName <[email protected]>',
ValidatedEmail(
MakeValidatedEmail(
local_part='me',
ascii_local_part='me',
smtputf8=False,
Expand All @@ -107,7 +116,7 @@
),
(
'My Name <[email protected]>',
ValidatedEmail(
MakeValidatedEmail(
local_part='me',
ascii_local_part='me',
smtputf8=False,
Expand All @@ -120,7 +129,7 @@
),
(
r'"My.\"Na\\me\".Is" <"me \" \\ me"@example.org>',
ValidatedEmail(
MakeValidatedEmail(
local_part=r'"me \" \\ me"',
ascii_local_part=r'"me \" \\ me"',
smtputf8=False,
Expand Down Expand Up @@ -157,7 +166,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
[
(
'伊昭傑@郵件.商務',
ValidatedEmail(
MakeValidatedEmail(
local_part='伊昭傑',
smtputf8=True,
ascii_domain='xn--5nqv22n.xn--lhr59c',
Expand All @@ -167,7 +176,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'राम@मोहन.ईन्फो',
ValidatedEmail(
MakeValidatedEmail(
local_part='राम',
smtputf8=True,
ascii_domain='xn--l2bl7a9d.xn--o1b8dj2ki',
Expand All @@ -177,7 +186,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'юзер@екзампл.ком',
ValidatedEmail(
MakeValidatedEmail(
local_part='юзер',
smtputf8=True,
ascii_domain='xn--80ajglhfv.xn--j1aef',
Expand All @@ -187,7 +196,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'θσερ@εχαμπλε.ψομ',
ValidatedEmail(
MakeValidatedEmail(
local_part='θσερ',
smtputf8=True,
ascii_domain='xn--mxahbxey0c.xn--xxaf0a',
Expand All @@ -197,7 +206,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'葉士豪@臺網中心.tw',
ValidatedEmail(
MakeValidatedEmail(
local_part='葉士豪',
smtputf8=True,
ascii_domain='xn--fiqq24b10vi0d.tw',
Expand All @@ -207,7 +216,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'葉士豪@臺網中心.台灣',
ValidatedEmail(
MakeValidatedEmail(
local_part='葉士豪',
smtputf8=True,
ascii_domain='xn--fiqq24b10vi0d.xn--kpry57d',
Expand All @@ -217,7 +226,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'jeff葉@臺網中心.tw',
ValidatedEmail(
MakeValidatedEmail(
local_part='jeff葉',
smtputf8=True,
ascii_domain='xn--fiqq24b10vi0d.tw',
Expand All @@ -227,7 +236,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'ñoñó@example.tld',
ValidatedEmail(
MakeValidatedEmail(
local_part='ñoñó',
smtputf8=True,
ascii_domain='example.tld',
Expand All @@ -237,7 +246,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'我買@example.tld',
ValidatedEmail(
MakeValidatedEmail(
local_part='我買',
smtputf8=True,
ascii_domain='example.tld',
Expand All @@ -247,7 +256,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'甲斐黒川日本@example.tld',
ValidatedEmail(
MakeValidatedEmail(
local_part='甲斐黒川日本',
smtputf8=True,
ascii_domain='example.tld',
Expand All @@ -257,7 +266,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'чебурашкаящик-с-апельсинами.рф@example.tld',
ValidatedEmail(
MakeValidatedEmail(
local_part='чебурашкаящик-с-апельсинами.рф',
smtputf8=True,
ascii_domain='example.tld',
Expand All @@ -267,7 +276,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'उदाहरण.परीक्ष@domain.with.idn.tld',
ValidatedEmail(
MakeValidatedEmail(
local_part='उदाहरण.परीक्ष',
smtputf8=True,
ascii_domain='domain.with.idn.tld',
Expand All @@ -277,7 +286,7 @@ def test_email_valid(email_input: str, output: ValidatedEmail) -> None:
),
(
'ιωάννης@εεττ.gr',
ValidatedEmail(
MakeValidatedEmail(
local_part='ιωάννης',
smtputf8=True,
ascii_domain='xn--qxaa9ba.gr',
Expand Down

0 comments on commit c8bb812

Please sign in to comment.