Skip to content

Commit

Permalink
Python 2.5-3.2 compatible!
Browse files Browse the repository at this point in the history
  • Loading branch information
rpatterson committed Mar 15, 2012
1 parent 60ae523 commit 20c0aba
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 67 deletions.
12 changes: 9 additions & 3 deletions repoze/sendmail/delivery.py
Expand Up @@ -32,7 +32,6 @@
from transaction.interfaces import IDataManager
import transaction

@implementer(IDataManager)
class MailDataManager(object):

def __init__(self, callable, args=(), onAbort=None):
Expand Down Expand Up @@ -74,6 +73,9 @@ def tpc_finish(self, transaction):

tpc_abort = abort

# BBB Python 2.5 compat
MailDataManager = implementer(IDataManager)(MailDataManager)


class AbstractMailDelivery(object):

Expand All @@ -98,7 +100,6 @@ def send(self, fromaddr, toaddrs, message):
return messageid


@implementer(IMailDelivery)
class DirectMailDelivery(AbstractMailDelivery):

def __init__(self, mailer):
Expand All @@ -108,8 +109,10 @@ def createDataManager(self, fromaddr, toaddrs, message):
return MailDataManager(self.mailer.send,
args=(fromaddr, toaddrs, message))

# BBB Python 2.5 compat
DirectMailDelivery = implementer(IMailDelivery)(DirectMailDelivery)


@implementer(IMailDelivery)
class QueuedMailDelivery(AbstractMailDelivery):

def __init__(self, queuePath):
Expand All @@ -126,6 +129,9 @@ def createDataManager(self, fromaddr, toaddrs, message):
tx_message = maildir.add(message)
return MailDataManager(tx_message.commit, onAbort=tx_message.abort)

# BBB Python 2.5 compat
QueuedMailDelivery = implementer(IMailDelivery)(QueuedMailDelivery)


