You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by he...@apache.org on 2015/05/29 22:40:59 UTC

[37/45] allura git commit: [#7878] Used 2to3 to see what issues would come up

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/github/tests/test_wiki.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/github/tests/test_wiki.py b/ForgeImporters/forgeimporters/github/tests/test_wiki.py
index 6523de6..ef071e3 100644
--- a/ForgeImporters/forgeimporters/github/tests/test_wiki.py
+++ b/ForgeImporters/forgeimporters/github/tests/test_wiki.py
@@ -17,6 +17,10 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 from unittest import TestCase
 from nose.tools import assert_equal
 from mock import Mock, patch, call
@@ -137,8 +141,8 @@ class TestGitHubWikiImporter(TestCase):
         assert_equal(upsert.call_args_list, [call('Home2'), call('Home3')])
 
         assert_equal(render.call_args_list, [
-            call('Home2.creole', u'**test message**'),
-            call('Home3.rest', u'test message')])
+            call('Home2.creole', '**test message**'),
+            call('Home3.rest', 'test message')])
 
     @patch('forgeimporters.github.wiki.git.Repo')
     @patch('forgeimporters.github.wiki.mkdtemp')
@@ -182,7 +186,7 @@ class TestGitHubWikiImporter(TestCase):
         importer._with_history(self.commit2)
         assert_equal(upsert.call_args_list, [call('Home')])
         assert_equal(render.call_args_list,
-                     [call('Home.rst', u'# test message')])
+                     [call('Home.rst', '# test message')])
 
     @skipif(module_not_available('html2text'))
     @patch('forgeimporters.github.wiki.WM.Page.upsert')
@@ -190,7 +194,7 @@ class TestGitHubWikiImporter(TestCase):
     def test_with_history_mediawiki(self, md2mkm, upsert):
         self.commit2.stats.files = {"Home.mediawiki": self.blob1}
         self.commit2.tree = {"Home.mediawiki": self.blob1}
-        md2mkm.return_value = u'# test message'
+        md2mkm.return_value = '# test message'
         importer = GitHubWikiImporter()
         importer._set_available_pages = Mock()
         importer.github_wiki_url = 'https://github.com/a/b/wiki'
@@ -198,28 +202,28 @@ class TestGitHubWikiImporter(TestCase):
         importer.app.config.options = {}
         importer.app.url = '/p/test/wiki/'
         importer.rewrite_links = Mock(return_value='')
-        importer.convert_gollum_tags = Mock(return_value=u'# test message')
+        importer.convert_gollum_tags = Mock(return_value='# test message')
         importer._with_history(self.commit2)
         assert_equal(upsert.call_args_list, [call('Home')])
-        assert_equal(md2mkm.call_args_list, [call(u'# test message')])
+        assert_equal(md2mkm.call_args_list, [call('# test message')])
 
     def test_set_available_pages(self):
         importer = GitHubWikiImporter()
         commit = Mock()
         blobs = [Mock() for i in range(3)]
-        blobs[0].name = u'Home-42.md'
-        blobs[1].name = u'image.png'
-        blobs[2].name = u'code & fun.textile'
+        blobs[0].name = 'Home-42.md'
+        blobs[1].name = 'image.png'
+        blobs[2].name = 'code & fun.textile'
         commit.tree.traverse.return_value = blobs
         importer._set_available_pages(commit)
-        assert_equal(importer.available_pages, [u'Home 42', u'code & fun'])
+        assert_equal(importer.available_pages, ['Home 42', 'code & fun'])
 
     def test_gollum_page_links_case_insensitive(self):
         i = GitHubWikiImporter()
-        i.available_pages = [u'Home 42', u'code & fun']
-        assert_equal(i.convert_gollum_tags(u'[[Code & Fun]]'), u'[code & fun]')
-        assert_equal(i.convert_gollum_tags(u'[[home-42]]'), u'[Home 42]')
-        assert_equal(i.convert_gollum_tags(u'[[Unknown]]'), u'[Unknown]')
+        i.available_pages = ['Home 42', 'code & fun']
+        assert_equal(i.convert_gollum_tags('[[Code & Fun]]'), '[code & fun]')
+        assert_equal(i.convert_gollum_tags('[[home-42]]'), '[Home 42]')
+        assert_equal(i.convert_gollum_tags('[[Unknown]]'), '[Unknown]')
 
     def test_convert_page_name(self):
         f = GitHubWikiImporter()._convert_page_name
@@ -229,57 +233,57 @@ class TestGitHubWikiImporter(TestCase):
 
     def test_convert_gollum_page_links(self):
         f = GitHubWikiImporter().convert_gollum_tags
-        assert_equal(f(u'[[Page]]'), u'[Page]')
-        assert_equal(f(u'[[Page Title|Page]]'), u'[Page Title](Page)')
-        assert_equal(f(u'[[Pagê Nâme]]'), u'[Pagê Nâme]')
+        assert_equal(f('[[Page]]'), '[Page]')
+        assert_equal(f('[[Page Title|Page]]'), '[Page Title](Page)')
+        assert_equal(f('[[Pagê Nâme]]'), '[Pagê Nâme]')
         # Github always converts spaces and slashes in links to hyphens,
         # to lookup page in the filesystem. During import we're converting
         # all hyphens in page name to spaces, but still supporting both link
         # formats.
-        assert_equal(f(u'[[Page With Spaces]]'), u'[Page With Spaces]')
-        assert_equal(f(u'[[Page-With-Spaces]]'), u'[Page With Spaces]')
-        assert_equal(f(u'[[Page / 1]]'), u'[Page   1]')
-        assert_equal(f(u'[[Title|Page With Spaces]]'),
-                     u'[Title](Page With Spaces)')
-        assert_equal(f(u'[[Title|Page-With-Spaces]]'),
-                     u'[Title](Page With Spaces)')
-        assert_equal(f(u'[[go here|Page / 1]]'), u'[go here](Page   1)')
+        assert_equal(f('[[Page With Spaces]]'), '[Page With Spaces]')
+        assert_equal(f('[[Page-With-Spaces]]'), '[Page With Spaces]')
+        assert_equal(f('[[Page / 1]]'), '[Page   1]')
+        assert_equal(f('[[Title|Page With Spaces]]'),
+                     '[Title](Page With Spaces)')
+        assert_equal(f('[[Title|Page-With-Spaces]]'),
+                     '[Title](Page With Spaces)')
+        assert_equal(f('[[go here|Page / 1]]'), '[go here](Page   1)')
 
     def test_convert_gollum_page_links_escaped(self):
         f = GitHubWikiImporter().convert_gollum_tags
