diff --git a/stdlib/email/__init__.pyi b/stdlib/email/__init__.pyi index fca302f5f1a7..c839187af074 100644 --- a/stdlib/email/__init__.pyi +++ b/stdlib/email/__init__.pyi @@ -1,3 +1,4 @@ +from _typeshed import Incomplete from collections.abc import Callable from email.message import Message from email.policy import Policy @@ -8,10 +9,16 @@ from typing_extensions import TypeAlias _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: ... +# TODO: These functions should be generic over the message with appropriate +# overloads. (#10762) +def message_from_string(s: str, _class: Callable[[], Message] = ..., *, policy: Policy[Incomplete] = ...) -> Message: ... +def message_from_bytes( + s: bytes | bytearray, _class: Callable[[], Message] = ..., *, policy: Policy[Incomplete] = ... +) -> Message: ... +def message_from_file(fp: IO[str], _class: Callable[[], Message] = ..., *, policy: Policy[Incomplete] = ...) -> Message: ... +def message_from_binary_file( + fp: IO[bytes], _class: Callable[[], Message] = ..., *, policy: Policy[Incomplete] = ... +) -> Message: ... # Names in __all__ with no definition: # base64mime diff --git a/stdlib/email/_header_value_parser.pyi b/stdlib/email/_header_value_parser.pyi index 806fc84cf784..00c5e334b672 100644 --- a/stdlib/email/_header_value_parser.pyi +++ b/stdlib/email/_header_value_parser.pyi @@ -36,7 +36,7 @@ class TokenList(list[TokenList | Terminal]): def as_ew_allowed(self) -> bool: ... @property def comments(self) -> list[str]: ... - def fold(self, *, policy: Policy) -> str: ... + def fold(self, *, policy: Policy[Any]) -> str: ... def pprint(self, indent: str = "") -> None: ... def ppstr(self, indent: str = "") -> str: ... @@ -297,7 +297,7 @@ class HeaderLabel(TokenList): class MsgID(TokenList): token_type: str as_ew_allowed: bool - def fold(self, policy: Policy) -> str: ... + def fold(self, policy: Policy[Any]) -> str: ... class MessageID(MsgID): token_type: str diff --git a/stdlib/email/_policybase.pyi b/stdlib/email/_policybase.pyi index a3dd61a282ce..cc13cda53229 100644 --- a/stdlib/email/_policybase.pyi +++ b/stdlib/email/_policybase.pyi @@ -3,32 +3,46 @@ from collections.abc import Callable from email.errors import MessageDefect from email.header import Header from email.message import Message -from typing import Any +from typing import Any, Generic, TypeVar from typing_extensions import Self +_MessageT = TypeVar("_MessageT", bound=Message) + class _PolicyBase: def __add__(self, other: Any) -> Self: ... def clone(self, **kw: Any) -> Self: ... -class Policy(_PolicyBase, metaclass=ABCMeta): +class Policy(_PolicyBase, Generic[_MessageT], metaclass=ABCMeta): max_line_length: int | None linesep: str cte_type: str raise_on_defect: bool mangle_from_: bool - message_factory: Callable[[Policy], Message] | None + message_factory: Callable[[[_MessageT]], [_MessageT]] | None + @overload + def __init__( + self: Policy[Message[str, str]], + *, + max_line_length: int | None = ..., + linesep: str = ..., + cte_type: str = ..., + raise_on_defect: bool = ..., + mangle_from_: bool = ..., + message_factory: None = None, + ) -> None: ... + @overload def __init__( self, *, - max_line_length: int | None = 78, - linesep: str = "\n", - cte_type: str = "8bit", - raise_on_defect: bool = False, - mangle_from_: bool = False, - message_factory: Callable[[Policy], Message] | None = None, + max_line_length: int | None = ..., + linesep: str = ..., + cte_type: str = ..., + raise_on_defect: bool = ..., + mangle_from_: bool = ..., + message_factory: Callable[[Policy[_MessageT]], _MessageT], ) -> None: ... - def handle_defect(self, obj: Message, defect: MessageDefect) -> None: ... - def register_defect(self, obj: Message, defect: MessageDefect) -> None: ... + def handle_defect(self, obj: _MessageT, defect: MessageDefect) -> None: ... + def register_defect(self, obj: _MessageT, defect: MessageDefect) -> None: ... def header_max_count(self, name: str) -> int | None: ... @abstractmethod def header_source_parse(self, sourcelines: list[str]) -> tuple[str, str]: ... @@ -41,11 +55,11 @@ class Policy(_PolicyBase, metaclass=ABCMeta): @abstractmethod def fold_binary(self, name: str, value: str) -> bytes: ... -class Compat32(Policy): +class Compat32(Policy[_MessageT]): def header_source_parse(self, sourcelines: list[str]) -> tuple[str, str]: ... def header_store_parse(self, name: str, value: str) -> tuple[str, str]: ... def header_fetch_parse(self, name: str, value: str) -> str | Header: ... # type: ignore[override] def fold(self, name: str, value: str) -> str: ... def fold_binary(self, name: str, value: str) -> bytes: ... -compat32: Compat32 +compat32: Compat32[Message] diff --git a/stdlib/email/feedparser.pyi b/stdlib/email/feedparser.pyi index 22920fc99c69..e23b76a70a41 100644 --- a/stdlib/email/feedparser.pyi +++ b/stdlib/email/feedparser.pyi @@ -9,15 +9,15 @@ _MessageT = TypeVar("_MessageT", bound=Message) class FeedParser(Generic[_MessageT]): @overload - def __init__(self: FeedParser[Message], _factory: None = None, *, policy: Policy = ...) -> None: ... + def __init__(self: FeedParser[Message], _factory: None = None, *, policy: Policy[Message] = ...) -> None: ... @overload - def __init__(self, _factory: Callable[[], _MessageT], *, policy: Policy = ...) -> None: ... + def __init__(self, _factory: Callable[[], _MessageT], *, policy: Policy[_MessageT] = ...) -> None: ... def feed(self, data: str) -> None: ... def close(self) -> _MessageT: ... class BytesFeedParser(FeedParser[_MessageT]): @overload - def __init__(self: BytesFeedParser[Message], _factory: None = None, *, policy: Policy = ...) -> None: ... + def __init__(self: BytesFeedParser[Message], _factory: None = None, *, policy: Policy[Message] = ...) -> None: ... @overload - def __init__(self, _factory: Callable[[], _MessageT], *, policy: Policy = ...) -> None: ... - def feed(self, data: bytes | bytearray) -> None: ... # type: ignore[override] + def __init__(self, _factory: Callable[[], _MessageT], *, policy: Policy[_MessageT] = ...) -> None: ... + def feed(self, data: bytes | bytearray) -> None: ... diff --git a/stdlib/email/generator.pyi b/stdlib/email/generator.pyi index faa6551fc925..33b9403e77a5 100644 --- a/stdlib/email/generator.pyi +++ b/stdlib/email/generator.pyi @@ -1,6 +1,7 @@ from _typeshed import SupportsWrite from email.message import Message from email.policy import Policy +from typing import Any from typing_extensions import Self __all__ = ["Generator", "DecodedGenerator", "BytesGenerator"] @@ -14,7 +15,7 @@ class Generator: mangle_from_: bool | None = None, maxheaderlen: int | None = None, *, - policy: Policy | None = None, + policy: Policy[Any] | None = None, ) -> None: ... def flatten(self, msg: Message, unixfrom: bool = False, linesep: str | None = None) -> None: ... @@ -25,7 +26,7 @@ class BytesGenerator(Generator): mangle_from_: bool | None = None, maxheaderlen: int | None = None, *, - policy: Policy | None = None, + policy: Policy[Any] | None = None, ) -> None: ... class DecodedGenerator(Generator): @@ -36,5 +37,5 @@ class DecodedGenerator(Generator): maxheaderlen: int | None = None, fmt: str | None = None, *, - policy: Policy | None = None, + policy: Policy[Any] | None = None, ) -> None: ... diff --git a/stdlib/email/headerregistry.pyi b/stdlib/email/headerregistry.pyi index 2ffdca9b2f22..913c5b032bae 100644 --- a/stdlib/email/headerregistry.pyi +++ b/stdlib/email/headerregistry.pyi @@ -25,7 +25,7 @@ class BaseHeader(str): def defects(self) -> tuple[MessageDefect, ...]: ... def __new__(cls, name: str, value: Any) -> Self: ... def init(self, name: str, *, parse_tree: TokenList, defects: Iterable[MessageDefect]) -> None: ... - def fold(self, *, policy: Policy) -> str: ... + def fold(self, *, policy: Policy[Any]) -> str: ... class UnstructuredHeader: max_count: ClassVar[Literal[1] | None] diff --git a/stdlib/email/message.pyi b/stdlib/email/message.pyi index 4032bc6136d4..e243e6231ddf 100644 --- a/stdlib/email/message.pyi +++ b/stdlib/email/message.pyi @@ -30,7 +30,7 @@ class _SupportsDecodeToPayload(Protocol): def decode(self, encoding: str, errors: str, /) -> _PayloadType | _MultipartPayloadType: ... class Message(Generic[_HeaderT, _HeaderParamT]): - policy: Policy # undocumented + policy: Policy[Any] # undocumented preamble: str | None epilogue: str | None defects: list[MessageDefect] @@ -125,8 +125,8 @@ class Message(Generic[_HeaderT, _HeaderParamT]): def get_charsets(self, failobj: _T) -> list[str | _T]: ... def walk(self) -> Generator[Self, None, None]: ... def get_content_disposition(self) -> str | None: ... - def as_string(self, unixfrom: bool = False, maxheaderlen: int = 0, policy: Policy | None = None) -> str: ... - def as_bytes(self, unixfrom: bool = False, policy: Policy | None = None) -> bytes: ... + def as_string(self, unixfrom: bool = False, maxheaderlen: int = 0, policy: Policy[Any] | None = None) -> str: ... + def as_bytes(self, unixfrom: bool = False, policy: Policy[Any] | None = None) -> bytes: ... def __bytes__(self) -> bytes: ... def set_param( self, @@ -138,13 +138,13 @@ class Message(Generic[_HeaderT, _HeaderParamT]): language: str = "", replace: bool = False, ) -> None: ... - def __init__(self, policy: Policy = ...) -> None: ... + def __init__(self, policy: Policy[Any] = ...) -> None: ... # The following two methods are undocumented, but a source code comment states that they are public API def set_raw(self, name: str, value: _HeaderParamT) -> None: ... def raw_items(self) -> Iterator[tuple[str, _HeaderT]]: ... class MIMEPart(Message[_HeaderRegistryT, _HeaderRegistryParamT]): - def __init__(self, policy: Policy | None = None) -> None: ... + def __init__(self, policy: Policy[Any] | None = None) -> None: ... def get_body(self, preferencelist: Sequence[str] = ("related", "html", "plain")) -> MIMEPart[_HeaderRegistryT] | None: ... def iter_attachments(self) -> Iterator[MIMEPart[_HeaderRegistryT]]: ... def iter_parts(self) -> Iterator[MIMEPart[_HeaderRegistryT]]: ... @@ -158,7 +158,7 @@ class MIMEPart(Message[_HeaderRegistryT, _HeaderRegistryParamT]): def add_attachment(self, *args: Any, content_manager: ContentManager | None = ..., **kw: Any) -> None: ... def clear(self) -> None: ... def clear_content(self) -> None: ... - def as_string(self, unixfrom: bool = False, maxheaderlen: int | None = None, policy: Policy | None = None) -> str: ... + def as_string(self, unixfrom: bool = False, maxheaderlen: int | None = None, policy: Policy[Any] | None = None) -> str: ... def is_attachment(self) -> bool: ... class EmailMessage(MIMEPart): ... diff --git a/stdlib/email/mime/application.pyi b/stdlib/email/mime/application.pyi index a7ab9dc75ce2..65fba9ab1e49 100644 --- a/stdlib/email/mime/application.pyi +++ b/stdlib/email/mime/application.pyi @@ -2,6 +2,7 @@ from collections.abc import Callable from email import _ParamsType from email.mime.nonmultipart import MIMENonMultipart from email.policy import Policy +from typing import Any __all__ = ["MIMEApplication"] @@ -12,6 +13,6 @@ class MIMEApplication(MIMENonMultipart): _subtype: str = "octet-stream", _encoder: Callable[[MIMEApplication], object] = ..., *, - policy: Policy | None = None, + policy: Policy[Any] | None = None, **_params: _ParamsType, ) -> None: ... diff --git a/stdlib/email/mime/audio.pyi b/stdlib/email/mime/audio.pyi index 090dfb960db6..953a64f7f0ff 100644 --- a/stdlib/email/mime/audio.pyi +++ b/stdlib/email/mime/audio.pyi @@ -2,6 +2,7 @@ from collections.abc import Callable from email import _ParamsType from email.mime.nonmultipart import MIMENonMultipart from email.policy import Policy +from typing import Any __all__ = ["MIMEAudio"] @@ -12,6 +13,6 @@ class MIMEAudio(MIMENonMultipart): _subtype: str | None = None, _encoder: Callable[[MIMEAudio], object] = ..., *, - policy: Policy | None = None, + policy: Policy[Any] | None = None, **_params: _ParamsType, ) -> None: ... diff --git a/stdlib/email/mime/base.pyi b/stdlib/email/mime/base.pyi index b733709f1b5a..e40f47796705 100644 --- a/stdlib/email/mime/base.pyi +++ b/stdlib/email/mime/base.pyi @@ -1,8 +1,9 @@ import email.message from email import _ParamsType from email.policy import Policy +from typing import Any __all__ = ["MIMEBase"] class MIMEBase(email.message.Message): - def __init__(self, _maintype: str, _subtype: str, *, policy: Policy | None = None, **_params: _ParamsType) -> None: ... + def __init__(self, _maintype: str, _subtype: str, *, policy: Policy[Any] | None = None, **_params: _ParamsType) -> None: ... diff --git a/stdlib/email/mime/image.pyi b/stdlib/email/mime/image.pyi index b47afa6ce592..0e782a035dbc 100644 --- a/stdlib/email/mime/image.pyi +++ b/stdlib/email/mime/image.pyi @@ -2,6 +2,7 @@ from collections.abc import Callable from email import _ParamsType from email.mime.nonmultipart import MIMENonMultipart from email.policy import Policy +from typing import Any __all__ = ["MIMEImage"] @@ -12,6 +13,6 @@ class MIMEImage(MIMENonMultipart): _subtype: str | None = None, _encoder: Callable[[MIMEImage], object] = ..., *, - policy: Policy | None = None, + policy: Policy[Any] | None = None, **_params: _ParamsType, ) -> None: ... diff --git a/stdlib/email/mime/message.pyi b/stdlib/email/mime/message.pyi index 23cf58619ad9..16bee94d58eb 100644 --- a/stdlib/email/mime/message.pyi +++ b/stdlib/email/mime/message.pyi @@ -1,8 +1,9 @@ from email.message import Message from email.mime.nonmultipart import MIMENonMultipart from email.policy import Policy +from typing import Any __all__ = ["MIMEMessage"] class MIMEMessage(MIMENonMultipart): - def __init__(self, _msg: Message, _subtype: str = "rfc822", *, policy: Policy | None = None) -> None: ... + def __init__(self, _msg: Message, _subtype: str = "rfc822", *, policy: Policy[Any] | None = None) -> None: ... diff --git a/stdlib/email/mime/multipart.pyi b/stdlib/email/mime/multipart.pyi index 6163810ed94a..707550d2d7f4 100644 --- a/stdlib/email/mime/multipart.pyi +++ b/stdlib/email/mime/multipart.pyi @@ -3,6 +3,7 @@ from email import _ParamsType from email.message import Message from email.mime.base import MIMEBase from email.policy import Policy +from typing import Any __all__ = ["MIMEMultipart"] @@ -13,6 +14,6 @@ class MIMEMultipart(MIMEBase): boundary: str | None = None, _subparts: Sequence[Message] | None = None, *, - policy: Policy | None = None, + policy: Policy[Any] | None = None, **_params: _ParamsType, ) -> None: ... diff --git a/stdlib/email/mime/text.pyi b/stdlib/email/mime/text.pyi index 74d5ef4c5cae..24b67b51811b 100644 --- a/stdlib/email/mime/text.pyi +++ b/stdlib/email/mime/text.pyi @@ -1,9 +1,10 @@ from email.mime.nonmultipart import MIMENonMultipart from email.policy import Policy +from typing import Any __all__ = ["MIMEText"] class MIMEText(MIMENonMultipart): def __init__( - self, _text: str, _subtype: str = "plain", _charset: str | None = None, *, policy: Policy | None = None + self, _text: str, _subtype: str = "plain", _charset: str | None = None, *, policy: Policy[Any] | None = None ) -> None: ... diff --git a/stdlib/email/parser.pyi b/stdlib/email/parser.pyi index fecb29d90b2e..a1a57b4eef4b 100644 --- a/stdlib/email/parser.pyi +++ b/stdlib/email/parser.pyi @@ -12,9 +12,9 @@ _MessageT = TypeVar("_MessageT", bound=Message, default=Message) class Parser(Generic[_MessageT]): @overload - def __init__(self: Parser[Message[str, str]], _class: None = None, *, policy: Policy = ...) -> None: ... + def __init__(self: Parser[Message[str, str]], _class: None = None, *, policy: Policy[Message[str, str]] = ...) -> None: ... @overload - def __init__(self, _class: Callable[[], _MessageT], *, policy: Policy = ...) -> None: ... + def __init__(self, _class: Callable[[], _MessageT], *, policy: Policy[_MessageT] = ...) -> None: ... def parse(self, fp: SupportsRead[str], headersonly: bool = False) -> _MessageT: ... def parsestr(self, text: str, headersonly: bool = False) -> _MessageT: ... @@ -25,9 +25,11 @@ class HeaderParser(Parser[_MessageT]): class BytesParser(Generic[_MessageT]): parser: Parser[_MessageT] @overload - def __init__(self: BytesParser[Message[str, str]], _class: None = None, *, policy: Policy = ...) -> None: ... + def __init__( + self: BytesParser[Message[str, str]], _class: None = None, *, policy: Policy[Message[str, str]] = ... + ) -> None: ... @overload - def __init__(self, _class: Callable[[], _MessageT], *, policy: Policy = ...) -> None: ... + def __init__(self, _class: Callable[[], _MessageT], *, policy: Policy[_MessageT] = ...) -> None: ... def parse(self, fp: _WrappedBuffer, headersonly: bool = False) -> _MessageT: ... def parsebytes(self, text: bytes | bytearray, headersonly: bool = False) -> _MessageT: ... diff --git a/stdlib/email/policy.pyi b/stdlib/email/policy.pyi index 5f1cf934eb3c..f06e710b2d8a 100644 --- a/stdlib/email/policy.pyi +++ b/stdlib/email/policy.pyi @@ -1,16 +1,34 @@ from collections.abc import Callable from email._policybase import Compat32 as Compat32, Policy as Policy, compat32 as compat32 from email.contentmanager import ContentManager -from email.message import Message -from typing import Any +from email.message import EmailMessage, Message +from typing import Any, TypeVar, overload __all__ = ["Compat32", "compat32", "Policy", "EmailPolicy", "default", "strict", "SMTP", "HTTP"] -class EmailPolicy(Policy): +_MessageT = TypeVar("_MessageT", bound=Message) + +class EmailPolicy(Policy[_MessageT]): utf8: bool refold_source: str header_factory: Callable[[str, Any], Any] 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 = ..., + message_factory: None = None, + utf8: bool = ..., + refold_source: str = ..., + header_factory: Callable[[str, str], str] = ..., + content_manager: ContentManager = ..., + ) -> None: ... + @overload def __init__( self, *, @@ -19,7 +37,7 @@ class EmailPolicy(Policy): cte_type: str = ..., raise_on_defect: bool = ..., mangle_from_: bool = ..., - message_factory: Callable[[Policy], Message] | None = ..., + message_factory: Callable[[Policy[_MessageT]], _MessageT], utf8: bool = ..., refold_source: str = ..., header_factory: Callable[[str, str], str] = ..., @@ -31,8 +49,8 @@ class EmailPolicy(Policy): def fold(self, name: str, value: str) -> Any: ... def fold_binary(self, name: str, value: str) -> bytes: ... -default: EmailPolicy -SMTP: EmailPolicy -SMTPUTF8: EmailPolicy -HTTP: EmailPolicy -strict: EmailPolicy +default: EmailPolicy[EmailMessage] +SMTP: EmailPolicy[EmailMessage] +SMTPUTF8: EmailPolicy[EmailMessage] +HTTP: EmailPolicy[EmailMessage] +strict: EmailPolicy[EmailMessage]