浏览代码

Fixed #22327 -- Turned BaseEmailBackend into a context manager

Changed the BaseEmailBackend to allow usage as context manager to open
and close connections.
Daniel Neuhäuser 11 年之前
父节点
当前提交
4aa80149e7
共有 4 个文件被更改,包括 52 次插入1 次删除
  1. 14 0
      django/core/mail/backends/base.py
  2. 2 1
      docs/releases/1.8.txt
  3. 15 0
      docs/topics/email.txt
  4. 21 0
      tests/mail/tests.py

+ 14 - 0
django/core/mail/backends/base.py

@@ -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

+ 2 - 1
docs/releases/1.8.txt

@@ -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
 ^^^^^^^^^^^^
 ^^^^^^^^^^^^

+ 15 - 0
docs/topics/email.txt

@@ -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
 -----------------------------------------
 -----------------------------------------
 
 

+ 21 - 0
tests/mail/tests.py

@@ -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'