-        assert_equal(f(u"'[[Page]]"), u'[[Page]]')
-        assert_equal(f(u"'[[Page Title|Page]]"), u'[[Page Title|Page]]')
-        assert_equal(f(u"'[[Page With Spaces]]"), u'[[Page With Spaces]]')
-        assert_equal(f(u"'[[Page-With-Spaces]]"), u'[[Page-With-Spaces]]')
-        assert_equal(f(u"'[[Page / 1]]"), u'[[Page / 1]]')
-        assert_equal(f(u"'[[Title|Page With Spaces]]"),
-                     u'[[Title|Page With Spaces]]')
-        assert_equal(f(u"'[[Title|Page-With-Spaces]]"),
-                     u'[[Title|Page-With-Spaces]]')
-        assert_equal(f(u"'[[go here|Page / 1]]"), u'[[go here|Page / 1]]')
+        assert_equal(f("'[[Page]]"), '[[Page]]')
+        assert_equal(f("'[[Page Title|Page]]"), '[[Page Title|Page]]')
+        assert_equal(f("'[[Page With Spaces]]"), '[[Page With Spaces]]')
+        assert_equal(f("'[[Page-With-Spaces]]"), '[[Page-With-Spaces]]')
+        assert_equal(f("'[[Page / 1]]"), '[[Page / 1]]')
+        assert_equal(f("'[[Title|Page With Spaces]]"),
+                     '[[Title|Page With Spaces]]')
+        assert_equal(f("'[[Title|Page-With-Spaces]]"),
+                     '[[Title|Page-With-Spaces]]')
+        assert_equal(f("'[[go here|Page / 1]]"), '[[go here|Page / 1]]')
 
     def test_convert_gollum_external_links(self):
         f = GitHubWikiImporter().convert_gollum_tags
-        assert_equal(f(u'[[http://domain.net]]'), u'<http://domain.net>')
-        assert_equal(f(u'[[https://domain.net]]'), u'<https://domain.net>')
-        assert_equal(f(u'[[Site|http://domain.net]]'),
-                     u'[Site](http://domain.net)')
+        assert_equal(f('[[http://domain.net]]'), '<http://domain.net>')
+        assert_equal(f('[[https://domain.net]]'), '<https://domain.net>')
+        assert_equal(f('[[Site|http://domain.net]]'),
+                     '[Site](http://domain.net)')
 
     def test_convert_gollum_external_links_escaped(self):
         f = GitHubWikiImporter().convert_gollum_tags
-        assert_equal(f(u"'[[http://domain.net]]"), u'[[http://domain.net]]')
-        assert_equal(f(u"'[[https://domain.net]]"), u'[[https://domain.net]]')
-        assert_equal(f(u"'[[Site|http://domain.net]]"),
-                     u'[[Site|http://domain.net]]')
+        assert_equal(f("'[[http://domain.net]]"), '[[http://domain.net]]')
+        assert_equal(f("'[[https://domain.net]]"), '[[https://domain.net]]')
+        assert_equal(f("'[[Site|http://domain.net]]"),
+                     '[[Site|http://domain.net]]')
 
     def test_convert_gollum_toc(self):
         f = GitHubWikiImporter().convert_gollum_tags
-        assert_equal(f(u'[[_TOC_]]'), u'[TOC]')
-        assert_equal(f(u"'[[_TOC_]]"), u'[[_TOC_]]')
+        assert_equal(f('[[_TOC_]]'), '[TOC]')
+        assert_equal(f("'[[_TOC_]]"), '[[_TOC_]]')
 
     def test_convert_gollum_tags(self):
         f = GitHubWikiImporter().convert_gollum_tags
-        source = u'''Look at [[this page|Some Page]]
+        source = '''Look at [[this page|Some Page]]
 
 More info at: [[MoreInfo]] [[Even More Info]]
 
