@@ -3,17 +3,27 @@ from email import _ParamsType, _ParamType
33from email .charset import Charset
44from email .contentmanager import ContentManager
55from email .errors import MessageDefect
6+ from email .header import Header
67from email .policy import Policy
7- from typing import Any , TypeVar , overload
8- from typing_extensions import Self , TypeAlias
8+ from typing import Any , Protocol , TypeVar , overload
9+ from typing_extensions import Literal , Self , TypeAlias
910
1011__all__ = ["Message" , "EmailMessage" ]
1112
1213_T = TypeVar ("_T" )
13-
14- _PayloadType : TypeAlias = list [Message ] | str | bytes | bytearray
14+ _PayloadType : TypeAlias = Message | str
15+ _EncodedPayloadType : TypeAlias = Message | bytes
16+ _MultipartPayloadType : TypeAlias = list [_PayloadType ]
1517_CharsetType : TypeAlias = Charset | str | None
18+ # Type returned by Policy.header_fetch_parse, AnyOf[str | Header]
1619_HeaderType : TypeAlias = Any
20+ _HeaderTypeParam : TypeAlias = str | Header
21+
22+ class _SupportsEncodeToPayload (Protocol ):
23+ def encode (self , __encoding : str ) -> _PayloadType | _MultipartPayloadType | _SupportsDecodeToPayload : ...
24+
25+ class _SupportsDecodeToPayload (Protocol ):
26+ def decode (self , __encoding : str , __errors : str ) -> _PayloadType | _MultipartPayloadType : ...
1727
1828class Message :
1929 policy : Policy # undocumented
@@ -23,16 +33,43 @@ class Message:
2333 def is_multipart (self ) -> bool : ...
2434 def set_unixfrom (self , unixfrom : str ) -> None : ...
2535 def get_unixfrom (self ) -> str | None : ...
26- def attach (self , payload : Message ) -> None : ...
27- def get_payload (self , i : int | None = None , decode : bool = False ) -> Any : ... # returns _PayloadType | None
28- def set_payload (self , payload : _PayloadType , charset : _CharsetType = None ) -> None : ...
36+ def attach (self , payload : _PayloadType ) -> None : ...
37+ # `i: int` without a multipart payload results in an error
38+ # `| Any`: can be None for cleared or unset payload, but annoying to check
39+ @overload # multipart
40+ def get_payload (self , i : int , decode : Literal [True ]) -> None : ...
41+ @overload # multipart
42+ def get_payload (self , i : int , decode : Literal [False ] = False ) -> _PayloadType | Any : ...
43+ @overload # either
44+ def get_payload (self , i : None = None , decode : Literal [False ] = False ) -> _PayloadType | _MultipartPayloadType | Any : ...
45+ @overload # not multipart
46+ def get_payload (self , i : None = None , * , decode : Literal [True ]) -> _EncodedPayloadType | Any : ...
47+ @overload # not multipart, IDEM but w/o kwarg
48+ def get_payload (self , i : None , decode : Literal [True ]) -> _EncodedPayloadType | Any : ...
49+ # If `charset=None` and payload supports both `encode` AND `decode`, then an invalid payload could be passed, but this is unlikely
50+ # Not[_SupportsEncodeToPayload]
51+ @overload
52+ def set_payload (
53+ self , payload : _SupportsDecodeToPayload | _PayloadType | _MultipartPayloadType , charset : None = None
54+ ) -> None : ...
55+ @overload
56+ def set_payload (
57+ self ,
58+ payload : _SupportsEncodeToPayload | _SupportsDecodeToPayload | _PayloadType | _MultipartPayloadType ,
59+ charset : Charset | str ,
60+ ) -> None : ...
2961 def set_charset (self , charset : _CharsetType ) -> None : ...
3062 def get_charset (self ) -> _CharsetType : ...
3163 def __len__ (self ) -> int : ...
3264 def __contains__ (self , name : str ) -> bool : ...
3365 def __iter__ (self ) -> Iterator [str ]: ...
66+ # Same as `get` with `failobj=None`, but with the expectation that it won't return None in most scenarios
67+ # This is important for protocols using __getitem__, like SupportsKeysAndGetItem
68+ # Morally, the return type should be `AnyOf[_HeaderType, None]`,
69+ # which we could spell as `_HeaderType | Any`,
70+ # *but* `_HeaderType` itself is currently an alias to `Any`...
3471 def __getitem__ (self , name : str ) -> _HeaderType : ...
35- def __setitem__ (self , name : str , val : _HeaderType ) -> None : ...
72+ def __setitem__ (self , name : str , val : _HeaderTypeParam ) -> None : ...
3673 def __delitem__ (self , name : str ) -> None : ...
3774 def keys (self ) -> list [str ]: ...
3875 def values (self ) -> list [_HeaderType ]: ...
@@ -46,7 +83,7 @@ class Message:
4683 @overload
4784 def get_all (self , name : str , failobj : _T ) -> list [_HeaderType ] | _T : ...
4885 def add_header (self , _name : str , _value : str , ** _params : _ParamsType ) -> None : ...
49- def replace_header (self , _name : str , _value : _HeaderType ) -> None : ...
86+ def replace_header (self , _name : str , _value : _HeaderTypeParam ) -> None : ...
5087 def get_content_type (self ) -> str : ...
5188 def get_content_maintype (self ) -> str : ...
5289 def get_content_subtype (self ) -> str : ...
@@ -100,7 +137,7 @@ class Message:
100137 ) -> None : ...
101138 def __init__ (self , policy : Policy = ...) -> None : ...
102139 # The following two methods are undocumented, but a source code comment states that they are public API
103- def set_raw (self , name : str , value : _HeaderType ) -> None : ...
140+ def set_raw (self , name : str , value : _HeaderTypeParam ) -> None : ...
104141 def raw_items (self ) -> Iterator [tuple [str , _HeaderType ]]: ...
105142
106143class MIMEPart (Message ):
0 commit comments