← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/python-oops/py3 into lp:python-oops

 

Colin Watson has proposed merging lp:~cjwatson/python-oops/py3 into lp:python-oops.

Commit message:
Add Python 3 support.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/python-oops/py3/+merge/337332

I ignored buildout and did everything in a virtualenv with pip.

I only noticed https://code.launchpad.net/~ralsina/python-oops/py3/+merge/261557 after finishing this, but I think my safe_unicode conversion is more correct.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/python-oops/py3 into lp:python-oops.
=== modified file '.bzrignore'
--- .bzrignore	2011-08-10 05:06:50 +0000
+++ .bzrignore	2018-02-08 08:31:24 +0000
@@ -1,3 +1,4 @@
+__pycache__
 ./eggs/*
 ./.installed.cfg
 ./develop-eggs

=== modified file 'NEWS'
--- NEWS	2012-08-10 02:18:06 +0000
+++ NEWS	2018-02-08 08:31:24 +0000
@@ -6,6 +6,8 @@
 NEXT
 ----
 
+* Add Python 3 support. (Colin Watson)
+
 0.0.13
 ------
 

=== modified file 'README'
--- README	2012-08-10 01:04:03 +0000
+++ README	2018-02-08 08:31:24 +0000
@@ -28,7 +28,7 @@
 Dependencies
 ============
 
-* Python 2.6+
+* Python 2.6+ or 3.3+
 * pytz (http://pypi.python.org/pypi/pytz/)
 
 Testing Dependencies

=== modified file 'oops/config.py'
--- oops/config.py	2012-06-26 20:57:41 +0000
+++ oops/config.py	2018-02-08 08:31:24 +0000
@@ -93,6 +93,8 @@
 """
 
 
+from __future__ import absolute_import, print_function
+
 __all__ = [
     'Config',
     ]
@@ -102,8 +104,8 @@
 from copy import deepcopy
 import warnings
 
-from createhooks import default_hooks
-from publishers import (
+from oops.createhooks import default_hooks
+from oops.publishers import (
     convert_result_to_list,
     publish_to_many,
     )

=== modified file 'oops/createhooks.py'
--- oops/createhooks.py	2011-11-13 21:24:42 +0000
+++ oops/createhooks.py	2018-02-08 08:31:24 +0000
@@ -19,6 +19,8 @@
 want.
 """
 
+from __future__ import absolute_import, print_function
+
 __all__ = [
     'attach_exc_info',
     'attach_date',
@@ -37,13 +39,11 @@
 import traceback
 
 from pytz import utc
+import six
 
 # Used to detect missing keys.
 _sentinel = object()
 
-# (Prep for python3 - should be set conditional on version
-strtypes = (basestring,)
-
 
 def _simple_copy(key):
     """Curry a simple hook that copies a key from context to report."""
@@ -67,19 +67,19 @@
     serialize it, but a representation is needed for the report. It is
     exposed a convenience for other on_create hook authors.
     """
-    if isinstance(obj, unicode):
+    if isinstance(obj, six.text_type):
         return obj
     # A call to str(obj) could raise anything at all.
     # We'll ignore these errors, and print something
     # useful instead, but also log the error.
     # We disable the pylint warning for the blank except.
     try:
-        value = unicode(obj)
+        value = six.text_type(obj)
     except:
         value = u'<unprintable %s object>' % (
-            unicode(type(obj).__name__))
+            six.text_type(type(obj).__name__))
     # Some objects give back bytestrings to __unicode__...
-    if isinstance(value, str):
+    if isinstance(value, six.binary_type):
         value = value.decode('latin-1')
     return value
 
@@ -107,7 +107,7 @@
         return
     report['type'] = getattr(info[0], '__name__', info[0])
     report['value'] = safe_unicode(info[1])
-    if isinstance(info[2], strtypes):
+    if isinstance(info[2], six.string_types):
         tb_text = info[2]
     else:
         tb_text = u''.join(map(safe_unicode, traceback.format_tb(info[2])))

=== modified file 'oops/publishers.py'
--- oops/publishers.py	2012-08-10 02:18:06 +0000
+++ oops/publishers.py	2018-02-08 08:31:24 +0000
@@ -15,6 +15,8 @@
 
 """Generic publisher support and utility code."""
 
+from __future__ import absolute_import, print_function
+
 __metaclass__ = type
 
 __all__ = [
@@ -28,7 +30,7 @@
 
 
 def pprint_to_stream(stream):
-    """Pretty print reports to stream.
+    """Pretty print reports to text stream.
     
     Reports will be given an id by hashing the report if none is present.
     """
@@ -36,7 +38,7 @@
         report = dict(report)
         output = pformat(report)
         if not report.get('id'):
-            report['id'] = md5(output).hexdigest()
+            report['id'] = md5(output.encode('UTF-8')).hexdigest()
             output = pformat(report)
         stream.write(output)
         stream.write('\n')

=== modified file 'oops/tests/__init__.py'
--- oops/tests/__init__.py	2011-11-13 21:24:42 +0000
+++ oops/tests/__init__.py	2018-02-08 08:31:24 +0000
@@ -15,6 +15,8 @@
 
 """Tests for oops."""
 
+from __future__ import absolute_import, print_function
+
 from unittest import TestLoader
 
 

=== modified file 'oops/tests/test_config.py'
--- oops/tests/test_config.py	2012-06-26 20:52:24 +0000
+++ oops/tests/test_config.py	2018-02-08 08:31:24 +0000
@@ -15,6 +15,8 @@
 
 """Tests for the oops config module."""
 
+from __future__ import absolute_import, print_function
+
 __metaclass__ = type
 
 from functools import partial

=== modified file 'oops/tests/test_createhooks.py'
--- oops/tests/test_createhooks.py	2011-11-13 21:24:42 +0000
+++ oops/tests/test_createhooks.py	2018-02-08 08:31:24 +0000
@@ -15,15 +15,16 @@
 
 """Tests for the oops config module."""
 
+from __future__ import absolute_import, print_function
+
 __metaclass__ = type
 
 import datetime
-from functools import partial
 import socket
 import sys
 
+import six
 import testtools
-from testtools.matchers import Is
 
 from oops.createhooks import (
     attach_exc_info,
@@ -51,7 +52,7 @@
             attach_exc_info(report, {'exc_info':sys.exc_info()})
         self.assertEqual('ValueError', report['type'])
         self.assertEqual('foo bar', report['value'])
-        self.assertIsInstance(report['tb_text'], basestring)
+        self.assertIsInstance(report['tb_text'], six.text_type)
 
     def test_attach_date(self):
         report = {}
@@ -78,7 +79,7 @@
             attach_exc_info(report, {'exc_info':sys.exc_info()})
         self.assertEqual(
                 '<unprintable UnprintableException object>', report['value'])
-        self.assertIsInstance(report['tb_text'], basestring)
+        self.assertIsInstance(report['tb_text'], six.text_type)
 
     def test_defaults(self):
         self.assertEqual([attach_exc_info, attach_date, copy_reporter, copy_topic,

=== modified file 'oops/tests/test_publishers.py'
--- oops/tests/test_publishers.py	2012-08-10 02:18:06 +0000
+++ oops/tests/test_publishers.py	2018-02-08 08:31:24 +0000
@@ -15,11 +15,19 @@
 
 """Tests for the publishers module."""
 
+from __future__ import absolute_import, print_function
+
 __metaclass__ = type
 
 from hashlib import md5
 from pprint import pformat
-from StringIO import StringIO
+
+# We need a StringIO-like object that accepts native strings, since that's
+# what pprint.pformat produces.
+if bytes == str:
+    from io import BytesIO as native_StringIO
+else:
+    from io import StringIO as native_StringIO
 
 import testtools
 
@@ -178,20 +186,21 @@
 class TestPPrintToStream(testtools.TestCase):
 
     def test_inherits_id_when_set(self):
-        output = StringIO()
+        output = native_StringIO()
         publisher = pprint_to_stream(output)
         published = publisher({'foo': 'bar', 'id': 'quux'})
         self.assertEqual(['quux'], published)
 
     def test_returns_pprint_hash(self):
-        output = StringIO()
+        output = native_StringIO()
         publisher = pprint_to_stream(output)
         published = publisher({'foo': 'bar'})
         pprint_value = pformat({'foo': 'bar'})
-        self.assertEqual([md5(pprint_value).hexdigest()], published)
+        self.assertEqual(
+            [md5(pprint_value.encode('UTF-8')).hexdigest()], published)
 
     def test_outputs_pprint(self):
-        output = StringIO()
+        output = native_StringIO()
         publisher = pprint_to_stream(output)
         publisher({'foo': 'bar'})
         self.assertEqual(

=== modified file 'setup.py'
--- setup.py	2012-08-10 02:18:56 +0000
+++ setup.py	2018-02-08 08:31:24 +0000
@@ -18,8 +18,8 @@
 from distutils.core import setup
 import os.path
 
-description = file(
-        os.path.join(os.path.dirname(__file__), 'README'), 'rb').read()
+with open(os.path.join(os.path.dirname(__file__), 'README')) as f:
+    description = f.read()
 
 setup(name="oops",
       version="0.0.14",
@@ -37,9 +37,12 @@
           'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
           'Operating System :: OS Independent',
           'Programming Language :: Python',
+          'Programming Language :: Python :: 2',
+          'Programming Language :: Python :: 3',
           ],
       install_requires = [
           'pytz',
+          'six',
           ],
       extras_require = dict(
           test=[

=== modified file 'versions.cfg'
--- versions.cfg	2011-08-10 06:08:53 +0000
+++ versions.cfg	2018-02-08 08:31:24 +0000
@@ -6,6 +6,7 @@
 iso8601 = 0.1.4
 pytz = 2010o
 setuptools = 0.6c11
+six = 1.11.0
 testtools = 0.9.11
 zc.recipe.egg = 1.3.2
 z3c.recipe.filetemplate = 2.1.0


Follow ups