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

4
.gitignore vendored
View File

@@ -8,4 +8,6 @@ out/
build/
dist/
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
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.message import Message
from email.mime.base import MIMEBase
from email.mime.message import MIMEMessage
from email.mime.multipart import MIMEMultipart
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_qp: Any
@@ -43,6 +45,11 @@ class SafeMIMEMultipart(MIMEMixin, MIMEMultipart):
self, _subtype: str = ..., boundary: None = ..., _subparts: None = ..., encoding: str = ..., **_params: Any
) -> None: ...
_AttachmentContent = Union[bytes, EmailMessage, Message, SafeMIMEText, str]
_AttachmentTuple = Union[
Tuple[str, _AttachmentContent], Tuple[Optional[str], _AttachmentContent, str], Tuple[str, _AttachmentContent, None]
]
class EmailMessage:
content_subtype: str = ...
mixed_subtype: str = ...
@@ -62,42 +69,42 @@ class EmailMessage:
subject: str = ...,
body: Optional[str] = ...,
from_email: Optional[str] = ...,
to: Optional[Union[Sequence[str], str]] = ...,
bcc: Optional[Union[Sequence[str], str]] = ...,
to: Optional[Sequence[str]] = ...,
bcc: Optional[Sequence[str]] = ...,
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]] = ...,
cc: Optional[Union[Sequence[str], str]] = ...,
reply_to: Optional[Union[List[Optional[str]], str]] = ...,
cc: Optional[Sequence[str]] = ...,
reply_to: Optional[Sequence[str]] = ...,
) -> None: ...
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
def message(self) -> Any: ...
def recipients(self) -> List[str]: ...
def send(self, fail_silently: bool = ...) -> int: ...
def attach(
self,
filename: Optional[Union[MIMEText, str]] = ...,
content: Optional[Union[bytes, EmailMessage, SafeMIMEText, str]] = ...,
mimetype: Optional[str] = ...,
) -> None: ...
@overload
def attach(self, filename: MIMEText = ...) -> None: ...
@overload
def attach(self, filename: None = ..., content: _AttachmentContent = ..., mimetype: str = ...) -> None: ...
@overload
def attach(self, filename: str = ..., content: _AttachmentContent = ..., mimetype: Optional[str] = ...) -> None: ...
def attach_file(self, path: str, mimetype: Optional[str] = ...) -> None: ...
class EmailMultiAlternatives(EmailMessage):
alternative_subtype: str = ...
alternatives: Any = ...
alternatives: Sequence[Tuple[_AttachmentContent, str]] = ...
def __init__(
self,
subject: str = ...,
body: str = ...,
from_email: Optional[str] = ...,
to: Optional[List[str]] = ...,
bcc: Optional[List[str]] = ...,
to: Optional[Sequence[str]] = ...,
bcc: Optional[Sequence[str]] = ...,
connection: Optional[Any] = ...,
attachments: None = ...,
attachments: Optional[Sequence[Union[MIMEBase, _AttachmentTuple]]] = ...,
headers: Optional[Dict[str, str]] = ...,
alternatives: Optional[List[Tuple[str, str]]] = ...,
cc: None = ...,
reply_to: None = ...,
alternatives: Optional[Sequence[Tuple[_AttachmentContent, str]]] = ...,
cc: Optional[Sequence[str]] = ...,
reply_to: Optional[Sequence[str]] = ...,
) -> 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',
'sitemaps_tests', 'staticfiles_tests', 'modeladmin', 'model_forms',
'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',
'template_tests', 'template_backends', 'test_runner', 'admin_scripts',
'sites_tests', 'inline_formsets', 'foreign_object', 'cache', 'test_client', 'test_client_regress'}
@@ -227,6 +227,17 @@ IGNORED_ERRORS = {
"Cannot resolve keyword 'porcupine' into field",
'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': [
'List item 0 has incompatible type "Dict[str, Message]"; expected "Message"',
'Too many arguments',