From 32ae92b3e96722caadea913ef06f895444fcf341 Mon Sep 17 00:00:00 2001 From: Brian Schubert Date: Sat, 21 Dec 2024 08:15:48 -0500 Subject: [PATCH 1/4] Make various `email.Policy` use sites generic over message type --- stdlib/email/__init__.pyi | 15 +++++++++------ stdlib/email/mime/message.pyi | 5 ++--- stdlib/email/mime/multipart.pyi | 7 +++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/stdlib/email/__init__.pyi b/stdlib/email/__init__.pyi index f564ced105bd..920bc145816f 100644 --- a/stdlib/email/__init__.pyi +++ b/stdlib/email/__init__.pyi @@ -1,6 +1,5 @@ from collections.abc import Callable -from email.message import Message -from email.policy import Policy +from email.policy import Policy, _MessageT from typing import IO from typing_extensions import TypeAlias @@ -31,7 +30,11 @@ __all__ = [ # noqa: F822 # Undefined names in __all__ _ParamType: TypeAlias = str | tuple[str | None, str | None, str] # noqa: Y047 _ParamsType: TypeAlias = str | None | tuple[str, str | None, str] # noqa: Y047 -def message_from_string(s: str, _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... -def message_from_bytes(s: bytes | bytearray, _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... -def message_from_file(fp: IO[str], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... -def message_from_binary_file(fp: IO[bytes], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... +def message_from_string(s: str, _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] = ...) -> _MessageT: ... +def message_from_bytes( + s: bytes | bytearray, _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] = ... +) -> _MessageT: ... +def message_from_file(fp: IO[str], _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] = ...) -> _MessageT: ... +def message_from_binary_file( + fp: IO[bytes], _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] = ... +) -> _MessageT: ... diff --git a/stdlib/email/mime/message.pyi b/stdlib/email/mime/message.pyi index 23cf58619ad9..2a5f46296150 100644 --- a/stdlib/email/mime/message.pyi +++ b/stdlib/email/mime/message.pyi @@ -1,8 +1,7 @@ -from email.message import Message from email.mime.nonmultipart import MIMENonMultipart -from email.policy import Policy +from email.policy import Policy, _MessageT __all__ = ["MIMEMessage"] class MIMEMessage(MIMENonMultipart): - def __init__(self, _msg: Message, _subtype: str = "rfc822", *, policy: Policy | None = None) -> None: ... + def __init__(self, _msg: _MessageT, _subtype: str = "rfc822", *, policy: Policy[_MessageT] | None = None) -> None: ... diff --git a/stdlib/email/mime/multipart.pyi b/stdlib/email/mime/multipart.pyi index 6163810ed94a..1c229f7436a8 100644 --- a/stdlib/email/mime/multipart.pyi +++ b/stdlib/email/mime/multipart.pyi @@ -1,8 +1,7 @@ from collections.abc import Sequence from email import _ParamsType -from email.message import Message from email.mime.base import MIMEBase -from email.policy import Policy +from email.policy import Policy, _MessageT __all__ = ["MIMEMultipart"] @@ -11,8 +10,8 @@ class MIMEMultipart(MIMEBase): self, _subtype: str = "mixed", boundary: str | None = None, - _subparts: Sequence[Message] | None = None, + _subparts: Sequence[_MessageT] | None = None, *, - policy: Policy | None = None, + policy: Policy[_MessageT] | None = None, **_params: _ParamsType, ) -> None: ... From 8bd95475755d75b6cdbc83c3284274b2223ba58c Mon Sep 17 00:00:00 2001 From: Brian Schubert Date: Sat, 21 Dec 2024 09:11:15 -0500 Subject: [PATCH 2/4] Add default arguments to satisfy pyright --- stdlib/email/__init__.pyi | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/stdlib/email/__init__.pyi b/stdlib/email/__init__.pyi index 920bc145816f..58126cb86ebf 100644 --- a/stdlib/email/__init__.pyi +++ b/stdlib/email/__init__.pyi @@ -1,5 +1,6 @@ from collections.abc import Callable from email.policy import Policy, _MessageT +from mailbox import Message from typing import IO from typing_extensions import TypeAlias @@ -30,11 +31,15 @@ __all__ = [ # noqa: F822 # Undefined names in __all__ _ParamType: TypeAlias = str | tuple[str | None, str | None, str] # noqa: Y047 _ParamsType: TypeAlias = str | None | tuple[str, str | None, str] # noqa: Y047 -def message_from_string(s: str, _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] = ...) -> _MessageT: ... +def message_from_string( + s: str, _class: Callable[[], _MessageT] = Message, *, policy: Policy[_MessageT] = ... # noqa: Y011 +) -> _MessageT: ... def message_from_bytes( - s: bytes | bytearray, _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] = ... + s: bytes | bytearray, _class: Callable[[], _MessageT] = Message, *, policy: Policy[_MessageT] = ... # noqa: Y011 +) -> _MessageT: ... +def message_from_file( + fp: IO[str], _class: Callable[[], _MessageT] = Message, *, policy: Policy[_MessageT] = ... # noqa: Y011 ) -> _MessageT: ... -def message_from_file(fp: IO[str], _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] = ...) -> _MessageT: ... def message_from_binary_file( - fp: IO[bytes], _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] = ... + fp: IO[bytes], _class: Callable[[], _MessageT] = Message, *, policy: Policy[_MessageT] = ... # noqa: Y011 ) -> _MessageT: ... From dfd268b514efe8706a095c8d27ba265359262c4b Mon Sep 17 00:00:00 2001 From: Brian Schubert Date: Sat, 21 Dec 2024 09:20:38 -0500 Subject: [PATCH 3/4] Switch to overloads to satisfy both mypy and pyright simultaneously --- stdlib/email/__init__.pyi | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/stdlib/email/__init__.pyi b/stdlib/email/__init__.pyi index 58126cb86ebf..d18f5ea6f173 100644 --- a/stdlib/email/__init__.pyi +++ b/stdlib/email/__init__.pyi @@ -1,7 +1,7 @@ from collections.abc import Callable +from email.message import Message from email.policy import Policy, _MessageT -from mailbox import Message -from typing import IO +from typing import IO, overload from typing_extensions import TypeAlias # At runtime, listing submodules in __all__ without them being imported is @@ -31,15 +31,29 @@ __all__ = [ # noqa: F822 # Undefined names in __all__ _ParamType: TypeAlias = str | tuple[str | None, str | None, str] # noqa: Y047 _ParamsType: TypeAlias = str | None | tuple[str, str | None, str] # noqa: Y047 -def message_from_string( - s: str, _class: Callable[[], _MessageT] = Message, *, policy: Policy[_MessageT] = ... # noqa: Y011 -) -> _MessageT: ... +@overload +def message_from_string(s: str) -> Message: ... +@overload +def message_from_string(s: str, _class: Callable[[], _MessageT]) -> _MessageT: ... +@overload +def message_from_string(s: str, _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT]) -> _MessageT: ... +@overload +def message_from_bytes(s: bytes | bytearray) -> _MessageT: ... +@overload +def message_from_bytes(s: bytes | bytearray, _class: Callable[[], _MessageT]) -> _MessageT: ... +@overload def message_from_bytes( - s: bytes | bytearray, _class: Callable[[], _MessageT] = Message, *, policy: Policy[_MessageT] = ... # noqa: Y011 -) -> _MessageT: ... -def message_from_file( - fp: IO[str], _class: Callable[[], _MessageT] = Message, *, policy: Policy[_MessageT] = ... # noqa: Y011 -) -> _MessageT: ... -def message_from_binary_file( - fp: IO[bytes], _class: Callable[[], _MessageT] = Message, *, policy: Policy[_MessageT] = ... # noqa: Y011 + s: bytes | bytearray, _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] ) -> _MessageT: ... +@overload +def message_from_file(fp: IO[str]) -> Message: ... +@overload +def message_from_file(fp: IO[str], _class: Callable[[], _MessageT]) -> _MessageT: ... +@overload +def message_from_file(fp: IO[str], _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT]) -> _MessageT: ... +@overload +def message_from_binary_file(fp: IO[bytes]) -> Message: ... +@overload +def message_from_binary_file(fp: IO[bytes], _class: Callable[[], _MessageT]) -> _MessageT: ... +@overload +def message_from_binary_file(fp: IO[bytes], _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT]) -> _MessageT: ... From 9093f4e4940295b5bd63987d01dda4c2fa0242f1 Mon Sep 17 00:00:00 2001 From: Brian Schubert Date: Sat, 21 Dec 2024 09:23:13 -0500 Subject: [PATCH 4/4] Fix typo in message_from_bytes base overload --- stdlib/email/__init__.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/email/__init__.pyi b/stdlib/email/__init__.pyi index d18f5ea6f173..628ffb2b793a 100644 --- a/stdlib/email/__init__.pyi +++ b/stdlib/email/__init__.pyi @@ -38,7 +38,7 @@ def message_from_string(s: str, _class: Callable[[], _MessageT]) -> _MessageT: . @overload def message_from_string(s: str, _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT]) -> _MessageT: ... @overload -def message_from_bytes(s: bytes | bytearray) -> _MessageT: ... +def message_from_bytes(s: bytes | bytearray) -> Message: ... @overload def message_from_bytes(s: bytes | bytearray, _class: Callable[[], _MessageT]) -> _MessageT: ... @overload