Hello community,
here is the log from the commit of package python-aiosmtplib for
openSUSE:Factory checked in at 2020-12-01 14:23:07
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-aiosmtplib (Old)
and /work/SRC/openSUSE:Factory/.python-aiosmtplib.new.5913 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-aiosmtplib"
Tue Dec 1 14:23:07 2020 rev:4 rq:851905 version:1.1.4
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-aiosmtplib/python-aiosmtplib.changes
2020-03-24 22:34:15.009145040 +0100
+++
/work/SRC/openSUSE:Factory/.python-aiosmtplib.new.5913/python-aiosmtplib.changes
2020-12-01 14:23:20.941629823 +0100
@@ -1,0 +2,13 @@
+Sun Nov 29 07:16:07 UTC 2020 - John Vandenberg <[email protected]>
+
+- Add docs/*.rst to %doc
+- Remove a test skip that has been resolved upstream
+- Update to v1.1.4
+ * Bugfix: parsing comma separated addresses in to header
+- from v1.1.3
+ * Feature: add pause and resume writing methods to SMTPProcotol,
+ via asyncio.streams.FlowControlMixin
+ * Bugfix: allow an empty sender
+ * Cleanup: more useful error message when login called without TLS
+
+-------------------------------------------------------------------
Old:
----
aiosmtplib-1.1.2.tar.gz
New:
----
aiosmtplib-1.1.4.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-aiosmtplib.spec ++++++
--- /var/tmp/diff_new_pack.QRkP7t/_old 2020-12-01 14:23:21.581630516 +0100
+++ /var/tmp/diff_new_pack.QRkP7t/_new 2020-12-01 14:23:21.585630520 +0100
@@ -19,21 +19,23 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-aiosmtplib
-Version: 1.1.2
+Version: 1.1.4
Release: 0
Summary: Python asyncio SMTP client
License: MIT
Group: Development/Languages/Python
URL: https://github.com/cole/aiosmtplib
Source:
https://files.pythonhosted.org/packages/source/a/aiosmtplib/aiosmtplib-%{version}.tar.gz
-BuildRequires: %{python_module aiosmtpd}
-BuildRequires: %{python_module hypothesis}
-BuildRequires: %{python_module pytest-asyncio}
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
Suggests: python-aiosmtpd
BuildArch: noarch
+# SECTION test requirements
+BuildRequires: %{python_module aiosmtpd}
+BuildRequires: %{python_module hypothesis}
+BuildRequires: %{python_module pytest-asyncio}
+# /SECTION
%python_subpackages
%description
@@ -52,11 +54,10 @@
%check
# test_qq_login or test_starttls_gmail are online
-# https://github.com/cole/aiosmtplib/issues/79 for
test_send_message_smtputf8_sender
-%pytest -k 'not (test_qq_login or test_starttls_gmail or
test_send_message_smtputf8_sender)'
+%pytest -rs -k 'not (test_qq_login or test_starttls_gmail)'
%files %{python_files}
-%doc README.rst
+%doc README.rst docs/*.rst
%license LICENSE.txt
%{python_sitelib}/*
++++++ aiosmtplib-1.1.2.tar.gz -> aiosmtplib-1.1.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/LICENSE.txt
new/aiosmtplib-1.1.4/LICENSE.txt
--- old/aiosmtplib-1.1.2/LICENSE.txt 2019-07-30 06:11:42.416175400 +0200
+++ new/aiosmtplib-1.1.4/LICENSE.txt 2020-09-12 19:19:34.795263800 +0200
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2019 Cole Maclean
+Copyright (c) 2020 Cole Maclean
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/PKG-INFO
new/aiosmtplib-1.1.4/PKG-INFO
--- old/aiosmtplib-1.1.2/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
+++ new/aiosmtplib-1.1.4/PKG-INFO 2020-09-12 19:20:12.445738000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: aiosmtplib
-Version: 1.1.2
+Version: 1.1.4
Summary: asyncio SMTP client
Home-page: https://github.com/cole/aiosmtplib
License: MIT
@@ -26,7 +26,7 @@
Classifier: Typing :: Typed
Provides-Extra: docs
Provides-Extra: uvloop
-Requires-Dist: sphinx (>=2.0.0,<3.0.0); extra == "docs"
+Requires-Dist: sphinx (>=2,<4); extra == "docs"
Requires-Dist: sphinx_autodoc_typehints (>=1.7.0,<2.0.0); extra == "docs"
Requires-Dist: uvloop (>=0.13,<0.15); extra == "uvloop"
Project-URL: Documentation, https://aiosmtplib.readthedocs.io/en/stable/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/aiosmtplib/__init__.py
new/aiosmtplib-1.1.4/aiosmtplib/__init__.py
--- old/aiosmtplib-1.1.2/aiosmtplib/__init__.py 2019-11-12 04:01:21.198798200
+0100
+++ new/aiosmtplib-1.1.4/aiosmtplib/__init__.py 2020-09-12 19:19:34.803263700
+0200
@@ -32,10 +32,10 @@
__title__ = "aiosmtplib"
-__version__ = "1.1.2"
+__version__ = "1.1.4"
__author__ = "Cole Maclean"
__license__ = "MIT"
-__copyright__ = "Copyright 2019 Cole Maclean"
+__copyright__ = "Copyright 2020 Cole Maclean"
__all__ = (
"send",
"SMTP",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/aiosmtplib/api.py
new/aiosmtplib-1.1.4/aiosmtplib/api.py
--- old/aiosmtplib-1.1.2/aiosmtplib/api.py 2019-11-12 04:01:21.154114700
+0100
+++ new/aiosmtplib-1.1.4/aiosmtplib/api.py 2020-09-12 19:19:34.807263600
+0200
@@ -1,11 +1,11 @@
"""
Main public API.
"""
+import email.message
import os
import socket
import ssl
import sys
-from email.message import Message
from typing import Dict, List, Optional, Sequence, Tuple, Union, overload
from .response import SMTPResponse
@@ -20,15 +20,17 @@
else:
SocketPathType = Union[str, bytes]
+# flake8: noqa F811
+
# overloaded matrix is split by:
# * message type (Message, str/bytes)
# * connection type (hostname/socket/socket path)
# * cert info (client_cert/tls_context)
-@overload # noqa: F811
+@overload
async def send(
- message: Message,
+ message: Union[email.message.EmailMessage, email.message.Message],
sender: Optional[str] = ...,
recipients: Optional[Union[str, Sequence[str]]] = ...,
hostname: str = ...,
@@ -52,7 +54,7 @@
...
-@overload # noqa: F811
+@overload
async def send(
message: Union[str, bytes],
sender: str = ...,
@@ -78,9 +80,9 @@
...
-@overload # noqa: F811
+@overload
async def send(
- message: Message,
+ message: Union[email.message.EmailMessage, email.message.Message],
sender: Optional[str] = ...,
recipients: Optional[Union[str, Sequence[str]]] = ...,
hostname: str = ...,
@@ -104,7 +106,7 @@
...
-@overload # noqa: F811
+@overload
async def send(
message: Union[str, bytes],
sender: str = ...,
@@ -130,9 +132,9 @@
...
-@overload # noqa: F811
+@overload
async def send(
- message: Message,
+ message: Union[email.message.EmailMessage, email.message.Message],
sender: Optional[str] = ...,
recipients: Optional[Union[str, Sequence[str]]] = ...,
hostname: None = ...,
@@ -156,7 +158,7 @@
...
-@overload # noqa: F811
+@overload
async def send(
message: Union[str, bytes],
sender: str = ...,
@@ -182,9 +184,9 @@
...
-@overload # noqa: F811
+@overload
async def send(
- message: Message,
+ message: Union[email.message.EmailMessage, email.message.Message],
sender: Optional[str] = ...,
recipients: Optional[Union[str, Sequence[str]]] = ...,
hostname: None = ...,
@@ -208,7 +210,7 @@
...
-@overload # noqa: F811
+@overload
async def send(
message: Union[str, bytes],
sender: str = ...,
@@ -234,9 +236,9 @@
...
-@overload # noqa: F811
+@overload
async def send(
- message: Message,
+ message: Union[email.message.EmailMessage, email.message.Message],
sender: Optional[str] = ...,
recipients: Optional[Union[str, Sequence[str]]] = ...,
hostname: None = ...,
@@ -260,7 +262,7 @@
...
-@overload # noqa: F811
+@overload
async def send(
message: Union[str, bytes],
sender: str = ...,
@@ -286,9 +288,9 @@
...
-@overload # noqa: F811
+@overload
async def send(
- message: Message,
+ message: Union[email.message.EmailMessage, email.message.Message],
sender: Optional[str] = ...,
recipients: Optional[Union[str, Sequence[str]]] = ...,
hostname: None = ...,
@@ -312,7 +314,7 @@
...
-@overload # noqa: F811
+@overload
async def send(
message: Union[str, bytes],
sender: str = ...,
@@ -338,7 +340,7 @@
...
-async def send(message, sender=None, recipients=None, **kwargs): # noqa: F811
+async def send(message, sender=None, recipients=None, **kwargs):
"""
Send an email message. On await, connects to the SMTP server using the
details
provided, sends the message, then disconnects.
@@ -383,7 +385,7 @@
:raises ValueError: required arguments missing or mutually exclusive
options
provided
"""
- if not isinstance(message, Message):
+ if not isinstance(message, (email.message.EmailMessage,
email.message.Message)):
if not recipients:
raise ValueError("Recipients must be provided with raw messages.")
if not sender:
@@ -392,7 +394,7 @@
client = SMTP(**kwargs)
async with client:
- if isinstance(message, Message):
+ if isinstance(message, (email.message.EmailMessage,
email.message.Message)):
result = await client.send_message(
message, sender=sender, recipients=recipients
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/aiosmtplib/auth.py
new/aiosmtplib-1.1.4/aiosmtplib/auth.py
--- old/aiosmtplib-1.1.2/aiosmtplib/auth.py 2019-11-12 04:01:21.156599000
+0100
+++ new/aiosmtplib-1.1.4/aiosmtplib/auth.py 2020-09-12 19:19:34.807263600
+0200
@@ -56,7 +56,14 @@
await self._ehlo_or_helo_if_needed()
if not self.supports_extension("auth"):
- raise SMTPException("SMTP AUTH extension not supported by server.")
+ if self.is_connected and self.get_transport_info("sslcontext") is
None:
+ raise SMTPException(
+ "The SMTP AUTH extension is not supported by this server.
Try "
+ "connecting via TLS (or STARTTLS)."
+ )
+ raise SMTPException(
+ "The SMTP AUTH extension is not supported by this server."
+ )
response = None # type: Optional[SMTPResponse]
exception = None # type: Optional[SMTPAuthenticationError]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/aiosmtplib/connection.py
new/aiosmtplib-1.1.4/aiosmtplib/connection.py
--- old/aiosmtplib-1.1.2/aiosmtplib/connection.py 2019-11-12
04:01:21.157382000 +0100
+++ new/aiosmtplib-1.1.4/aiosmtplib/connection.py 2020-09-12
19:19:34.815263700 +0200
@@ -7,7 +7,7 @@
import ssl
import sys
import warnings
-from typing import Any, Optional, Type, Union, cast
+from typing import Any, Optional, Type, Union
from .compat import create_connection, create_unix_connection, get_running_loop
from .default import Default, _default
@@ -194,7 +194,7 @@
This method can be called multiple times.
"""
if hostname is not _default:
- self.hostname = cast(Optional[str], hostname)
+ self.hostname = hostname
if loop is not _default:
if loop is not None:
warnings.warn(
@@ -203,7 +203,7 @@
DeprecationWarning,
stacklevel=3,
)
- self.loop = cast(Optional[asyncio.AbstractEventLoop], loop)
+ self.loop = loop
if use_tls is not None:
self.use_tls = use_tls
if start_tls is not None:
@@ -211,28 +211,28 @@
if validate_certs is not None:
self.validate_certs = validate_certs
if port is not _default:
- self.port = cast(Optional[int], port)
+ self.port = port
if username is not _default:
- self._login_username = cast(Optional[str], username)
+ self._login_username = username
if password is not _default:
- self._login_password = cast(Optional[str], password)
+ self._login_password = password
if timeout is not _default:
- self.timeout = cast(Optional[float], timeout)
+ self.timeout = timeout
if source_address is not _default:
- self._source_address = cast(Optional[str], source_address)
+ self._source_address = source_address
if client_cert is not _default:
- self.client_cert = cast(Optional[str], client_cert)
+ self.client_cert = client_cert
if client_key is not _default:
- self.client_key = cast(Optional[str], client_key)
+ self.client_key = client_key
if tls_context is not _default:
- self.tls_context = cast(Optional[ssl.SSLContext], tls_context)
+ self.tls_context = tls_context
if cert_bundle is not _default:
- self.cert_bundle = cast(Optional[str], cert_bundle)
+ self.cert_bundle = cert_bundle
if socket_path is not _default:
- self.socket_path = cast(Optional[SocketPathType], socket_path)
+ self.socket_path = socket_path
if sock is not _default:
- self.sock = cast(Optional[socket.socket], sock)
+ self.sock = sock
def _validate_config(self) -> None:
if self._start_tls_on_connect and self.use_tls:
@@ -364,7 +364,7 @@
try:
transport, _ = await asyncio.wait_for(connect_coro,
timeout=self.timeout)
- except (ConnectionRefusedError, OSError) as exc:
+ except OSError as exc:
raise SMTPConnectError(
"Error connecting to {host} on port {port}: {err}".format(
host=self.hostname, port=self.port, err=exc
@@ -416,7 +416,6 @@
if timeout is _default:
timeout = self.timeout
- timeout = cast(Optional[float], timeout)
response = await self.protocol.execute_command(*args, timeout=timeout)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/aiosmtplib/email.py
new/aiosmtplib-1.1.4/aiosmtplib/email.py
--- old/aiosmtplib-1.1.2/aiosmtplib/email.py 2019-11-12 04:01:21.160953000
+0100
+++ new/aiosmtplib-1.1.4/aiosmtplib/email.py 2020-09-12 19:19:34.819263700
+0200
@@ -72,7 +72,9 @@
def flatten_message(
- message: email.message.Message, utf8: bool = False, cte_type: str = "8bit"
+ message: Union[email.message.EmailMessage, email.message.Message],
+ utf8: bool = False,
+ cte_type: str = "8bit",
) -> bytes:
# Make a local copy so we can delete the bcc headers.
message_copy = copy.copy(message)
@@ -119,12 +121,14 @@
charset = "ascii"
addresses.append(parse_address(str(address_bytes,
encoding=charset)))
else:
- addresses.append(parse_address(header))
+ addresses.extend(addr for _, addr in
email.utils.getaddresses([header]))
return addresses
-def extract_sender(message: email.message.Message) -> Optional[str]:
+def extract_sender(
+ message: Union[email.message.EmailMessage, email.message.Message]
+) -> Optional[str]:
"""
Extract the sender from the message object given.
"""
@@ -151,7 +155,9 @@
return extract_addresses(sender_header)[0]
-def extract_recipients(message: email.message.Message) -> List[str]:
+def extract_recipients(
+ message: Union[email.message.EmailMessage, email.message.Message]
+) -> List[str]:
"""
Extract the recipients from the message object given.
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/aiosmtplib/esmtp.py
new/aiosmtplib-1.1.4/aiosmtplib/esmtp.py
--- old/aiosmtplib-1.1.2/aiosmtplib/esmtp.py 2019-11-12 04:01:21.162656800
+0100
+++ new/aiosmtplib-1.1.4/aiosmtplib/esmtp.py 2020-09-12 19:19:34.823263600
+0200
@@ -3,7 +3,7 @@
"""
import re
import ssl
-from typing import Dict, Iterable, List, Optional, Tuple, Union, cast
+from typing import Dict, Iterable, List, Optional, Tuple, Union
from .connection import SMTPConnection
from .default import Default, _default
@@ -324,7 +324,6 @@
if timeout is _default:
timeout = self.timeout
- timeout = cast(Optional[float], timeout)
if isinstance(message, str):
message = message.encode("ascii")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/aiosmtplib/protocol.py
new/aiosmtplib-1.1.4/aiosmtplib/protocol.py
--- old/aiosmtplib-1.1.2/aiosmtplib/protocol.py 2019-11-12 04:01:21.163550400
+0100
+++ new/aiosmtplib-1.1.4/aiosmtplib/protocol.py 2020-09-12 19:19:34.823263600
+0200
@@ -26,13 +26,76 @@
PERIOD_REGEX = re.compile(rb"(?m)^\.")
-class SMTPProtocol(asyncio.Protocol):
+class FlowControlMixin(asyncio.Protocol):
+ """
+ Reusable flow control logic for StreamWriter.drain().
+ This implements the protocol methods pause_writing(),
+ resume_writing() and connection_lost(). If the subclass overrides
+ these it must call the super methods.
+ StreamWriter.drain() must wait for _drain_helper() coroutine.
+
+ Copied from stdlib as per recommendation:
https://bugs.python.org/msg343685.
+ Logging and asserts removed, type annotations added.
+ """
+
+ def __init__(self, loop: Optional[asyncio.AbstractEventLoop] = None):
+ if loop is None:
+ self._loop = asyncio.get_event_loop()
+ else:
+ self._loop = loop
+ self._paused = False
+ self._drain_waiter = None # type: Optional[asyncio.Future[None]]
+ self._connection_lost = False
+
+ def pause_writing(self) -> None:
+ self._paused = True
+
+ def resume_writing(self) -> None:
+ self._paused = False
+
+ waiter = self._drain_waiter
+ if waiter is not None:
+ self._drain_waiter = None
+ if not waiter.done():
+ waiter.set_result(None)
+
+ def connection_lost(self, exc) -> None:
+ self._connection_lost = True
+ # Wake up the writer if currently paused.
+ if not self._paused:
+ return
+ waiter = self._drain_waiter
+ if waiter is None:
+ return
+ self._drain_waiter = None
+ if waiter.done():
+ return
+ if exc is None:
+ waiter.set_result(None)
+ else:
+ waiter.set_exception(exc)
+
+ async def _drain_helper(self) -> None:
+ if self._connection_lost:
+ raise ConnectionResetError("Connection lost")
+ if not self._paused:
+ return
+ waiter = self._drain_waiter
+ waiter = self._loop.create_future()
+ self._drain_waiter = waiter
+ await waiter
+
+ def _get_close_waiter(self, stream: asyncio.StreamWriter) ->
asyncio.Future:
+ raise NotImplementedError
+
+
+class SMTPProtocol(FlowControlMixin, asyncio.Protocol):
def __init__(
self,
loop: Optional[asyncio.AbstractEventLoop] = None,
connection_lost_callback: Optional[Callable] = None,
) -> None:
- self._loop = loop or asyncio.get_event_loop()
+ super().__init__(loop=loop)
self._over_ssl = False
self._buffer = bytearray()
self._response_waiter = None # type:
Optional[asyncio.Future[SMTPResponse]]
@@ -41,6 +104,7 @@
self.transport = None # type: Optional[asyncio.Transport]
self._command_lock = None # type: Optional[asyncio.Lock]
+ self._closed = self._loop.create_future() # type: asyncio.Future[None]
def __del__(self):
waiters = (self._response_waiter, self._connection_lost_waiter)
@@ -49,6 +113,9 @@
# Avoid 'Future exception was never retrieved' warnings
waiter.exception()
+ def _get_close_waiter(self, stream: asyncio.StreamWriter) ->
asyncio.Future:
+ return self._closed
+
@property
def is_connected(self) -> bool:
"""
@@ -69,6 +136,8 @@
)
def connection_lost(self, exc: Optional[Exception]) -> None:
+ super().connection_lost(exc)
+
if exc:
smtp_exc = SMTPServerDisconnected("Connection lost")
smtp_exc.__cause__ = exc
@@ -172,7 +241,7 @@
async def read_response(self, timeout: Optional[float] = None) ->
SMTPResponse:
"""
- Get a status reponse from the server.
+ Get a status response from the server.
This method must be awaited once per command sent; if multiple commands
are written to the transport without awaiting, response data will be
lost.
@@ -186,7 +255,9 @@
raise SMTPServerDisconnected("Connection lost")
try:
- result = await asyncio.wait_for(self._response_waiter, timeout)
+ result = await asyncio.wait_for(
+ self._response_waiter, timeout
+ ) # type: SMTPResponse
except asyncio.TimeoutError as exc:
raise SMTPReadTimeoutError("Timed out waiting for server
response") from exc
finally:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/aiosmtplib/py.typed
new/aiosmtplib-1.1.4/aiosmtplib/py.typed
--- old/aiosmtplib-1.1.2/aiosmtplib/py.typed 1970-01-01 01:00:00.000000000
+0100
+++ new/aiosmtplib-1.1.4/aiosmtplib/py.typed 2020-09-12 19:19:34.827263600
+0200
@@ -0,0 +1 @@
+This file exists to help mypy (and other tools) find inline type hints. See PR
#141 and PEP 561.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/aiosmtplib/smtp.py
new/aiosmtplib-1.1.4/aiosmtplib/smtp.py
--- old/aiosmtplib-1.1.2/aiosmtplib/smtp.py 2019-11-12 04:01:21.164341700
+0100
+++ new/aiosmtplib-1.1.4/aiosmtplib/smtp.py 2020-09-12 19:19:34.831263500
+0200
@@ -8,7 +8,7 @@
* :class:`.connection.SMTPConnection` - connection handling
"""
import asyncio
-from email.message import Message
+import email.message
from typing import Dict, Iterable, Optional, Sequence, Tuple, Union
from .auth import SMTPAuth
@@ -35,7 +35,7 @@
Basic usage:
>>> loop = asyncio.get_event_loop()
- >>> smtp = aiosmtplib.SMTP(hostname="127.0.0.1", port=1025, loop=loop)
+ >>> smtp = aiosmtplib.SMTP(hostname="127.0.0.1", port=1025)
>>> loop.run_until_complete(smtp.connect())
(220, ...)
>>> sender = "root@localhost"
@@ -212,7 +212,7 @@
async def send_message(
self,
- message: Message,
+ message: Union[email.message.EmailMessage, email.message.Message],
sender: Optional[str] = None,
recipients: Optional[Union[str, Sequence[str]]] = None,
mail_options: Optional[Iterable[str]] = None,
@@ -251,7 +251,7 @@
if sender is None:
sender = extract_sender(message)
- if not sender:
+ if sender is None:
raise ValueError("No From header provided in message")
if isinstance(recipients, str):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/docs/conf.py
new/aiosmtplib-1.1.4/docs/conf.py
--- old/aiosmtplib-1.1.2/docs/conf.py 2019-11-12 04:01:21.165280000 +0100
+++ new/aiosmtplib-1.1.4/docs/conf.py 2020-09-12 19:19:34.843263600 +0200
@@ -17,17 +17,11 @@
# documentation root, use os.path.abspath to make it absolute, like shown here.
import datetime
-import os
import pathlib
import re
-import sys
from typing import Dict, List
-sys.path.insert(0, os.path.abspath("../src"))
-sys.path.insert(0, os.path.abspath("."))
-
-
VERSION_REGEX = r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]'
@@ -182,7 +176,7 @@
)
]
-intersphinx_mapping = {"python": ("https://docs.python.org/3.7", None)}
+intersphinx_mapping = {"python": ("https://docs.python.org/3.8", None)}
html_sidebars = {
"**": ["globaltoc.html", "relations.html", "sourcelink.html",
"searchbox.html"]
@@ -191,6 +185,7 @@
nitpick_ignore = [
("py:class", "typing.Tuple"),
("py:class", "concurrent.futures._base.TimeoutError"),
+ ("py:class", "asyncio.exceptions.TimeoutError"),
]
doctest_global_setup = """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/docs/usage.rst
new/aiosmtplib-1.1.4/docs/usage.rst
--- old/aiosmtplib-1.1.2/docs/usage.rst 2019-11-07 03:31:35.193945400 +0100
+++ new/aiosmtplib-1.1.4/docs/usage.rst 2020-09-12 19:19:34.855263500 +0200
@@ -16,7 +16,7 @@
For details on creating :py:class:`email.message.EmailMessage` objects, see
`the stdlib documentation examples
-<https://docs.python.org/3.7/library/email.examples.html>`_.
+<https://docs.python.org/3.8/library/email.examples.html>`_.
.. note:: Confusingly, :py:class:`email.message.Message` objects are part of
the
legacy email API (prior to Python 3.3), while
:py:class:`email.message.EmailMessage`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/pyproject.toml
new/aiosmtplib-1.1.4/pyproject.toml
--- old/aiosmtplib-1.1.2/pyproject.toml 2019-11-12 04:01:21.199175600 +0100
+++ new/aiosmtplib-1.1.4/pyproject.toml 2020-09-12 19:19:34.859263700 +0200
@@ -1,10 +1,10 @@
[build-system]
-requires = ["poetry>=1.0.0b4"]
+requires = ["poetry>=1.0.0"]
build-backend = "poetry.masonry.api"
[tool.poetry]
name = "aiosmtplib"
-version = "1.1.2"
+version = "1.1.4"
description = "asyncio SMTP client"
authors = ["Cole Maclean <[email protected]>"]
license = "MIT"
@@ -42,16 +42,17 @@
python = "^3.5.2"
uvloop = { version = ">=0.13,<0.15", optional = true }
-sphinx = { version = "^2.0.0", optional = true }
+sphinx = { version = ">=2,<4", optional = true }
sphinx_autodoc_typehints = { version = "^1.7.0", optional = true }
[tool.poetry.dev-dependencies]
-pytest = "^5.2.2"
-pytest-asyncio = "^0.10.0"
-pytest-cov = "^2.8.1"
-coverage = "^4.5.4"
-hypothesis = "^4.43.8"
+pytest = "^5.4.3"
+pytest-asyncio = "^0.12.0"
+pytest-cov = "^2.9.0"
+coverage = "^5.1"
+hypothesis = "~4.57"
aiosmtpd = "1.2"
+pytest-xdist = "^1.32.0"
[tool.poetry.extras]
docs = ["sphinx", "sphinx_autodoc_typehints"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/setup.py
new/aiosmtplib-1.1.4/setup.py
--- old/aiosmtplib-1.1.2/setup.py 1970-01-01 01:00:00.000000000 +0100
+++ new/aiosmtplib-1.1.4/setup.py 2020-09-12 19:20:12.445069300 +0200
@@ -8,12 +8,12 @@
{'': ['*'], 'tests': ['certs/*']}
extras_require = \
-{'docs': ['sphinx>=2.0.0,<3.0.0', 'sphinx_autodoc_typehints>=1.7.0,<2.0.0'],
+{'docs': ['sphinx>=2,<4', 'sphinx_autodoc_typehints>=1.7.0,<2.0.0'],
'uvloop': ['uvloop>=0.13,<0.15']}
setup_kwargs = {
'name': 'aiosmtplib',
- 'version': '1.1.2',
+ 'version': '1.1.4',
'description': 'asyncio SMTP client',
'long_description': 'aiosmtplib\n==========\n\n|circleci| |codecov|
|pypi-version| |pypi-python-versions| |pypi-status|\n|pypi-license|
|black|\n\n------------\n\naiosmtplib is an asynchronous SMTP client for use
with asyncio.\n\nFor documentation, see `Read The
Docs`_.\n\nQuickstart\n----------\n\n.. code-block:: python\n\n import
asyncio\n from email.message import EmailMessage\n\n import
aiosmtplib\n\n message = EmailMessage()\n message["From"] =
"root@localhost"\n message["To"] = "[email protected]"\n
message["Subject"] = "Hello World!"\n message.set_content("Sent via
aiosmtplib")\n\n loop = asyncio.get_event_loop()\n
loop.run_until_complete(aiosmtplib.send(message, hostname="127.0.0.1",
port=25))\n\n\nRequirements\n------------\nPython 3.5.2+, compiled with SSL
support, is required.\n\n\nBug reporting\n-------------\nBug reports (and
feature requests) are welcome via Github issues.\n\n\n\n.. |circleci| image::
https://circleci.com/gh/cole/aiosmtplib/tree/master.svg?style=shield\n
:target: https://circleci.com/gh/cole/aiosmtplib/tree/master\n :alt:
"aiosmtplib CircleCI build status"\n.. |pypi-version| image::
https://img.shields.io/pypi/v/aiosmtplib.svg\n :target:
https://pypi.python.org/pypi/aiosmtplib\n :alt: "aiosmtplib on
the Python Package Index"\n.. |pypi-python-versions| image::
https://img.shields.io/pypi/pyversions/aiosmtplib.svg\n.. |pypi-status| image::
https://img.shields.io/pypi/status/aiosmtplib.svg\n.. |pypi-license| image::
https://img.shields.io/pypi/l/aiosmtplib.svg\n.. |codecov| image::
https://codecov.io/gh/cole/aiosmtplib/branch/master/graph/badge.svg\n
:target: https://codecov.io/gh/cole/aiosmtplib\n.. |black| image::
https://img.shields.io/badge/code%20style-black-000000.svg\n :target:
https://github.com/ambv/black\n :alt: "Code style: black"\n.. _Read
The Docs: https://aiosmtplib.readthedocs.io/en/stable/overview.html\n',
'author': 'Cole Maclean',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/tests/conftest.py
new/aiosmtplib-1.1.4/tests/conftest.py
--- old/aiosmtplib-1.1.2/tests/conftest.py 2019-11-09 22:05:06.226744000
+0100
+++ new/aiosmtplib-1.1.4/tests/conftest.py 2020-09-12 19:19:34.879263400
+0200
@@ -9,6 +9,7 @@
import socket
import ssl
import sys
+import traceback
from pathlib import Path
import hypothesis
@@ -40,6 +41,10 @@
hypothesis.settings.register_profile("ci", parent=base_settings,
max_examples=100)
+class AsyncPytestWarning(pytest.PytestWarning):
+ pass
+
+
def pytest_addoption(parser):
parser.addoption(
"--event-loop",
@@ -72,13 +77,20 @@
@pytest.fixture(scope="function")
def event_loop(request, event_loop_policy):
+ verbosity = request.config.getoption("verbose", default=0)
old_loop = event_loop_policy.get_event_loop()
loop = event_loop_policy.new_event_loop()
event_loop_policy.set_event_loop(loop)
def handle_async_exception(loop, context):
- """Fail on exceptions by default"""
- pytest.fail("{}: {}".format(context["message"],
repr(context["exception"])))
+ message = "{}: {}".format(context["message"],
repr(context["exception"]))
+ if verbosity > 1:
+ message += "\n"
+ message += "Future: {}".format(repr(context["future"]))
+ message += "\nTraceback:\n"
+ message +=
"".join(traceback.format_list(context["source_traceback"]))
+
+ request.node.warn(AsyncPytestWarning(message))
loop.set_exception_handler(handle_async_exception)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/tests/smtpd.py
new/aiosmtplib-1.1.4/tests/smtpd.py
--- old/aiosmtplib-1.1.2/tests/smtpd.py 2019-09-03 04:09:27.761034500 +0200
+++ new/aiosmtplib-1.1.4/tests/smtpd.py 2020-09-12 19:19:34.879263400 +0200
@@ -38,7 +38,10 @@
async def handle_EHLO(self, server, session, envelope, hostname):
"""Advertise auth login support."""
session.host_name = hostname
- return "250-AUTH LOGIN\r\n250 HELP"
+ if server._tls_protocol:
+ return "250-AUTH LOGIN\r\n250 HELP"
+ else:
+ return "250 HELP"
class TestSMTPD(SMTPD):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/tests/test_auth.py
new/aiosmtplib-1.1.4/tests/test_auth.py
--- old/aiosmtplib-1.1.2/tests/test_auth.py 2019-09-03 04:09:27.762322400
+0200
+++ new/aiosmtplib-1.1.4/tests/test_auth.py 2020-09-12 19:19:34.887263500
+0200
@@ -48,9 +48,11 @@
async def test_login_without_extension_raises_error(mock_auth):
mock_auth.esmtp_extensions = {}
- with pytest.raises(SMTPException):
+ with pytest.raises(SMTPException) as excinfo:
await mock_auth.login("username", "bogus")
+ assert "Try connecting via TLS" not in excinfo.value.args[0]
+
async def test_login_unknown_method_raises_error(mock_auth):
mock_auth.AUTH_METHODS = ("fakeauth",)
@@ -179,3 +181,11 @@
with pytest.raises(SMTPAuthenticationError):
await mock_auth.auth_crammd5("username", "bogus")
+
+
+async def test_login_without_starttls_exception(smtp_client, smtpd_server):
+ async with smtp_client:
+ with pytest.raises(SMTPException) as excinfo:
+ await smtp_client.login("test", "test")
+
+ assert "Try connecting via TLS" in excinfo.value.args[0]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/tests/test_email_utils.py
new/aiosmtplib-1.1.4/tests/test_email_utils.py
--- old/aiosmtplib-1.1.2/tests/test_email_utils.py 2019-11-07
04:19:54.547639000 +0100
+++ new/aiosmtplib-1.1.4/tests/test_email_utils.py 2020-09-12
19:19:34.899263400 +0200
@@ -155,11 +155,11 @@
"compat32_cc_header,expected_recipients",
(
(
- "Alice Smith <[email protected]>",
+ "Alice Smith <[email protected]>, [email protected]",
"Bob <[email protected]>",
- "Alice Smith <[email protected]>",
+ "Alice Smith <[email protected]>, [email protected]",
"Bob <[email protected]>",
- ["[email protected]", "[email protected]"],
+ ["[email protected]", "[email protected]", "[email protected]"],
),
(
Address(display_name="Alice Smith", username="alice",
domain="example.com"),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/tests/test_live.py
new/aiosmtplib-1.1.4/tests/test_live.py
--- old/aiosmtplib-1.1.2/tests/test_live.py 2019-10-16 06:21:56.106305100
+0200
+++ new/aiosmtplib-1.1.4/tests/test_live.py 2020-09-12 19:19:34.907263500
+0200
@@ -4,10 +4,11 @@
These aren't generally run as part of the test suite.
"""
import os
+from email.message import EmailMessage
import pytest
-from aiosmtplib import SMTP, SMTPAuthenticationError, SMTPStatus
+from aiosmtplib import SMTP, SMTPAuthenticationError, SMTPStatus, send
pytestmark = [
@@ -28,6 +29,8 @@
assert response.code == SMTPStatus.completed
assert "smtp.gmail.com at your service" in response.message
+ assert client.server_auth_methods
+
with pytest.raises(SMTPAuthenticationError):
await client.login("test", "test")
@@ -41,3 +44,21 @@
with pytest.raises(SMTPAuthenticationError):
await client.login("test", "test")
+
+
+async def test_office365_auth_send():
+ message = EmailMessage()
+ message["From"] = "[email protected]"
+ message["To"] = "[email protected]"
+ message["Subject"] = "Hello World!"
+ message.set_content("Sent via aiosmtplib")
+
+ with pytest.raises(SMTPAuthenticationError):
+ await send(
+ message,
+ hostname="smtp.office365.com",
+ port=587,
+ start_tls=True,
+ password="test",
+ username="test",
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/aiosmtplib-1.1.2/tests/test_sendmail.py
new/aiosmtplib-1.1.4/tests/test_sendmail.py
--- old/aiosmtplib-1.1.2/tests/test_sendmail.py 2019-11-03 21:59:55.923034400
+0100
+++ new/aiosmtplib-1.1.4/tests/test_sendmail.py 2020-09-12 19:19:34.915263400
+0200
@@ -13,7 +13,7 @@
SMTPResponseException,
SMTPStatus,
)
-
+from aiosmtplib.email import formataddr
pytestmark = pytest.mark.asyncio()
@@ -370,6 +370,16 @@
await smtp_client.send_message(message)
+async def test_send_message_with_formataddr(smtp_client, smtpd_server,
message):
+ message["To"] = formataddr(("æøå", "[email protected]"))
+
+ async with smtp_client:
+ errors, response = await smtp_client.send_message(message)
+
+ assert not errors
+ assert response != ""
+
+
async def test_send_compat32_message_utf8_text_without_smtputf8(
smtp_client, smtpd_server, compat32_message, received_commands,
received_messages
):
@@ -422,3 +432,14 @@
"[email protected]",
"=?utf-8?b?cmXDp2lww6/DqW50IDxyZWNpcGllbnQyQGV4YW1wbGUuY29tPg==?=",
]
+
+
+async def test_sendmail_empty_sender(
+ smtp_client, smtpd_server, recipient_str, message_str
+):
+ async with smtp_client:
+ errors, response = await smtp_client.sendmail("", [recipient_str],
message_str)
+
+ assert not errors
+ assert isinstance(errors, dict)
+ assert response != ""
_______________________________________________
openSUSE Commits mailing list -- [email protected]
To unsubscribe, email [email protected]
List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette
List Archives:
https://lists.opensuse.org/archives/list/[email protected]