Fixed #22327 -- Turned BaseEmailBackend into a context manager

Changed the BaseEmailBackend to allow usage as context manager to open
and close connections.
This commit is contained in:
Daniel Neuhäuser 2014-03-23 17:29:10 +01:00 committed by Tim Graham
parent d902fd625d
commit 4aa80149e7
4 changed files with 52 additions and 1 deletions

View File

@ -6,6 +6,13 @@ class BaseEmailBackend(object):
Base class for email backend implementations. Base class for email backend implementations.
Subclasses must at least overwrite send_messages(). Subclasses must at least overwrite send_messages().
open() and close() can be called indirectly by using a backend object as a
context manager:
with backend as connection:
# do something with connection
pass
""" """
def __init__(self, fail_silently=False, **kwargs): def __init__(self, fail_silently=False, **kwargs):
self.fail_silently = fail_silently self.fail_silently = fail_silently
@ -32,6 +39,13 @@ class BaseEmailBackend(object):
"""Close a network connection.""" """Close a network connection."""
pass pass
def __enter__(self):
self.open()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.close()
def send_messages(self, email_messages): def send_messages(self, email_messages):
""" """
Sends one or more EmailMessage objects and returns the number of email Sends one or more EmailMessage objects and returns the number of email

View File

@ -91,7 +91,8 @@ Cache
Email Email
^^^^^ ^^^^^
* ... * :ref:`Email backends <topic-email-backends>` now support the context manager
protocol for opening and closing connections.
File Storage File Storage
^^^^^^^^^^^^ ^^^^^^^^^^^^

View File

@ -393,6 +393,21 @@ The email backend class has the following methods:
connection afterwards. If the connection is already open, it will be connection afterwards. If the connection is already open, it will be
left open after mail has been sent. left open after mail has been sent.
It can also be used as a context manager, which will automatically call
``open()`` and ``close()`` as needed::
from django.core import mail
with mail.get_connection() as connection:
mail.EmailMessage(subject1, body1, from1, [to1],
connection=connection).send()
mail.EmailMessage(subject2, body2, from2, [to2],
connection=connection).send()
.. versionadded:: 1.8
The context manager protocol was added.
Obtaining an instance of an email backend Obtaining an instance of an email backend
----------------------------------------- -----------------------------------------

View File

@ -638,6 +638,27 @@ class BaseEmailBackendTests(HeadersCheckMixin, object):
except Exception as e: except Exception as e:
self.fail("close() unexpectedly raised an exception: %s" % e) self.fail("close() unexpectedly raised an exception: %s" % e)
def test_use_as_contextmanager(self):
"""
Test that the connection can be used as a contextmanager.
"""
opened = [False]
closed = [False]
conn = mail.get_connection(username='', password='')
def open():
opened[0] = True
conn.open = open
def close():
closed[0] = True
conn.close = close
with conn as same_conn:
self.assertTrue(opened[0])
self.assertIs(same_conn, conn)
self.assertFalse(closed[0])
self.assertTrue(closed[0])
class LocmemBackendTests(BaseEmailBackendTests, SimpleTestCase): class LocmemBackendTests(BaseEmailBackendTests, SimpleTestCase):
email_backend = 'django.core.mail.backends.locmem.EmailBackend' email_backend = 'django.core.mail.backends.locmem.EmailBackend'