Skip to content

Commit 6bc4589

Browse files
committed
Use "PEP 585, type hinting generics in standard collections"
First added in Python 3.9, since support for Python 3.8 is dropped.
1 parent 1a7468e commit 6bc4589

File tree

7 files changed

+21
-16
lines changed

7 files changed

+21
-16
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
In Development
2+
--------------
3+
4+
* Python 3.8 is no longer supported.
5+
16
2.3.0 (August 26, 2025)
27
-----------------------
38

email_validator/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import json
1818
import os
1919
import sys
20-
from typing import Any, Dict, Optional
20+
from typing import Any, Optional
2121

2222
from .validate_email import validate_email, _Resolver
2323
from .deliverability import caching_resolver
@@ -28,7 +28,7 @@ def main(dns_resolver: Optional[_Resolver] = None) -> None:
2828
# The dns_resolver argument is for tests.
2929

3030
# Set options from environment variables.
31-
options: Dict[str, Any] = {}
31+
options: dict[str, Any] = {}
3232
for varname in ('ALLOW_SMTPUTF8', 'ALLOW_EMPTY_LOCAL', 'ALLOW_QUOTED_LOCAL', 'ALLOW_DOMAIN_LITERAL',
3333
'ALLOW_DISPLAY_NAME',
3434
'GLOBALLY_DELIVERABLE', 'CHECK_DELIVERABILITY', 'TEST_ENVIRONMENT'):

email_validator/deliverability.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, List, Optional, Tuple, TypedDict
1+
from typing import Any, Optional, TypedDict
22

33
import ipaddress
44

@@ -19,7 +19,7 @@ def caching_resolver(*, timeout: Optional[int] = None, cache: Any = None, dns_re
1919

2020

2121
DeliverabilityInfo = TypedDict("DeliverabilityInfo", {
22-
"mx": List[Tuple[int, str]],
22+
"mx": list[tuple[int, str]],
2323
"mx_fallback_type": Optional[str],
2424
"unknown-deliverability": str,
2525
}, total=False)

email_validator/syntax.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
import unicodedata
99
import idna # implements IDNA 2008; Python's codec is only IDNA 2003
1010
import ipaddress
11-
from typing import Optional, Tuple, TypedDict, Union
11+
from typing import Optional, TypedDict, Union
1212

1313

14-
def split_email(email: str) -> Tuple[Optional[str], str, str, bool]:
14+
def split_email(email: str) -> tuple[Optional[str], str, str, bool]:
1515
# Return the display name, unescaped local part, and domain part
1616
# of the address, and whether the local part was quoted. If no
1717
# display name was present and angle brackets do not surround
@@ -47,7 +47,7 @@ def split_email(email: str) -> Tuple[Optional[str], str, str, bool]:
4747
# We assume the input string is already stripped of leading and
4848
# trailing CFWS.
4949

50-
def split_string_at_unquoted_special(text: str, specials: Tuple[str, ...]) -> Tuple[str, str]:
50+
def split_string_at_unquoted_special(text: str, specials: tuple[str, ...]) -> tuple[str, str]:
5151
# Split the string at the first character in specials (an @-sign
5252
# or left angle bracket) that does not occur within quotes and
5353
# is not followed by a Unicode combining character.
@@ -112,7 +112,7 @@ def split_string_at_unquoted_special(text: str, specials: Tuple[str, ...]) -> Tu
112112

113113
return left_part, right_part
114114

115-
def unquote_quoted_string(text: str) -> Tuple[str, bool]:
115+
def unquote_quoted_string(text: str) -> tuple[str, bool]:
116116
# Remove surrounding quotes and unescape escaped backslashes
117117
# and quotes. Escapes are parsed liberally. I think only
118118
# backslashes and quotes can be escaped but we'll allow anything

email_validator/types.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import warnings
2-
from typing import Any, Dict, List, Optional, Tuple, Union
2+
from typing import Any, Optional, Union
33

44

55
class ValidatedEmail:
@@ -41,7 +41,7 @@ class ValidatedEmail:
4141

4242
"""If a deliverability check is performed and if it succeeds, a list of (priority, domain)
4343
tuples of MX records specified in the DNS for the domain."""
44-
mx: List[Tuple[int, str]]
44+
mx: list[tuple[int, str]]
4545

4646
"""If no MX records are actually specified in DNS and instead are inferred, through an obsolete
4747
mechanism, from A or AAAA records, the value is the type of DNS record used instead (`A` or `AAAA`)."""
@@ -68,7 +68,7 @@ def email(self) -> str:
6868

6969
"""For backwards compatibility, some fields are also exposed through a dict-like interface. Note
7070
that some of the names changed when they became attributes."""
71-
def __getitem__(self, key: str) -> Union[Optional[str], bool, List[Tuple[int, str]]]:
71+
def __getitem__(self, key: str) -> Union[Optional[str], bool, list[tuple[int, str]]]:
7272
warnings.warn("dict-like access to the return value of validate_email is deprecated and may not be supported in the future.", DeprecationWarning, stacklevel=2)
7373
if key == "email":
7474
return self.normalized
@@ -119,7 +119,7 @@ def as_constructor(self) -> str:
119119
+ ")"
120120

121121
"""Convenience method for accessing ValidatedEmail as a dict"""
122-
def as_dict(self) -> Dict[str, Any]:
122+
def as_dict(self) -> dict[str, Any]:
123123
d = self.__dict__
124124
if d.get('domain_address'):
125125
d['domain_address'] = repr(d['domain_address'])

tests/mocked_dns_response.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Dict, Iterator, Optional
1+
from typing import Any, Iterator, Optional
22

33
import dns.exception
44
import dns.rdataset
@@ -42,7 +42,7 @@ def create_resolver() -> dns.resolver.Resolver:
4242
return caching_resolver(cache=MockedDnsResponseData.INSTANCE, dns_resolver=dns_resolver)
4343

4444
def __init__(self) -> None:
45-
self.data: Dict[dns.resolver.CacheKey, Optional[MockedDnsResponseData.Ans]] = {}
45+
self.data: dict[dns.resolver.CacheKey, Optional[MockedDnsResponseData.Ans]] = {}
4646

4747
# Loads the saved DNS response data from the JSON file and
4848
# re-structures it into dnspython classes.

tests/test_deliverability.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Dict
1+
from typing import Any
22

33
import pytest
44
import re
@@ -69,7 +69,7 @@ def test_deliverability_dns_timeout() -> None:
6969
def test_caching_dns_resolver() -> None:
7070
class TestCache:
7171
def __init__(self) -> None:
72-
self.cache: Dict[Any, Any] = {}
72+
self.cache: dict[Any, Any] = {}
7373

7474
def get(self, key: Any) -> Any:
7575
return self.cache.get(key)

0 commit comments

Comments
 (0)