Cleanup EmailMessage types (#208)

* Cleanup EmailMessage types

* Typecheck email module tests.
This commit is contained in:
Konstantin Alekseev
2019-12-01 17:14:16 +03:00
committed by Maksim Kurnikov
parent f824003cc4
commit c0c5d1e588
8 changed files with 70 additions and 23 deletions

2
.gitignore vendored
View File

@@ -9,3 +9,5 @@ build/
dist/ dist/
pip-wheel-metadata/ pip-wheel-metadata/
.pytest_cache/ .pytest_cache/
/.envrc
/.direnv

View File

@@ -0,0 +1,3 @@
from django.core.mail.backends.base import BaseEmailBackend
class EmailBackend(BaseEmailBackend): ...

View File

@@ -0,0 +1,3 @@
from django.core.mail.backends.base import BaseEmailBackend
class EmailBackend(BaseEmailBackend): ...

View File

@@ -0,0 +1,3 @@
from django.core.mail.backends.base import BaseEmailBackend
class EmailBackend(BaseEmailBackend): ...

View File

@@ -0,0 +1,3 @@
from django.core.mail.backends.base import BaseEmailBackend
class EmailBackend(BaseEmailBackend): ...

View File

@@ -1,3 +1,18 @@
import smtplib
import threading
from typing import Optional, Union
from django.core.mail.backends.base import BaseEmailBackend from django.core.mail.backends.base import BaseEmailBackend
class EmailBackend(BaseEmailBackend): ... class EmailBackend(BaseEmailBackend):
host: str = ...
port: int = ...
username: str = ...
password: str = ...
use_tls: bool = ...
use_ssl: bool = ...
timeout: Optional[int] = ...
ssl_keyfile: Optional[str] = ...
ssl_certfile: Optional[str] = ...
connection: Union[smtplib.SMTP_SSL, smtplib.SMTP, None] = ...
_lock: threading.RLock = ...

View File

@@ -1,8 +1,10 @@
from email._policybase import Policy # type: ignore from email._policybase import Policy # type: ignore
from email.message import Message
from email.mime.base import MIMEBase
from email.mime.message import MIMEMessage from email.mime.message import MIMEMessage
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText from email.mime.text import MIMEText
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union from typing import Any, Dict, List, Optional, Sequence, Tuple, Union, overload
utf8_charset: Any utf8_charset: Any
utf8_charset_qp: Any utf8_charset_qp: Any
@@ -43,6 +45,11 @@ class SafeMIMEMultipart(MIMEMixin, MIMEMultipart):
self, _subtype: str = ..., boundary: None = ..., _subparts: None = ..., encoding: str = ..., **_params: Any self, _subtype: str = ..., boundary: None = ..., _subparts: None = ..., encoding: str = ..., **_params: Any
) -> None: ... ) -> None: ...
_AttachmentContent = Union[bytes, EmailMessage, Message, SafeMIMEText, str]
_AttachmentTuple = Union[
Tuple[str, _AttachmentContent], Tuple[Optional[str], _AttachmentContent, str], Tuple[str, _AttachmentContent, None]
]
class EmailMessage: class EmailMessage:
content_subtype: str = ... content_subtype: str = ...
mixed_subtype: str = ... mixed_subtype: str = ...
@@ -62,42 +69,42 @@ class EmailMessage:
subject: str = ..., subject: str = ...,
body: Optional[str] = ..., body: Optional[str] = ...,
from_email: Optional[str] = ..., from_email: Optional[str] = ...,
to: Optional[Union[Sequence[str], str]] = ..., to: Optional[Sequence[str]] = ...,
bcc: Optional[Union[Sequence[str], str]] = ..., bcc: Optional[Sequence[str]] = ...,
connection: Optional[Any] = ..., connection: Optional[Any] = ...,
attachments: Optional[Union[List[Tuple[str, Union[str, bytes], str]], List[MIMEText]]] = ..., attachments: Optional[Sequence[Union[MIMEBase, _AttachmentTuple]]] = ...,
headers: Optional[Dict[str, str]] = ..., headers: Optional[Dict[str, str]] = ...,
cc: Optional[Union[Sequence[str], str]] = ..., cc: Optional[Sequence[str]] = ...,
reply_to: Optional[Union[List[Optional[str]], str]] = ..., reply_to: Optional[Sequence[str]] = ...,
) -> None: ... ) -> None: ...
def get_connection(self, fail_silently: bool = ...) -> Any: ... def get_connection(self, fail_silently: bool = ...) -> Any: ...
# TODO: when typeshed gets more types for email.Message, move it to MIMEMessage, now it has too many false-positives # TODO: when typeshed gets more types for email.Message, move it to MIMEMessage, now it has too many false-positives
def message(self) -> Any: ... def message(self) -> Any: ...
def recipients(self) -> List[str]: ... def recipients(self) -> List[str]: ...
def send(self, fail_silently: bool = ...) -> int: ... def send(self, fail_silently: bool = ...) -> int: ...
def attach( @overload
self, def attach(self, filename: MIMEText = ...) -> None: ...
filename: Optional[Union[MIMEText, str]] = ..., @overload
content: Optional[Union[bytes, EmailMessage, SafeMIMEText, str]] = ..., def attach(self, filename: None = ..., content: _AttachmentContent = ..., mimetype: str = ...) -> None: ...
mimetype: Optional[str] = ..., @overload
) -> None: ... def attach(self, filename: str = ..., content: _AttachmentContent = ..., mimetype: Optional[str] = ...) -> None: ...
def attach_file(self, path: str, mimetype: Optional[str] = ...) -> None: ... def attach_file(self, path: str, mimetype: Optional[str] = ...) -> None: ...
class EmailMultiAlternatives(EmailMessage): class EmailMultiAlternatives(EmailMessage):
alternative_subtype: str = ... alternative_subtype: str = ...
alternatives: Any = ... alternatives: Sequence[Tuple[_AttachmentContent, str]] = ...
def __init__( def __init__(
self, self,
subject: str = ..., subject: str = ...,
body: str = ..., body: str = ...,
from_email: Optional[str] = ..., from_email: Optional[str] = ...,
to: Optional[List[str]] = ..., to: Optional[Sequence[str]] = ...,
bcc: Optional[List[str]] = ..., bcc: Optional[Sequence[str]] = ...,
connection: Optional[Any] = ..., connection: Optional[Any] = ...,
attachments: None = ..., attachments: Optional[Sequence[Union[MIMEBase, _AttachmentTuple]]] = ...,
headers: Optional[Dict[str, str]] = ..., headers: Optional[Dict[str, str]] = ...,
alternatives: Optional[List[Tuple[str, str]]] = ..., alternatives: Optional[Sequence[Tuple[_AttachmentContent, str]]] = ...,
cc: None = ..., cc: Optional[Sequence[str]] = ...,
reply_to: None = ..., reply_to: Optional[Sequence[str]] = ...,
) -> None: ... ) -> None: ...
def attach_alternative(self, content: str, mimetype: str) -> None: ... def attach_alternative(self, content: _AttachmentContent, mimetype: str) -> None: ...

