diff --git a/djrill/mail/backends/djrill.py b/djrill/mail/backends/djrill.py index d63faf4..3c7d43d 100644 --- a/djrill/mail/backends/djrill.py +++ b/djrill/mail/backends/djrill.py @@ -6,7 +6,6 @@ from django.core.mail.backends.base import BaseEmailBackend from django.core.mail.message import sanitize_address, DEFAULT_ATTACHMENT_MIME_TYPE from djrill import MANDRILL_API_URL, MandrillAPIError, NotSupportedByMandrillError, __version__ -from djrill.exceptions import removed_in_djrill_2 from base64 import b64encode from datetime import date, datetime @@ -37,19 +36,6 @@ def encode_date_for_mandrill(dt): return dt -class JSONDateUTCEncoder(json.JSONEncoder): - """[deprecated] JSONEncoder that encodes dates in string format used by Mandrill.""" - def default(self, obj): - if isinstance(obj, date): - removed_in_djrill_2( - "You've used the date '%r' as a Djrill message attribute " - "(perhaps in merge vars or metadata). Djrill 2.0 will require " - "you to explicitly convert this date to a string." % obj - ) - return encode_date_for_mandrill(obj) - return super(JSONDateUTCEncoder, self).default(obj) - - class DjrillBackend(BaseEmailBackend): """ Mandrill API Email Backend @@ -153,7 +139,7 @@ class DjrillBackend(BaseEmailBackend): return False try: - api_data = json.dumps(api_params, cls=JSONDateUTCEncoder) + api_data = json.dumps(api_params) except TypeError as err: # Add some context to the "not JSON serializable" message if not err.args: diff --git a/djrill/tests/test_legacy.py b/djrill/tests/test_legacy.py index 0298808..3e632fd 100644 --- a/djrill/tests/test_legacy.py +++ b/djrill/tests/test_legacy.py @@ -1,58 +1,8 @@ # Tests deprecated Djrill features -from datetime import date, datetime -import warnings - -from django.core import mail from django.test import TestCase from djrill import NotSupportedByMandrillError -from djrill.tests.mock_backend import DjrillBackendMockAPITestCase -from djrill.tests.utils import reset_warning_registry - - -class DjrillBackendDeprecationTests(DjrillBackendMockAPITestCase): - - def setUp(self): - reset_warning_registry() - super(DjrillBackendDeprecationTests, self).setUp() - - def test_deprecated_json_date_encoding(self): - """Djrill 2.0+ avoids a blanket JSONDateUTCEncoder""" - # Djrill allows dates for send_at, so shouldn't warn: - message = mail.EmailMessage('Subject', 'Body', 'from@example.com', ['to@example.com']) - message.send_at = datetime(2022, 10, 11, 12, 13, 14, 567) - self.assertNotWarns(DeprecationWarning, message.send) - - # merge_vars need to be json-serializable, so should generate a warning: - message = mail.EmailMessage('Subject', 'Body', 'from@example.com', ['to@example.com']) - message.global_merge_vars = {'DATE': date(2022, 10, 11)} - self.assertWarnsMessage(DeprecationWarning, - "Djrill 2.0 will require you to explicitly convert this date to a string", - message.send) - # ... but should still encode the date (for now): - data = self.get_api_call_data() - self.assertEqual(data['message']['global_merge_vars'], - [{'name': 'DATE', 'content': "2022-10-11 00:00:00"}]) - - def assertWarnsMessage(self, warning, message, callable, *args, **kwds): - """Checks that `callable` issues a warning of category `warning` containing `message`""" - with warnings.catch_warnings(record=True) as warned: - warnings.simplefilter("always") - callable(*args, **kwds) - self.assertGreater(len(warned), 0, msg="No warnings issued") - self.assertTrue( - any(issubclass(w.category, warning) and message in str(w.message) for w in warned), - msg="%r(%r) not found in %r" % (warning, message, [str(w) for w in warned])) - - def assertNotWarns(self, warning, callable, *args, **kwds): - """Checks that `callable` does not issue any warnings of category `warning`""" - with warnings.catch_warnings(record=True) as warned: - warnings.simplefilter("always") - callable(*args, **kwds) - relevant_warnings = [w for w in warned if issubclass(w.category, warning)] - self.assertEqual(len(relevant_warnings), 0, - msg="Unexpected warnings %r" % [str(w) for w in relevant_warnings]) class DjrillLegacyExceptionTests(TestCase): diff --git a/djrill/tests/test_mandrill_send.py b/djrill/tests/test_mandrill_send.py index 80cabc5..83e318b 100644 --- a/djrill/tests/test_mandrill_send.py +++ b/djrill/tests/test_mandrill_send.py @@ -529,7 +529,7 @@ class DjrillMandrillFeatureTests(DjrillBackendMockAPITestCase): self.assertEqual(sent, 0) self.assertIsNone(msg.mandrill_response) - def test_json_serialization_warnings(self): + def test_json_serialization_errors(self): """Try to provide more information about non-json-serializable data""" self.message.global_merge_vars = {'PRICE': Decimal('19.99')} with self.assertRaisesMessage( @@ -539,6 +539,12 @@ class DjrillMandrillFeatureTests(DjrillBackendMockAPITestCase): ): self.message.send() + def test_dates_not_serialized(self): + """Pre-2.0 Djrill accidentally serialized dates to ISO""" + self.message.global_merge_vars = {'SHIP_DATE': date(2015, 12, 2)} + with self.assertRaises(TypeError): + self.message.send() + @override_settings(MANDRILL_SETTINGS={ 'from_name': 'Djrill Test', diff --git a/docs/history.rst b/docs/history.rst index 260f936..5f4d8c0 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -48,6 +48,16 @@ Removed DjrillAdminSite (Do this only if you changed to SimpleAdminConfig for Djrill, and aren't creating custom admin sites for any other Django apps you use.) +Removed unintended date-to-string conversion + If your code was relying on Djrill to automatically convert date or datetime + values to strings in :attr:`merge_vars`, :attr:`metadata`, or other Mandrill + message attributes, you must now explicitly do the string conversion + yourself. See :ref:`formatting-merge-data` for an explanation. + (Djrill 1.4 reported a DeprecationWarning for this case.) + + (The exception is :attr:`send_at`, which Djrill expects can be a date or + datetime.) + Removed DjrillMessage class The ``DjrillMessage`` class has not been needed since Djrill 0.2. You should replace any uses of it with the standard @@ -58,24 +68,6 @@ Removed DjrillBackendHTTPError with :exc:`djrill.MandrillAPIError`. -**Dates in merge data and other attributes** - -Djrill automatically converts :attr:`send_at` date and datetime -values to the ISO 8601 string format expected by the Mandrill API. - -Unintentionally, it also converts dates used in other Mandrill message -attributes (such as :attr:`merge_vars` or :attr:`metadata`) where it -might not be expected (or appropriate). - -Djrill 2.0 will remove this automatic date formatting, except -for attributes that are inherently dates (currently only `send_at`). - -To assist in detecting code relying on the (undocumented) current -behavior, Djrill 1.4 will report a DeprecationWarning for date -or datetime values used in any Mandrill message attributes other -than `send_at`. See :ref:`formatting-merge-data` for other options. - - Older Releases --------------