From 971a3a393c998204a38ccb8f20bd4b114b9dc086 Mon Sep 17 00:00:00 2001 From: Mathieu Agopian Date: Sun, 28 Jul 2013 00:16:43 +0200 Subject: [PATCH] compatible python3 --- .travis.yml | 8 +++++--- Makefile | 3 ++- README.rst | 4 ++-- docs/source/conf.py | 20 ++++++++++---------- mailbot/callback.py | 17 +++++++++++++---- mailbot/compat.py | 13 +++++++++++++ mailbot/mailbot.py | 2 +- setup.py | 6 +++++- tox.ini | 26 +++++++++++++++++++------- 9 files changed, 70 insertions(+), 29 deletions(-) create mode 100644 mailbot/compat.py diff --git a/.travis.yml b/.travis.yml index 2819c50..175c890 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,12 @@ language: python python: - - "2.6" - "2.7" + - "3.3" install: - - pip install --use-mirrors imapclient unittest2 flake8 mock - - python setup.py develop + - pip install --use-mirrors flake8 mock + - if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then pip install --use-mirrors unittest2py3k; fi + - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --use-mirrors unittest2; fi + - pip install -e . script: - unit2 discover mailbot.tests - flake8 mailbot diff --git a/Makefile b/Makefile index 69e7a4e..dcc9f53 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ bin/python: virtualenv . --python python2 + bin/pip install -U setuptools bin/python setup.py develop test: bin/python @@ -10,7 +11,7 @@ test: bin/python livetest: bin/python bin/pip install tox - bin/tox -e py26-live,py27-live + bin/tox -e py27-live,py33-live docs: bin/pip install sphinx diff --git a/README.rst b/README.rst index 7126214..c7c1641 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,7 @@ MailBot: register callbacks to be executed on mail reception. * Authors: Mathieu Agopian and `contributors `_ * Licence: BSD -* Compatibility: Django 1.4+, python2.6 up to python3.3 +* Compatibility: Python 2.7 and Python 3.3 * Project URL: https://github.com/magopian/mailbot * Documentation: http://mailbot.rtfd.org/ @@ -27,7 +27,7 @@ Setup your environment: cd mailbot Hack and run the tests using `Tox `_ to test -on all the supported python and Django versions: +on all the supported python versions: :: diff --git a/docs/source/conf.py b/docs/source/conf.py index bdf960c..60f0fb0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# django-mail-factory documentation build configuration file, created by +# mailbot documentation build configuration file, created by # sphinx-quickstart on Wed Jan 23 17:31:52 2013. # # This file is execfile()d with the current directory set to its containing dir. @@ -40,8 +40,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'django-mail-factory' -copyright = u'2013, Rémy HUBSCHER' +project = u'mailbot' +copyright = u'2013, Mathieu Agopian' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -164,7 +164,7 @@ html_static_path = ['_static'] #html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'django-mail-factorydoc' +htmlhelp_basename = 'mailbotdoc' # -- Options for LaTeX output -------------------------------------------------- @@ -183,8 +183,8 @@ latex_elements = { # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'django-mail-factory.tex', u'django-mail-factory Documentation', - u'Rémy HUBSCHER', 'manual'), + ('index', 'mailbot.tex', u'mailbot Documentation', + u'Mathieu Agopian', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -213,8 +213,8 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'django-mail-factory', u'django-mail-factory Documentation', - [u'Rémy HUBSCHER'], 1) + ('index', 'mailbot', u'mailbot Documentation', + [u'Mathieu Agopian'], 1) ] # If true, show URL addresses after external links. @@ -227,8 +227,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'django-mail-factory', u'django-mail-factory Documentation', - u'Rémy HUBSCHER', 'django-mail-factory', 'One line description of project.', + ('index', 'mailbot', u'mailbot Documentation', + u'Mathieu Agopian', 'mailbot', 'One line description of project.', 'Miscellaneous'), ] diff --git a/mailbot/callback.py b/mailbot/callback.py index dc8a2cf..6d0090a 100644 --- a/mailbot/callback.py +++ b/mailbot/callback.py @@ -1,9 +1,13 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import + from collections import defaultdict from email.header import decode_header from re import findall +from .compat import text_type, encoded_padding + class Callback(object): """Base class for callbacks.""" @@ -27,7 +31,7 @@ class Callback(object): return True rules_tests = [self.check_item(item, regexps) - for item, regexps in rules.iteritems()] + for item, regexps in rules.items()] return all(rules_tests) # True only if at least one value is @@ -53,8 +57,10 @@ class Callback(object): else: value = message[item] # decode header (might be encoded as latin-1, utf-8... - value = ' '.join(chunk.decode(encoding or 'ASCII') - for chunk, encoding in decode_header(value)) + value = encoded_padding.join( + chunk.decode(encoding or 'ASCII') + if not isinstance(chunk, text_type) else chunk + for chunk, encoding in decode_header(value)) for regexp in regexps: # store all captures for easy access self.matches[item] += findall(regexp, value) @@ -80,7 +86,10 @@ class Callback(object): if content_type == 'text/plain' and filename is None: # text body of the mail, not an attachment encoding = part.get_content_charset() or 'ASCII' - return part.get_payload(decode=True).decode(encoding) + content = part.get_payload() + if not isinstance(content, text_type): + content = part.get_payload(decode=True).decode(encoding) + return content return '' diff --git a/mailbot/compat.py b/mailbot/compat.py new file mode 100644 index 0000000..73778e4 --- /dev/null +++ b/mailbot/compat.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +import sys + +# encoded padding is to cope with this ugly bug: +# http://bugs.python.org/issue1467619 +# For some reason, in py27, the whitespace separating encoded pieces is eaten +# up +encoded_padding = '' +text_type = str +if sys.version < '3': + encoded_padding = ' ' + text_type = unicode # noqa diff --git a/mailbot/mailbot.py b/mailbot/mailbot.py index 6883e5e..b9520f3 100644 --- a/mailbot/mailbot.py +++ b/mailbot/mailbot.py @@ -80,7 +80,7 @@ class MailBot(object): # compare datetimes without tzinfo, as UTC date_pivot = datetime.utcnow() - timedelta(seconds=self.timeout) - to_reset = [msg_id for msg_id, data in messages.iteritems() + to_reset = [msg_id for msg_id, data in messages.items() if data['INTERNALDATE'].replace(tzinfo=None) < date_pivot] if to_reset: diff --git a/setup.py b/setup.py index d3a94c6..73ff2a6 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,11 @@ if __name__ == '__main__': # ``import setup`` doesn't trigger setup(). 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Natural Language :: English', - 'Programming Language :: Python'], + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3'], keywords='mail callback', author='Mathieu Agopian', author_email='mathieu.agopian@gmail.com', diff --git a/tox.ini b/tox.ini index 571c6ac..88beb4c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,26 +1,38 @@ - [tox] -envlist = py26, py27 +envlist = py27, py33 +toxworkdir = {homedir}/.tox-mailbot [testenv] commands = python setup.py develop - coverage run --branch --source=mailbot bin/unit2 discover mailbot.tests + coverage run --branch --source=mailbot {envbindir}/unit2 discover mailbot.tests coverage report -m --omit=mailbot/tests/*,mailbot/livetests/* flake8 mailbot deps = - imapclient - unittest2 mock flake8 coverage -[testenv:py26-live] +[testenv:py27] +basepython = python2.7 +deps = + unittest2 + {[testenv]deps} + +[testenv:py33] +basepython = python3.3 +deps = + unittest2py3k + {[testenv]deps} + +[testenv:py27-live] +basepython = python2.7 commands = python setup.py develop unit2 discover mailbot.livetests -[testenv:py27-live] +[testenv:py33-live] +basepython = python3.3 commands = python setup.py develop unit2 discover mailbot.livetests