def copy_message(message):
parser = Parser()
Expand Down
5 changes: 4 additions & 1 deletion repoze/sendmail/maildir.py
Expand Up @@ -17,6 +17,7 @@
Read/write access to `Maildir` folders.
"""

import sys
import os
import errno
import socket
Expand Down Expand Up @@ -87,7 +88,9 @@ def add(self, message):
os.O_CREAT|os.O_EXCL|os.O_WRONLY,
384 # BBB Python 2 vs 3, 0o600 in octal
)
except OSError as e:
except OSError:
# BBB Python 2.5 compat
e = sys.exc_info()[1]
if e.errno != errno.EEXIST:
raise
# File exists
Expand Down
14 changes: 11 additions & 3 deletions repoze/sendmail/mailer.py
Expand Up @@ -15,16 +15,21 @@
from email.message import Message

import socket
import ssl
from smtplib import SMTP

try:
from ssl import SSLError
except ImportError:
# BBB Python 2.5
from socket import sslerror as SSLError

from zope.interface import implementer
from repoze.sendmail.interfaces import IMailer
from repoze.sendmail import encoding

have_ssl = hasattr(socket, 'ssl')

@implementer(IMailer)

class SMTPMailer(object):

smtp = SMTP
Expand Down Expand Up @@ -78,6 +83,9 @@ def send(self, fromaddr, toaddrs, message):
connection.sendmail(fromaddr, toaddrs, message)
try:
connection.quit()
except ssl.SSLError:
except SSLError:
#something weird happened while quiting
connection.close()

# BBB Python 2.5 compat
SMTPMailer = implementer(IMailer)(SMTPMailer)
28 changes: 21 additions & 7 deletions repoze/sendmail/queue.py
Expand Up @@ -135,7 +135,9 @@ def _send_message(self, filename):
age = None
mtime = os.stat(tmp_filename)[stat.ST_MTIME]
age = time.time() - mtime
except OSError as e:
except OSError:
# BBB Python 2.5 compat
e = sys.exc_info()[1]
if e.errno == errno.ENOENT: # file does not exist
# the tmp file could not be stated because it
# doesn't exist, that's fine, keep going
Expand All @@ -160,7 +162,9 @@ def _send_message(self, filename):
return
# if we get here, the file existed, but was too
# old, so it was unlinked
except OSError as e:
except OSError:
# BBB Python 2.5 compat
e = sys.exc_info()[1]
if e.errno == errno.ENOENT: # file does not exist
# it looks like someone else removed the tmp
# file, that's fine, we'll try to deliver the
Expand All @@ -174,7 +178,9 @@ def _send_message(self, filename):
# more processes to touch the file "simultaneously")
try:
os.utime(filename, None)
except OSError as e:
except OSError:
# BBB Python 2.5 compat
e = sys.exc_info()[1]
if e.errno == errno.ENOENT: # file does not exist
# someone removed the message before we could
# touch it, no need to complain, we'll just keep
Expand All @@ -189,7 +195,9 @@ def _send_message(self, filename):
# also sending this message
try:
_os_link(filename, tmp_filename)
except OSError as e:
except OSError:
# BBB Python 2.5 compat
e = sys.exc_info()[1]
if e.errno == errno.EEXIST: # file exists, *nix
# it looks like someone else is sending this
# message too; we'll try again later
Expand All @@ -212,7 +220,9 @@ def _send_message(self, filename):
fromaddr, toaddrs, message = self._parseMessage(open(filename))
try:
self.mailer.send(fromaddr, toaddrs, message)
except smtplib.SMTPResponseException as e:
except smtplib.SMTPResponseException:
# BBB Python 2.5 compat
e = sys.exc_info()[1]
if 500 <= e.smtp_code <= 599:
# permanent error, ditch the message
self.log.error(
Expand All @@ -226,7 +236,9 @@ def _send_message(self, filename):

try:
os.remove(filename)
except OSError as e:
except OSError:
# BBB Python 2.5 compat
e = sys.exc_info()[1]
if e.errno == errno.ENOENT: # file does not exist
# someone else unlinked the file; oh well
pass
Expand All @@ -236,7 +248,9 @@ def _send_message(self, filename):

try:
os.remove(tmp_filename)
except OSError as e:
except OSError:
# BBB Python 2.5 compat
e = sys.exc_info()[1]
if e.errno == errno.ENOENT: # file does not exist
# someone else unlinked the file; oh well
pass
Expand Down
12 changes: 8 additions & 4 deletions repoze/sendmail/tests/test_delivery.py
Expand Up @@ -15,11 +15,13 @@
import unittest
from unittest import TestCase, TestSuite, makeSuite

raw_header = str
# BBB Python 2 & 3 compat
raw_header = b = str
try:
raw_header = unicode
except NameError:
pass # Python 2 & 3 compat
import codecs
def b(x): return codecs.latin_1_encode(x)[0]

import transaction
from zope.interface import implementer
Expand All @@ -28,7 +30,6 @@
from repoze.sendmail.interfaces import IMailer


@implementer(IMailer)
class MailerStub(object):

def __init__(self, *args, **kw):
Expand All @@ -37,6 +38,9 @@ def __init__(self, *args, **kw):
def send(self, fromaddr, toaddrs, message):
self.sent_messages.append((fromaddr, toaddrs, message))

# BBB Python 2.5 compat
MailerStub = implementer(IMailer)(MailerStub)


class TestMailDataManager(TestCase):

Expand Down Expand Up @@ -207,7 +211,7 @@ def testNonASCIIAddrs(self):
from repoze.sendmail.delivery import QueuedMailDelivery
delivery = QueuedMailDelivery('/path/to/mailbox')

non_ascii = b'LaPe\xc3\xb1a'.decode('utf-8')
non_ascii = b('LaPe\xc3\xb1a').decode('utf-8')
fromaddr = non_ascii+' <jim@example.com>'
toaddrs = (non_ascii+' <guido@recip.com>',)
message = Message()
Expand Down
57 changes: 33 additions & 24 deletions repoze/sendmail/tests/test_encoding.py
Expand Up @@ -19,6 +19,14 @@
from email.mime import multipart
from email.mime import application

# BBB Python 2.5 & 3 compat
b = str
try:
unicode
except NameError:
import codecs
def b(x): return codecs.latin_1_encode(x)[0]

try:
from urllib.parse import quote
except ImportError:
Expand All @@ -30,9 +38,9 @@ class TestEncoding(unittest.TestCase):

def setUp(self):
self.message = message.Message()
self.latin_1_encoded = b'LaPe\xf1a'
self.latin_1_encoded = b('LaPe\xf1a')
self.latin_1 = self.latin_1_encoded.decode('latin_1')
self.utf_8_encoded = b'mo \xe2\x82\xac'
self.utf_8_encoded = b('mo \xe2\x82\xac')
self.utf_8 = self.utf_8_encoded.decode('utf_8')

def encode(self, message=None):
Expand All @@ -45,7 +53,7 @@ def test_best_charset_ascii(self):
from repoze.sendmail import encoding
value = 'foo'
best, encoded = encoding.best_charset(value)
self.assertEqual(encoded, b'foo')
self.assertEqual(encoded, b('foo'))
self.assertEqual(best, 'ascii')

def test_best_charset_latin_1(self):
Expand Down Expand Up @@ -74,10 +82,10 @@ def test_encoding_ascii_headers(self):
encoded = self.encode()

self.assertTrue(
b'To: Chris McDonough <chrism@example.com>, "Chris Rossi,'
b('To: Chris McDonough <chrism@example.com>, "Chris Rossi,')
in encoded)
self.assertTrue(b'From: '+from_.encode('ascii') in encoded)
self.assertTrue(b'Subject: '+subject.encode('ascii') in encoded)
self.assertTrue(b('From: ')+from_.encode('ascii') in encoded)
self.assertTrue(b('Subject: ')+subject.encode('ascii') in encoded)

def test_encoding_latin_1_headers(self):
to = ', '.join([
Expand All @@ -91,12 +99,12 @@ def test_encoding_latin_1_headers(self):

encoded = self.encode()

self.assertTrue(b'To: =?iso-8859-1?' in encoded)
self.assertTrue(b'From: =?iso-8859-1?' in encoded)
self.assertTrue(b'Subject: =?iso-8859-1?' in encoded)
self.assertTrue(b'<chrism@example.com>' in encoded)
self.assertTrue(b'<chrisr@example.com>' in encoded)
self.assertTrue(b'<rpatterson@example.com>' in encoded)
self.assertTrue(b('To: =?iso-8859-1?') in encoded)
self.assertTrue(b('From: =?iso-8859-1?') in encoded)
self.assertTrue(b('Subject: =?iso-8859-1?') in encoded)
self.assertTrue(b('<chrism@example.com>') in encoded)
self.assertTrue(b('<chrisr@example.com>') in encoded)
self.assertTrue(b('<rpatterson@example.com>') in encoded)

def test_encoding_utf_8_headers(self):
to = ', '.join([
Expand All @@ -110,12 +118,12 @@ def test_encoding_utf_8_headers(self):

encoded = self.encode()

self.assertTrue(b'To: =?utf' in encoded)
self.assertTrue(b'From: =?utf' in encoded)
self.assertTrue(b'Subject: =?utf' in encoded)
self.assertTrue(b'<chrism@example.com>' in encoded)
self.assertTrue(b'<chrisr@example.com>' in encoded)
self.assertTrue(b'<rpatterson@example.com>' in encoded)
self.assertTrue(b('To: =?utf') in encoded)
self.assertTrue(b('From: =?utf') in encoded)
self.assertTrue(b('Subject: =?utf') in encoded)
self.assertTrue(b('<chrism@example.com>') in encoded)
self.assertTrue(b('<chrisr@example.com>') in encoded)
self.assertTrue(b('<rpatterson@example.com>') in encoded)

def test_encoding_ascii_header_parameters(self):
self.message['Content-Disposition'] = (
Expand All @@ -124,7 +132,8 @@ def test_encoding_ascii_header_parameters(self):
encoded = self.encode()

self.assertTrue(
b'Content-Disposition: attachment; filename="foo.ppt"' in encoded)
b('Content-Disposition: attachment; filename="foo.ppt"')
in encoded)

def test_encoding_latin_1_header_parameters(self):
self.message['Content-Disposition'] = (
Expand All @@ -133,8 +142,8 @@ def test_encoding_latin_1_header_parameters(self):
encoded = self.encode()

self.assertTrue(
b"Content-Disposition: attachment; filename*=" in encoded)
self.assertTrue(b"latin_1''"+quote(
b("Content-Disposition: attachment; filename*=") in encoded)
self.assertTrue(b("latin_1''")+quote(
self.latin_1_encoded).encode('ascii') in encoded)

def test_encoding_utf_8_header_parameters(self):
Expand All @@ -144,8 +153,8 @@ def test_encoding_utf_8_header_parameters(self):
encoded = self.encode()

self.assertTrue(
b"Content-Disposition: attachment; filename*=" in encoded)
self.assertTrue(b"utf_8''"+quote(self.utf_8_encoded).encode('ascii')
b("Content-Disposition: attachment; filename*=") in encoded)
self.assertTrue(b("utf_8''")+quote(self.utf_8_encoded).encode('ascii')
in encoded)

def test_encoding_ascii_body(self):
Expand Down Expand Up @@ -173,7 +182,7 @@ def test_encoding_utf_8_body(self):
self.assertTrue(base64.encodestring(body.encode('utf_8')) in encoded)

def test_binary_body(self):
body = b'I know what you did last PyCon'
body = b('I know what you did last PyCon')
self.message = multipart.MIMEMultipart()
self.message.attach(application.MIMEApplication(body))

Expand Down
9 changes: 7 additions & 2 deletions repoze/sendmail/tests/test_mailer.py
Expand Up @@ -15,9 +15,14 @@
from zope.interface.verify import verifyObject
from repoze.sendmail.mailer import SMTPMailer
import email
import ssl
import unittest

try:
from ssl import SSLError
except ImportError:
# BBB Python 2.5
from socket import sslerror as SSLError


class TestSMTPMailer(unittest.TestCase):

Expand Down Expand Up @@ -50,7 +55,7 @@ def login(self, username, password):

def quit(self):
if self.fail_on_quit:
raise ssl.SSLError("dang")
raise SSLError("dang")
self.quitted = True
self.close()

Expand Down

0 comments on commit 20c0aba

Please sign in to comment.