@@ -287,7 +291,7 @@ Our website is [[http://domain.net]].
 
 '[[Escaped Tag]]'''
 
-        result = u'''Look at [this page](Some Page)
+        result = '''Look at [this page](Some Page)
 
 More info at: [MoreInfo] [Even More Info]
 
@@ -306,7 +310,7 @@ Our website is <http://domain.net>.
         importer.github_markdown_converter = GitHubMarkdownConverter(
             'user', 'proj')
         f = importer.convert_markup
-        source = u'''Look at [[this page|Some Page]]
+        source = '''Look at [[this page|Some Page]]
 
 More info at: [[MoreInfo]] [[Even More Info]]
 
@@ -323,7 +327,7 @@ ticket #1
 #1 header
 
 sha aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'''
-        result = u'''Look at [this page](Some Page)
+        result = '''Look at [this page](Some Page)
 
 More info at: [MoreInfo] [Even More Info]
 
@@ -341,7 +345,7 @@ ticket [#1]
 sha [aaaaaa]'''
         assert_equal(f(source, 'test.md').strip(), result)
 
-        assert_equal(f(u'h1. Hello', 't.textile').strip(), u'# Hello')
+        assert_equal(f('h1. Hello', 't.textile').strip(), '# Hello')
 
     @without_module('html2text')
     def test_convert_markup_without_html2text(self):
@@ -350,7 +354,7 @@ sha [aaaaaa]'''
         importer.app = Mock()
         importer.app.url = '/p/test/wiki/'
         f = importer.convert_markup
-        source = u'''Look at [[this page|Some Page]]
+        source = '''Look at [[this page|Some Page]]
 
 More info at: [[MoreInfo]] [[Even More Info]]
 
@@ -362,7 +366,7 @@ Our website is [[http://domain.net]].
 
 [External link](https://github.com/a/b/issues/1)'''
 
-        result = u'''<p>Look at [[this page|Some Page]]</p>
+        result = '''<p>Look at [[this page|Some Page]]</p>
 <p>More info at: [[MoreInfo]] [[Even More Info]]</p>
 <p>Our website is [[http://domain.net]].</p>
 <p>'[[Escaped Tag]]</p>
@@ -376,25 +380,25 @@ Our website is [[http://domain.net]].
         prefix = 'https://github/a/b/wiki'
         new = '/p/test/wiki/'
         assert_equal(
-            f(u'<a href="https://github/a/b/wiki/Test Page">Test Page</a>',
+            f('<a href="https://github/a/b/wiki/Test Page">Test Page</a>',
               prefix, new),
-            u'<a href="/p/test/wiki/Test Page">Test Page</a>')
+            '<a href="/p/test/wiki/Test Page">Test Page</a>')
         assert_equal(
-            f(u'<a href="https://github/a/b/wiki/Test-Page">Test-Page</a>',
+            f('<a href="https://github/a/b/wiki/Test-Page">Test-Page</a>',
               prefix, new),
-            u'<a href="/p/test/wiki/Test Page">Test Page</a>')
+            '<a href="/p/test/wiki/Test Page">Test Page</a>')
         assert_equal(
-            f(u'<a href="https://github/a/b/issues/1" class="1"></a>',
+            f('<a href="https://github/a/b/issues/1" class="1"></a>',
               prefix, new),
-            u'<a href="https://github/a/b/issues/1" class="1"></a>')
+            '<a href="https://github/a/b/issues/1" class="1"></a>')
         assert_equal(
-            f(u'<a href="https://github/a/b/wiki/Test Page">https://github/a/b/wiki/Test Page</a>',
+            f('<a href="https://github/a/b/wiki/Test Page">https://github/a/b/wiki/Test Page</a>',
               prefix, new),
-            u'<a href="/p/test/wiki/Test Page">/p/test/wiki/Test Page</a>')
+            '<a href="/p/test/wiki/Test Page">/p/test/wiki/Test Page</a>')
         assert_equal(
-            f(u'<a href="https://github/a/b/wiki/Test Page">Test <b>Page</b></a>',
+            f('<a href="https://github/a/b/wiki/Test Page">Test <b>Page</b></a>',
               prefix, new),
-            u'<a href="/p/test/wiki/Test Page">Test <b>Page</b></a>')
+            '<a href="/p/test/wiki/Test Page">Test <b>Page</b></a>')
 
     @skipif(module_not_available('html2text'))
     def test_convert_markup_with_mediawiki2markdown(self):
@@ -403,7 +407,7 @@ Our website is [[http://domain.net]].
         importer.app = Mock()
         importer.app.url = '/p/test/wiki/'
         f = importer.convert_markup
-        source = u'''
+        source = '''
 ''Al'fredas 235 BC''
 == See also ==
 * [https://github.com/a/b/wiki/AgentSpring-running-instructions-for-d13n-model Test1]
@@ -411,7 +415,7 @@ Our website is [[http://domain.net]].
 * [https://github.com/a/b/wiki/AgentSpring-Q&A Test3]
 * [https://github.com/a/b/wiki/Extensions Test4]'''
 
-        result = u'''_Al'fredas 235 BC_
+        result = '''_Al'fredas 235 BC_
 
 ## See also
 
@@ -430,7 +434,7 @@ Our website is [[http://domain.net]].
         importer.app = Mock()
         importer.app.url = '/p/test/wiki/'
         f = importer.convert_markup
-        source = u'''h1. Header 1
+        source = '''h1. Header 1
 
 Some text 1.
 
@@ -438,7 +442,7 @@ h2. Header 2
 
 See [[Page]]'''
 
-        result = u'''# Header 1
+        result = '''# Header 1
 
 Some text 1.
 
@@ -454,8 +458,8 @@ See [Page]'''
         importer.app = Mock()
         importer.app.url = '/p/test/wiki/'
         f = importer.convert_markup
-        source = u'[[Ticks & Leeches]]'
-        result = u'[Ticks & Leeches]'
+        source = '[[Ticks & Leeches]]'
+        result = '[Ticks & Leeches]'
         # markdown should be untouched
         assert_equal(f(source, 'test.rst').strip(), result)
 
@@ -468,13 +472,13 @@ See [Page]'''
         f = importer.convert_markup
 
         # check if lists converting works properly
-        source = u'''There are good reasons for this:
+        source = '''There are good reasons for this:
 
   # Duplicate libraries regularly break builds
   # Subtle bugs emerge with duplicate libraries, and to a lesser extent, duplicate tools
   # We want you to try harder to make your formula work with what OS X comes with
 '''
-        result = u'''There are good reasons for this:
+        result = '''There are good reasons for this:
 
   1. Duplicate libraries regularly break builds
   2. Subtle bugs emerge with duplicate libraries, and to a lesser extent, duplicate tools
@@ -489,13 +493,13 @@ See [Page]'''
         assert_equal(f(source, 'test2.textile'), result)
 
         # links with formatting converts normal in textile now
-        source = u'''*[[this checklist|Troubleshooting]]*
+        source = '''*[[this checklist|Troubleshooting]]*
 
 some text and *[[Tips n' Tricks]]*
 
 *[[link|http://otherlink.com]]*
 '''
-        result = u'''**[this checklist](Troubleshooting)**
+        result = '''**[this checklist](Troubleshooting)**
 
 some text and **[Tips n' Tricks]**
 
@@ -510,9 +514,9 @@ some text and **[Tips n' Tricks]**
         importer.app = Mock()
         importer.app.url = '/p/test/wiki/'
         f = importer.convert_markup
-        source = u'*[[this checklist|Troubleshooting]]*'
+        source = '*[[this checklist|Troubleshooting]]*'
         assert_equal(f(source, 't.textile').strip(),
-                     u'**[this checklist](Troubleshooting)**')
+                     '**[this checklist](Troubleshooting)**')
 
     @without_module('html2text')
     def test_convert_textile_special_tag_without_html2text(self):
@@ -521,8 +525,8 @@ some text and **[Tips n' Tricks]**
         importer.app = Mock()
         importer.app.url = '/p/test/wiki/'
         f = importer.convert_markup
-        source = u'*[[this checklist|Troubleshooting]]*'
-        result = u'<p><strong>[[this checklist|Troubleshooting]]</strong></p>'
+        source = '*[[this checklist|Troubleshooting]]*'
+        result = '<p><strong>[[this checklist|Troubleshooting]]</strong></p>'
         assert_equal(f(source, 't.textile').strip(), result)
 
     @patch('forgeimporters.github.wiki.mkdtemp', autospec=True)
@@ -571,11 +575,11 @@ class TestGitHubWikiImportController(TestController, TestCase):
         self.assertEqual(r.location, 'http://localhost/p/%s/admin/' %
                          test_project_with_wiki)
         args = import_tool.post.call_args[1]
-        self.assertEqual(u'GitHub Wiki', args['mount_label'])
-        self.assertEqual(u'gh-wiki', args['mount_point'])
-        self.assertEqual(u'mulder', args['project_name'])
-        self.assertEqual(u'spooky', args['user_name'])
-        self.assertEqual(u'import_history', args['tool_option'])
+        self.assertEqual('GitHub Wiki', args['mount_label'])
+        self.assertEqual('gh-wiki', args['mount_point'])
+        self.assertEqual('mulder', args['project_name'])
+        self.assertEqual('spooky', args['user_name'])
+        self.assertEqual('import_history', args['tool_option'])
         self.assertEqual(requests.head.call_count, 1)
 
         # without history
@@ -585,11 +589,11 @@ class TestGitHubWikiImportController(TestController, TestCase):
         self.assertEqual(r.location, 'http://localhost/p/%s/admin/' %
                          test_project_with_wiki)
         args = import_tool.post.call_args[1]
-        self.assertEqual(u'GitHub Wiki', args['mount_label'])
-        self.assertEqual(u'gh-wiki', args['mount_point'])
-        self.assertEqual(u'mulder', args['project_name'])
-        self.assertEqual(u'spooky', args['user_name'])
-        self.assertEqual(u'', args['tool_option'])
+        self.assertEqual('GitHub Wiki', args['mount_label'])
+        self.assertEqual('gh-wiki', args['mount_point'])
+        self.assertEqual('mulder', args['project_name'])
+        self.assertEqual('spooky', args['user_name'])
+        self.assertEqual('', args['tool_option'])
         self.assertEqual(requests.head.call_count, 1)
 
     @with_wiki

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/github/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/github/tracker.py b/ForgeImporters/forgeimporters/github/tracker.py
index cbc017d..269c2f3 100644
--- a/ForgeImporters/forgeimporters/github/tracker.py
+++ b/ForgeImporters/forgeimporters/github/tracker.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -18,12 +22,12 @@
 import re
 import logging
 from datetime import datetime
-from urllib2 import HTTPError
+from urllib.error import HTTPError
 
 try:
-    from cStringIO import StringIO
+    from io import StringIO
 except ImportError:
-    from StringIO import StringIO
+    from io import StringIO
 
 from formencode import validators as fev
 from tg import (
@@ -156,7 +160,7 @@ class GitHubTrackerImporter(ToolImporter):
         return datetime.strptime(datetime_string, '%Y-%m-%dT%H:%M:%SZ')
 
     def get_user_link(self, user):
-        return u'[{0}](https://github.com/{0})'.format(user)
+        return '[{0}](https://github.com/{0})'.format(user)
 
     def process_fields(self, extractor, ticket, issue):
         ticket.summary = issue['title']
@@ -172,10 +176,10 @@ class GitHubTrackerImporter(ToolImporter):
         body, attachments = self._get_attachments(extractor, issue['body'])
         ticket.add_multiple_attachments(attachments)
         ticket.description = (
-            u'*Originally created by:* {creator}\n'
-            u'{owner}'
-            u'\n'
-            u'{body}').format(
+            '*Originally created by:* {creator}\n'
+            '{owner}'
+            '\n'
+            '{body}').format(
             creator=self.get_user_link(issue['user']['login']),
             owner=owner_line,
             body=self.github_markdown_converter.convert(body),
@@ -187,7 +191,7 @@ class GitHubTrackerImporter(ToolImporter):
             body, attachments = self._get_attachments(
                 extractor, comment['body'])
             if comment['user']:
-                posted_by = u'*Originally posted by:* {}\n\n'.format(
+                posted_by = '*Originally posted by:* {}\n\n'.format(
                     self.get_user_link(comment['user']['login']))
                 body = posted_by + body
             p = ticket.discussion_thread.add_post(
@@ -241,7 +245,7 @@ class GitHubTrackerImporter(ToolImporter):
         for milestone in self.open_milestones:
             global_milestones['milestones'].append({
                 'name': milestone[0],
-                'due_date': unicode(milestone[1].date()) if milestone[1] else None,
+                'due_date': str(milestone[1].date()) if milestone[1] else None,
                 'complete': False,
             })
         return [global_milestones]

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/github/utils.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/github/utils.py b/ForgeImporters/forgeimporters/github/utils.py
index 3f00310..32ff1b3 100644
--- a/ForgeImporters/forgeimporters/github/utils.py
+++ b/ForgeImporters/forgeimporters/github/utils.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -22,7 +26,7 @@ class GitHubMarkdownConverter(object):
 
     def __init__(self, gh_user, gh_project):
         self.gh_project = '%s/%s' % (gh_user, gh_project)
-        self.gh_base_url = u'https://github.com/'
+        self.gh_base_url = 'https://github.com/'
         self.code_patterns = ['```', '~~~']
 
     def convert(self, text):
@@ -110,10 +114,10 @@ class GitHubMarkdownConverter(object):
         return text
 
     def _gh_commit_url(self, project, sha, title):
-        return u'[%s](%s)' % (title, self.gh_base_url + project + '/commit/' + sha)
+        return '[%s](%s)' % (title, self.gh_base_url + project + '/commit/' + sha)
 
     def _gh_ticket_url(self, project, tid, title):
-        return u'[%s](%s)' % (title, self.gh_base_url + project + '/issues/' + str(tid))
+        return '[%s](%s)' % (title, self.gh_base_url + project + '/issues/' + str(tid))
 
     def _convert_sha(self, m):
         return '%s[%s]%s' % (m.group(1), m.group(2)[:6], m.group(3))

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/github/wiki.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/github/wiki.py b/ForgeImporters/forgeimporters/github/wiki.py
index 5b787d9..cc92535 100644
--- a/ForgeImporters/forgeimporters/github/wiki.py
+++ b/ForgeImporters/forgeimporters/github/wiki.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -68,7 +72,7 @@ log = logging.getLogger(__name__)
 class GitHubWikiImportForm(ToolImportForm):
     gh_project_name = GitHubProjectNameValidator()
     gh_user_name = fev.UnicodeString(not_empty=True)
-    tool_option = fev.UnicodeString(if_missing=u'')
+    tool_option = fev.UnicodeString(if_missing='')
 
 
 class GitHubWikiImportController(ToolImportController, GitHubOAuthMixin):
@@ -192,7 +196,7 @@ class GitHubWikiImporter(ToolImporter):
 
     def _set_available_pages(self, commit):
         pages = [blob.name for blob in commit.tree.traverse()]
-        pages = map(os.path.splitext, pages)
+        pages = list(map(os.path.splitext, pages))
         pages = [self._convert_page_name(name) for name, ext in pages
                  if ext in self.supported_formats]
         self.available_pages = pages
@@ -203,7 +207,7 @@ class GitHubWikiImporter(ToolImporter):
             self._make_page(page.data_stream.read(), page.name, commit)
 
     def _with_history(self, commit):
-        for filename in commit.stats.files.keys():
+        for filename in list(commit.stats.files.keys()):
             self._set_available_pages(commit)
             renamed_to = None
             if '=>' in filename:
@@ -372,7 +376,7 @@ class GitHubWikiImporter(ToolImporter):
         title = options = None
         if len(link) == 1:
             link = link[0]
-        elif any(map(lambda opt: link[1].startswith(opt), available_options)):
+        elif any([link[1].startswith(opt) for opt in available_options]):
             # second element is option -> first is the link
             link, options = link[0], link[1:]
         else:
@@ -390,12 +394,12 @@ class GitHubWikiImporter(ToolImporter):
 
     def _gollum_external_link(self, link, title, options):
         if title:
-            return u'[{}]({})'.format(title, link)
-        return u'<{}>'.format(link)
+            return '[{}]({})'.format(title, link)
+        return '<{}>'.format(link)
 
     def _gollum_page_link(self, link, title, options):
         page = self._convert_page_name(link)
-        page = page.replace(u'&amp;', u'&')  # allow & in page links
+        page = page.replace('&amp;', '&')  # allow & in page links
         # gollum page lookups are case-insensitive, you'll always get link to
         # whatever comes first in the file system, no matter how you refer to a page.
         # E.g. if you have two pages: a.md and A.md both [[a]] and [[A]] will refer a.md.
@@ -409,8 +413,8 @@ class GitHubWikiImporter(ToolImporter):
             page = self.available_pages[idx]
 
         if title:
-            return u'[{}]({})'.format(title, page)
-        return u'[{}]'.format(page)
+            return '[{}]({})'.format(title, page)
+        return '[{}]'.format(page)
 
     def rewrite_links(self, html, prefix, new_prefix):
         if not prefix.endswith('/'):
@@ -427,7 +431,7 @@ class GitHubWikiImporter(ToolImporter):
                     a.setString(new_page)
                 elif a.text == prefix + page:
                     a.setString(new_prefix + new_page)
-        return unicode(soup)
+        return str(soup)
 
     def _prepare_textile_text(self, text):
         # need to convert lists properly

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index 302544e..409fc0b 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -16,9 +20,9 @@
 #       under the License.
 
 import re
-import urllib
-from urllib2 import HTTPError
-from urlparse import urlparse, urljoin, parse_qs
+import urllib.request, urllib.parse, urllib.error
+from urllib.error import HTTPError
+from urllib.parse import urlparse, urljoin, parse_qs
 from collections import defaultdict
 import logging
 import os
@@ -44,7 +48,7 @@ def _as_text(node, chunks=None):
     if chunks is None:
         chunks = []
     for n in node:
-        if isinstance(n, basestring):
+        if isinstance(n, str):
             chunks.append(n)
         elif n.name == 'br':
             chunks.append('\n')
@@ -103,7 +107,7 @@ def _as_markdown(tag, project_name):
         else:
             # convert all others to plain MD
             fragment = h.plain2markdown(
-                unicode(fragment), preserve_multiple_spaces=True, has_html_entities=True)
+                str(fragment), preserve_multiple_spaces=True, has_html_entities=True)
         fragments.append(fragment)
     return ''.join(fragments).strip()
 
@@ -206,7 +210,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
         # override, to handle hosted domains
         hosted_domain_prefix, project_name = split_project_name(self.project_name)
         return self.PAGE_MAP[page_name].format(
-            project_name=urllib.quote(project_name),
+            project_name=urllib.parse.quote(project_name),
             hosted_domain_prefix=hosted_domain_prefix,
             **kw)
 
@@ -224,7 +228,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
         icon_url = urljoin(self.url, page.find(itemprop='image').get('src'))
         if icon_url == self.DEFAULT_ICON:
             return
-        icon_name = urllib.unquote(urlparse(icon_url).path).split('/')[-1]
+        icon_name = urllib.parse.unquote(urlparse(icon_url).path).split('/')[-1]
         icon = File(icon_url, icon_name)
         filetype = icon.type
         # work around Google Code giving us bogus file type
@@ -425,17 +429,17 @@ class Comment(object):
     @property
     def annotated_text(self):
         text = (
-            u'*Originally posted by:* {author}\n'
-            u'\n'
-            u'{body}\n'
-            u'\n'
-            u'{updates}'
+            '*Originally posted by:* {author}\n'
+            '\n'
+            '{body}\n'
+            '\n'
+            '{updates}'
         ).format(
             author=self.author,
             body=self.body,
             updates='\n'.join(
                 '**%s** %s' % (k, v)
-                for k, v in self.updates.items()
+                for k, v in list(self.updates.items())
             ),
         )
         return text

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/google/code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/code.py b/ForgeImporters/forgeimporters/google/code.py
index 6a3f43c..11da875 100644
--- a/ForgeImporters/forgeimporters/google/code.py
+++ b/ForgeImporters/forgeimporters/google/code.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -15,7 +19,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-import urllib2
+import urllib.request, urllib.error, urllib.parse
 
 import formencode as fe
 from formencode import validators as fev
@@ -76,7 +80,7 @@ class GoogleRepoImportForm(fe.schema.Schema):
         try:
             repo_type = GoogleCodeProjectExtractor(
                 gc_project_name).get_repo_type()
-        except urllib2.HTTPError as e:
+        except urllib.error.HTTPError as e:
             if e.code == 404:
                 msg = 'No such project'
             else:

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/google/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/project.py b/ForgeImporters/forgeimporters/google/project.py
index 9ffade1..5003531 100644
--- a/ForgeImporters/forgeimporters/google/project.py
+++ b/ForgeImporters/forgeimporters/google/project.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/google/tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tasks.py b/ForgeImporters/forgeimporters/google/tasks.py
index b0cb76f..f6727d8 100644
--- a/ForgeImporters/forgeimporters/google/tasks.py
+++ b/ForgeImporters/forgeimporters/google/tasks.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/google/tests/test_code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tests/test_code.py b/ForgeImporters/forgeimporters/google/tests/test_code.py
index 1b6cacc..9c9106d 100644
--- a/ForgeImporters/forgeimporters/google/tests/test_code.py
+++ b/ForgeImporters/forgeimporters/google/tests/test_code.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -121,11 +125,11 @@ class TestGoogleRepoImportController(TestController, TestCase):
         self.assertEqual(
             r.location, 'http://localhost/p/{}/admin/'.format(test_project_with_repo))
         self.assertEqual(
-            u'mymount', import_tool.post.call_args[1]['mount_point'])
+            'mymount', import_tool.post.call_args[1]['mount_point'])
         self.assertEqual(
-            u'mylabel', import_tool.post.call_args[1]['mount_label'])
+            'mylabel', import_tool.post.call_args[1]['mount_label'])
         self.assertEqual(
-            u'poop', import_tool.post.call_args[1]['project_name'])
+            'poop', import_tool.post.call_args[1]['project_name'])
 
     @patch('forgeimporters.google.code.GoogleCodeProjectExtractor')
     @patch('forgeimporters.base.import_tool')

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/google/tests/test_init.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tests/test_init.py b/ForgeImporters/forgeimporters/google/tests/test_init.py
index 37bf4c2..d81f58a 100644
--- a/ForgeImporters/forgeimporters/google/tests/test_init.py
+++ b/ForgeImporters/forgeimporters/google/tests/test_init.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index 7873aa6..a13e36f 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -151,7 +155,7 @@ class GoogleCodeTrackerImporter(ToolImporter):
             self.custom_fields[name] = {
                 'type': self.field_types[name.lower()],
                 'label': name,
-                'name': u'_%s' % name.lower(),
+                'name': '_%s' % name.lower(),
                 'options': set(),
             }
         return self.custom_fields[name]
@@ -170,10 +174,10 @@ class GoogleCodeTrackerImporter(ToolImporter):
         else:
             owner_line = ''
         ticket.description = (
-            u'*Originally created by:* {creator}\n'
-            u'{owner}'
-            u'\n'
-            u'{body}').format(
+            '*Originally created by:* {creator}\n'
+            '{owner}'
+            '\n'
+            '{body}').format(
             creator=issue.get_issue_creator(),
             owner=owner_line,
             body=issue.get_issue_description(),
@@ -184,8 +188,8 @@ class GoogleCodeTrackerImporter(ToolImporter):
         labels = set()
         custom_fields = defaultdict(set)
         for label in issue.get_issue_labels():
-            if u'-' in label:
-                name, value = label.split(u'-', 1)
+            if '-' in label:
+                name, value = label.split('-', 1)
                 cf = self.custom_field(name)
                 cf['options'].add(value)
                 custom_fields[cf['name']].add(value)
@@ -194,8 +198,8 @@ class GoogleCodeTrackerImporter(ToolImporter):
             else:
                 labels.add(label)
         ticket.labels = list(labels)
-        ticket.custom_fields = {n: u', '.join(sorted(v))
-                                for n, v in custom_fields.iteritems()}
+        ticket.custom_fields = {n: ', '.join(sorted(v))
+                                for n, v in custom_fields.items()}
 
     def process_comments(self, ticket, issue):
         for comment in issue.iter_comments():
@@ -208,7 +212,7 @@ class GoogleCodeTrackerImporter(ToolImporter):
 
     def postprocess_custom_fields(self):
         custom_fields = []
-        for name, field in self.custom_fields.iteritems():
+        for name, field in self.custom_fields.items():
             if field['name'] == '_milestone':
                 field['milestones'] = [{
                     'name': milestone,

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/forge/test_tracker.py b/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
index e985763..8781e0e 100644
--- a/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -18,7 +22,7 @@
 from datetime import datetime
 from unittest import TestCase
 from cgi import FieldStorage
-from cStringIO import StringIO
+from io import StringIO
 
 import mock
 from ming.odm import ThreadLocalORMSession
@@ -358,9 +362,9 @@ class TestForgeTrackerImportController(TestController, TestCase):
         self.assertEqual(r.location, 'http://localhost/p/test/admin/')
         sui.assert_called_once_with(project, 'tickets.json', '{"key": "val"}')
         self.assertEqual(
-            u'mymount', import_tool.post.call_args[1]['mount_point'])
+            'mymount', import_tool.post.call_args[1]['mount_point'])
         self.assertEqual(
-            u'mylabel', import_tool.post.call_args[1]['mount_label'])
+            'mylabel', import_tool.post.call_args[1]['mount_label'])
 
     @with_tracker
     @mock.patch('forgeimporters.forge.tracker.save_importer_upload')

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/github/functional/test_github.py b/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
index 6577e4d..ac3f8ba 100644
--- a/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
+++ b/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/github/test_extractor.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/github/test_extractor.py b/ForgeImporters/forgeimporters/tests/github/test_extractor.py
index d91c25b..7ee4b71 100644
--- a/ForgeImporters/forgeimporters/tests/github/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/github/test_extractor.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -17,7 +21,7 @@
 
 import json
 from unittest import TestCase
-import urllib2
+import urllib.request, urllib.error, urllib.parse
 
 from mock import patch, Mock
 
@@ -25,7 +29,7 @@ from ... import github
 
 # Can't use cStringIO here, because we cannot set attributes or subclass it,
 # and this is needed in mocked_urlopen below
-from StringIO import StringIO
+from io import StringIO
 
 
 class TestGitHubProjectExtractor(TestCase):
@@ -35,28 +39,28 @@ class TestGitHubProjectExtractor(TestCase):
         'has_wiki': True,
     }
     CLOSED_ISSUES_LIST = [
-        {u'number': 1},
-        {u'number': 2},
+        {'number': 1},
+        {'number': 2},
     ]
     OPENED_ISSUES_LIST = [
-        {u'number': 3},
-        {u'number': 4},
-        {u'number': 5},
+        {'number': 3},
+        {'number': 4},
+        {'number': 5},
     ]
     OPENED_ISSUES_LIST_PAGE2 = [
-        {u'number': 6},
-        {u'number': 7},
-        {u'number': 8},
+        {'number': 6},
+        {'number': 7},
+        {'number': 8},
     ]
-    ISSUE_COMMENTS = [u'hello', u'mocked_comment']
-    ISSUE_COMMENTS_PAGE2 = [u'hello2', u'mocked_comment2']
+    ISSUE_COMMENTS = ['hello', 'mocked_comment']
+    ISSUE_COMMENTS_PAGE2 = ['hello2', 'mocked_comment2']
     ISSUE_EVENTS = [
-        {u'event': u'closed'},
-        {u'event': u'reopened'},
+        {'event': 'closed'},
+        {'event': 'reopened'},
     ]
     ISSUE_EVENTS_PAGE2 = [
-        {u'event': u'assigned'},
-        {u'event': u'not-supported-event'},
+        {'event': 'assigned'},
+        {'event': 'not-supported-event'},
     ]
 
     def mocked_urlopen(self, url):
@@ -110,9 +114,9 @@ class TestGitHubProjectExtractor(TestCase):
 
     def test_iter_issues(self):
         issues = list(self.extractor.iter_issues())
-        all_issues = zip((1, 2), self.CLOSED_ISSUES_LIST)
-        all_issues += zip((3, 4, 5), self.OPENED_ISSUES_LIST)
-        all_issues += zip((6, 7, 8), self.OPENED_ISSUES_LIST_PAGE2)
+        all_issues = list(zip((1, 2), self.CLOSED_ISSUES_LIST))
+        all_issues += list(zip((3, 4, 5), self.OPENED_ISSUES_LIST))
+        all_issues += list(zip((6, 7, 8), self.OPENED_ISSUES_LIST_PAGE2))
         self.assertEqual(issues, all_issues)
 
     def test_iter_comments(self):
@@ -202,7 +206,7 @@ class TestGitHubProjectExtractor(TestCase):
             mock_resp = StringIO('{}')
             mock_resp.info = lambda: {}
             urlopen.side_effect = [mock_resp]
-            raise urllib2.HTTPError(
+            raise urllib.error.HTTPError(
                 'url', 403, 'msg', limit_exceeded_headers, StringIO('{}'))
         urlopen.side_effect = urlopen_side_effect
         e = github.GitHubProjectExtractor('test_project')

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/github/test_tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/github/test_tasks.py b/ForgeImporters/forgeimporters/tests/github/test_tasks.py
index cf58644..3ee3856 100644
--- a/ForgeImporters/forgeimporters/tests/github/test_tasks.py
+++ b/ForgeImporters/forgeimporters/tests/github/test_tasks.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/github/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/github/test_tracker.py b/ForgeImporters/forgeimporters/tests/github/test_tracker.py
index e02ac5a..f170f68 100644
--- a/ForgeImporters/forgeimporters/tests/github/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/github/test_tracker.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -17,7 +21,7 @@
 
 from datetime import datetime
 from unittest import TestCase
-from urllib2 import HTTPError
+from urllib.error import HTTPError
 import mock
 
 from ...github import tracker
@@ -116,9 +120,9 @@ class TestTrackerImporter(TestCase):
                 'label': 'Milestone',
                 'milestones': [
                         {'name': 'first', 'due_date':
-                            u'2015-04-23', 'complete': False},
+                            '2015-04-23', 'complete': False},
                     {'name': 'second', 'due_date':
-                     u'2015-04-25', 'complete': False},
+                     '2015-04-25', 'complete': False},
                 ],
             },
         ])

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
index 938d1c7..c38d6fd 100644
--- a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/google/test_extractor.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_extractor.py b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
index fe74f9c..e30eff0 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -17,7 +21,7 @@
 
 from unittest import TestCase
 import pkg_resources
-from urllib2 import HTTPError
+from urllib.error import HTTPError
 
 import mock
 from datadiff.tools import assert_equal
@@ -260,7 +264,7 @@ class TestGoogleCodeProjectExtractor(TestCase):
         self.assertEqual(gpe.get_issue_stars(), 1)
 
     def test_get_issue_summary(self):
-        html = u"""
+        html = """
         <div id="issueheader">
             <table>
                 <tbody>
@@ -272,10 +276,10 @@ class TestGoogleCodeProjectExtractor(TestCase):
             </table>
         </div>
         """
-        gpe = self._make_extractor(html % u'')
-        self.assertEqual(gpe.get_issue_summary(), u'')
-        gpe = self._make_extractor(html % u'My Summary')
-        self.assertEqual(gpe.get_issue_summary(), u'My Summary')
+        gpe = self._make_extractor(html % '')
+        self.assertEqual(gpe.get_issue_summary(), '')
+        gpe = self._make_extractor(html % 'My Summary')
+        self.assertEqual(gpe.get_issue_summary(), 'My Summary')
 
     def test_get_issue_labels(self):
         test_issue = open(pkg_resources.resource_filename(
@@ -584,17 +588,17 @@ class TestComment(TestCase):
         html = BeautifulSoup(self.html)
         comment = google.Comment(html.find('div', 'issuecomment'), 'pychess')
         self.assertEqual(comment.updates, {
-            u'Summary:': u'Make PyChess keyboard accessible',
-            u'Status:': u'Accepted',
+            'Summary:': 'Make PyChess keyboard accessible',
+            'Status:': 'Accepted',
         })
 
 
 class TestAsMarkdown(TestCase):
 
     def soup(self, tag):
-        return BeautifulSoup(u'<pre>%s</pre>' % tag).first()
+        return BeautifulSoup('<pre>%s</pre>' % tag).first()
 
     def test_unicode(self):
-        tag = self.soup(u'\ua000 foo <a href="http://example.com/">bar</a>')
+        tag = self.soup('\ua000 foo <a href="http://example.com/">bar</a>')
         res = google._as_markdown(tag, 'pn')
-        self.assertEqual(res, u'\ua000 foo [bar](http://example.com/)')
+        self.assertEqual(res, '\ua000 foo [bar](http://example.com/)')

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/google/test_tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tasks.py b/ForgeImporters/forgeimporters/tests/google/test_tasks.py
index 01bab68..1668137 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tasks.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tasks.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
index e8f12bb..82131d3 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -314,11 +318,11 @@ class TestGoogleCodeTrackerImportController(TestController, TestCase):
                           status=302)
         self.assertEqual(r.location, 'http://localhost/p/test/admin/')
         self.assertEqual(
-            u'mymount', import_tool.post.call_args[1]['mount_point'])
+            'mymount', import_tool.post.call_args[1]['mount_point'])
         self.assertEqual(
-            u'mylabel', import_tool.post.call_args[1]['mount_label'])
+            'mylabel', import_tool.post.call_args[1]['mount_label'])
         self.assertEqual(
-            u'test', import_tool.post.call_args[1]['project_name'])
+            'test', import_tool.post.call_args[1]['project_name'])
 
     @with_tracker
     @patch('forgeimporters.base.import_tool')

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/tests/test_base.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
index 22844a0..2b18167 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/trac/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/__init__.py b/ForgeImporters/forgeimporters/trac/__init__.py
index 12e677a..96b7858 100644
--- a/ForgeImporters/forgeimporters/trac/__init__.py
+++ b/ForgeImporters/forgeimporters/trac/__init__.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/trac/project.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/project.py b/ForgeImporters/forgeimporters/trac/project.py
index 0f44259..d62dd61 100644
--- a/ForgeImporters/forgeimporters/trac/project.py
+++ b/ForgeImporters/forgeimporters/trac/project.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
index e3c8f7e..1e7098e 100644
--- a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -140,12 +144,12 @@ class TestTracTicketImportController(TestController, TestCase):
                           status=302)
         self.assertEqual(r.location, 'http://localhost/p/test/admin/')
         self.assertEqual(
-            u'mymount', import_tool.post.call_args[1]['mount_point'])
+            'mymount', import_tool.post.call_args[1]['mount_point'])
         self.assertEqual(
-            u'mylabel', import_tool.post.call_args[1]['mount_label'])
+            'mylabel', import_tool.post.call_args[1]['mount_label'])
         self.assertEqual('{"orig_user": "new_user"}',
                          import_tool.post.call_args[1]['user_map'])
-        self.assertEqual(u'http://example.com/trac/url/',
+        self.assertEqual('http://example.com/trac/url/',
                          import_tool.post.call_args[1]['trac_url'])
 
     @with_tracker
@@ -211,7 +215,7 @@ class TestTracImportSupport(TestCase):
             '#200 unchanged':
             '#200 unchanged',
         }
-        for input, expected in cases.items():
+        for input, expected in list(cases.items()):
             actual = import_support.link_processing(input)
             self.assertEqual(actual, expected)
 

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/forgeimporters/trac/tickets.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/trac/tickets.py b/ForgeImporters/forgeimporters/trac/tickets.py
index 466b4f7..9e05d30 100644
--- a/ForgeImporters/forgeimporters/trac/tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tickets.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -169,8 +173,7 @@ class TracImportSupport(ImportSupport):
         comments = ticket.discussion_thread.post_class().query.find(dict(
             discussion_id=ticket.discussion_thread.discussion_id,
             thread_id=ticket.discussion_thread._id,
-            status={'$in': ['ok', 'pending']},
-            deleted=False)).sort('timestamp')
+            status={'$in': ['ok', 'pending']})).sort('timestamp')
 
         if comment <= comments.count():
             return comments.all()[comment - 1].slug

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeImporters/setup.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/setup.py b/ForgeImporters/setup.py
index 4d5f866..e4ac972 100644
--- a/ForgeImporters/setup.py
+++ b/ForgeImporters/setup.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeLink/forgelink/link_main.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index bfcf9f9..75a78d4 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeLink/forgelink/tests/functional/test_rest.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/tests/functional/test_rest.py b/ForgeLink/forgelink/tests/functional/test_rest.py
index d7bb7da..0635238 100644
--- a/ForgeLink/forgelink/tests/functional/test_rest.py
+++ b/ForgeLink/forgelink/tests/functional/test_rest.py
@@ -17,6 +17,10 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 from nose.tools import assert_equal
 from allura.tests import decorators as td
 from alluratest.controller import TestRestApiBase
@@ -35,20 +39,20 @@ class TestLinkApi(TestRestApiBase):
         h.set_context('test', 'link', neighborhood='Projects')
 
     def test_rest_link(self):
-        r = self.api_get(u'/rest/p/test/link'.encode('utf-8'))
+        r = self.api_get('/rest/p/test/link'.encode('utf-8'))
         assert_equal(r.json['url'], None)
 
-        r = self.api_post(u'/rest/p/test/link'.encode('utf-8'),
+        r = self.api_post('/rest/p/test/link'.encode('utf-8'),
                           url='http://google.com')
         assert_equal(r.json['url'], 'http://google.com')
 
-        self.api_post(u'/rest/p/test/link'.encode('utf-8'),
+        self.api_post('/rest/p/test/link'.encode('utf-8'),
                       url='http://yahoo.com')
-        r = self.api_get(u'/rest/p/test/link'.encode('utf-8'))
+        r = self.api_get('/rest/p/test/link'.encode('utf-8'))
         assert_equal(r.json['url'], 'http://yahoo.com')
 
-        self.api_post(u'/rest/p/test/link'.encode('utf-8'))
-        r = self.api_get(u'/rest/p/test/link'.encode('utf-8'))
+        self.api_post('/rest/p/test/link'.encode('utf-8'))
+        r = self.api_get('/rest/p/test/link'.encode('utf-8'))
         assert_equal(r.json['url'], 'http://yahoo.com')
 
     def test_rest_link_get_permissions(self):
@@ -76,5 +80,5 @@ class TestLinkApi(TestRestApiBase):
                       params={'url': 'http://yahoo.com'},
                       extra_environ={'username': '*anonymous'},
                       status=200)
-        r = self.api_get(u'/rest/p/test/link'.encode('utf-8'))
+        r = self.api_get('/rest/p/test/link'.encode('utf-8'))
         assert_equal(r.json['url'], 'http://yahoo.com')

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeLink/forgelink/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/tests/functional/test_root.py b/ForgeLink/forgelink/tests/functional/test_root.py
index e4fc656..6552028 100644
--- a/ForgeLink/forgelink/tests/functional/test_root.py
+++ b/ForgeLink/forgelink/tests/functional/test_root.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -66,17 +70,17 @@ class TestRootController(TestController):
     def test_set_url_validation(self):
         r = self.app.post('/p/test/admin/link/set_url', {})
         expected = {'status': 'error',
-                    'errors': {'url': u'Please enter a value'}}
+                    'errors': {'url': 'Please enter a value'}}
         assert_equal(r.json, expected)
 
         r = self.app.post('/p/test/admin/link/set_url', {'url': ''})
         expected = {'status': 'error',
-                    'errors': {'url': u'Please enter a value'}}
+                    'errors': {'url': 'Please enter a value'}}
         assert_equal(r.json, expected)
 
         r = self.app.post('/p/test/admin/link/set_url', {'url': 'bad url'})
         expected = {'status': 'error',
-                    'errors': {'url': u'That is not a valid URL'}}
+                    'errors': {'url': 'That is not a valid URL'}}
         assert_equal(r.json, expected)
 
         p = M.Project.query.get(shortname='test')

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeLink/forgelink/tests/test_app.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/tests/test_app.py b/ForgeLink/forgelink/tests/test_app.py
index f4bbe84..98491d2 100644
--- a/ForgeLink/forgelink/tests/test_app.py
+++ b/ForgeLink/forgelink/tests/test_app.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeLink/forgelink/version.py
----------------------------------------------------------------------
diff --git a/ForgeLink/forgelink/version.py b/ForgeLink/forgelink/version.py
index 1b493f8..8f5910c 100644
--- a/ForgeLink/forgelink/version.py
+++ b/ForgeLink/forgelink/version.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeLink/setup.py
----------------------------------------------------------------------
diff --git a/ForgeLink/setup.py b/ForgeLink/setup.py
index fc91792..7c1991f 100644
--- a/ForgeLink/setup.py
+++ b/ForgeLink/setup.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeSVN/forgesvn/controllers.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/controllers.py b/ForgeSVN/forgesvn/controllers.py
index 35af8e7..05b9898 100644
--- a/ForgeSVN/forgesvn/controllers.py
+++ b/ForgeSVN/forgesvn/controllers.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeSVN/forgesvn/model/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/model/__init__.py b/ForgeSVN/forgesvn/model/__init__.py
index b19a8c6..4a2dd0f 100644
--- a/ForgeSVN/forgesvn/model/__init__.py
+++ b/ForgeSVN/forgesvn/model/__init__.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -15,4 +19,4 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from svn import Repository
+from .svn import Repository

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeSVN/forgesvn/model/svn.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/model/svn.py b/ForgeSVN/forgesvn/model/svn.py
index cd410e3..67c0645 100644
--- a/ForgeSVN/forgesvn/model/svn.py
+++ b/ForgeSVN/forgesvn/model/svn.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -25,7 +29,7 @@ import time
 import operator as op
 from subprocess import Popen, PIPE
 from hashlib import sha1
-from cStringIO import StringIO
+from io import StringIO
 from datetime import datetime
 import tempfile
 from shutil import rmtree
@@ -247,7 +251,7 @@ class SVNImplementation(M.RepositoryImplementation):
                               'hooks', hook_name)
             with open(fn, 'wb') as fp:
                 fp.write('#!/bin/sh\n')
-            os.chmod(fn, 0755)
+            os.chmod(fn, 0o755)
 
         def clear_hook(hook_name):
             fn = os.path.join(self._repo.fs_path, self._repo.name,
@@ -338,7 +342,7 @@ class SVNImplementation(M.RepositoryImplementation):
         commit) and ending with the root (first commit).
         """
         head_revno = self.head
-        return map(self._oid, range(head_revno, 0, -1))
+        return list(map(self._oid, list(range(head_revno, 0, -1))))
 
     def new_commits(self, all_commits=False):
         head_revno = self.head
@@ -627,7 +631,7 @@ class SVNImplementation(M.RepositoryImplementation):
                           'hooks', 'post-commit')
         with open(fn, 'wb') as fp:
             fp.write(text)
-        os.chmod(fn, 0755)
+        os.chmod(fn, 0o755)
 
     def _revno(self, oid):
         return int(oid.split(':')[1])

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeSVN/forgesvn/svn_main.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/svn_main.py b/ForgeSVN/forgesvn/svn_main.py
index 5dda325..f0b1eac 100644
--- a/ForgeSVN/forgesvn/svn_main.py
+++ b/ForgeSVN/forgesvn/svn_main.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -205,7 +209,7 @@ class SVNCommitBrowserController(BaseController):
             data['commits'].append(str(commit['id']))
             data['built_tree'][commit['id']] = {
                 'column': 0,
-                'parents': map(str, commit['parents']),
+                'parents': list(map(str, commit['parents'])),
                 'short_id': '[r%s]' % commit['id'],
                 'message': commit['message'],
                 'oid': str(commit['id']),

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeSVN/forgesvn/tests/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/tests/__init__.py b/ForgeSVN/forgesvn/tests/__init__.py
index d152a9e..eaaa26c 100644
--- a/ForgeSVN/forgesvn/tests/__init__.py
+++ b/ForgeSVN/forgesvn/tests/__init__.py
@@ -19,6 +19,10 @@
 
 
 # Make our own SVN tool test decorator
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 from allura.tests.decorators import with_tool
 
 with_svn = with_tool('test', 'SVN', 'src', 'SVN')

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeSVN/forgesvn/tests/functional/test_auth.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/tests/functional/test_auth.py b/ForgeSVN/forgesvn/tests/functional/test_auth.py
index 7394c1b..6ca14d6 100644
--- a/ForgeSVN/forgesvn/tests/functional/test_auth.py
+++ b/ForgeSVN/forgesvn/tests/functional/test_auth.py
@@ -17,6 +17,10 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 import json
 from datadiff.tools import assert_equal
 

http://git-wip-us.apache.org/repos/asf/allura/blob/d52f8e2a/ForgeSVN/forgesvn/tests/functional/test_controllers.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/tests/functional/test_controllers.py b/ForgeSVN/forgesvn/tests/functional/test_controllers.py
index 6aeca55..af5c8dd 100644
--- a/ForgeSVN/forgesvn/tests/functional/test_controllers.py
+++ b/ForgeSVN/forgesvn/tests/functional/test_controllers.py
@@ -1,3 +1,7 @@
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import unicode_literals
 #       Licensed to the Apache Software Foundation (ASF) under one
 #       or more contributor license agreements.  See the NOTICE file
 #       distributed with this work for additional information
@@ -100,7 +104,7 @@ class TestRootController(SVNTestController):
         data = json.loads(resp.body)
         assert_equal(data['max_row'], 5)
         assert_equal(data['next_column'], 1)
-        for val in data['built_tree'].values():
+        for val in list(data['built_tree'].values()):
             if val['url'] == '/p/test/src/1/':
                 assert_equal(val['short_id'], '[r1]')
                 assert_equal(val['column'], 0)