You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by ke...@apache.org on 2020/01/24 18:58:54 UTC

[allura] 01/13: [#7878] run: python-modernize -n -w --no-diffs -f unicode_type .

This is an automated email from the ASF dual-hosted git repository.

kentontaylor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 5fde6376aaf4693498bc96fcb9e14c76e6a34087
Author: Dave Brondsema <db...@slashdotmedia.com>
AuthorDate: Thu Jan 16 18:02:27 2020 +0000

    [#7878] run: python-modernize -n -w --no-diffs -f unicode_type .
---
 Allura/allura/lib/app_globals.py                   |  3 +-
 Allura/allura/lib/helpers.py                       |  9 +++---
 Allura/allura/lib/macro.py                         |  3 +-
 Allura/allura/lib/mail_util.py                     |  6 ++--
 Allura/allura/lib/markdown_extensions.py           |  3 +-
 Allura/allura/lib/plugin.py                        |  3 +-
 Allura/allura/lib/search.py                        |  3 +-
 Allura/allura/lib/solr.py                          |  3 +-
 Allura/allura/lib/spam/stopforumspamfilter.py      |  5 ++--
 Allura/allura/lib/utils.py                         |  5 ++--
 Allura/allura/lib/widgets/project_list.py          | 11 ++++----
 Allura/allura/model/webhook.py                     |  7 +++--
 Allura/allura/scripts/scripttask.py                |  3 +-
 Allura/allura/scripts/trac_export.py               |  3 +-
 Allura/allura/tasks/mail_tasks.py                  |  5 ++--
 Allura/allura/tests/test_helpers.py                |  7 +++--
 Allura/allura/tests/test_mail_util.py              | 15 +++++-----
 Allura/allura/tests/test_webhooks.py               | 33 +++++++++++-----------
 Allura/allura/webhooks.py                          |  7 +++--
 ForgeBlog/forgeblog/main.py                        |  3 +-
 .../forgegit/tests/functional/test_controllers.py  |  3 +-
 ForgeImporters/forgeimporters/github/tracker.py    |  3 +-
 ForgeImporters/forgeimporters/github/wiki.py       |  2 +-
 ForgeTracker/forgetracker/model/ticket.py          |  2 +-
 ForgeWiki/forgewiki/converters.py                  |  3 +-
 scripts/teamforge-import.py                        |  3 +-
 26 files changed, 88 insertions(+), 65 deletions(-)

diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index 6ef4626..8770a5c 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -66,6 +66,7 @@ from allura.lib.widgets import analytics
 from allura.lib.security import Credentials
 from allura.lib.solr import MockSOLR, make_solr_from_config
 from allura.model.session import artifact_orm_session
+import six
 
 __all__ = ['Globals']
 
@@ -583,7 +584,7 @@ class Globals(object):
 
     @LazyProperty
     def noreply(self):
-        return unicode(config.get('noreply', 'noreply@%s' % config['domain']))
+        return six.text_type(config.get('noreply', 'noreply@%s' % config['domain']))
 
     @property
     def build_key(self):
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 69342c5..1ea60ef 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -41,6 +41,7 @@ import cgi
 
 import emoji
 import tg
+import six
 try:
     import cchardet as chardet
 except ImportError:
@@ -182,13 +183,13 @@ def _attempt_encodings(s, encodings):
     for enc in encodings:
         try:
             if enc is None:
-                return unicode(s)  # try default encoding
+                return six.text_type(s)  # try default encoding
             else:
-                return unicode(s, enc)
+                return six.text_type(s, enc)
         except (UnicodeDecodeError, LookupError):
             pass
     # Return the repr of the str -- should always be safe
-    return unicode(repr(str(s)))[1:-1]
+    return six.text_type(repr(str(s)))[1:-1]
 
 
 def really_unicode(s):
@@ -1209,7 +1210,7 @@ def slugify(name, allow_periods=False):
     """
     dash_collapse_pattern = r'[^.\w]+' if allow_periods else r'[^\w]+'
     slug = re.sub(r'(^-)|(-$)', '',  # leading - or trailing - gets removed
-                  unicode(
+                  six.text_type(
                       re.sub(dash_collapse_pattern, '-',  # replace non ". alphanum_" sequences into single -
                              re.sub(r"'", '',  # remove any apostrophes
                                     unicodedata.normalize('NFKD', name)
diff --git a/Allura/allura/lib/macro.py b/Allura/allura/lib/macro.py
index 4dc1f54..ae467cd 100644
--- a/Allura/allura/lib/macro.py
+++ b/Allura/allura/lib/macro.py
@@ -36,6 +36,7 @@ from bs4 import BeautifulSoup
 from allura.lib.utils import socket_default_timeout
 from . import helpers as h
 from . import security
+import six
 
 log = logging.getLogger(__name__)
 
@@ -62,7 +63,7 @@ class parse(object):
             if s.startswith('quote '):
                 return '[[' + s[len('quote '):] + ']]'
             try:
-                parts = [unicode(x, 'utf-8')
+                parts = [six.text_type(x, 'utf-8')
                          for x in shlex.split(s.encode('utf-8'))]
                 if not parts:
                     return '[[' + s + ']]'
diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index f1de6de..c6c6aac 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -52,11 +52,11 @@ def Header(text, *more_text):
     # email.header.Header handles str vs unicode differently
     # see
     # http://docs.python.org/library/email.header.html#email.header.Header.append
-    if type(text) != unicode:
+    if type(text) != six.text_type:
         raise TypeError('This must be unicode: %r' % text)
     head = header.Header(text)
     for m in more_text:
-        if type(m) != unicode:
+        if type(m) != six.text_type:
             raise TypeError('This must be unicode: %r' % text)
         head.append(m)
     return head
@@ -285,7 +285,7 @@ class SMTPClient(object):
         smtp_addrs = [a for a in smtp_addrs if isvalid(a)]
         if not smtp_addrs:
             log.warning('No valid addrs in %s, so not sending mail',
-                        map(unicode, addrs))
+                        map(six.text_type, addrs))
             return
         try:
             self._client.sendmail(
diff --git a/Allura/allura/lib/markdown_extensions.py b/Allura/allura/lib/markdown_extensions.py
index a8c38c4..f27e7a3 100644
--- a/Allura/allura/lib/markdown_extensions.py
+++ b/Allura/allura/lib/markdown_extensions.py
@@ -33,6 +33,7 @@ from . import macro
 from . import helpers as h
 from allura import model as M
 from allura.lib.utils import ForgeHTMLSanitizerFilter, is_nofollow_url
+import six
 
 log = logging.getLogger(__name__)
 
@@ -450,7 +451,7 @@ class RelativeLinkRewriter(markdown.postprocessors.Postprocessor):
             rewrite(link, 'src')
 
         # html5lib parser adds html/head/body tags, so output <body> without its own tags
-        return unicode(soup.body)[len('<body>'):-len('</body>')]
+        return six.text_type(soup.body)[len('<body>'):-len('</body>')]
 
     def _rewrite(self, tag, attr):
         val = tag.get(attr)
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index d3c3318..33c61c7 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -33,6 +33,7 @@ from hashlib import sha256
 from base64 import b64encode
 from datetime import datetime, timedelta
 import calendar
+import six
 
 try:
     import ldap
@@ -1466,7 +1467,7 @@ class ThemeProvider(object):
             Takes an instance of class Application, or else a string.
             Expected to be overriden by derived Themes.
         """
-        if isinstance(app, unicode):
+        if isinstance(app, six.text_type):
             app = str(app)
         if isinstance(app, str):
             if app in self.icons and size in self.icons[app]:
diff --git a/Allura/allura/lib/search.py b/Allura/allura/lib/search.py
index c94c526..fdad56e 100644
--- a/Allura/allura/lib/search.py
+++ b/Allura/allura/lib/search.py
@@ -31,6 +31,7 @@ from pysolr import SolrError
 from allura.lib import helpers as h
 from allura.lib.solr import escape_solr_arg
 from allura.lib.utils import urlencode
+import six
 
 log = getLogger(__name__)
 
@@ -141,7 +142,7 @@ def search(q, short_timeout=False, ignore_errors=True, **kw):
     except (SolrError, socket.error) as e:
         log.exception('Error in solr search')
         if not ignore_errors:
-            match = re.search(r'<pre>(.*)</pre>', unicode(e))
+            match = re.search(r'<pre>(.*)</pre>', six.text_type(e))
             raise SearchError(u'Error running search query: %s' %
                               (match.group(1) if match else e))
 
diff --git a/Allura/allura/lib/solr.py b/Allura/allura/lib/solr.py
index e4adba8..3df3a6f 100644
--- a/Allura/allura/lib/solr.py
+++ b/Allura/allura/lib/solr.py
@@ -21,6 +21,7 @@ import logging
 from tg import config
 from paste.deploy.converters import asbool
 import pysolr
+import six
 
 
 log = logging.getLogger(__name__)
@@ -150,7 +151,7 @@ class MockSOLR(object):
     def search(self, q, fq=None, **kw):
         if q is None:
             q = ''  # shlex will hang on None
-        if isinstance(q, unicode):
+        if isinstance(q, six.text_type):
             q = q.encode('latin-1')
         # Parse query
         preds = []
diff --git a/Allura/allura/lib/spam/stopforumspamfilter.py b/Allura/allura/lib/spam/stopforumspamfilter.py
index 616d99f..9499fec 100644
--- a/Allura/allura/lib/spam/stopforumspamfilter.py
+++ b/Allura/allura/lib/spam/stopforumspamfilter.py
@@ -24,6 +24,7 @@ from tg import request
 
 from allura.lib import utils
 from allura.lib.spam import SpamFilter
+import six
 
 log = logging.getLogger(__name__)
 
@@ -49,7 +50,7 @@ class StopForumSpamSpamFilter(SpamFilter):
                 if int(record[1]) > int(config.get('spam.stopforumspam.threshold', 20)):
                     ip = record[0]
                     # int is the smallest memory representation of an IP addr
-                    ip_int = int(ipaddress.ip_address(unicode(ip)))
+                    ip_int = int(ipaddress.ip_address(six.text_type(ip)))
                     self.packed_ips.add(ip_int)
         # to get actual memory usage, use: from pympler.asizeof import asizeof
         log.info('Read stopforumspam file; %s recs, probably %s bytes stored in memory', len(self.packed_ips),
@@ -58,7 +59,7 @@ class StopForumSpamSpamFilter(SpamFilter):
     def check(self, text, artifact=None, user=None, content_type='comment', **kw):
         ip = utils.ip_address(request)
         if ip:
-            ip_int = int(ipaddress.ip_address(unicode(ip)))
+            ip_int = int(ipaddress.ip_address(six.text_type(ip)))
             res = ip_int in self.packed_ips
             self.record_result(res, artifact, user)
         else:
diff --git a/Allura/allura/lib/utils.py b/Allura/allura/lib/utils.py
index 8529a23..2554af3 100644
--- a/Allura/allura/lib/utils.py
+++ b/Allura/allura/lib/utils.py
@@ -54,6 +54,7 @@ from ew import jinja2_ew as ew
 from ming.utils import LazyProperty
 from ming.odm.odmsession import ODMCursor
 from ming.odm import session
+import six
 
 MARKDOWN_EXTENSIONS = ['.markdown', '.mdown', '.mkdn', '.mkd', '.md']
 
@@ -785,8 +786,8 @@ def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'):
                 # further exception.
                 return ' '.join([smart_str(arg, encoding, strings_only,
                                            errors) for arg in s])
-            return unicode(s).encode(encoding, errors)
-    elif isinstance(s, unicode):
+            return six.text_type(s).encode(encoding, errors)
+    elif isinstance(s, six.text_type):
         r = s.encode(encoding, errors)
         return r
     elif s and encoding != 'utf-8':
diff --git a/Allura/allura/lib/widgets/project_list.py b/Allura/allura/lib/widgets/project_list.py
index 1d511b5..ad9d063 100644
--- a/Allura/allura/lib/widgets/project_list.py
+++ b/Allura/allura/lib/widgets/project_list.py
@@ -23,6 +23,7 @@ from paste.deploy.converters import asbool
 
 from allura import model as M
 from allura.lib.security import Credentials
+import six
 
 
 class ProjectSummary(ew_core.Widget):
@@ -49,21 +50,21 @@ class ProjectSummary(ew_core.Widget):
         if response['accolades'] is None:
             response['accolades'] = value.accolades
 
-        if type(response['columns']) == unicode:
+        if type(response['columns']) == six.text_type:
             response['columns'] = int(response['columns'])
 
         true_list = ['true', 't', '1', 'yes', 'y']
-        if type(response['show_proj_icon']) == unicode:
+        if type(response['show_proj_icon']) == six.text_type:
             if response['show_proj_icon'].lower() in true_list:
                 response['show_proj_icon'] = True
             else:
                 response['show_proj_icon'] = False
-        if type(response['show_download_button']) == unicode:
+        if type(response['show_download_button']) == six.text_type:
             if response['show_download_button'].lower() in true_list:
                 response['show_download_button'] = True
             else:
                 response['show_download_button'] = False
-        if type(response['show_awards_banner']) == unicode:
+        if type(response['show_awards_banner']) == six.text_type:
             if response['show_awards_banner'].lower() in true_list:
                 response['show_awards_banner'] = True
             else:
@@ -101,7 +102,7 @@ class ProjectList(ew_core.Widget):
         if response['accolades_index'] is None and response['show_awards_banner']:
             response['accolades_index'] = M.Project.accolades_index(projects)
 
-        if type(response['columns']) == unicode:
+        if type(response['columns']) == six.text_type:
             response['columns'] = int(response['columns'])
 
         return response
diff --git a/Allura/allura/model/webhook.py b/Allura/allura/model/webhook.py
index bb36e5f..96a9ded 100644
--- a/Allura/allura/model/webhook.py
+++ b/Allura/allura/model/webhook.py
@@ -24,6 +24,7 @@ from tg import config
 
 from allura.model import Artifact
 from allura.lib import helpers as h
+import six
 
 
 class Webhook(Artifact):
@@ -64,9 +65,9 @@ class Webhook(Artifact):
 
     def __json__(self):
         return {
-            '_id': unicode(self._id),
+            '_id': six.text_type(self._id),
             'url': h.absurl(u'/rest' + self.url()),
-            'type': unicode(self.type),
-            'hook_url': unicode(self.hook_url),
+            'type': six.text_type(self.type),
+            'hook_url': six.text_type(self.hook_url),
             'mod_date': self.mod_date,
         }
diff --git a/Allura/allura/scripts/scripttask.py b/Allura/allura/scripts/scripttask.py
index c46d7b6..fb97c2a 100644
--- a/Allura/allura/scripts/scripttask.py
+++ b/Allura/allura/scripts/scripttask.py
@@ -50,6 +50,7 @@ import shlex
 import sys
 
 from allura.lib.decorators import task
+import six
 
 
 log = logging.getLogger(__name__)
@@ -74,7 +75,7 @@ class ScriptTask(object):
     @classmethod
     def _execute_task(cls, arg_string):
         try:
-            if isinstance(arg_string, unicode):
+            if isinstance(arg_string, six.text_type):
                 # shlex doesn't support unicode fully, so encode it http://stackoverflow.com/a/14219159/79697
                 # decode has to happen in the arg parser (e.g. see delete_projects.py)
                 arg_string = arg_string.encode('utf8')
diff --git a/Allura/allura/scripts/trac_export.py b/Allura/allura/scripts/trac_export.py
index 86b90bb..5560fd0 100644
--- a/Allura/allura/scripts/trac_export.py
+++ b/Allura/allura/scripts/trac_export.py
@@ -31,6 +31,7 @@ from itertools import islice
 from bs4 import BeautifulSoup, NavigableString
 import dateutil.parser
 import pytz
+import six
 
 try:
     from forgeimporters.base import ProjectExtractor
@@ -172,7 +173,7 @@ class TracExport(object):
                 r'.* by ', '', comment.find('h3', 'change').text).strip()
             c['date'] = self.trac2z_date(
                 comment.find('a', 'timeline')['title'].replace(' in Timeline', ''))
-            changes = unicode(comment.find('ul', 'changes') or '')
+            changes = six.text_type(comment.find('ul', 'changes') or '')
             body = comment.find('div', 'comment')
             body = body.renderContents('utf8').decode('utf8') if body else ''
             c['comment'] = html2text.html2text(changes + body)
diff --git a/Allura/allura/tasks/mail_tasks.py b/Allura/allura/tasks/mail_tasks.py
index 43a9f1a..bab4d69 100644
--- a/Allura/allura/tasks/mail_tasks.py
+++ b/Allura/allura/tasks/mail_tasks.py
@@ -27,6 +27,7 @@ from allura.lib import helpers as h
 from allura.lib.decorators import task
 from allura.lib import mail_util
 from allura.lib import exceptions as exc
+import six
 
 log = logging.getLogger(__name__)
 
@@ -265,8 +266,8 @@ def send_system_mail_to_user(user_or_emailaddr, subject, text):
             config['site_name'],
             config['forgemail.return_path']
         ),
-        'sender': unicode(config['forgemail.return_path']),
-        'reply_to': unicode(config['forgemail.return_path']),
+        'sender': six.text_type(config['forgemail.return_path']),
+        'reply_to': six.text_type(config['forgemail.return_path']),
         'message_id': h.gen_message_id(),
         'subject': subject,
         'text': text,
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 8fccf90..dd3e264 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -41,6 +41,7 @@ from allura.lib.security import has_access
 from allura.lib.security import Credentials
 from allura.tests import decorators as td
 from alluratest.controller import setup_basic_test
+import six
 
 
 def setUp(self):
@@ -91,12 +92,12 @@ def test_really_unicode():
     assert s.startswith(u'\ufeff')
     s = h.really_unicode(
         open(path.join(here_dir, 'data/unicode_test.txt')).read())
-    assert isinstance(s, unicode)
+    assert isinstance(s, six.text_type)
     # try non-ascii string in legacy 8bit encoding
     h.really_unicode(u'\u0410\u0401'.encode('cp1251'))
     # ensure invalid encodings are handled gracefully
     s = h._attempt_encodings('foo', ['LKDJFLDK'])
-    assert isinstance(s, unicode)
+    assert isinstance(s, six.text_type)
 
 
 def test_find_project():
@@ -181,7 +182,7 @@ def test_context_setters():
 
 def test_encode_keys():
     kw = h.encode_keys({u'foo': 5})
-    assert type(kw.keys()[0]) != unicode
+    assert type(kw.keys()[0]) != six.text_type
 
 
 def test_ago():
diff --git a/Allura/allura/tests/test_mail_util.py b/Allura/allura/tests/test_mail_util.py
index 7b75f16..deb16e0 100644
--- a/Allura/allura/tests/test_mail_util.py
+++ b/Allura/allura/tests/test_mail_util.py
@@ -40,6 +40,7 @@ from allura.lib.mail_util import (
 )
 from allura.lib.exceptions import AddressException
 from allura.tests import decorators as td
+import six
 
 config = ConfigProxy(
     common_suffix='forgemail.domain',
@@ -96,7 +97,7 @@ class TestReactor(unittest.TestCase):
         msg1['Message-ID'] = '<fo...@bar.com>'
         s_msg = msg1.as_string()
         msg2 = parse_message(s_msg)
-        assert isinstance(msg2['payload'], unicode)
+        assert isinstance(msg2['payload'], six.text_type)
         assert_in(u'всех', msg2['payload'])
 
     def test_more_encodings(self):
@@ -115,7 +116,7 @@ c28uMyIsClRoZSBhcHBsaWNhdGlvbidzIGNvbW11bmljYXRpb24gd29yayB3ZWxsICxidXQgdGhl
 IGZ0cCx0ZWxuZXQscGluZyBjYW4ndCB3b3JrICEKCgpXaHk/
 """
         msg = parse_message(s_msg)
-        assert isinstance(msg['payload'], unicode)
+        assert isinstance(msg['payload'], six.text_type)
         assert_in(u'The Snap7 application', msg['payload'])
 
         s_msg = u"""Date: Sat, 25 May 2019 09:32:00 +1000
@@ -134,7 +135,7 @@ Content-Transfer-Encoding: 8bit
 > 
 """
         msg = parse_message(s_msg)
-        assert isinstance(msg['payload'], unicode)
+        assert isinstance(msg['payload'], six.text_type)
         assert_in(u'• foo', msg['payload'])
 
         s_msg = u"""Date: Sat, 25 May 2019 09:32:00 +1000
@@ -147,7 +148,7 @@ Content-Transfer-Encoding: 8BIT
 programmed or èrogrammed ?
 """
         msg = parse_message(s_msg)
-        assert isinstance(msg['payload'], unicode)
+        assert isinstance(msg['payload'], six.text_type)
         assert_in(u'èrogrammed', msg['payload'])
 
     def test_more_encodings_multipart(self):
@@ -177,8 +178,8 @@ Content-Type: text/html; charset="utf-8"
 &gt; • foo.txt (1.0 kB; text/plain)
 """
         msg = parse_message(s_msg)
-        assert isinstance(msg['parts'][1]['payload'], unicode)
-        assert isinstance(msg['parts'][2]['payload'], unicode)
+        assert isinstance(msg['parts'][1]['payload'], six.text_type)
+        assert isinstance(msg['parts'][2]['payload'], six.text_type)
         assert_in(u'• foo', msg['parts'][1]['payload'])
         assert_in(u'• foo', msg['parts'][2]['payload'])
 
@@ -207,7 +208,7 @@ Content-Type: text/html; charset="utf-8"
         for part in msg2['parts']:
             if part['payload'] is None:
                 continue
-            assert isinstance(part['payload'], unicode)
+            assert isinstance(part['payload'], six.text_type)
 
 
 class TestHeader(object):
diff --git a/Allura/allura/tests/test_webhooks.py b/Allura/allura/tests/test_webhooks.py
index 497dad8..60853be 100644
--- a/Allura/allura/tests/test_webhooks.py
+++ b/Allura/allura/tests/test_webhooks.py
@@ -48,6 +48,7 @@ from alluratest.controller import (
     TestController,
     TestRestApiBase,
 )
+import six
 
 
 # important to be distinct from 'test' and 'test2' which ForgeGit and
@@ -123,7 +124,7 @@ class TestValidators(TestWebhookBase):
         wh.app_config_id = app.config._id
         session(wh).flush(wh)
         assert_equal(v.to_python(wh._id), wh)
-        assert_equal(v.to_python(unicode(wh._id)), wh)
+        assert_equal(v.to_python(six.text_type(wh._id)), wh)
 
 
 class TestWebhookController(TestController):
@@ -275,7 +276,7 @@ class TestWebhookController(TestController):
         form = r.forms[0]
         assert_equal(form['url'].value, data1['url'])
         assert_equal(form['secret'].value, data1['secret'])
-        assert_equal(form['webhook'].value, unicode(wh1._id))
+        assert_equal(form['webhook'].value, six.text_type(wh1._id))
         form['url'] = 'http://host.org/hook'
         form['secret'] = 'new secret'
         msg = 'edit webhook repo-push\n{} => {}\n{}'.format(
@@ -318,7 +319,7 @@ class TestWebhookController(TestController):
         # invalid id in hidden field, just in case
         r = self.app.get(self.url + '/repo-push/%s' % wh._id)
         data = {k: v[0].value for (k, v) in r.forms[0].fields.items()}
-        data['webhook'] = unicode(invalid._id)
+        data['webhook'] = six.text_type(invalid._id)
         self.app.post(self.url + '/repo-push/edit', data, status=404)
 
         # empty values
@@ -337,7 +338,7 @@ class TestWebhookController(TestController):
         self.create_webhook(data).follow()
         assert_equal(M.Webhook.query.find().count(), 1)
         wh = M.Webhook.query.get(hook_url=data['url'])
-        data = {'webhook': unicode(wh._id)}
+        data = {'webhook': six.text_type(wh._id)}
         msg = 'delete webhook repo-push {} {}'.format(
             wh.hook_url, self.git.config.url())
         with td.audits(msg):
@@ -357,7 +358,7 @@ class TestWebhookController(TestController):
         data = {'webhook': ''}
         self.app.post(self.url + '/repo-push/delete', data, status=404)
 
-        data = {'webhook': unicode(invalid._id)}
+        data = {'webhook': six.text_type(invalid._id)}
         self.app.post(self.url + '/repo-push/delete', data, status=404)
         assert_equal(M.Webhook.query.find().count(), 1)
 
@@ -658,7 +659,7 @@ class TestModels(TestWebhookBase):
 
     def test_json(self):
         expected = {
-            '_id': unicode(self.wh._id),
+            '_id': six.text_type(self.wh._id),
             'url': u'http://localhost/rest/adobe/adobe-1/admin'
                    u'/src/webhooks/repo-push/{}'.format(self.wh._id),
             'type': u'repo-push',
@@ -711,12 +712,12 @@ class TestWebhookRestController(TestRestApiBase):
     def test_webhooks_list(self):
         r = self.api_get(self.url)
         webhooks = [{
-            '_id': unicode(wh._id),
+            '_id': six.text_type(wh._id),
             'url': 'http://localhost/rest/adobe/adobe-1/admin'
                    '/src/webhooks/repo-push/{}'.format(wh._id),
             'type': 'repo-push',
             'hook_url': 'http://httpbin.org/post/{}'.format(n),
-            'mod_date': unicode(wh.mod_date),
+            'mod_date': six.text_type(wh.mod_date),
         } for n, wh in enumerate(self.webhooks)]
         expected = {
             'webhooks': webhooks,
@@ -731,12 +732,12 @@ class TestWebhookRestController(TestRestApiBase):
         webhook = self.webhooks[0]
         r = self.api_get('{}/repo-push/{}'.format(self.url, webhook._id))
         expected = {
-            '_id': unicode(webhook._id),
+            '_id': six.text_type(webhook._id),
             'url': 'http://localhost/rest/adobe/adobe-1/admin'
                    '/src/webhooks/repo-push/{}'.format(webhook._id),
             'type': 'repo-push',
             'hook_url': 'http://httpbin.org/post/0',
-            'mod_date': unicode(webhook.mod_date),
+            'mod_date': six.text_type(webhook.mod_date),
         }
         dd.assert_equal(r.status_int, 200)
         dd.assert_equal(r.json, expected)
@@ -775,12 +776,12 @@ class TestWebhookRestController(TestRestApiBase):
         webhook = M.Webhook.query.get(hook_url=data['url'])
         assert_equal(webhook.secret, 'super-secret')  # secret generated
         expected = {
-            '_id': unicode(webhook._id),
+            '_id': six.text_type(webhook._id),
             'url': 'http://localhost/rest/adobe/adobe-1/admin'
                    '/src/webhooks/repo-push/{}'.format(webhook._id),
             'type': 'repo-push',
             'hook_url': data['url'],
-            'mod_date': unicode(webhook.mod_date),
+            'mod_date': six.text_type(webhook.mod_date),
         }
         dd.assert_equal(r.json, expected)
         assert_equal(M.Webhook.query.find().count(), len(self.webhooks) + 1)
@@ -835,12 +836,12 @@ class TestWebhookRestController(TestRestApiBase):
         assert_equal(webhook.hook_url, data['url'])
         assert_equal(webhook.secret, 'secret-0')
         expected = {
-            '_id': unicode(webhook._id),
+            '_id': six.text_type(webhook._id),
             'url': 'http://localhost/rest/adobe/adobe-1/admin'
                    '/src/webhooks/repo-push/{}'.format(webhook._id),
             'type': 'repo-push',
             'hook_url': data['url'],
-            'mod_date': unicode(webhook.mod_date),
+            'mod_date': six.text_type(webhook.mod_date),
         }
         dd.assert_equal(r.json, expected)
 
@@ -855,12 +856,12 @@ class TestWebhookRestController(TestRestApiBase):
         assert_equal(webhook.hook_url, 'http://hook.slack.com/abcd')
         assert_equal(webhook.secret, 'new-secret')
         expected = {
-            '_id': unicode(webhook._id),
+            '_id': six.text_type(webhook._id),
             'url': 'http://localhost/rest/adobe/adobe-1/admin'
                    '/src/webhooks/repo-push/{}'.format(webhook._id),
             'type': 'repo-push',
             'hook_url': 'http://hook.slack.com/abcd',
-            'mod_date': unicode(webhook.mod_date),
+            'mod_date': six.text_type(webhook.mod_date),
         }
         dd.assert_equal(r.json, expected)
 
diff --git a/Allura/allura/webhooks.py b/Allura/allura/webhooks.py
index be9b75b..d07268d 100644
--- a/Allura/allura/webhooks.py
+++ b/Allura/allura/webhooks.py
@@ -41,6 +41,7 @@ from allura.lib import helpers as h
 from allura.lib.decorators import require_post, task
 from allura.lib.utils import DateJSONEncoder
 from allura import model as M
+import six
 
 
 log = logging.getLogger(__name__)
@@ -200,7 +201,7 @@ class WebhookController(BaseController, AdminControllerMixin):
             raise exc.HTTPNotFound()
         c.form_values = {'url': kw.get('url') or wh.hook_url,
                          'secret': kw.get('secret') or wh.secret,
-                         'webhook': unicode(wh._id)}
+                         'webhook': six.text_type(wh._id)}
         return {'sender': self.sender,
                 'action': 'edit',
                 'form': form}
@@ -219,7 +220,7 @@ class WebhookRestController(BaseController):
         if error:
             _error = {}
             for k, v in error.iteritems():
-                _error[k] = unicode(v)
+                _error[k] = six.text_type(v)
             return _error
         error = getattr(e, 'msg', None)
         if not error:
@@ -297,7 +298,7 @@ class WebhookRestController(BaseController):
         try:
             params = {'secret': kw.pop('secret', old_secret),
                       'url': kw.pop('url', old_url),
-                      'webhook': unicode(webhook._id)}
+                      'webhook': six.text_type(webhook._id)}
             valid = form.to_python(params)
         except Exception as e:
             response.status_int = 400
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index 179340b..d867c1b 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -58,6 +58,7 @@ from allura.controllers.feed import FeedArgs, FeedController
 from forgeblog import model as BM
 from forgeblog import version
 from forgeblog import widgets
+import six
 
 log = logging.getLogger(__name__)
 
@@ -542,7 +543,7 @@ class BlogAdminController(DefaultAdminController):
     @require_post()
     def set_exfeed(self, new_exfeed=None, **kw):
         exfeed_val = kw.get('exfeed', [])
-        if type(exfeed_val) == unicode:
+        if type(exfeed_val) == six.text_type:
             tmp_exfeed_list = []
             tmp_exfeed_list.append(exfeed_val)
         else:
diff --git a/ForgeGit/forgegit/tests/functional/test_controllers.py b/ForgeGit/forgegit/tests/functional/test_controllers.py
index 61b821d..afaaea3 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -41,6 +41,7 @@ from allura.tests.decorators import with_tool
 from allura.tests.test_globals import squish_spaces
 from forgegit.tests import with_git
 from forgegit import model as GM
+import six
 
 
 class _TestCase(TestController):
@@ -813,7 +814,7 @@ class TestFork(_TestCase):
         assert '<p>changed description</p' in r
         assert 'Merge Request #1: changed summary (open)' in r
         changes = r.html.findAll('div', attrs={'class': 'markdown_content'})[-1]
-        dd_assert_equal(unicode(changes), """
+        dd_assert_equal(six.text_type(changes), """
 <div class="markdown_content"><ul>
 <li>
 <p><strong>Summary</strong>: summary --&gt; changed summary</p>
diff --git a/ForgeImporters/forgeimporters/github/tracker.py b/ForgeImporters/forgeimporters/github/tracker.py
index 0c54f3f..1a915bc 100644
--- a/ForgeImporters/forgeimporters/github/tracker.py
+++ b/ForgeImporters/forgeimporters/github/tracker.py
@@ -19,6 +19,7 @@ import re
 import logging
 from datetime import datetime
 from urllib2 import HTTPError
+import six
 
 try:
     from cStringIO import StringIO
@@ -242,7 +243,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': six.text_type(milestone[1].date()) if milestone[1] else None,
                 'complete': False,
             })
         return [global_milestones]
diff --git a/ForgeImporters/forgeimporters/github/wiki.py b/ForgeImporters/forgeimporters/github/wiki.py
index 53093f4..220eef3 100644
--- a/ForgeImporters/forgeimporters/github/wiki.py
+++ b/ForgeImporters/forgeimporters/github/wiki.py
@@ -427,7 +427,7 @@ class GitHubWikiImporter(ToolImporter):
                     a.string = new_page
                 elif a.string == prefix + page:
                     a.string = new_prefix + new_page
-        return unicode(soup)
+        return six.text_type(soup)
 
     def _prepare_textile_text(self, text):
         # need to convert lists properly
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 85210d3..a3b5f46 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -716,7 +716,7 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
             # Pre solr-4.2.1 code expects all custom fields to be indexed
             # as strings.
             if not config.get_bool('new_solr'):
-                result[k + '_s'] = unicode(v)
+                result[k + '_s'] = six.text_type(v)
 
             # Now let's also index with proper Solr types.
             solr_type = self.app.globals.get_custom_field_solr_type(k)
diff --git a/ForgeWiki/forgewiki/converters.py b/ForgeWiki/forgewiki/converters.py
index 2793967..c4fea2f 100644
--- a/ForgeWiki/forgewiki/converters.py
+++ b/ForgeWiki/forgewiki/converters.py
@@ -18,6 +18,7 @@
 #-*- python -*-
 import re
 from bs4 import BeautifulSoup
+import six
 
 _inline_img = re.compile(r'\[\[(File|Image):([^\]|]+)[^]]*\]\]', re.UNICODE)
 _inline_img_markdown = r'[[img src=\2]]'
@@ -53,7 +54,7 @@ def _convert_toc(wiki_html):
     soup = BeautifulSoup(wiki_html, 'html.parser')
     for toc_div in soup.findAll('div', id='toc'):
         toc_div.replaceWith('[TOC]')
-    return unicode(soup)
+    return six.text_type(soup)
 
 
 def mediawiki2markdown(source):
diff --git a/scripts/teamforge-import.py b/scripts/teamforge-import.py
index 9e7ba6b..9bd88a6 100644
--- a/scripts/teamforge-import.py
+++ b/scripts/teamforge-import.py
@@ -41,6 +41,7 @@ from ming.base import Object
 from allura import model as M
 from allura.lib import helpers as h
 from allura.lib import utils
+import six
 
 log = logging.getLogger('teamforge-import')
 
@@ -663,7 +664,7 @@ def load(project_id, *paths):
     in_file = os.path.join(options.output_dir, project_id, *paths)
     with open(in_file) as input:
         content = input.read()
-    return unicode(content, 'utf-8')
+    return six.text_type(content, 'utf-8')
 
 
 def loadjson(*args):