From 2544ef725dd004f85cc5821172a75e46211799ff Mon Sep 17 00:00:00 2001 From: rbas Date: Thu, 23 Oct 2014 23:26:40 +0200 Subject: [PATCH] Add support for python 3 Re #26 --- .travis.yml | 5 ++++ imbox/parser.py | 19 +++++++++------- imbox/utils.py | 14 ++++++++++++ setup.py | 29 ++++++++++++----------- tests/parser_tests.py | 53 +++++++++++++++++++------------------------ 5 files changed, 67 insertions(+), 53 deletions(-) create mode 100644 imbox/utils.py diff --git a/.travis.yml b/.travis.yml index aad9ab8..2ccd2ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,9 @@ language: python python: - "2.6" - "2.7" + - "3.2" + - "3.3" + - "3.4" +install: + - python setup.py -q install script: nosetests diff --git a/imbox/parser.py b/imbox/parser.py index 99ff752..892c36d 100644 --- a/imbox/parser.py +++ b/imbox/parser.py @@ -1,11 +1,14 @@ +from __future__ import unicode_literals +from six import StringIO + import re -import StringIO import email import base64 import quopri import time from datetime import datetime from email.header import decode_header +from imbox.utils import str_encode, str_decode class Struct(object): @@ -26,17 +29,17 @@ def decode_mail_header(value, default_charset='us-ascii'): try: headers = decode_header(value) except email.errors.HeaderParseError: - return value.encode(default_charset, 'replace').decode(default_charset) + return str_decode(str_encode(value, default_charset, 'replace'), default_charset) else: for index, (text, charset) in enumerate(headers): try: - headers[index] = text.decode(charset or default_charset, - 'replace') + headers[index] = str_decode(text, charset or default_charset, + 'replace') except LookupError: # if the charset is unknown, force default - headers[index] = text.decode(default_charset, 'replace') + headers[index] = str_decode(text, default_charset, 'replace') - return u"".join(headers) + return ''.join(headers) def get_mail_addresses(message, header_name): @@ -65,7 +68,7 @@ def decode_param(param): value = quopri.decodestring(code) elif type_ == 'B': value = base64.decodestring(code) - value = unicode(value, encoding) + value = str_encode(value, encoding) value_results.append(value) if value_results: v = ''.join(value_results) @@ -151,7 +154,7 @@ def parse_email(raw_email): 'content-type'] parsed_email['headers'] = [] - for key, value in email_dict.iteritems(): + for key, value in email_dict.items(): if key.lower() in value_headers_keys: valid_key_name = key.lower().replace('-', '_') diff --git a/imbox/utils.py b/imbox/utils.py new file mode 100644 index 0000000..d3ef304 --- /dev/null +++ b/imbox/utils.py @@ -0,0 +1,14 @@ +from six import PY3 + +if PY3: + def str_encode(value='', encoding=None, errors='strict'): + return str(value, encoding, errors) + + def str_decode(value='', encoding=None, errors='strict'): + return bytes(value, encoding, errors).decode('utf-8') +else: + def str_encode(string=u'', encoding=None, errors='strict'): + return unicode(string, encoding, errors) + + def str_decode(value='', encoding=None, errors='strict'): + return value.decode(encoding, errors) diff --git a/setup.py b/setup.py index 91a8e82..42a810b 100644 --- a/setup.py +++ b/setup.py @@ -8,18 +8,17 @@ def read(filename): return open(os.path.join(os.path.dirname(__file__), filename)).read() setup( - name='imbox', - version=version, - description="Python IMAP for Human beings", - long_description= read('README.md'), - keywords='email, IMAP, parsing emails', - author='Martin Rusev', - author_email='martinrusev@live.com', - url='https://github.com/martinrusev/imbox', - license='MIT', - packages=['imbox'], - package_dir={'imbox':'imbox'}, - zip_safe=False, - install_requires=[], - -) \ No newline at end of file + name='imbox', + version=version, + description="Python IMAP for Human beings", + long_description= read('README.md'), + keywords='email, IMAP, parsing emails', + author='Martin Rusev', + author_email='martinrusev@live.com', + url='https://github.com/martinrusev/imbox', + license='MIT', + packages=['imbox'], + package_dir={'imbox':'imbox'}, + zip_safe=False, + install_requires=['six',], +) diff --git a/tests/parser_tests.py b/tests/parser_tests.py index f4e544a..996e2a9 100644 --- a/tests/parser_tests.py +++ b/tests/parser_tests.py @@ -1,5 +1,4 @@ import unittest -import email from imbox.parser import * raw_email = """Delivered-To: johndoe@gmail.com @@ -12,7 +11,7 @@ MIME-Version: 1.0 To: John Doe Subject: Test email - no attachment Content-Type: multipart/alternative; - boundary="------------080505090108000500080106" + boundary="------------080505090108000500080106" X-OriginalArrivalTime: 30 Jul 2013 12:56:43.0604 (UTC) FILETIME=[3DD52140:01CE8D24] --------------080505090108000500080106 @@ -35,40 +34,34 @@ Hi, this is a test email with no attachments', parsed_email.message_id) - self.assertEqual(raw_email, parsed_email.raw_email) - self.assertEqual(u'Test email - no attachment', parsed_email.subject) - self.assertEqual(u'Tue, 30 Jul 2013 15:56:29 +0300', parsed_email.date) - self.assertEqual(u'', parsed_email.message_id) + def test_parse_email_ignores_header_casing(self): + self.assertEqual('one', parse_email('Message-ID: one').message_id) + self.assertEqual('one', parse_email('Message-Id: one').message_id) + self.assertEqual('one', parse_email('Message-id: one').message_id) + self.assertEqual('one', parse_email('message-id: one').message_id) + # TODO - Complete the test suite + def test_parse_attachment(self): + pass - def test_parse_email_ignores_header_casing(self): - self.assertEqual('one', parse_email('Message-ID: one').message_id) - self.assertEqual('one', parse_email('Message-Id: one').message_id) - self.assertEqual('one', parse_email('Message-id: one').message_id) - self.assertEqual('one', parse_email('message-id: one').message_id) - - - # TODO - Complete the test suite - def test_parse_attachment(self): - pass - - def test_decode_mail_header(self): - pass + def test_decode_mail_header(self): + pass - - - def test_get_mail_addresses(self): + def test_get_mail_addresses(self): - to_message_object = email.message_from_string("To: John Doe ") - self.assertEqual([{'email': 'johndoe@gmail.com', 'name': u'John Doe'}], get_mail_addresses(to_message_object, 'to')) - - from_message_object = email.message_from_string("From: John Smith ") - self.assertEqual([{'email': 'johnsmith@gmail.com', 'name': u'John Smith'}], get_mail_addresses(from_message_object, 'from')) + to_message_object = email.message_from_string("To: John Doe ") + self.assertEqual([{'email': 'johndoe@gmail.com', 'name': u'John Doe'}], get_mail_addresses(to_message_object, 'to')) + from_message_object = email.message_from_string("From: John Smith ") + self.assertEqual([{'email': 'johnsmith@gmail.com', 'name': u'John Smith'}], get_mail_addresses(from_message_object, 'from'))