From 6873a2e3e72e8457aa9170d81033a8b3d661139d Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 10 Sep 2026 11:58:19 +0200 Subject: [PATCH 1/7] [email] Various improvements * Parametrize `Message` type returned from `message_from_*()`, when no class or policy is provided. * Use protocols instead of `IO` for `message_from_(binary_)file`. * Fix ambiguous overload of `EmailPolicy.__init__`. * Add defaults for `EmailPolicy.__init__`. * Replace instances of `Any` with `Incomplete`. --- stdlib/email/__init__.pyi | 24 ++++++++++++-------- stdlib/email/policy.pyi | 46 +++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/stdlib/email/__init__.pyi b/stdlib/email/__init__.pyi index aabdca32d506..503674f1f602 100644 --- a/stdlib/email/__init__.pyi +++ b/stdlib/email/__init__.pyi @@ -1,8 +1,10 @@ +from _typeshed import SupportsRead from collections.abc import Callable from email._policybase import _MessageT from email.message import Message from email.policy import Policy -from typing import IO, TypeAlias, overload +from io import _WrappedBuffer +from typing import TypeAlias, overload # At runtime, listing submodules in __all__ without them being imported is # valid, and causes them to be included in a star import. See #6523 @@ -32,14 +34,14 @@ _ParamType: TypeAlias = str | tuple[str | None, str | None, str] # noqa: Y047 _ParamsType: TypeAlias = str | None | tuple[str, str | None, str] # noqa: Y047 @overload -def message_from_string(s: str) -> Message: ... +def message_from_string(s: str) -> Message[str, str]: ... @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) -> Message: ... +def message_from_bytes(s: bytes | bytearray) -> Message[str, str]: ... @overload def message_from_bytes(s: bytes | bytearray, _class: Callable[[], _MessageT]) -> _MessageT: ... @overload @@ -48,15 +50,19 @@ def message_from_bytes( ) -> _MessageT: ... @overload -def message_from_file(fp: IO[str]) -> Message: ... +def message_from_file(fp: SupportsRead[str]) -> Message[str, str]: ... @overload -def message_from_file(fp: IO[str], _class: Callable[[], _MessageT]) -> _MessageT: ... +def message_from_file(fp: SupportsRead[str], _class: Callable[[], _MessageT]) -> _MessageT: ... @overload -def message_from_file(fp: IO[str], _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT]) -> _MessageT: ... +def message_from_file( + fp: SupportsRead[str], _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] +) -> _MessageT: ... @overload -def message_from_binary_file(fp: IO[bytes]) -> Message: ... +def message_from_binary_file(fp: _WrappedBuffer) -> Message[str, str]: ... @overload -def message_from_binary_file(fp: IO[bytes], _class: Callable[[], _MessageT]) -> _MessageT: ... +def message_from_binary_file(fp: _WrappedBuffer, _class: Callable[[], _MessageT]) -> _MessageT: ... @overload -def message_from_binary_file(fp: IO[bytes], _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT]) -> _MessageT: ... +def message_from_binary_file( + fp: _WrappedBuffer, _class: Callable[[], _MessageT] = ..., *, policy: Policy[_MessageT] +) -> _MessageT: ... diff --git a/stdlib/email/policy.pyi b/stdlib/email/policy.pyi index 6b719f3c93fa..803b558b0029 100644 --- a/stdlib/email/policy.pyi +++ b/stdlib/email/policy.pyi @@ -1,8 +1,9 @@ +from _typeshed import Incomplete from collections.abc import Callable from email._policybase import Compat32 as Compat32, Policy as Policy, _MessageFactory, _MessageT, compat32 as compat32 from email.contentmanager import ContentManager from email.message import EmailMessage -from typing import Any, overload +from typing import overload from typing_extensions import Self __all__ = ["Compat32", "compat32", "Policy", "EmailPolicy", "default", "strict", "SMTP", "HTTP"] @@ -10,23 +11,23 @@ __all__ = ["Compat32", "compat32", "Policy", "EmailPolicy", "default", "strict", class EmailPolicy(Policy[_MessageT]): utf8: bool refold_source: str - header_factory: Callable[[str, Any], Any] + header_factory: Callable[[str, Incomplete], Incomplete] content_manager: ContentManager @overload def __init__( self: EmailPolicy[EmailMessage], *, - max_line_length: int | None = ..., - linesep: str = ..., - cte_type: str = ..., - raise_on_defect: bool = ..., - mangle_from_: bool = ..., + max_line_length: int | None = 78, + linesep: str = "\n", + cte_type: str = "8bit", + raise_on_defect: bool = False, + mangle_from_: bool = ..., # default depends on sub-class message_factory: None = None, # Added in Python 3.9.20, 3.10.15, 3.11.10, 3.12.5 - verify_generated_headers: bool = ..., - utf8: bool = ..., - refold_source: str = ..., + verify_generated_headers: bool = True, + utf8: bool = False, + refold_source: str = "long", header_factory: Callable[[str, str], str] = ..., content_manager: ContentManager = ..., ) -> None: ... @@ -34,24 +35,23 @@ class EmailPolicy(Policy[_MessageT]): def __init__( self, *, - max_line_length: int | None = ..., - linesep: str = ..., - cte_type: str = ..., - raise_on_defect: bool = ..., - mangle_from_: bool = ..., - message_factory: _MessageFactory[_MessageT] | None = ..., + max_line_length: int | None = 78, + linesep: str = "\n", + cte_type: str = "8bit", + raise_on_defect: bool = False, + mangle_from_: bool = ..., # default depends on sub-class + message_factory: _MessageFactory[_MessageT], # Added in Python 3.9.20, 3.10.15, 3.11.10, 3.12.5 - verify_generated_headers: bool = ..., - utf8: bool = ..., - refold_source: str = ..., + verify_generated_headers: bool = True, + utf8: bool = False, + refold_source: str = "long", header_factory: Callable[[str, str], str] = ..., content_manager: ContentManager = ..., ) -> None: ... - def header_source_parse(self, sourcelines: list[str]) -> tuple[str, str]: ... - def header_store_parse(self, name: str, value: Any) -> tuple[str, Any]: ... - def header_fetch_parse(self, name: str, value: str) -> Any: ... - def fold(self, name: str, value: str) -> Any: ... + def header_store_parse(self, name: str, value: Incomplete) -> tuple[str, Incomplete]: ... + def header_fetch_parse(self, name: str, value: str) -> Incomplete: ... + def fold(self, name: str, value: str) -> Incomplete: ... def fold_binary(self, name: str, value: str) -> bytes: ... def clone( self, From 14cb60d289a2e2b8c315b0ae43bc72a7c499bd46 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2026 10:00:38 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/email/policy.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/email/policy.pyi b/stdlib/email/policy.pyi index 803b558b0029..76e4435ae95a 100644 --- a/stdlib/email/policy.pyi +++ b/stdlib/email/policy.pyi @@ -48,6 +48,7 @@ class EmailPolicy(Policy[_MessageT]): header_factory: Callable[[str, str], str] = ..., content_manager: ContentManager = ..., ) -> None: ... + def header_source_parse(self, sourcelines: list[str]) -> tuple[str, str]: ... def header_store_parse(self, name: str, value: Incomplete) -> tuple[str, Incomplete]: ... def header_fetch_parse(self, name: str, value: str) -> Incomplete: ... From bc5d9296ec0fa6276fce2d2621405c8857f41d74 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 10 Sep 2026 12:03:13 +0200 Subject: [PATCH 3/7] Incomplete --- stdlib/email/_header_value_parser.pyi | 17 ++++++++-------- stdlib/email/contentmanager.pyi | 10 ++++----- stdlib/email/headerregistry.pyi | 29 ++++++++++++++------------- stdlib/email/message.pyi | 12 +++++------ stdlib/email/policy.pyi | 2 +- 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/stdlib/email/_header_value_parser.pyi b/stdlib/email/_header_value_parser.pyi index e75e7ba1cf06..019503cf8538 100644 --- a/stdlib/email/_header_value_parser.pyi +++ b/stdlib/email/_header_value_parser.pyi @@ -1,9 +1,10 @@ import sys +from _typeshed import Incomplete from collections.abc import Iterable, Iterator from email.errors import HeaderParseError, MessageDefect from email.policy import Policy from re import Pattern -from typing import Any, Final +from typing import Final from typing_extensions import Self WSP: Final[set[str]] @@ -23,11 +24,11 @@ NLSET: Final[set[str]] SPECIALSNL: Final[set[str]] # Added in Python 3.10.17, 3.11.12, 3.12.9, 3.13.2 -def make_quoted_pairs(value: Any) -> str: ... -def quote_string(value: Any) -> str: ... +def make_quoted_pairs(value) -> str: ... +def quote_string(value) -> str: ... # Added in Python 3.10.20, 3.11.15, 3.12.13, 3.13.12, 3.14.3 -def make_parenthesis_pairs(value: Any) -> str: ... +def make_parenthesis_pairs(value) -> str: ... rfc2047_matcher: Final[Pattern[str]] @@ -36,7 +37,7 @@ class TokenList(list[TokenList | Terminal]): syntactic_break: bool ew_combine_allowed: bool defects: list[MessageDefect] - def __init__(self, *args: Any, **kw: Any) -> None: ... + def __init__(self, *args, **kw) -> None: ... @property def value(self) -> str: ... @property @@ -91,7 +92,7 @@ class BareQuotedString(QuotedString): class Comment(WhiteSpaceTokenList): token_type: str - def quote(self, value: Any) -> str: ... + def quote(self, value) -> str: ... @property def content(self) -> str: ... @@ -293,7 +294,7 @@ class ContentType(ParameterizedHeaderValue): class ContentDisposition(ParameterizedHeaderValue): token_type: str as_ew_allowed: bool - content_disposition: Any + content_disposition: Incomplete class ContentTransferEncoding(TokenList): token_type: str @@ -370,7 +371,7 @@ def get_quoted_string(value: str) -> tuple[QuotedString, str]: ... def get_atom(value: str) -> tuple[Atom, str]: ... def get_dot_atom_text(value: str) -> tuple[DotAtomText, str]: ... def get_dot_atom(value: str) -> tuple[DotAtom, str]: ... -def get_word(value: str) -> tuple[Any, str]: ... +def get_word(value: str) -> tuple[Incomplete, str]: ... def get_phrase(value: str) -> tuple[Phrase, str]: ... def get_local_part(value: str) -> tuple[LocalPart, str]: ... def get_obs_local_part(value: str) -> tuple[ObsLocalPart, str]: ... diff --git a/stdlib/email/contentmanager.pyi b/stdlib/email/contentmanager.pyi index 3214f1a4781d..78d22b4d9202 100644 --- a/stdlib/email/contentmanager.pyi +++ b/stdlib/email/contentmanager.pyi @@ -1,11 +1,11 @@ +from _typeshed import Incomplete from collections.abc import Callable from email.message import Message -from typing import Any class ContentManager: - def get_content(self, msg: Message, *args: Any, **kw: Any) -> Any: ... - def set_content(self, msg: Message, obj: Any, *args: Any, **kw: Any) -> Any: ... - def add_get_handler(self, key: str, handler: Callable[..., Any]) -> None: ... - def add_set_handler(self, typekey: type, handler: Callable[..., Any]) -> None: ... + def get_content(self, msg: Message, *args: Incomplete, **kw: Incomplete) -> Incomplete: ... + def set_content(self, msg: Message, obj: Incomplete, *args: Incomplete, **kw: Incomplete) -> Incomplete: ... + def add_get_handler(self, key: str, handler: Callable[..., Incomplete]) -> None: ... + def add_set_handler(self, typekey: type, handler: Callable[..., Incomplete]) -> None: ... raw_data_manager: ContentManager diff --git a/stdlib/email/headerregistry.pyi b/stdlib/email/headerregistry.pyi index 8033f0ab4356..cb5df247b018 100644 --- a/stdlib/email/headerregistry.pyi +++ b/stdlib/email/headerregistry.pyi @@ -1,5 +1,6 @@ import sys import types +from _typeshed import Incomplete from collections.abc import Iterable, Mapping from datetime import datetime as _datetime from email._header_value_parser import ( @@ -14,7 +15,7 @@ from email._header_value_parser import ( ) from email.errors import MessageDefect from email.policy import Policy -from typing import Any, ClassVar, Literal, Protocol, type_check_only +from typing import ClassVar, Literal, Protocol, type_check_only from typing_extensions import Self class BaseHeader(str): @@ -24,7 +25,7 @@ class BaseHeader(str): def name(self) -> str: ... @property def defects(self) -> tuple[MessageDefect, ...]: ... - def __new__(cls, name: str, value: Any) -> Self: ... + def __new__(cls, name: str, value) -> Self: ... def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect]) -> None: ... def fold(self, *, policy: Policy) -> str: ... @@ -33,7 +34,7 @@ class UnstructuredHeader: @staticmethod def value_parser(value: str) -> UnstructuredTokenList: ... @classmethod - def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... + def parse(cls, value: str, kwds: dict[str, Incomplete]) -> None: ... class UniqueUnstructuredHeader(UnstructuredHeader): max_count: ClassVar[Literal[1]] @@ -46,7 +47,7 @@ class DateHeader: @staticmethod def value_parser(value: str) -> UnstructuredTokenList: ... @classmethod - def parse(cls, value: str | _datetime, kwds: dict[str, Any]) -> None: ... + def parse(cls, value: str | _datetime, kwds: dict[str, Incomplete]) -> None: ... class UniqueDateHeader(DateHeader): max_count: ClassVar[Literal[1]] @@ -61,7 +62,7 @@ class AddressHeader: @staticmethod def value_parser(value: str) -> AddressList: ... @classmethod - def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... + def parse(cls, value: str, kwds: dict[str, Incomplete]) -> None: ... class UniqueAddressHeader(AddressHeader): max_count: ClassVar[Literal[1]] @@ -94,15 +95,15 @@ class MIMEVersionHeader: @staticmethod def value_parser(value: str) -> MIMEVersion: ... @classmethod - def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... + def parse(cls, value: str, kwds: dict[str, Incomplete]) -> None: ... class ParameterizedMIMEHeader: max_count: ClassVar[Literal[1]] - def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect], params: Mapping[str, Any]) -> None: ... + def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect], params: Mapping[str, Incomplete]) -> None: ... @property - def params(self) -> types.MappingProxyType[str, Any]: ... + def params(self) -> types.MappingProxyType[str, Incomplete]: ... @classmethod - def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... + def parse(cls, value: str, kwds: dict[str, Incomplete]) -> None: ... class ContentTypeHeader(ParameterizedMIMEHeader): @property @@ -127,14 +128,14 @@ class ContentTransferEncodingHeader: @property def cte(self) -> str: ... @classmethod - def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... + def parse(cls, value: str, kwds: dict[str, Incomplete]) -> None: ... @staticmethod def value_parser(value: str) -> ContentTransferEncoding: ... class MessageIDHeader: max_count: ClassVar[Literal[1]] @classmethod - def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... + def parse(cls, value: str, kwds: dict[str, Incomplete]) -> None: ... @staticmethod def value_parser(value: str) -> MessageID: ... @@ -145,7 +146,7 @@ if sys.version_info >= (3, 13): class ReferencesHeader: max_count: ClassVar[Literal[1]] @classmethod - def parse(cls, value: str, kwds: dict[str, Any]) -> None: ... + def parse(cls, value: str, kwds: dict[str, Incomplete]) -> None: ... @staticmethod def value_parser(value: str) -> MessageIDList: ... @@ -155,7 +156,7 @@ class _HeaderParser(Protocol): @staticmethod def value_parser(value: str, /) -> TokenList: ... @classmethod - def parse(cls, value: str, kwds: dict[str, Any], /) -> None: ... + def parse(cls, value: str, kwds: dict[str, Incomplete], /) -> None: ... class HeaderRegistry: registry: dict[str, type[_HeaderParser]] @@ -166,7 +167,7 @@ class HeaderRegistry: ) -> None: ... def map_to_type(self, name: str, cls: type[BaseHeader]) -> None: ... def __getitem__(self, name: str) -> type[BaseHeader]: ... - def __call__(self, name: str, value: Any) -> BaseHeader: ... + def __call__(self, name: str, value) -> BaseHeader: ... class Address: @property diff --git a/stdlib/email/message.pyi b/stdlib/email/message.pyi index 784c2cace425..2dde88a7c480 100644 --- a/stdlib/email/message.pyi +++ b/stdlib/email/message.pyi @@ -1,4 +1,4 @@ -from _typeshed import MaybeNone +from _typeshed import Incomplete, MaybeNone from collections.abc import Generator, Iterator, Sequence from email import _ParamsType, _ParamType from email.charset import Charset @@ -175,14 +175,14 @@ class MIMEPart(Message[_HeaderRegistryT_co, _HeaderRegistryParamT_contra]): # cause unforseen consequences. def iter_attachments(self) -> Iterator[Self]: ... def iter_parts(self) -> Iterator[MIMEPart[_HeaderRegistryT_co, _HeaderRegistryParamT_contra]]: ... - def get_content(self, *args: Any, content_manager: ContentManager | None = None, **kw: Any) -> Any: ... - def set_content(self, *args: Any, content_manager: ContentManager | None = None, **kw: Any) -> None: ... + def get_content(self, *args: Incomplete, content_manager: ContentManager | None = None, **kw) -> Incomplete: ... + def set_content(self, *args: Incomplete, content_manager: ContentManager | None = None, **kw) -> None: ... def make_related(self, boundary: str | None = None) -> None: ... def make_alternative(self, boundary: str | None = None) -> None: ... def make_mixed(self, boundary: str | None = None) -> None: ... - def add_related(self, *args: Any, content_manager: ContentManager | None = ..., **kw: Any) -> None: ... - def add_alternative(self, *args: Any, content_manager: ContentManager | None = ..., **kw: Any) -> None: ... - def add_attachment(self, *args: Any, content_manager: ContentManager | None = ..., **kw: Any) -> None: ... + def add_related(self, *args: Incomplete, content_manager: ContentManager | None = ..., **kw) -> None: ... + def add_alternative(self, *args: Incomplete, content_manager: ContentManager | None = ..., **kw) -> None: ... + def add_attachment(self, *args: Incomplete, content_manager: ContentManager | None = ..., **kw) -> None: ... def clear(self) -> None: ... def clear_content(self) -> None: ... def as_string(self, unixfrom: bool = False, maxheaderlen: int | None = None, policy: Policy[Any] | None = None) -> str: ... diff --git a/stdlib/email/policy.pyi b/stdlib/email/policy.pyi index 76e4435ae95a..7b75da16a99b 100644 --- a/stdlib/email/policy.pyi +++ b/stdlib/email/policy.pyi @@ -50,7 +50,7 @@ class EmailPolicy(Policy[_MessageT]): ) -> None: ... def header_source_parse(self, sourcelines: list[str]) -> tuple[str, str]: ... - def header_store_parse(self, name: str, value: Incomplete) -> tuple[str, Incomplete]: ... + def header_store_parse(self, name: str, value) -> tuple[str, Incomplete]: ... def header_fetch_parse(self, name: str, value: str) -> Incomplete: ... def fold(self, name: str, value: str) -> Incomplete: ... def fold_binary(self, name: str, value: str) -> bytes: ... From 543d25e5004ad1232db7856324c8c9cba92901c1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2026 10:06:38 +0000 Subject: [PATCH 4/7] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/email/headerregistry.pyi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/email/headerregistry.pyi b/stdlib/email/headerregistry.pyi index cb5df247b018..3eaacda0ac77 100644 --- a/stdlib/email/headerregistry.pyi +++ b/stdlib/email/headerregistry.pyi @@ -99,7 +99,9 @@ class MIMEVersionHeader: class ParameterizedMIMEHeader: max_count: ClassVar[Literal[1]] - def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect], params: Mapping[str, Incomplete]) -> None: ... + def init( + self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect], params: Mapping[str, Incomplete] + ) -> None: ... @property def params(self) -> types.MappingProxyType[str, Incomplete]: ... @classmethod From 50694fd299bc4570fbe1331f9cab51f1ebafc538 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 10 Sep 2026 12:23:30 +0200 Subject: [PATCH 5/7] Remove redundant incompletes --- stdlib/email/contentmanager.pyi | 4 ++-- stdlib/email/message.pyi | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/stdlib/email/contentmanager.pyi b/stdlib/email/contentmanager.pyi index 78d22b4d9202..eb239abd8cec 100644 --- a/stdlib/email/contentmanager.pyi +++ b/stdlib/email/contentmanager.pyi @@ -3,8 +3,8 @@ from collections.abc import Callable from email.message import Message class ContentManager: - def get_content(self, msg: Message, *args: Incomplete, **kw: Incomplete) -> Incomplete: ... - def set_content(self, msg: Message, obj: Incomplete, *args: Incomplete, **kw: Incomplete) -> Incomplete: ... + def get_content(self, msg: Message, *args, **kw) -> Incomplete: ... + def set_content(self, msg: Message, obj, *args, **kw) -> Incomplete: ... def add_get_handler(self, key: str, handler: Callable[..., Incomplete]) -> None: ... def add_set_handler(self, typekey: type, handler: Callable[..., Incomplete]) -> None: ... diff --git a/stdlib/email/message.pyi b/stdlib/email/message.pyi index 2dde88a7c480..5b5dc3f1571a 100644 --- a/stdlib/email/message.pyi +++ b/stdlib/email/message.pyi @@ -175,14 +175,14 @@ class MIMEPart(Message[_HeaderRegistryT_co, _HeaderRegistryParamT_contra]): # cause unforseen consequences. def iter_attachments(self) -> Iterator[Self]: ... def iter_parts(self) -> Iterator[MIMEPart[_HeaderRegistryT_co, _HeaderRegistryParamT_contra]]: ... - def get_content(self, *args: Incomplete, content_manager: ContentManager | None = None, **kw) -> Incomplete: ... - def set_content(self, *args: Incomplete, content_manager: ContentManager | None = None, **kw) -> None: ... + def get_content(self, *args, content_manager: ContentManager | None = None, **kw) -> Incomplete: ... + def set_content(self, *args, content_manager: ContentManager | None = None, **kw) -> None: ... def make_related(self, boundary: str | None = None) -> None: ... def make_alternative(self, boundary: str | None = None) -> None: ... def make_mixed(self, boundary: str | None = None) -> None: ... - def add_related(self, *args: Incomplete, content_manager: ContentManager | None = ..., **kw) -> None: ... - def add_alternative(self, *args: Incomplete, content_manager: ContentManager | None = ..., **kw) -> None: ... - def add_attachment(self, *args: Incomplete, content_manager: ContentManager | None = ..., **kw) -> None: ... + def add_related(self, *args, content_manager: ContentManager | None = ..., **kw) -> None: ... + def add_alternative(self, *args, content_manager: ContentManager | None = ..., **kw) -> None: ... + def add_attachment(self, *args, content_manager: ContentManager | None = ..., **kw) -> None: ... def clear(self) -> None: ... def clear_content(self) -> None: ... def as_string(self, unixfrom: bool = False, maxheaderlen: int | None = None, policy: Policy[Any] | None = None) -> str: ... From f96e6b4078e7f9550ec530222723e07ba876399d Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 10 Sep 2026 12:32:03 +0200 Subject: [PATCH 6/7] Remove redundant incompletes --- stdlib/email/contentmanager.pyi | 4 ++-- stdlib/email/message.pyi | 4 ++-- stdlib/email/policy.pyi | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/stdlib/email/contentmanager.pyi b/stdlib/email/contentmanager.pyi index eb239abd8cec..343667213a3e 100644 --- a/stdlib/email/contentmanager.pyi +++ b/stdlib/email/contentmanager.pyi @@ -3,8 +3,8 @@ from collections.abc import Callable from email.message import Message class ContentManager: - def get_content(self, msg: Message, *args, **kw) -> Incomplete: ... - def set_content(self, msg: Message, obj, *args, **kw) -> Incomplete: ... + def get_content(self, msg: Message, *args, **kw): ... + def set_content(self, msg: Message, obj, *args, **kw): ... def add_get_handler(self, key: str, handler: Callable[..., Incomplete]) -> None: ... def add_set_handler(self, typekey: type, handler: Callable[..., Incomplete]) -> None: ... diff --git a/stdlib/email/message.pyi b/stdlib/email/message.pyi index 5b5dc3f1571a..e17b98474948 100644 --- a/stdlib/email/message.pyi +++ b/stdlib/email/message.pyi @@ -1,4 +1,4 @@ -from _typeshed import Incomplete, MaybeNone +from _typeshed import MaybeNone from collections.abc import Generator, Iterator, Sequence from email import _ParamsType, _ParamType from email.charset import Charset @@ -175,7 +175,7 @@ class MIMEPart(Message[_HeaderRegistryT_co, _HeaderRegistryParamT_contra]): # cause unforseen consequences. def iter_attachments(self) -> Iterator[Self]: ... def iter_parts(self) -> Iterator[MIMEPart[_HeaderRegistryT_co, _HeaderRegistryParamT_contra]]: ... - def get_content(self, *args, content_manager: ContentManager | None = None, **kw) -> Incomplete: ... + def get_content(self, *args, content_manager: ContentManager | None = None, **kw): ... def set_content(self, *args, content_manager: ContentManager | None = None, **kw) -> None: ... def make_related(self, boundary: str | None = None) -> None: ... def make_alternative(self, boundary: str | None = None) -> None: ... diff --git a/stdlib/email/policy.pyi b/stdlib/email/policy.pyi index 7b75da16a99b..d964801c8132 100644 --- a/stdlib/email/policy.pyi +++ b/stdlib/email/policy.pyi @@ -51,8 +51,8 @@ class EmailPolicy(Policy[_MessageT]): def header_source_parse(self, sourcelines: list[str]) -> tuple[str, str]: ... def header_store_parse(self, name: str, value) -> tuple[str, Incomplete]: ... - def header_fetch_parse(self, name: str, value: str) -> Incomplete: ... - def fold(self, name: str, value: str) -> Incomplete: ... + def header_fetch_parse(self, name: str, value: str): ... + def fold(self, name: str, value: str): ... def fold_binary(self, name: str, value: str) -> bytes: ... def clone( self, From c0e82fc297c6d2b5db9dcea32990477c5aa8082e Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 10 Sep 2026 12:47:36 +0200 Subject: [PATCH 7/7] Remove email from the stricter pyright config --- pyrightconfig.stricter.json | 1 + 1 file changed, 1 insertion(+) diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index 56343ebc54f1..d3d66b8fd7fc 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -14,6 +14,7 @@ "stdlib/distutils/cmd.pyi", "stdlib/distutils/command", "stdlib/distutils/dist.pyi", + "stdlib/email/*.pyi", "stdlib/encodings/__init__.pyi", "stdlib/lib2to3/fixes/*.pyi", "stdlib/numbers.pyi",