View File

@@ -5,7 +5,7 @@ import re
IGNORED_MODULES = {'schema', 'gis_tests', 'admin_widgets', 'admin_filters', 'migrations', IGNORED_MODULES = {'schema', 'gis_tests', 'admin_widgets', 'admin_filters', 'migrations',
'sitemaps_tests', 'staticfiles_tests', 'modeladmin', 'model_forms', 'sitemaps_tests', 'staticfiles_tests', 'modeladmin', 'model_forms',
'generic_views', 'forms_tests', 'flatpages_tests', 'admin_utils', 'generic_views', 'forms_tests', 'flatpages_tests', 'admin_utils',
'admin_ordering', 'admin_changelist', 'admin_views', 'mail', 'redirects_tests', 'admin_ordering', 'admin_changelist', 'admin_views', 'redirects_tests',
'invalid_models_tests', 'i18n', 'migrate_signals', 'model_formsets', 'invalid_models_tests', 'i18n', 'migrate_signals', 'model_formsets',
'template_tests', 'template_backends', 'test_runner', 'admin_scripts', 'template_tests', 'template_backends', 'test_runner', 'admin_scripts',
'sites_tests', 'inline_formsets', 'foreign_object', 'cache', 'test_client', 'test_client_regress'} 'sites_tests', 'inline_formsets', 'foreign_object', 'cache', 'test_client', 'test_client_regress'}
@@ -227,6 +227,17 @@ IGNORED_ERRORS = {
"Cannot resolve keyword 'porcupine' into field", "Cannot resolve keyword 'porcupine' into field",
'Argument 1 to "set" of "RelatedManager" has incompatible type "int"', 'Argument 1 to "set" of "RelatedManager" has incompatible type "int"',
], ],
'mail': [
'List item 1 has incompatible type "None"; expected "str"',
'Incompatible return value type (got "None", expected "bool")',
'Argument 1 to "push" of "SMTPChannel" has incompatible type "str"; expected "bytes"',
'Value of type "Union[List[Message], str, bytes, None]" is not indexable',
'Incompatible types in assignment '
+ '(expression has type "bool", variable has type "Union[SMTP_SSL, SMTP, None]")',
re.compile(
r'Item "(int|str)" of "Union\[Message, str, int, Any\]" has no attribute "(get_content_type|get_filename)"'
)
],
'messages_tests': [ 'messages_tests': [
'List item 0 has incompatible type "Dict[str, Message]"; expected "Message"', 'List item 0 has incompatible type "Dict[str, Message]"; expected "Message"',
'Too many arguments', 'Too many arguments',