1+ import warnings
12from datetime import datetime
23
3- from ..exceptions import AnymailRequestsAPIError
4+ from ..exceptions import AnymailRequestsAPIError , AnymailWarning
45from ..message import AnymailRecipientStatus , ANYMAIL_STATUSES
56from ..utils import last , combine , get_anymail_setting
67
@@ -43,14 +44,8 @@ def parse_recipient_status(self, response, payload, message):
4344 return recipient_status
4445
4546
46- def _expand_merge_vars (vardict ):
47- """Convert a Python dict to an array of name-content used by Mandrill.
48-
49- { name: value, ... } --> [ {'name': name, 'content': value }, ... ]
50- """
51- # For testing reproducibility, we sort the keys
52- return [{'name' : name , 'content' : vardict [name ]}
53- for name in sorted (vardict .keys ())]
47+ class DjrillDeprecationWarning (AnymailWarning , DeprecationWarning ):
48+ """Warning for features carried over from Djrill that will be removed soon"""
5449
5550
5651def encode_date_for_mandrill (dt ):
@@ -69,13 +64,18 @@ def encode_date_for_mandrill(dt):
6964
7065class MandrillPayload (RequestsPayload ):
7166
67+ def __init__ (self , * args , ** kwargs ):
68+ self .esp_extra = {} # late-bound in serialize_data
69+ super (MandrillPayload , self ).__init__ (* args , ** kwargs )
70+
7271 def get_api_endpoint (self ):
7372 if 'template_name' in self .data :
7473 return "messages/send-template.json"
7574 else :
7675 return "messages/send.json"
7776
7877 def serialize_data (self ):
78+ self .process_esp_extra ()
7979 return self .serialize_json (self .data )
8080
8181 #
@@ -89,7 +89,9 @@ def init_payload(self):
8989 }
9090
9191 def set_from_email (self , email ):
92- if not getattr (self .message , "use_template_from" , False ): # Djrill compat!
92+ if getattr (self .message , "use_template_from" , False ):
93+ self .deprecation_warning ('message.use_template_from' , 'message.from_email = None' )
94+ else :
9395 self .data ["message" ]["from_email" ] = email .email
9496 if email .name :
9597 self .data ["message" ]["from_name" ] = email .name
@@ -100,7 +102,9 @@ def add_recipient(self, recipient_type, email):
100102 to_list .append ({"email" : email .email , "name" : email .name , "type" : recipient_type })
101103
102104 def set_subject (self , subject ):
103- if not getattr (self .message , "use_template_subject" , False ): # Djrill compat!
105+ if getattr (self .message , "use_template_subject" , False ):
106+ self .deprecation_warning ('message.use_template_subject' , 'message.subject = None' )
107+ else :
104108 self .data ["message" ]["subject" ] = subject
105109
106110 def set_reply_to (self , emails ):
@@ -166,9 +170,59 @@ def set_merge_global_data(self, merge_global_data):
166170 ]
167171
168172 def set_esp_extra (self , extra ):
169- pass
173+ # late bind in serialize_data, so that obsolete Djrill attrs can contribute
174+ self .esp_extra = extra
170175
171- # Djrill leftovers
176+ def process_esp_extra (self ):
177+ if self .esp_extra is not None and len (self .esp_extra ) > 0 :
178+ esp_extra = self .esp_extra
179+ # Convert pythonic template_content dict to Mandrill name/content list
180+ try :
181+ template_content = esp_extra ['template_content' ]
182+ except KeyError :
183+ pass
184+ else :
185+ if hasattr (template_content , 'items' ): # if it's dict-like
186+ if esp_extra is self .esp_extra :
187+ esp_extra = self .esp_extra .copy () # don't modify caller's value
188+ esp_extra ['template_content' ] = [
189+ {'name' : var , 'content' : value }
190+ for var , value in template_content .items ()]
191+ # Convert pythonic recipient_metadata dict to Mandrill rcpt/values list
192+ try :
193+ recipient_metadata = esp_extra ['message' ]['recipient_metadata' ]
194+ except KeyError :
195+ pass
196+ else :
197+ if hasattr (recipient_metadata , 'keys' ): # if it's dict-like
198+ if esp_extra ['message' ] is self .esp_extra ['message' ]:
199+ esp_extra ['message' ] = self .esp_extra ['message' ].copy () # don't modify caller's value
200+ # For testing reproducibility, we sort the recipients
201+ esp_extra ['message' ]['recipient_metadata' ] = [
202+ {'rcpt' : rcpt , 'values' : recipient_metadata [rcpt ]}
203+ for rcpt in sorted (recipient_metadata .keys ())]
204+ # Merge esp_extra with payload data: shallow merge within ['message'] and top-level keys
205+ self .data .update ({k :v for k ,v in esp_extra .items () if k != 'message' })
206+ try :
207+ self .data ['message' ].update (esp_extra ['message' ])
208+ except KeyError :
209+ pass
210+
211+ # Djrill deprecated message attrs
212+
213+ def deprecation_warning (self , feature , replacement = None ):
214+ msg = "Djrill's `%s` will be removed in an upcoming Anymail release." % feature
215+ if replacement :
216+ msg += " Use `%s` instead." % replacement
217+ warnings .warn (msg , DjrillDeprecationWarning )
218+
219+ def deprecated_to_esp_extra (self , attr , in_message_dict = False ):
220+ feature = "message.%s" % attr
221+ if in_message_dict :
222+ replacement = "message.esp_extra = {'message': {'%s': <value>}}" % attr
223+ else :
224+ replacement = "message.esp_extra = {'%s': <value>}" % attr
225+ self .deprecation_warning (feature , replacement )
172226
173227 esp_message_attrs = (
174228 ('async' , last , None ),
@@ -188,25 +242,40 @@ def set_esp_extra(self, extra):
188242 ('subaccount' , last , None ),
189243 ('google_analytics_domains' , last , None ),
190244 ('google_analytics_campaign' , last , None ),
245+ ('global_merge_vars' , combine , None ),
246+ ('merge_vars' , combine , None ),
191247 ('recipient_metadata' , combine , None ),
192- ('template_content' , combine , _expand_merge_vars ),
248+ ('template_name' , last , None ),
249+ ('template_content' , combine , None ),
193250 )
194251
195252 def set_async (self , async ):
196- self .data ["async" ] = async
253+ self .deprecated_to_esp_extra ('async' )
254+ self .esp_extra ['async' ] = async
197255
198256 def set_ip_pool (self , ip_pool ):
199- self .data ["ip_pool" ] = ip_pool
257+ self .deprecated_to_esp_extra ('ip_pool' )
258+ self .esp_extra ['ip_pool' ] = ip_pool
259+
260+ def set_global_merge_vars (self , global_merge_vars ):
261+ self .deprecation_warning ('message.global_merge_vars' , 'message.merge_global_data' )
262+ self .set_merge_global_data (global_merge_vars )
263+
264+ def set_merge_vars (self , merge_vars ):
265+ self .deprecation_warning ('message.merge_vars' , 'message.merge_data' )
266+ self .set_merge_data (merge_vars )
267+
268+ def set_template_name (self , template_name ):
269+ self .deprecation_warning ('message.template_name' , 'message.template_id' )
270+ self .set_template_id (template_name )
200271
201272 def set_template_content (self , template_content ):
202- self .data ["template_content" ] = template_content
273+ self .deprecated_to_esp_extra ('template_content' )
274+ self .esp_extra ['template_content' ] = template_content
203275
204276 def set_recipient_metadata (self , recipient_metadata ):
205- # For testing reproducibility, we sort the recipients
206- self .data ['message' ]['recipient_metadata' ] = [
207- {'rcpt' : rcpt , 'values' : recipient_metadata [rcpt ]}
208- for rcpt in sorted (recipient_metadata .keys ())
209- ]
277+ self .deprecated_to_esp_extra ('recipient_metadata' , in_message_dict = True )
278+ self .esp_extra .setdefault ('message' , {})['recipient_metadata' ] = recipient_metadata
210279
211280 # Set up simple set_<attr> functions for any missing esp_message_attrs attrs
212281 # (avoids dozens of simple `self.data["message"][<attr>] = value` functions)
@@ -225,7 +294,8 @@ def define_message_attr_setters(cls):
225294 def make_setter (attr , setter_name ):
226295 # sure wish we could use functools.partial to create instance methods (descriptors)
227296 def setter (self , value ):
228- self .data ["message" ][attr ] = value
297+ self .deprecated_to_esp_extra (attr , in_message_dict = True )
298+ self .esp_extra .setdefault ('message' , {})[attr ] = value
229299 setter .__name__ = setter_name
230300 return setter
231301
0 commit comments