From b72e0b0274ae4c8e7f6743f2cfdcd467be806b3e Mon Sep 17 00:00:00 2001 From: medmunds Date: Wed, 21 Mar 2018 17:08:35 -0700 Subject: [PATCH] Internal: Hoist RequestsPayload.serialize_json to BasePayload (Non-Requests payloads sometimes want to serialize json, too.) --- anymail/backends/base.py | 31 ++++++++++++++++++++++++++++++- anymail/backends/base_requests.py | 25 +------------------------ 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/anymail/backends/base.py b/anymail/backends/base.py index b7af863..d8357c4 100644 --- a/anymail/backends/base.py +++ b/anymail/backends/base.py @@ -1,3 +1,4 @@ +import json from datetime import date, datetime import six @@ -6,7 +7,9 @@ from django.core.mail.backends.base import BaseEmailBackend from django.utils.timezone import is_naive, get_current_timezone, make_aware, utc from requests.structures import CaseInsensitiveDict -from ..exceptions import AnymailCancelSend, AnymailError, AnymailUnsupportedFeature, AnymailRecipientsRefused +from ..exceptions import ( + AnymailCancelSend, AnymailError, AnymailUnsupportedFeature, AnymailRecipientsRefused, + AnymailSerializationError) from ..message import AnymailStatus from ..signals import pre_send, post_send from ..utils import ( @@ -489,3 +492,29 @@ class BasePayload(object): # ESP-specific payload construction def set_esp_extra(self, extra): self.unsupported_feature("esp_extra") + + # + # Helpers for concrete implementations + # + + def serialize_json(self, data): + """Returns data serialized to json, raising appropriate errors. + + Essentially json.dumps with added context in any errors. + + Useful for implementing, e.g., serialize_data in a subclass, + """ + try: + return json.dumps(data, default=self._json_default) + except TypeError as err: + # Add some context to the "not JSON serializable" message + raise AnymailSerializationError(orig_err=err, email_message=self.message, + backend=self.backend, payload=self) + + @staticmethod + def _json_default(o): + """json.dump default function that handles some common Payload data types""" + if isinstance(o, CaseInsensitiveDict): # used for headers + return dict(o) + raise TypeError("Object of type '%s' is not JSON serializable" % + o.__class__.__name__) diff --git a/anymail/backends/base_requests.py b/anymail/backends/base_requests.py index 1e4edd1..df3d8af 100644 --- a/anymail/backends/base_requests.py +++ b/anymail/backends/base_requests.py @@ -1,12 +1,9 @@ -import json - import requests -from requests.structures import CaseInsensitiveDict from six.moves.urllib.parse import urljoin from anymail.utils import get_anymail_setting from .base import AnymailBaseBackend, BasePayload -from ..exceptions import AnymailRequestsAPIError, AnymailSerializationError +from ..exceptions import AnymailRequestsAPIError from .._version import __version__ @@ -149,23 +146,3 @@ class RequestsPayload(BasePayload): def serialize_data(self): """Performs any necessary serialization on self.data, and returns the result.""" return self.data - - def serialize_json(self, data): - """Returns data serialized to json, raising appropriate errors. - - Useful for implementing serialize_data in a subclass, - """ - try: - return json.dumps(data, default=self._json_default) - except TypeError as err: - # Add some context to the "not JSON serializable" message - raise AnymailSerializationError(orig_err=err, email_message=self.message, - backend=self.backend, payload=self) - - @staticmethod - def _json_default(o): - """json.dump default function that handles some common Payload data types""" - if isinstance(o, CaseInsensitiveDict): # used for headers - return dict(o) - raise TypeError("Object of type '%s' is not JSON serializable" % - o.__class__.__name__)