Changeset 107 for trunk

Show
Ignore:
Timestamp:
10/16/08 15:58:20 (3 months ago)
Author:
fs
Message:

Message class refactoring: re-enable positional parameters, several cleanups
'authors' attribute is missing (was partly non-functional in the constructor anyway) but will be
added soon.
See #79 for background information

Location:
trunk
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • trunk/tests/test_debug_provider.py

    r105 r107  
    2121                            'debug': DebugProviderFactory()} 
    2222        interface.start(extra_classes=fake_setuptools) 
    23         self.msg = Message(author='foo@example.com', to='to@example.com', 
    24                            subject='Test', plain='Plain text body') 
     23        self.msg = Message('foo@example.com', 'to@example.com', 'Test',  
     24                           plain='Plain text body') 
    2525     
    2626    def tearDown(self): 
  • trunk/tests/test_message.py

    r101 r107  
    44"""Test the TurboMail Message class.""" 
    55 
    6  
    7 import unittest 
    8 from turbomail.message import Message 
    9 from email.Header import Header 
     6import email 
     7from email.Header import decode_header, Header 
    108try: 
    119    from email.mime.text import MIMEText 
     
    1311    # Python < 2.5 has no email.mime module 
    1412    from email.MIMEText import MIMEText 
     13import logging 
     14import unittest 
    1515 
    16 import logging 
     16 
     17from turbomail.message import Message 
     18 
    1719logging.disable(logging.WARNING) 
    1820 
     
    2022class TestBasicMessage(unittest.TestCase): 
    2123    """Test the basic output of the Message class.""" 
    22  
     24     
    2325    def setUp(self): 
    2426        self.message = Message( 
     
    3436        self.failUnless(isinstance(self.message.mime, MIMEText)) 
    3537     
    36     def test_message_string(self): 
    37         self.failUnless("To: Recipient <recipient@example.com>" in str(self.message)) 
    38         self.failUnless("From: Author <author@example.com>" in str(self.message)) 
    39         self.failUnless("Subject: Test message subject." in str(self.message)) 
    40         self.failUnless("\n\nThis is a test message plain text body." in str(self.message)) 
     38    def test_message_string_with_basic(self): 
     39        message_string = str(self.message) 
     40        msg = email.message_from_string(message_string) 
     41        self.assertEqual('Author <author@example.com>', msg['From']) 
     42        self.assertEqual('Recipient <recipient@example.com>', msg['To']) 
     43        self.assertEqual('Test message subject.', msg['Subject']) 
     44        self.assertEqual('This is a test message plain text body.', msg.get_payload()) 
     45     
     46    def test_message_recipients_and_addresses(self): 
     47        self.message.cc = 'cc@example.com' 
     48        self.message.bcc = 'bcc@example.com' 
     49        self.message.sender = 'sender@example.com' 
     50        self.message.reply_to = 'replyto@example.com' 
     51        self.message.disposition = 'disposition@example.com' 
     52         
     53        message_string = str(self.message) 
     54        msg = email.message_from_string(message_string) 
     55         
     56        self.assertEqual('cc@example.com', msg['cc']) 
     57        # BCC must not be encoded in the message itself, it is only sent in the 
     58        # smtp envelope 
     59        self.assertEqual(None, msg['bcc']) 
     60        self.assertEqual('sender@example.com', msg['sender']) 
     61        self.assertEqual('replyto@example.com', msg['reply-to']) 
     62        self.assertEqual('disposition@example.com', msg['disposition-notification-to']) 
    4163     
    4264    def test_mime_generation(self): 
     
    4870    def test_recipients_collection(self): 
    4971        self.message.cc.append("copied@example.com") 
    50         self.assertEqual(self.message.recipients.addresses, ["recipient@example.com", "copied@example.com"]) 
     72        self.assertEqual(["recipient@example.com", "copied@example.com"], 
     73                         self.message.recipients.addresses) 
    5174     
    5275    def test_subject_with_umlaut(self): 
     
    5578        self.message.encoding = "UTF-8" 
    5679         
    57         msg_string = str(self.message) 
    58         subject_string = "Subject: " + str(Header(subject_string, "UTF-8")) 
    59         self.failUnless(subject_string in msg_string) 
     80        msg = email.message_from_string(str(self.message)) 
     81        encoded_subject = str(Header(subject_string, "UTF-8")) 
     82        self.assertEqual(encoded_subject, msg['Subject']) 
    6083     
    6184    def test_from_with_umlaut(self): 
     
    6689        self.message.encoding = "ISO-8859-1" 
    6790         
    68         msg_string = str(self.message) 
    69         encoded_name = str(Header(from_name, "ISO-8859-1")) 
    70         from_string = "From: %s <%s>" % (encoded_name, from_email) 
    71         self.failUnless(from_string in msg_string) 
     91        msg = email.message_from_string(str(self.message)) 
     92        encoded_name = "%s <%s>" % ( str(Header(from_name, "ISO-8859-1")), from_email) 
     93        self.assertEqual(encoded_name, msg['From']) 
  • trunk/turbomail/message.py

    r105 r107  
    77from turbomail.util import AddressList 
    88from turbomail.control import interface 
    9 import re, os, email 
     9import os 
    1010 
    1111import email.Message 
     
    4242 
    4343 
     44 
    4445class Message(object): 
    4546    """Simple e-mail message class.""" 
    4647     
    47     def __init__(self, **kw): 
     48    def __init__(self, author=None, to=None, subject=None, **kw): 
    4849        """Instantiate a new Message object. 
    4950         
     
    5354        arguments can be used to quickly prepare a simple message. 
    5455        """ 
    55          
    5656        super(Message, self).__init__() 
     57        # if sender != None and author == None -> warning, sender -> author, sender=None 
     58        # if recipient != None and to == None -> warning, recipient -> to 
     59        # recipients support later 
     60         
     61        def kwpop(name, configkey=None, default=None): 
     62            value = None 
     63            if configkey != None: 
     64                value = kw.get(name, interface.config.get(configkey, default)) 
     65            else: 
     66                value = kw.get(name, default) 
     67            return value 
     68         
     69        self._author = AddressList(author or interface.config.get("mail.message.author", None)) 
     70        self._to = AddressList(to or interface.config.get("mail.message.to", None)) 
     71        self._cc = AddressList(kwpop("cc", "mail.message.cc")) 
     72        self._bcc = AddressList(kwpop("bcc", "mail.message.bcc")) 
     73        self._sender = AddressList(kwpop("sender", "mail.message.sender")) 
     74        self._reply_to = AddressList(kwpop("reply_to", "mail.message.reply_to")) 
     75        self._disposition = AddressList(kwpop("disposition", "mail.message.disposition")) 
     76         
     77        self.subject = subject 
     78        self.date = kwpop("date", formatdate(localtime=True)) 
     79        self.encoding = kwpop("encoding", "mail.encoding", 'us-ascii') 
     80        self.organization = kwpop("organization", "mail.message.organization") 
     81        self.priority = kwpop("priority", "mail.message.priority") 
     82         
     83        self.plain = kwpop("plain", None) 
     84        self.rich = kwpop("rich", None) 
     85        self.attachments = kwpop("attachments", default=[]) 
     86        self.embedded = kwpop("embedded", default=[]) 
     87        self.headers = kwpop("headers", "mail.message.headers", default=[]) 
     88         
     89        # TODO: This parameter should be present in a base message class 
     90        # smtp provider assumes that all messages have it! 
     91        self.tries = kwpop("tries", "mail.tries", 3) 
     92         
     93        self._id = kw.get("id", None) 
    5794         
    5895        self._processed = False 
    5996        self._dirty = False 
    60          
    61         def configget(name, key, default=None): 
    62             return kw.get(name, interface.config.get(key, default)) 
    63          
    64         self.date = kw.get("date", formatdate(localtime=True)) 
    65          
    66         if 'authors' in kw: kw['author'] == kw['authors'] 
    67         if 'senders' in kw: kw['sender'] == kw['senders'] 
    68          
    69         self._author = AddressList(configget("author", "mail.message.author")) 
    70         self._sender = AddressList(configget("sender", "mail.message.sender")) 
    71         self._reply = AddressList(configget("reply", "mail.message.reply")) 
    72         self._to = AddressList(kw.get("to", None)) 
    73         self._cc = AddressList(configget("cc", "mail.message.cc")) 
    74         self._bcc = AddressList(configget("bcc", "mail.message.bcc")) 
    75         self._disposition = AddressList(configget("disposition", "mail.message.disposition")) 
    76          
    77         self.organization = configget("organization", "mail.message.organization") 
    78         self.encoding = configget("encoding", "mail.encoding", 'us-ascii') 
    79         self.priority = configget("priority", "mail.message.priority") 
    80         self.subject = kw.get("subject", None) 
    81         self.plain = kw.get("plain", None) 
    82         self.rich = kw.get("rich", None) 
    83         self.attachments = kw.get("attachments", []) 
    84         self.embedded = kw.get("embedded", []) 
    85         self.headers = configget("headers", "mail.message.headers", []) 
    86         self.tries = configget("tries", "mail.tries", 3) 
    87          
    88         self._id = kw.get("id", None) 
    89      
    90     def __setattr__(self, name, value): 
    91         """Set the dirty flag as properties are updated.""" 
    92          
    93         super(Message, self).__setattr__(name, value) 
    94          
    95         if name not in ('bcc', '_dirty', '_processed'): self.__dict__['_dirty'] = True 
    96      
    97     def __str__(self): 
    98         return self.mime.as_string() 
     97     
    9998     
    10099    author = AddressList.protected('_author') 
    101     authors = AddressList.protected('_author') 
    102     sender = AddressList.protected('_sender') 
    103     senders = AddressList.protected('_sender') 
    104     reply = AddressList.protected('_reply') 
    105100    to = AddressList.protected('_to') 
    106101    cc = AddressList.protected('_cc') 
    107102    bcc = AddressList.protected('_bcc') 
     103    sender = AddressList.protected('_sender') 
     104    reply_to = AddressList.protected('_reply_to') 
    108105    disposition = AddressList.protected('_disposition') 
     106     
     107     
     108    def __setattr__(self, name, value): 
     109        """Set the dirty flag as properties are updated.""" 
     110        super(Message, self).__setattr__(name, value) 
     111        if name not in ('bcc', '_dirty', '_processed'):  
     112            self.__dict__['_dirty'] = True 
     113     
     114     
     115    def __str__(self): 
     116        return self.mime.as_string() 
     117     
    109118     
    110119    def id(self): 
    111120        if not self._id or (self._processed and self._dirty): 
    112121            self.__dict__['_id'] = make_msgid() 
    113              
    114122            self._processed = False 
    115          
    116123        return self._id 
    117      
    118124    id = property(id) 
     125     
    119126     
    120127    def envelope(self): 
     
    122129            return AddressList(self.sender) 
    123130        return AddressList(self.author) 
    124      
    125131    envelope = property(envelope) 
     132     
    126133     
    127134    def recipients(self): 
    128135        return AddressList(self.to + self.cc + self.bcc) 
    129      
    130136    recipients = property(recipients) 
     137     
    131138     
    132139    def mime_document(self, plain, rich=None): 
     
    179186                ('Sender', self.sender), 
    180187                ('From', self.author), 
    181                 ('Reply-To', self.reply), 
     188                ('Reply-To', self.reply_to), 
    182189                ('Subject', self.subject), 
    183190                ('Date', self.date),