You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by di...@apache.org on 2022/09/23 18:43:26 UTC

[allura] 01/10: 8455 nose2pytest for ./Allura

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

dill0wn pushed a commit to branch dw/8455-part2
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 1655e93e2dfacd18d3377bbeea489702b65e6000
Author: Kenton Taylor <kt...@slashdotmedia.com>
AuthorDate: Mon Aug 22 19:11:42 2022 +0000

    8455 nose2pytest for ./Allura
---
 Allura/allura/tests/decorators.py                  |   7 +-
 Allura/allura/tests/functional/test_admin.py       | 174 ++++----
 Allura/allura/tests/functional/test_auth.py        | 482 ++++++++++-----------
 Allura/allura/tests/functional/test_discuss.py     |  18 +-
 Allura/allura/tests/functional/test_gravatar.py    |   4 +-
 Allura/allura/tests/functional/test_home.py        |  52 +--
 .../allura/tests/functional/test_neighborhood.py   |  60 +--
 .../tests/functional/test_personal_dashboard.py    |  28 +-
 Allura/allura/tests/functional/test_rest.py        | 158 +++----
 Allura/allura/tests/functional/test_root.py        |  12 +-
 Allura/allura/tests/functional/test_site_admin.py  | 230 +++++-----
 .../allura/tests/functional/test_trovecategory.py  |  44 +-
 .../allura/tests/functional/test_user_profile.py   |  56 +--
 Allura/allura/tests/model/test_artifact.py         |  30 +-
 Allura/allura/tests/model/test_auth.py             | 200 ++++-----
 Allura/allura/tests/model/test_discussion.py       |  48 +-
 Allura/allura/tests/model/test_filesystem.py       |  16 +-
 Allura/allura/tests/model/test_notification.py     |  40 +-
 Allura/allura/tests/model/test_oauth.py            |   6 +-
 Allura/allura/tests/model/test_project.py          |  32 +-
 Allura/allura/tests/model/test_repo.py             |  80 ++--
 Allura/allura/tests/model/test_timeline.py         |   2 +-
 .../tests/scripts/test_create_sitemap_files.py     |   6 +-
 .../allura/tests/scripts/test_delete_projects.py   |   2 +-
 Allura/allura/tests/scripts/test_misc_scripts.py   |   6 +-
 Allura/allura/tests/scripts/test_reindexes.py      |   4 +-
 .../tests/templates/jinja_master/test_lib.py       |  10 +-
 Allura/allura/tests/test_app.py                    |  24 +-
 Allura/allura/tests/test_commands.py               |  65 ++-
 Allura/allura/tests/test_decorators.py             |  24 +-
 Allura/allura/tests/test_globals.py                | 203 +++++----
 Allura/allura/tests/test_helpers.py                | 156 +++----
 Allura/allura/tests/test_mail_util.py              |  68 +--
 Allura/allura/tests/test_middlewares.py            |  30 +-
 Allura/allura/tests/test_multifactor.py            |  36 +-
 Allura/allura/tests/test_patches.py                |   8 +-
 Allura/allura/tests/test_plugin.py                 | 204 ++++-----
 Allura/allura/tests/test_security.py               |  30 +-
 Allura/allura/tests/test_tasks.py                  | 156 +++----
 Allura/allura/tests/test_utils.py                  |  68 +--
 Allura/allura/tests/test_webhooks.py               | 224 +++++-----
 .../test_discussion_moderation_controller.py       |   8 +-
 Allura/allura/tests/unit/phone/test_nexmo.py       |  40 +-
 .../allura/tests/unit/phone/test_phone_service.py  |   8 +-
 Allura/allura/tests/unit/spam/test_spam_filter.py  |  10 +-
 .../allura/tests/unit/spam/test_stopforumspam.py   |   6 +-
 Allura/allura/tests/unit/test_app.py               |   2 +-
 Allura/allura/tests/unit/test_discuss.py           |   8 +-
 Allura/allura/tests/unit/test_helpers/test_ago.py  |   2 +-
 .../allura/tests/unit/test_ldap_auth_provider.py   |  24 +-
 .../allura/tests/unit/test_package_path_loader.py  |  40 +-
 Allura/allura/tests/unit/test_repo.py              |  30 +-
 Allura/allura/tests/unit/test_solr.py              |  26 +-
 requirements.in                                    |   1 +
 requirements.txt                                   |  22 +-
 55 files changed, 1669 insertions(+), 1661 deletions(-)

diff --git a/Allura/allura/tests/decorators.py b/Allura/allura/tests/decorators.py
index 34854ad0f..4e6711a4a 100644
--- a/Allura/allura/tests/decorators.py
+++ b/Allura/allura/tests/decorators.py
@@ -237,7 +237,6 @@ def assert_logmsg_and_no_warnings_or_errors(logs, msg):
 def assert_equivalent_urls(url1, url2):
     base1, _, qs1 = url1.partition('?')
     base2, _, qs2 = url2.partition('?')
-    assert_equal(
-        (base1, parse_qs(qs1)),
-        (base2, parse_qs(qs2)),
-    )
+    assert (
+        (base1, parse_qs(qs1)) ==
+        (base2, parse_qs(qs2)))
diff --git a/Allura/allura/tests/functional/test_admin.py b/Allura/allura/tests/functional/test_admin.py
index 96138ffea..d8570c668 100644
--- a/Allura/allura/tests/functional/test_admin.py
+++ b/Allura/allura/tests/functional/test_admin.py
@@ -108,7 +108,7 @@ class TestProjectAdmin(TestController):
         # check tool in the nav
         r = self.app.get('/p/test/test-tool/').follow()
         active_link = r.html.findAll('li', {'class': 'selected'})
-        assert_equals(len(active_link), 1)
+        assert len(active_link) == 1
         assert active_link[0].contents[1]['href'] == '/p/test/test-tool/'
         with audits('install tool test-tool2'):
             r = self.app.post('/admin/update_mounts', params={
@@ -160,11 +160,11 @@ class TestProjectAdmin(TestController):
             'task_name': 'allura.tasks.event_tasks.event',
             'args': 'project_menu_updated'
         }).all()
-        assert_equals(len(menu_updated_events), 7)
+        assert len(menu_updated_events) == 7
 
     def test_features(self):
         proj = M.Project.query.get(shortname='test')
-        assert_equals(proj.features, [])
+        assert proj.features == []
         with audits(r"change project features to \[{u}'One', {u}'Two'\]".format(u='')):
             resp = self.app.post('/admin/update', params={
                 'features-0.feature': 'One',
@@ -172,32 +172,32 @@ class TestProjectAdmin(TestController):
                 'features-2.feature': ' Two '})
             if resp.status_int == 200:
                 errors = resp.html.findAll('', attrs={'class': 'fielderror'})
-                assert_equals([], errors)
+                assert [] == errors
                 errors = resp.html.findAll('', attrs={'class': 'error'})
-                assert_equals([], errors)
+                assert [] == errors
                 raise AssertionError('Should be a 301 not 200 response')
 
         r = self.app.get('/admin/overview')
         features = r.html.find('div', {'id': 'features'})
         features = features.findAll('input', {'type': 'text'})
         # two features + extra empty input + stub hidden input for js
-        assert_equals(len(features), 2+1+1)
-        assert_equals(features[0]['value'], 'One')
-        assert_equals(features[1]['value'], 'Two')
+        assert len(features) == 2+1+1
+        assert features[0]['value'] == 'One'
+        assert features[1]['value'] == 'Two'
         proj = M.Project.query.get(shortname='test')
-        assert_equals(proj.features, ['One', 'Two'])
+        assert proj.features == ['One', 'Two']
 
     @td.with_wiki
     def test_block_user_empty_data(self):
         r = self.app.post('/admin/wiki/block_user',
                           params={'username': '', 'perm': '', 'reason': ''})
-        assert_equals(r.json, dict(error='Enter username'))
+        assert r.json == dict(error='Enter username')
 
     @td.with_wiki
     def test_unblock_user_empty_data(self):
         r = self.app.post('/admin/wiki/unblock_user',
                           params={'user_id': '', 'perm': ''})
-        assert_equals(r.json, dict(error='Select user to unblock'))
+        assert r.json == dict(error='Select user to unblock')
 
     @td.with_wiki
     def test_block_user(self):
@@ -207,14 +207,14 @@ class TestProjectAdmin(TestController):
         user = M.User.by_username('test-admin')
         r = self.app.post('/admin/wiki/block_user',
                           params={'username': 'test-admin', 'perm': 'read', 'reason': 'Comment'})
-        assert_equals(
-            r.json, dict(user_id=str(user._id), username='test-admin', reason='Comment'))
+        assert (
+            r.json == dict(user_id=str(user._id), username='test-admin', reason='Comment'))
         user = M.User.by_username('test-admin')
         admin_role = M.ProjectRole.by_user(user)
         project = M.Project.query.get(shortname='test')
         app = project.app_instance('wiki')
         ace = M.ACL.contains(M.ACE.deny(admin_role._id, 'read'), app.acl)
-        assert_equals(ace.reason, 'Comment')
+        assert ace.reason == 'Comment'
         audit_log = M.AuditLog.query.find(
             {'project_id': project._id}).sort('_id', -1).first()
         assert 'blocked user "test-admin"' in audit_log.message
@@ -237,7 +237,7 @@ class TestProjectAdmin(TestController):
         assert M.ACL.contains(ace, app.acl) is not None
         r = self.app.post('/admin/wiki/unblock_user',
                           params={'user_id': str(user._id), 'perm': 'read'})
-        assert_equals(r.json, dict(unblocked=[str(user._id)]))
+        assert r.json == dict(unblocked=[str(user._id)])
         assert M.ACL.contains(ace, app.acl) is None
         r = self.app.get('/admin/wiki/permissions')
         assert '<input type="checkbox" name="user_id"' not in r
@@ -293,7 +293,7 @@ class TestProjectAdmin(TestController):
         assert M.ACL.contains(M.ACE.deny(user_role._id, 'post'), app.acl)
         # ...and all old ACEs also
         for ace in old_acl:
-            assert_in(ace, app.acl)
+            assert ace in app.acl
 
     def test_tool_permissions(self):
         BUILTIN_APPS = ['activity', 'blog', 'discussion', 'git', 'link',
@@ -335,7 +335,7 @@ class TestProjectAdmin(TestController):
             c.project = M.Project.query.get(shortname='test')
             data = c.project.nav_data(admin_options=True)
             menu = [tool['text'] for tool in data['installable_tools']]
-            assert_in('Wiki', menu)
+            assert 'Wiki' in menu
 
             r = self.app.post('/p/test/admin/update_mounts/', params={
                 'new.install': 'install',
@@ -347,7 +347,7 @@ class TestProjectAdmin(TestController):
             c.project = M.Project.query.get(shortname='test')
             data = c.project.nav_data(admin_options=True)
             menu = [tool['text'] for tool in data['installable_tools']]
-            assert_not_in('Wiki', menu)
+            assert 'Wiki' not in menu
 
             r = self.app.post('/p/test/admin/update_mounts/', params={
                 'new.install': 'install',
@@ -361,17 +361,17 @@ class TestProjectAdmin(TestController):
 
     def test_install_tool_form(self):
         r = self.app.get('/admin/install_tool?tool_name=wiki')
-        assert_in('Installing Wiki', r)
+        assert 'Installing Wiki' in r
 
     def test_install_tool_form_options(self):
         opts = ['AllowEmailPosting']
         with mock.patch.object(ForgeWikiApp, 'config_on_install', new=opts):
             r = self.app.get('/admin/install_tool?tool_name=wiki')
-            assert_in('<input id="AllowEmailPosting" name="AllowEmailPosting"', r)
+            assert '<input id="AllowEmailPosting" name="AllowEmailPosting"' in r
 
     def test_install_tool_form_subproject(self):
         r = self.app.get('/admin/install_tool?tool_name=subproject')
-        assert_in('Installing Sub Project', r)
+        assert 'Installing Sub Project' in r
 
     def test_project_icon(self):
         file_name = 'neo-icon-set-454545-256x350.png'
@@ -452,12 +452,12 @@ class TestProjectAdmin(TestController):
                                       neighborhood_id=p_nbhd._id)
         # first uploaded is first by default
         screenshots = project.get_screenshots()
-        assert_equals(screenshots[0].filename, 'admin_24.png')
+        assert screenshots[0].filename == 'admin_24.png'
         # reverse order
         params = {str(ss._id): str(len(screenshots) - 1 - i)
                       for i, ss in enumerate(screenshots)}
         self.app.post('/admin/sort_screenshots', params)
-        assert_equals(project.get_screenshots()[0].filename, 'admin_32.png')
+        assert project.get_screenshots()[0].filename == 'admin_32.png'
 
     def test_project_delete_undelete(self):
         # create a subproject
@@ -586,7 +586,7 @@ class TestProjectAdmin(TestController):
             r = form.submit()
         r = r.follow()
         p = M.Project.query.get(shortname='test', neighborhood_id=p_nbhd._id)
-        assert_equals(p.labels, ['asdf'])
+        assert p.labels == ['asdf']
         assert form['labels'].value == 'asdf'
 
     @td.with_wiki
@@ -611,7 +611,7 @@ class TestProjectAdmin(TestController):
 
     def test_project_permissions(self):
         r = self.app.get('/admin/permissions/', status=302)
-        assert_in('/admin/groups', r.location)
+        assert '/admin/groups' in r.location
 
     def test_subproject_permissions(self):
         with audits('create subproject test-subproject'):
@@ -952,7 +952,7 @@ class TestProjectAdmin(TestController):
             foo_page = main_page.click(description='Foo Settings')
             url = foo_page.request.path
             assert url.endswith('/admin/ext/foo'), url
-            assert_equals('here the foo settings go', foo_page.text)
+            assert 'here the foo settings go' == foo_page.text
 
     def test_nbhd_invitations(self):
         r = self.app.get('/admin/invitations')
@@ -975,19 +975,19 @@ class TestExport(TestController):
         exportable_tools = AdminApp.exportable_tools_for(project)
         exportable_mount_points = [
             t.options.mount_point for t in exportable_tools]
-        assert_equals(exportable_mount_points, ['admin', 'wiki', 'wiki2'])
+        assert exportable_mount_points == ['admin', 'wiki', 'wiki2']
 
     def test_access(self):
         r = self.app.get('/admin/export',
                          extra_environ={'username': '*anonymous'}).follow()
-        assert_equals(r.request.url,
+        assert (r.request.url ==
                       'http://localhost/auth/?return_to=%2Fadmin%2Fexport')
         self.app.get('/admin/export',
                      extra_environ={'username': 'test-user'},
                      status=403)
         r = self.app.post('/admin/export',
                           extra_environ={'username': '*anonymous'}).follow()
-        assert_equals(r.request.url, 'http://localhost/auth/')
+        assert r.request.url == 'http://localhost/auth/'
         self.app.post('/admin/export',
                       extra_environ={'username': 'test-user'},
                       status=403)
@@ -995,22 +995,22 @@ class TestExport(TestController):
     def test_ini_option(self):
         tg.config['bulk_export_enabled'] = 'false'
         r = self.app.get('/admin/')
-        assert_not_in('Export', r)
+        assert 'Export' not in r
         r = self.app.get('/admin/export', status=404)
         tg.config['bulk_export_enabled'] = 'true'
         r = self.app.get('/admin/')
-        assert_in('Export', r)
+        assert 'Export' in r
 
     @mock.patch('allura.model.session.project_doc_session')
     def test_export_page_contains_exportable_tools(self, session):
         session.return_value = {'result': [{"total_size": 10000}]}
 
         r = self.app.get('/admin/export')
-        assert_in('Wiki</label> <a href="/p/test/wiki/">/p/test/wiki/</a>', r)
-        assert_in(
-            'Wiki2</label> <a href="/p/test/wiki2/">/p/test/wiki2/</a>', r)
-        assert_not_in(
-            'Search</label> <a href="/p/test/search/">/p/test/search/</a>', r)
+        assert 'Wiki</label> <a href="/p/test/wiki/">/p/test/wiki/</a>' in r
+        assert (
+            'Wiki2</label> <a href="/p/test/wiki2/">/p/test/wiki2/</a>' in r)
+        assert (
+            'Search</label> <a href="/p/test/search/">/p/test/search/</a>' not in r)
 
     def test_export_page_contains_hidden_tools(self):
         with mock.patch('allura.ext.search.search_main.SearchApp.exportable'):
@@ -1018,22 +1018,22 @@ class TestExport(TestController):
             exportable_tools = AdminApp.exportable_tools_for(project)
             exportable_mount_points = [
                 t.options.mount_point for t in exportable_tools]
-            assert_equals(exportable_mount_points,
+            assert (exportable_mount_points ==
                           ['admin', 'search', 'wiki', 'wiki2'])
 
     def test_tools_not_selected(self):
         r = self.app.post('/admin/export')
-        assert_in('error', self.webflash(r))
+        assert 'error' in self.webflash(r)
 
     def test_bad_tool(self):
         r = self.app.post('/admin/export', {'tools': 'search'})
-        assert_in('error', self.webflash(r))
+        assert 'error' in self.webflash(r)
 
     @mock.patch('allura.ext.admin.admin_main.export_tasks')
     @mock.patch.dict(tg.config, {'bulk_export_filename': '{project}.zip'})
     def test_selected_one_tool(self, export_tasks):
         r = self.app.post('/admin/export', {'tools': 'wiki'})
-        assert_in('ok', self.webflash(r))
+        assert 'ok' in self.webflash(r)
         export_tasks.bulk_export.post.assert_called_once_with(
             ['wiki'], 'test.zip', send_email=True, with_attachments=False)
 
@@ -1041,7 +1041,7 @@ class TestExport(TestController):
     @mock.patch.dict(tg.config, {'bulk_export_filename': '{project}.zip'})
     def test_selected_multiple_tools(self, export_tasks):
         r = self.app.post('/admin/export', {'tools': ['wiki', 'wiki2']})
-        assert_in('ok', self.webflash(r))
+        assert 'ok' in self.webflash(r)
         export_tasks.bulk_export.post.assert_called_once_with(
             ['wiki', 'wiki2'], 'test.zip', send_email=True, with_attachments=False)
 
@@ -1051,12 +1051,12 @@ class TestExport(TestController):
         session.return_value = {'result': [{"total_size": 10000}]}
         export_tasks.bulk_export.post(['wiki'])
         r = self.app.get('/admin/export')
-        assert_in('<h2>Busy</h2>', r.text)
+        assert '<h2>Busy</h2>' in r.text
 
     @td.with_user_project('test-user')
     def test_bulk_export_path_for_user_project(self):
         project = M.Project.query.get(shortname='u/test-user')
-        assert_equals(project.bulk_export_path(tg.config['bulk_export_path']),
+        assert (project.bulk_export_path(tg.config['bulk_export_path']) ==
                       '/tmp/bulk_export/u/test-user')
 
     @td.with_user_project('test-user')
@@ -1074,15 +1074,15 @@ class TestExport(TestController):
 
     def test_bulk_export_path_for_nbhd(self):
         project = M.Project.query.get(name='Home Project for Projects')
-        assert_equals(project.bulk_export_path(tg.config['bulk_export_path']), '/tmp/bulk_export/p/p')
+        assert project.bulk_export_path(tg.config['bulk_export_path']) == '/tmp/bulk_export/p/p'
 
     @mock.patch('allura.model.session.project_doc_session')
     def test_export_page_contains_check_all_checkbox(self, session):
         session.return_value = {'result': [{"total_size": 10000}]}
 
         r = self.app.get('/admin/export')
-        assert_in('<input type="checkbox" id="check-all">', r)
-        assert_in('Check All</label>', r)
+        assert '<input type="checkbox" id="check-all">' in r
+        assert 'Check All</label>' in r
 
 
 class TestRestExport(TestRestApiBase):
@@ -1091,11 +1091,11 @@ class TestRestExport(TestRestApiBase):
     def test_export_status(self, MonQTask):
         MonQTask.query.get.return_value = None
         r = self.api_get('/rest/p/test/admin/export_status')
-        assert_equals(r.json, {'status': 'ready'})
+        assert r.json == {'status': 'ready'}
 
         MonQTask.query.get.return_value = 'something'
         r = self.api_get('/rest/p/test/admin/export_status')
-        assert_equals(r.json, {'status': 'busy'})
+        assert r.json == {'status': 'busy'}
 
     @mock.patch('allura.model.project.MonQTask')
     @mock.patch('allura.ext.admin.admin_main.AdminApp.exportable_tools_for')
@@ -1105,7 +1105,7 @@ class TestRestExport(TestRestApiBase):
         exportable_tools.return_value = []
         self.api_post('/rest/p/test/admin/export',
                       tools='tickets, discussion', status=400)
-        assert_equals(bulk_export.post.call_count, 0)
+        assert bulk_export.post.call_count == 0
 
     @mock.patch('allura.model.project.MonQTask')
     @mock.patch('allura.ext.admin.admin_main.AdminApp.exportable_tools_for')
@@ -1117,7 +1117,7 @@ class TestRestExport(TestRestApiBase):
             mock.Mock(options=mock.Mock(mount_point='discussion')),
         ]
         self.api_post('/rest/p/test/admin/export', status=400)
-        assert_equals(bulk_export.post.call_count, 0)
+        assert bulk_export.post.call_count == 0
 
     @mock.patch('allura.model.project.MonQTask')
     @mock.patch('allura.ext.admin.admin_main.AdminApp.exportable_tools_for')
@@ -1130,7 +1130,7 @@ class TestRestExport(TestRestApiBase):
         ]
         self.api_post('/rest/p/test/admin/export',
                       tools='tickets, discussion', status=503)
-        assert_equals(bulk_export.post.call_count, 0)
+        assert bulk_export.post.call_count == 0
 
     @mock.patch('allura.model.project.MonQTask')
     @mock.patch('allura.ext.admin.admin_main.AdminApp.exportable_tools_for')
@@ -1144,10 +1144,10 @@ class TestRestExport(TestRestApiBase):
         ]
         r = self.api_post('/rest/p/test/admin/export',
                           tools='tickets, discussion', status=200)
-        assert_equals(r.json, {
+        assert r.json == {
             'filename': 'test.zip',
             'status': 'in progress',
-        })
+        }
         bulk_export.post.assert_called_once_with(
             ['tickets', 'discussion'], 'test.zip', send_email=False, with_attachments=False)
 
@@ -1163,8 +1163,8 @@ class TestRestInstallTool(TestRestApiBase):
             'tool': 'tickets'
         }
         r = self.api_post('/rest/p/test/admin/install_tool/', **data)
-        assert_equals(r.json['success'], False)
-        assert_equals(r.json['info'], 'All arguments required.')
+        assert r.json['success'] == False
+        assert r.json['info'] == 'All arguments required.'
 
     def test_invalid_tool(self):
         r = self.api_get('/rest/p/test/')
@@ -1177,8 +1177,8 @@ class TestRestInstallTool(TestRestApiBase):
             'mount_label': 'tickets_label1'
         }
         r = self.api_post('/rest/p/test/admin/install_tool/', **data)
-        assert_equals(r.json['success'], False)
-        assert_equals(r.json['info'],
+        assert r.json['success'] == False
+        assert (r.json['info'] ==
                       'Incorrect tool name, or limit is reached.')
 
     def test_bad_mount(self):
@@ -1192,8 +1192,8 @@ class TestRestInstallTool(TestRestApiBase):
             'mount_label': 'tickets_label1'
         }
         r = self.api_post('/rest/p/test/admin/install_tool/', **data)
-        assert_equals(r.json['success'], False)
-        assert_equals(r.json['info'],
+        assert r.json['success'] == False
+        assert (r.json['info'] ==
                       'Mount point "tickets_mount1" is invalid')
 
     def test_install_tool_ok(self):
@@ -1207,17 +1207,17 @@ class TestRestInstallTool(TestRestApiBase):
             'mount_label': 'tickets_label1'
         }
         r = self.api_post('/rest/p/test/admin/install_tool/', **data)
-        assert_equals(r.json['success'], True)
-        assert_equals(r.json['info'],
+        assert r.json['success'] == True
+        assert (r.json['info'] ==
                       'Tool %s with mount_point %s and mount_label %s was created.'
                       % ('tickets', 'ticketsmount1', 'tickets_label1'))
 
         project = M.Project.query.get(shortname='test')
-        assert_equals(project.ordered_mounts()
-                      [-1]['ac'].options.mount_point, 'ticketsmount1')
+        assert (project.ordered_mounts()
+                      [-1]['ac'].options.mount_point == 'ticketsmount1')
         audit_log = M.AuditLog.query.find(
             {'project_id': project._id}).sort('_id', -1).first()
-        assert_equals(audit_log.message, 'install tool ticketsmount1')
+        assert audit_log.message == 'install tool ticketsmount1'
 
     def test_tool_exists(self):
         with mock.patch.object(ForgeWikiApp, 'max_instances') as mi:
@@ -1235,8 +1235,8 @@ class TestRestInstallTool(TestRestApiBase):
             with h.push_config(c, user=M.User.query.get()):
                 project.install_app('wiki', mount_point=data['mount_point'])
             r = self.api_post('/rest/p/test/admin/install_tool/', **data)
-            assert_equals(r.json['success'], False)
-            assert_equals(r.json['info'], 'Mount point already exists.')
+            assert r.json['success'] == False
+            assert r.json['info'] == 'Mount point already exists.'
 
     def test_tool_installation_limit(self):
         with mock.patch.object(ForgeWikiApp, 'max_instances') as mi:
@@ -1251,13 +1251,13 @@ class TestRestInstallTool(TestRestApiBase):
                 'mount_label': 'wiki_label'
             }
             r = self.api_post('/rest/p/test/admin/install_tool/', **data)
-            assert_equals(r.json['success'], True)
+            assert r.json['success'] == True
 
             data['mount_point'] = 'wikimount1'
             data['mount_label'] = 'wiki_label1'
             r = self.api_post('/rest/p/test/admin/install_tool/', **data)
-            assert_equals(r.json['success'], False)
-            assert_equals(r.json['info'],
+            assert r.json['success'] == False
+            assert (r.json['info'] ==
                           'Incorrect tool name, or limit is reached.')
 
     def test_unauthorized(self):
@@ -1274,7 +1274,7 @@ class TestRestInstallTool(TestRestApiBase):
                           extra_environ={'username': '*anonymous'},
                           status=401,
                           params=data)
-        assert_equals(r.status, '401 Unauthorized')
+        assert r.status == '401 Unauthorized'
 
     def test_order(self):
         def get_labels():
@@ -1286,7 +1286,7 @@ class TestRestInstallTool(TestRestApiBase):
                 elif 'sub' in mount:
                     labels.append(mount['sub'].name)
             return labels
-        assert_equals(get_labels(),
+        assert (get_labels() ==
                       ['Admin', 'Search', 'Activity', 'A Subproject'])
 
         data = [
@@ -1316,39 +1316,39 @@ class TestRestInstallTool(TestRestApiBase):
         ]
         for datum in data:
             r = self.api_post('/rest/p/test/admin/install_tool/', **datum)
-            assert_equals(r.json['success'], True)
-            assert_equals(r.json['info'],
+            assert r.json['success'] == True
+            assert (r.json['info'] ==
                           'Tool %s with mount_point %s and mount_label %s was created.'
                           % (datum['tool'], datum['mount_point'], datum['mount_label']))
 
-        assert_equals(
-            get_labels(), ['t1', 'Admin', 'Search', 'Activity', 'A Subproject', 'ta', 'tb', 'tc'])
+        assert (
+            get_labels() == ['t1', 'Admin', 'Search', 'Activity', 'A Subproject', 'ta', 'tb', 'tc'])
 
 
 class TestRestAdminOptions(TestRestApiBase):
     def test_no_mount_point(self):
         r = self.api_get('/rest/p/test/admin/admin_options/', status=400)
-        assert_in('Must provide a mount point', r.text)
+        assert 'Must provide a mount point' in r.text
 
     def test_invalid_mount_point(self):
         r = self.api_get('/rest/p/test/admin/admin_options/?mount_point=asdf', status=400)
-        assert_in('The mount point you provided was invalid', r.text)
+        assert 'The mount point you provided was invalid' in r.text
 
     @td.with_tool('test', 'Git', 'git')
     def test_valid_mount_point(self):
         r = self.api_get('/rest/p/test/admin/admin_options/?mount_point=git', status=200)
-        assert_is_not_none(r.json['options'])
+        assert r.json['options'] is not None
 
 
 class TestRestMountOrder(TestRestApiBase):
     def test_no_kw(self):
         r = self.api_post('/rest/p/test/admin/mount_order/', status=400)
-        assert_in('Expected kw params in the form of "ordinal: mount_point"', r.text)
+        assert 'Expected kw params in the form of "ordinal: mount_point"' in r.text
 
     def test_invalid_kw(self):
         data = {'1': 'git', 'two': 'admin'}
         r = self.api_post('/rest/p/test/admin/mount_order/', status=400, **data)
-        assert_in('Invalid kw: expected "ordinal: mount_point"', r.text)
+        assert 'Invalid kw: expected "ordinal: mount_point"' in r.text
 
     @td.with_wiki
     def test_reorder(self):
@@ -1374,19 +1374,19 @@ class TestRestMountOrder(TestRestApiBase):
 
         # Set initial order to d1
         r = self.api_post('/rest/p/test/admin/mount_order/', **d1)
-        assert_equals(r.json['status'], 'ok')
+        assert r.json['status'] == 'ok'
 
         # Get index of sub1
         a = self.api_get('/p/test/_nav.json').json['menu'].index(tool)
 
         # Set order to d2
         r = self.api_post('/rest/p/test/admin/mount_order/', **d2)
-        assert_equals(r.json['status'], 'ok')
+        assert r.json['status'] == 'ok'
 
         # Get index of sub1 after reordering
         b = self.api_get('/p/test/_nav.json').json['menu'].index(tool)
 
-        assert_greater(b, a)
+        assert b > a
 
 
 class TestRestToolGrouping(TestRestApiBase):
@@ -1394,7 +1394,7 @@ class TestRestToolGrouping(TestRestApiBase):
         for invalid_value in ('100', 'asdf'):
             r = self.api_post('/rest/p/test/admin/configure_tool_grouping/', grouping_threshold=invalid_value,
                               status=400)
-            assert_in('Invalid threshold. Expected a value between 1 and 10', r.text)
+            assert 'Invalid threshold. Expected a value between 1 and 10' in r.text
 
     @td.with_wiki
     @td.with_tool('test', 'Wiki', 'wiki2')
@@ -1405,17 +1405,17 @@ class TestRestToolGrouping(TestRestApiBase):
 
         # The 'wiki' mount_point should not exist at the top level
         result1 = self.app.get('/p/test/_nav.json')
-        assert_not_in('wiki', [tool['mount_point'] for tool in result1.json['menu']])
+        assert 'wiki' not in [tool['mount_point'] for tool in result1.json['menu']]
 
         # Set threshold to 3
         r = self.api_post('/rest/p/test/admin/configure_tool_grouping/', grouping_threshold='3', status=200)
 
         # The wiki mount_point should now be at the top level of the menu
         result2 = self.app.get('/p/test/_nav.json')
-        assert_in('wiki', [tool['mount_point'] for tool in result2.json['menu']])
+        assert 'wiki' in [tool['mount_point'] for tool in result2.json['menu']]
 
 
 class TestInstallableTools(TestRestApiBase):
     def test_installable_tools_response(self):
         r = self.api_get('/rest/p/test/admin/installable_tools', status=200)
-        assert_in('External Link', [tool['tool_label'] for tool in r.json['tools']])
+        assert 'External Link' in [tool['tool_label'] for tool in r.json['tools']]
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index 4c4dddc14..27f62dfe8 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -80,7 +80,7 @@ class TestAuth(TestController):
                 username='test-user', password='foo',
                 _session_id=self.app.cookies['_session_id']),
                 antispam=True).follow()
-            assert_equal(r.headers['Location'], 'http://localhost/dashboard')
+            assert r.headers['Location'] == 'http://localhost/dashboard'
 
         r = self.app.post('/auth/do_login', antispam=True, params=dict(
             username='test-user', password='foo', honey1='robot',  # bad honeypot value
@@ -88,8 +88,8 @@ class TestAuth(TestController):
                           extra_environ={'regular_antispam_err_handling_even_when_tests': 'true'},
                           status=302)
         wf = json.loads(self.webflash(r))
-        assert_equal(wf['status'], 'error')
-        assert_equal(wf['message'], 'Spambot protection engaged')
+        assert wf['status'] == 'error'
+        assert wf['message'] == 'Spambot protection engaged'
 
         with audits('Failed login', user=True):
             r = self.app.post('/auth/do_login', antispam=True, params=dict(
@@ -137,8 +137,8 @@ class TestAuth(TestController):
                                     'regular_antispam_err_handling_even_when_tests': 'true'},
                      status=302)
         wf = json.loads(self.webflash(r))
-        assert_equal(wf['status'], 'error')
-        assert_equal(wf['message'], 'Spambot protection engaged')
+        assert wf['status'] == 'error'
+        assert wf['message'] == 'Spambot protection engaged'
 
     @patch('allura.lib.plugin.AuthenticationProvider.hibp_password_check_enabled', Mock(return_value=True))
     @patch('allura.tasks.mail_tasks.sendsimplemail')
@@ -158,11 +158,11 @@ class TestAuth(TestController):
         r.mustcontain('reset your password via email.<br>\nPlease check your email')
 
         args, kwargs = sendsimplemail.post.call_args
-        assert_equal(sendsimplemail.post.call_count, 1)
-        assert_equal(kwargs['subject'], 'Update your %s password' % config['site_name'])
-        assert_in('/auth/forgotten_password/', kwargs['text'])
+        assert sendsimplemail.post.call_count == 1
+        assert kwargs['subject'] == 'Update your %s password' % config['site_name']
+        assert '/auth/forgotten_password/' in kwargs['text']
 
-        assert_equal([], M.UserLoginDetails.query.find().all())  # no records created
+        assert [] == M.UserLoginDetails.query.find().all()  # no records created
 
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     def test_login_hibp_compromised_password_trusted_client(self, sendsimplemail):
@@ -191,8 +191,8 @@ class TestAuth(TestController):
                 r = f.submit(status=302)
 
             assert r.session.get('pwd-expired')
-            assert_equal(r.session.get('expired-reason'), 'hibp')
-            assert_equal(r.location, 'http://localhost/auth/pwd_expired')
+            assert r.session.get('expired-reason') == 'hibp'
+            assert r.location == 'http://localhost/auth/pwd_expired'
 
             r = r.follow()
             r.mustcontain('must be updated to be more secure')
@@ -243,19 +243,19 @@ class TestAuth(TestController):
 
         logged_in_session = r.session['_id']
         links = r.html.find(*nav_pattern).findAll('a')
-        assert_equal(links[-1].string, "Log Out")
+        assert links[-1].string == "Log Out"
 
         r = self.app.get('/auth/logout').follow().follow()
         logged_out_session = r.session['_id']
         assert logged_in_session is not logged_out_session
         links = r.html.find(*nav_pattern).findAll('a')
-        assert_equal(links[-1].string, 'Log In')
+        assert links[-1].string == 'Log In'
 
     def test_track_login(self):
         user = M.User.by_username('test-user')
-        assert_equal(user.last_access['login_date'], None)
-        assert_equal(user.last_access['login_ip'], None)
-        assert_equal(user.last_access['login_ua'], None)
+        assert user.last_access['login_date'] == None
+        assert user.last_access['login_ip'] == None
+        assert user.last_access['login_ua'] == None
 
         self.app.get('/').follow()  # establish session
         self.app.post('/auth/do_login',
@@ -269,9 +269,9 @@ class TestAuth(TestController):
                       antispam=True,
                       )
         user = M.User.by_username('test-user')
-        assert_not_equal(user.last_access['login_date'], None)
-        assert_equal(user.last_access['login_ip'], '127.0.0.1')
-        assert_equal(user.last_access['login_ua'], 'browser')
+        assert user.last_access['login_date'] != None
+        assert user.last_access['login_ip'] == '127.0.0.1'
+        assert user.last_access['login_ua'] == 'browser'
 
     def test_rememberme(self):
         username = M.User.query.get(username='test-user').username
@@ -283,24 +283,24 @@ class TestAuth(TestController):
             username='test-user', password='foo',
             _session_id=self.app.cookies['_session_id'],
         ), antispam=True)
-        assert_equal(r.session['username'], username)
-        assert_equal(r.session['login_expires'], True)
+        assert r.session['username'] == username
+        assert r.session['login_expires'] == True
 
         for header, contents in r.headerlist:
             if header == 'Set-cookie':
-                assert_not_in('expires', contents)
+                assert 'expires' not in contents
 
         # Login as test-user with remember me checkbox on
         r = self.app.post('/auth/do_login', params=dict(
             username='test-user', password='foo', rememberme='on',
             _session_id=self.app.cookies['_session_id'],
         ), antispam=True)
-        assert_equal(r.session['username'], username)
-        assert_not_equal(r.session['login_expires'], True)
+        assert r.session['username'] == username
+        assert r.session['login_expires'] != True
 
         for header, contents in r.headerlist:
             if header == 'Set-cookie':
-                assert_in('expires', contents)
+                assert 'expires' in contents
 
     @td.with_user_project('test-admin')
     def test_user_can_not_claim_duplicate_emails(self):
@@ -530,25 +530,25 @@ class TestAuth(TestController):
         # logged out, gets redirected to login page
         r = self.app.get('/auth/verify_addr', params=dict(a=email.nonce),
                          extra_environ=dict(username='*anonymous'))
-        assert_in('/auth/?return_to=%2Fauth%2Fverify_addr', r.location)
+        assert '/auth/?return_to=%2Fauth%2Fverify_addr' in r.location
 
         # logged in as someone else
         r = self.app.get('/auth/verify_addr', params=dict(a=email.nonce),
                          extra_environ=dict(username='test-admin'))
-        assert_in('/auth/?return_to=%2Fauth%2Fverify_addr', r.location)
-        assert_equal('You must be logged in to the correct account', json.loads(self.webflash(r))['message'])
-        assert_equal('warning', json.loads(self.webflash(r))['status'])
+        assert '/auth/?return_to=%2Fauth%2Fverify_addr' in r.location
+        assert 'You must be logged in to the correct account' == json.loads(self.webflash(r))['message']
+        assert 'warning' == json.loads(self.webflash(r))['status']
 
         # logged in as correct user
         r = self.app.get('/auth/verify_addr', params=dict(a=email.nonce),
                          extra_environ=dict(username='test-user'))
-        assert_in('confirmed', json.loads(self.webflash(r))['message'])
-        assert_equal('ok', json.loads(self.webflash(r))['status'])
+        assert 'confirmed' in json.loads(self.webflash(r))['message']
+        assert 'ok' == json.loads(self.webflash(r))['status']
 
         # assert 'email added' notification email sent
         args, kwargs = sendsimplemail.post.call_args
-        assert_equal(kwargs['toaddr'], user._id)
-        assert_equal(kwargs['subject'], 'New Email Address Added')
+        assert kwargs['toaddr'] == user._id
+        assert kwargs['subject'] == 'New Email Address Added'
 
     @staticmethod
     def _create_password_reset_hash():
@@ -566,8 +566,8 @@ class TestAuth(TestController):
         session(user).flush(user)
 
         hash_expiry = user.get_tool_data('AuthPasswordReset', 'hash_expiry')
-        assert_equal(hash, 'generated_hash_value')
-        assert_equal(hash_expiry, '04-08-2020')
+        assert hash == 'generated_hash_value'
+        assert hash_expiry == '04-08-2020'
         return user
 
     def test_token_generator(self):
@@ -611,8 +611,8 @@ class TestAuth(TestController):
 
         u = M.User.by_username('test-admin')
         print(u.get_tool_data('AuthPasswordReset', 'hash'))
-        assert_equal(u.get_tool_data('AuthPasswordReset', 'hash'), '')
-        assert_equal(u.get_tool_data('AuthPasswordReset', 'hash_expiry'), '')
+        assert u.get_tool_data('AuthPasswordReset', 'hash') == ''
+        assert u.get_tool_data('AuthPasswordReset', 'hash_expiry') == ''
 
     @td.with_user_project('test-admin')
     def test_change_password(self):
@@ -633,17 +633,17 @@ class TestAuth(TestController):
                           })
 
         # Confirm password was changed.
-        assert_not_equal(old_pass, user.get_pref('password'))
+        assert old_pass != user.get_pref('password')
 
         # Confirm any existing tokens were reset.
-        assert_equal(user.get_tool_data('AuthPasswordReset', 'hash'), '')
-        assert_equal(user.get_tool_data('AuthPasswordReset', 'hash_expiry'), '')
+        assert user.get_tool_data('AuthPasswordReset', 'hash') == ''
+        assert user.get_tool_data('AuthPasswordReset', 'hash_expiry') == ''
 
         # Confirm an email was sent
         tasks = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendsimplemail')).all()
-        assert_equal(len(tasks), 1)
-        assert_equal(tasks[0].kwargs['subject'], 'Password Changed')
-        assert_in('The password for your', tasks[0].kwargs['text'])
+        assert len(tasks) == 1
+        assert tasks[0].kwargs['subject'] == 'Password Changed'
+        assert 'The password for your' in tasks[0].kwargs['text']
 
     @patch('allura.lib.plugin.AuthenticationProvider.hibp_password_check_enabled', Mock(return_value=True))
     @td.with_user_project('test-admin')
@@ -677,7 +677,7 @@ class TestAuth(TestController):
 
         # Confirm password was changed.
         user = M.User.by_username('test-admin')
-        assert_not_equal(old_pass, user.get_pref('password'))
+        assert old_pass != user.get_pref('password')
 
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')
@@ -688,7 +688,7 @@ class TestAuth(TestController):
         # check preconditions of test data
         assert 'test@example.com' not in r
         assert 'test-admin@users.localhost' in r
-        assert_equal(M.User.query.get(username='test-admin').get_pref('email_address'),
+        assert (M.User.query.get(username='test-admin').get_pref('email_address') ==
                      'test-admin@users.localhost')
 
         # add test@example
@@ -706,7 +706,7 @@ class TestAuth(TestController):
         r = self.app.get('/auth/preferences/')
         assert 'test@example.com' in r
         user = M.User.query.get(username='test-admin')
-        assert_equal(user.get_pref('email_address'), 'test-admin@users.localhost')
+        assert user.get_pref('email_address') == 'test-admin@users.localhost'
 
         # remove test-admin@users.localhost
         with td.audits('Email address deleted: test-admin@users.localhost', user=True):
@@ -725,14 +725,14 @@ class TestAuth(TestController):
 
         # assert 'email_removed' notification email sent
         args, kwargs = sendsimplemail.post.call_args
-        assert_equal(kwargs['toaddr'], user._id)
-        assert_equal(kwargs['subject'], 'Email Address Removed')
+        assert kwargs['toaddr'] == user._id
+        assert kwargs['subject'] == 'Email Address Removed'
 
         r = self.app.get('/auth/preferences/')
         assert 'test-admin@users.localhost' not in r
         # preferred address has not changed if email is not verified
         user = M.User.query.get(username='test-admin')
-        assert_equal(user.get_pref('email_address'), None)
+        assert user.get_pref('email_address') == None
 
         with td.audits('Display Name changed Test Admin => Admin', user=True):
             r = self.app.post('/auth/preferences/update',
@@ -756,22 +756,22 @@ class TestAuth(TestController):
         r = self.app.post('/auth/preferences/update_emails',
                           params=new_email_params,
                           extra_environ=dict(username='test-admin'))
-        assert_in('You must provide your current password to claim new email', self.webflash(r))
-        assert_not_in('test@example.com', r.follow())
+        assert 'You must provide your current password to claim new email' in self.webflash(r)
+        assert 'test@example.com' not in r.follow()
         new_email_params['password'] = 'bad pass'
 
         r = self.app.post('/auth/preferences/update_emails',
                           params=new_email_params,
                           extra_environ=dict(username='test-admin'))
-        assert_in('You must provide your current password to claim new email', self.webflash(r))
-        assert_not_in('test@example.com', r.follow())
+        assert 'You must provide your current password to claim new email' in self.webflash(r)
+        assert 'test@example.com' not in r.follow()
         new_email_params['password'] = 'foo'  # valid password
 
         r = self.app.post('/auth/preferences/update_emails',
                           params=new_email_params,
                           extra_environ=dict(username='test-admin'))
-        assert_not_in('You must provide your current password to claim new email', self.webflash(r))
-        assert_in('test@example.com', r.follow())
+        assert 'You must provide your current password to claim new email' not in self.webflash(r)
+        assert 'test@example.com' in r.follow()
 
         # Change primary address
         change_primary_params = {
@@ -782,28 +782,28 @@ class TestAuth(TestController):
         r = self.app.post('/auth/preferences/update_emails',
                           params=change_primary_params,
                           extra_environ=dict(username='test-admin'))
-        assert_in('You must provide your current password to change primary address', self.webflash(r))
-        assert_equal(M.User.by_username('test-admin').get_pref('email_address'), 'test-admin@users.localhost')
+        assert 'You must provide your current password to change primary address' in self.webflash(r)
+        assert M.User.by_username('test-admin').get_pref('email_address') == 'test-admin@users.localhost'
         change_primary_params['password'] = 'bad pass'
 
         r = self.app.post('/auth/preferences/update_emails',
                           params=change_primary_params,
                           extra_environ=dict(username='test-admin'))
-        assert_in('You must provide your current password to change primary address', self.webflash(r))
-        assert_equal(M.User.by_username('test-admin').get_pref('email_address'), 'test-admin@users.localhost')
+        assert 'You must provide your current password to change primary address' in self.webflash(r)
+        assert M.User.by_username('test-admin').get_pref('email_address') == 'test-admin@users.localhost'
         change_primary_params['password'] = 'foo'  # valid password
 
         self.app.get('/auth/preferences/')  # let previous 'flash' message cookie get used up
         r = self.app.post('/auth/preferences/update_emails',
                           params=change_primary_params,
                           extra_environ=dict(username='test-admin'))
-        assert_not_in('You must provide your current password to change primary address', self.webflash(r))
-        assert_equal(M.User.by_username('test-admin').get_pref('email_address'), 'test@example.com')
+        assert 'You must provide your current password to change primary address' not in self.webflash(r)
+        assert M.User.by_username('test-admin').get_pref('email_address') == 'test@example.com'
 
         # assert 'email added' notification email sent using original primary addr
         args, kwargs = sendsimplemail.post.call_args
-        assert_equal(kwargs['toaddr'], 'test-admin@users.localhost')
-        assert_equal(kwargs['subject'], 'Primary Email Address Changed')
+        assert kwargs['toaddr'] == 'test-admin@users.localhost'
+        assert kwargs['subject'] == 'Primary Email Address Changed'
 
         # Remove email
         remove_email_params = {
@@ -817,20 +817,20 @@ class TestAuth(TestController):
         r = self.app.post('/auth/preferences/update_emails',
                           params=remove_email_params,
                           extra_environ=dict(username='test-admin'))
-        assert_in('You must provide your current password to delete an email', self.webflash(r))
-        assert_in('test@example.com', r.follow())
+        assert 'You must provide your current password to delete an email' in self.webflash(r)
+        assert 'test@example.com' in r.follow()
         remove_email_params['password'] = 'bad pass'
         r = self.app.post('/auth/preferences/update_emails',
                           params=remove_email_params,
                           extra_environ=dict(username='test-admin'))
-        assert_in('You must provide your current password to delete an email', self.webflash(r))
-        assert_in('test@example.com', r.follow())
+        assert 'You must provide your current password to delete an email' in self.webflash(r)
+        assert 'test@example.com' in r.follow()
         remove_email_params['password'] = 'foo'  # vallid password
         r = self.app.post('/auth/preferences/update_emails',
                           params=remove_email_params,
                           extra_environ=dict(username='test-admin'))
-        assert_not_in('You must provide your current password to delete an email', self.webflash(r))
-        assert_not_in('test@example.com', r.follow())
+        assert 'You must provide your current password to delete an email' not in self.webflash(r)
+        assert 'test@example.com' not in r.follow()
 
     @td.with_user_project('test-admin')
     def test_prefs_subscriptions(self):
@@ -938,10 +938,10 @@ class TestAuth(TestController):
         r = self.app.post('/auth/save_new',
                           params=dict(username='AAA', pw='123',
                                       _session_id=self.app.cookies['_session_id']))
-        assert_in('Enter a value 6 characters long or more', r)
-        assert_in('Usernames must include only small letters, numbers, '
+        assert 'Enter a value 6 characters long or more' in r
+        assert ('Usernames must include only small letters, numbers, '
                   'and dashes. They must also start with a letter and be '
-                  'at least 3 characters long.', r)
+                  'at least 3 characters long.' in r)
         r = self.app.post(
             '/auth/save_new',
             params=dict(
@@ -985,7 +985,7 @@ class TestAuth(TestController):
                 ))
             user = M.User.query.get(username='aaa')
             assert not user.pending
-            assert_equal(M.Project.query.find({'name': 'u/aaa'}).count(), 1)
+            assert M.Project.query.find({'name': 'u/aaa'}).count() == 1
         with h.push_config(config, **{'auth.require_email_addr': 'true'}):
             self.app.post(
                 '/auth/save_new',
@@ -999,7 +999,7 @@ class TestAuth(TestController):
                 ))
             user = M.User.query.get(username='bbb')
             assert user.pending
-            assert_equal(M.Project.query.find({'name': 'u/bbb'}).count(), 0)
+            assert M.Project.query.find({'name': 'u/bbb'}).count() == 0
 
     def test_verify_email(self):
         with h.push_config(config, **{'auth.require_email_addr': 'true'}):
@@ -1024,7 +1024,7 @@ class TestAuth(TestController):
             assert not user.pending
             assert em.confirmed
             assert user.get_pref('email_address')
-            assert_equal(M.Project.query.find({'name': 'u/aaa'}).count(), 1)
+            assert M.Project.query.find({'name': 'u/aaa'}).count() == 1
 
     def test_create_account_disabled_header_link(self):
         with h.push_config(config, **{'auth.allow_user_registration': 'false'}):
@@ -1085,7 +1085,7 @@ class TestAuth(TestController):
         assert not user.disabled
         r = self.app.get('/p/test/admin/',
                          extra_environ={'username': 'test-admin'})
-        assert_equal(r.status_int, 200, 'Redirect to %s' % r.location)
+        assert r.status_int == 200, 'Redirect to %s' % r.location
         user.disabled = True
         sess.save(user)
         sess.flush()
@@ -1093,8 +1093,8 @@ class TestAuth(TestController):
         assert user.disabled
         r = self.app.get('/p/test/admin/',
                          extra_environ={'username': 'test-admin'})
-        assert_equal(r.status_int, 302)
-        assert_equal(r.location, 'http://localhost/auth/?return_to=%2Fp%2Ftest%2Fadmin%2F')
+        assert r.status_int == 302
+        assert r.location == 'http://localhost/auth/?return_to=%2Fp%2Ftest%2Fadmin%2F'
 
     def test_no_open_return_to(self):
         r = self.app.get('/auth/logout').follow().follow()
@@ -1104,28 +1104,28 @@ class TestAuth(TestController):
             _session_id=self.app.cookies['_session_id']),
             antispam=True
         )
-        assert_equal(r.location, 'http://localhost/foo')
+        assert r.location == 'http://localhost/foo'
 
         r = self.app.get('/auth/logout')
         r = self.app.post('/auth/do_login', antispam=True, params=dict(
             username='test-user', password='foo',
             return_to='http://localhost/foo',
             _session_id=self.app.cookies['_session_id']))
-        assert_equal(r.location, 'http://localhost/foo')
+        assert r.location == 'http://localhost/foo'
 
         r = self.app.get('/auth/logout')
         r = self.app.post('/auth/do_login', antispam=True, params=dict(
             username='test-user', password='foo',
             return_to='http://example.com/foo',
             _session_id=self.app.cookies['_session_id'])).follow()
-        assert_equal(r.location, 'http://localhost/dashboard')
+        assert r.location == 'http://localhost/dashboard'
 
         r = self.app.get('/auth/logout')
         r = self.app.post('/auth/do_login', antispam=True, params=dict(
             username='test-user', password='foo',
             return_to='//example.com/foo',
             _session_id=self.app.cookies['_session_id'])).follow()
-        assert_equal(r.location, 'http://localhost/dashboard')
+        assert r.location == 'http://localhost/dashboard'
 
     def test_no_injected_headers_in_return_to(self):
         r = self.app.get('/auth/logout').follow().follow()
@@ -1136,28 +1136,28 @@ class TestAuth(TestController):
             _session_id=self.app.cookies['_session_id']),
             antispam=True
         )
-        assert_equal(r.location, 'http://localhost/')
-        assert_not_equal(r.content_length, 777)
+        assert r.location == 'http://localhost/'
+        assert r.content_length != 777
 
 
 class TestAuthRest(TestRestApiBase):
 
     def test_tools_list_anon(self):
         resp = self.api_get('/rest/auth/tools/wiki', user='*anonymous')
-        assert_equal(resp.json, {
+        assert resp.json == {
             'tools': []
-        })
+        }
 
     def test_tools_list_invalid_tool(self):
         resp = self.api_get('/rest/auth/tools/af732q9547235')
-        assert_equal(resp.json, {
+        assert resp.json == {
             'tools': []
-        })
+        }
 
     @td.with_tool('test', 'Wiki', mount_point='docs', mount_label='Documentation')
     def test_tools_list_wiki(self):
         resp = self.api_get('/rest/auth/tools/wiki')
-        assert_equal(resp.json, {
+        assert resp.json == {
             'tools': [
                 {
                     'mount_label': 'Wiki',
@@ -1176,7 +1176,7 @@ class TestAuthRest(TestRestApiBase):
                     'api_url': 'http://localhost/rest/p/test/docs/',
                 },
             ]
-        })
+        }
 
 
 class TestPreferences(TestController):
@@ -1259,8 +1259,8 @@ class TestPreferences(TestController):
                                   ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 1
-        assert_equal(user.socialnetworks[0].socialnetwork, socialnetwork)
-        assert_equal(user.socialnetworks[0].accounturl, accounturl)
+        assert user.socialnetworks[0].socialnetwork == socialnetwork
+        assert user.socialnetworks[0].accounturl == accounturl
 
         # Add second social network account
         socialnetwork2 = 'Twitter'
@@ -1272,8 +1272,8 @@ class TestPreferences(TestController):
                                   ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 2
-        assert_in({'socialnetwork': socialnetwork, 'accounturl': accounturl}, user.socialnetworks)
-        assert_in({'socialnetwork': socialnetwork2, 'accounturl': accounturl2}, user.socialnetworks)
+        assert {'socialnetwork': socialnetwork, 'accounturl': accounturl} in user.socialnetworks
+        assert {'socialnetwork': socialnetwork2, 'accounturl': accounturl2} in user.socialnetworks
 
         # Remove first social network account
         self.app.post('/auth/user_info/contacts/remove_social_network',
@@ -1283,7 +1283,7 @@ class TestPreferences(TestController):
                                   ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 1
-        assert_in({'socialnetwork': socialnetwork2, 'accounturl': accounturl2}, user.socialnetworks)
+        assert {'socialnetwork': socialnetwork2, 'accounturl': accounturl2} in user.socialnetworks
 
         # Add empty social network account
         self.app.post('/auth/user_info/contacts/add_social_network',
@@ -1292,7 +1292,7 @@ class TestPreferences(TestController):
                                   ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 1
-        assert_in({'socialnetwork': socialnetwork2, 'accounturl': accounturl2}, user.socialnetworks)
+        assert {'socialnetwork': socialnetwork2, 'accounturl': accounturl2} in user.socialnetworks
 
         # Add invalid social network account
         self.app.post('/auth/user_info/contacts/add_social_network',
@@ -1301,7 +1301,7 @@ class TestPreferences(TestController):
                                   ))
         user = M.User.query.get(username='test-admin')
         assert len(user.socialnetworks) == 1
-        assert_in({'socialnetwork': socialnetwork2, 'accounturl': accounturl2}, user.socialnetworks)
+        assert {'socialnetwork': socialnetwork2, 'accounturl': accounturl2} in user.socialnetworks
 
         # Add telephone number
         telnumber = '+3902123456'
@@ -1389,8 +1389,8 @@ class TestPreferences(TestController):
         user = M.User.query.get(username='test-admin')
         timeslot2dict = dict(week_day=weekday2, start_time=starttime2, end_time=endtime2)
         assert len(user.availability) == 2
-        assert_in(timeslot1dict, user.get_availability_timeslots())
-        assert_in(timeslot2dict, user.get_availability_timeslots())
+        assert timeslot1dict in user.get_availability_timeslots()
+        assert timeslot2dict in user.get_availability_timeslots()
 
         # Remove availability timeslot
         r = self.app.post('/auth/user_info/availability/remove_timeslot',
@@ -1446,8 +1446,8 @@ class TestPreferences(TestController):
         user = M.User.query.get(username='test-admin')
         period2dict = dict(start_date=startdate2, end_date=enddate2)
         assert len(user.inactiveperiod) == 2
-        assert_in(period1dict, user.get_inactive_periods())
-        assert_in(period2dict, user.get_inactive_periods())
+        assert period1dict in user.get_inactive_periods()
+        assert period2dict in user.get_inactive_periods()
 
         # Remove first inactivity period
         r = self.app.post(
@@ -1558,7 +1558,7 @@ class TestPreferences(TestController):
         with mock.patch.object(plugin.UserPreferencesProvider, 'get') as upp_get:
             upp_get.return_value = MyPP()
             r = self.app.get('/auth/new_page')
-            assert_equal(r.text, 'new page')
+            assert r.text == 'new page'
             self.app.get('/auth/not_page', status=404)
 
 
@@ -1624,7 +1624,7 @@ class TestPasswordReset(TestController):
             hash = user.get_tool_data('AuthPasswordReset', 'hash')
             assert hash is not None
             args, kwargs = sendmail.post.call_args
-            assert_equal(kwargs['toaddr'], self.test_primary_email)
+            assert kwargs['toaddr'] == self.test_primary_email
 
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')
@@ -1644,7 +1644,7 @@ class TestPasswordReset(TestController):
             hash = user.get_tool_data('AuthPasswordReset', 'hash')
             assert hash is not None
             args, kwargs = sendmail.post.call_args
-            assert_equal(kwargs['toaddr'], email1.email)
+            assert kwargs['toaddr'] == email1.email
 
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')
@@ -1684,9 +1684,9 @@ To update your password on %s, please visit the following URL:
 
         # load reset form and fill it out
         r = self.app.get('/auth/forgotten_password/%s' % hash)
-        assert_in('Enter a new password for: test-admin', r)
-        assert_in('New Password:', r)
-        assert_in('New Password (again):', r)
+        assert 'Enter a new password for: test-admin' in r
+        assert 'New Password:' in r
+        assert 'New Password (again):' in r
         form = r.forms[0]
         form['pw'] = form['pw2'] = new_password = '154321'
         with td.audits(r'Password changed \(through recovery process\)', user=True):
@@ -1695,21 +1695,21 @@ To update your password on %s, please visit the following URL:
 
         # verify 'Password Changed' email sent
         args, kwargs = sendsimplemail.post.call_args
-        assert_equal(kwargs['toaddr'], user._id)
-        assert_equal(kwargs['subject'], 'Password Changed')
+        assert kwargs['toaddr'] == user._id
+        assert kwargs['subject'] == 'Password Changed'
 
         # confirm password changed and works
         user = M.User.query.get(username='test-admin')
-        assert_not_equal(old_pw_hash, user.password)
+        assert old_pw_hash != user.password
         provider = plugin.LocalAuthenticationProvider(None)
-        assert_true(provider._validate_password(user, new_password))
+        assert provider._validate_password(user, new_password)
 
         # confirm reset fields cleared
         user = M.User.query.get(username='test-admin')
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
         hash_expiry = user.get_tool_data('AuthPasswordReset', 'hash_expiry')
-        assert_equal(hash, '')
-        assert_equal(hash_expiry, '')
+        assert hash == ''
+        assert hash_expiry == ''
 
         # confirm can log in now in same session
         r = r.follow()
@@ -1739,16 +1739,16 @@ To update your password on %s, please visit the following URL:
         user.set_tool_data('AuthPasswordReset',
                            hash_expiry=datetime(2000, 10, 10))
         r = self.app.get('/auth/forgotten_password/%s' % hash.encode('utf-8'))
-        assert_in('Unable to process reset, please try again', r.follow().text)
+        assert 'Unable to process reset, please try again' in r.follow().text
         r = self.app.post('/auth/set_new_password/%s' %
                           hash.encode('utf-8'), {'pw': '154321', 'pw2': '154321',
                                                  '_session_id': self.app.cookies['_session_id'],
                                                  })
-        assert_in('Unable to process reset, please try again', r.follow().text)
+        assert 'Unable to process reset, please try again' in r.follow().text
 
     def test_hash_invalid(self):
         r = self.app.get('/auth/forgotten_password/123412341234', status=302)
-        assert_in('Unable to process reset, please try again', r.follow().text)
+        assert 'Unable to process reset, please try again' in r.follow().text
 
     @patch('allura.lib.plugin.AuthenticationProvider')
     def test_provider_disabled(self, AP):
@@ -1799,7 +1799,7 @@ To update your password on %s, please visit the following URL:
         # confirm password changed and works
         user = M.User.query.get(username='test-admin')
         provider = plugin.LocalAuthenticationProvider(None)
-        assert_true(provider._validate_password(user, new_password))
+        assert provider._validate_password(user, new_password)
 
         # confirm can log in now in same session
         r = r.follow()
@@ -1823,7 +1823,7 @@ class TestOAuth(TestController):
                                   }).follow()
         assert 'oautstapp' in r
         # deregister
-        assert_equal(r.forms[0].action, 'deregister')
+        assert r.forms[0].action == 'deregister'
         r.forms[0].submit()
         r = self.app.get('/auth/oauth/')
         assert 'oautstapp' not in r
@@ -1836,24 +1836,24 @@ class TestOAuth(TestController):
                                   '_session_id': self.app.cookies['_session_id'],
                                   }, status=302)
         r = self.app.get('/auth/oauth/')
-        assert_equal(r.forms[1].action, 'generate_access_token')
+        assert r.forms[1].action == 'generate_access_token'
         r = r.forms[1].submit(extra_environ={'username': 'test-user'})  # not the right user
-        assert_in("Invalid app ID", self.webflash(r))                   # gets an error
+        assert "Invalid app ID" in self.webflash(r)                   # gets an error
         r = self.app.get('/auth/oauth/')                                # do it again
         r = r.forms[1].submit()                                         # as correct user
-        assert_equal('', self.webflash(r))
+        assert '' == self.webflash(r)
 
         r = self.app.get('/auth/oauth/')
         assert 'Bearer Token:' in r
-        assert_not_equal(
-            M.OAuthAccessToken.for_user(M.User.by_username('test-admin')), [])
+        assert (
+            M.OAuthAccessToken.for_user(M.User.by_username('test-admin')) != [])
         # revoke
-        assert_equal(r.forms[0].action, 'revoke_access_token')
+        assert r.forms[0].action == 'revoke_access_token'
         r.forms[0].submit()
         r = self.app.get('/auth/oauth/')
-        assert_not_equal(r.forms[0].action, 'revoke_access_token')
-        assert_equal(
-            M.OAuthAccessToken.for_user(M.User.by_username('test-admin')), [])
+        assert r.forms[0].action != 'revoke_access_token'
+        assert (
+            M.OAuthAccessToken.for_user(M.User.by_username('test-admin')) == [])
 
     def test_interactive(self):
         user = M.User.by_username('test-admin')
@@ -2140,8 +2140,8 @@ class TestOAuthAccessToken(TestController):
         oauth_params = dict(self.oauth_params, signature_type=signature_type)
         r = self.app.get(*oauth1_webtest('/rest/oauth/access_token', self.oauth_params))
         atok = parse_qs(r.text)
-        assert_equal(len(atok['oauth_token']), 1)
-        assert_equal(len(atok['oauth_token_secret']), 1)
+        assert len(atok['oauth_token']) == 1
+        assert len(atok['oauth_token_secret']) == 1
 
     def test_access_token_ok_by_query(self):
         self.test_access_token_ok(signature_type='query')
@@ -2152,8 +2152,8 @@ class TestDisableAccount(TestController):
         r = self.app.get(
             '/auth/disable/',
             extra_environ={'username': '*anonymous'})
-        assert_equal(r.status_int, 302)
-        assert_equal(r.location,
+        assert r.status_int == 302
+        assert (r.location ==
                      'http://localhost/auth/?return_to=%2Fauth%2Fdisable%2F')
 
     def test_lists_user_projects(self):
@@ -2162,8 +2162,8 @@ class TestDisableAccount(TestController):
         for p in user.my_projects_by_role_name('Admin'):
             if p.name == 'u/test-admin':
                 continue
-            assert_in(p.name, r)
-            assert_in(p.url(), r)
+            assert p.name in r
+            assert p.url() in r
 
     def test_has_asks_password(self):
         r = self.app.get('/auth/disable/')
@@ -2174,21 +2174,21 @@ class TestDisableAccount(TestController):
         self.app.get('/').follow()  # establish session
         r = self.app.post('/auth/disable/do_disable', {'password': 'bad',
                                                        '_session_id': self.app.cookies['_session_id'], })
-        assert_in('Invalid password', r)
+        assert 'Invalid password' in r
         user = M.User.by_username('test-admin')
-        assert_equal(user.disabled, False)
+        assert user.disabled == False
 
     def test_disable(self):
         self.app.get('/').follow()  # establish session
         r = self.app.post('/auth/disable/do_disable', {'password': 'foo',
                                                        '_session_id': self.app.cookies['_session_id'], })
-        assert_equal(r.status_int, 302)
-        assert_equal(r.location, 'http://localhost/')
+        assert r.status_int == 302
+        assert r.location == 'http://localhost/'
         flash = json.loads(self.webflash(r))
-        assert_equal(flash['status'], 'ok')
-        assert_equal(flash['message'], 'Your account was successfully disabled!')
+        assert flash['status'] == 'ok'
+        assert flash['message'] == 'Your account was successfully disabled!'
         user = M.User.by_username('test-admin')
-        assert_equal(user.disabled, True)
+        assert user.disabled == True
 
 
 class TestPasswordExpire(TestController):
@@ -2204,14 +2204,14 @@ class TestPasswordExpire(TestController):
 
     def assert_redirects(self, where='/'):
         resp = self.app.get(where, extra_environ={'username': 'test-user'}, status=302)
-        assert_equal(resp.location, 'http://localhost/auth/pwd_expired?' + urlencode({'return_to': where}))
+        assert resp.location == 'http://localhost/auth/pwd_expired?' + urlencode({'return_to': where})
 
     def assert_not_redirects(self, where='/neighborhood'):
         self.app.get(where, extra_environ={'username': 'test-user'}, status=200)
 
     def test_disabled(self):
         r = self.login()
-        assert_false(r.session.get('pwd-expired'))
+        assert not r.session.get('pwd-expired')
         self.assert_not_redirects()
 
     def expired(self, r):
@@ -2228,12 +2228,12 @@ class TestPasswordExpire(TestController):
 
         with h.push_config(config, **{'auth.pwdexpire.days': 180}):
             r = self.login()
-            assert_false(self.expired(r))
+            assert not self.expired(r)
             self.assert_not_redirects()
 
         with h.push_config(config, **{'auth.pwdexpire.days': 90}):
             r = self.login()
-            assert_true(self.expired(r))
+            assert self.expired(r)
             self.assert_redirects()
 
     def test_before(self):
@@ -2243,31 +2243,31 @@ class TestPasswordExpire(TestController):
         before = calendar.timegm(before.timetuple())
         with h.push_config(config, **{'auth.pwdexpire.before': before}):
             r = self.login()
-            assert_false(self.expired(r))
+            assert not self.expired(r)
             self.assert_not_redirects()
 
         before = datetime.utcnow() - timedelta(days=90)
         before = calendar.timegm(before.timetuple())
         with h.push_config(config, **{'auth.pwdexpire.before': before}):
             r = self.login()
-            assert_true(self.expired(r))
+            assert self.expired(r)
             self.assert_redirects()
 
     def test_logout(self):
         self.set_expire_for_user()
         with h.push_config(config, **{'auth.pwdexpire.days': 90}):
             r = self.login()
-            assert_true(self.expired(r))
+            assert self.expired(r)
             self.assert_redirects()
             r = self.app.get('/auth/logout', extra_environ={'username': 'test-user'})
-            assert_false(self.expired(r))
+            assert not self.expired(r)
             self.assert_not_redirects()
 
     def test_change_pwd(self):
         self.set_expire_for_user()
         with h.push_config(config, **{'auth.pwdexpire.days': 90}):
             r = self.login()
-            assert_true(self.expired(r))
+            assert self.expired(r)
             self.assert_redirects()
 
             user = M.User.by_username('test-user')
@@ -2279,28 +2279,28 @@ class TestPasswordExpire(TestController):
             f['pw'] = 'qwerty'
             f['pw2'] = 'qwerty'
             r = f.submit(extra_environ={'username': 'test-user'}, status=302)
-            assert_equal(r.location, 'http://localhost/')
-            assert_false(self.expired(r))
+            assert r.location == 'http://localhost/'
+            assert not self.expired(r)
             user = M.User.by_username('test-user')
-            assert_true(user.last_password_updated > old_update_time)
-            assert_not_equal(user.password, old_password)
+            assert user.last_password_updated > old_update_time
+            assert user.password != old_password
 
             # Can log in with new password and change isn't required anymore
             r = self.login(pwd='qwerty').follow()
-            assert_equal(r.location, 'http://localhost/dashboard')
-            assert_not_in('Invalid login', r)
-            assert_false(self.expired(r))
+            assert r.location == 'http://localhost/dashboard'
+            assert 'Invalid login' not in r
+            assert not self.expired(r)
             self.assert_not_redirects()
 
             # and can't log in with old password
             r = self.login(pwd='foo')
-            assert_in('Invalid login', r)
+            assert 'Invalid login' in r
 
     def test_expired_pwd_change_invalidates_token(self):
         self.set_expire_for_user()
         with h.push_config(config, **{'auth.pwdexpire.days': 90}):
             r = self.login()
-            assert_true(self.expired(r))
+            assert self.expired(r)
             self.assert_redirects()
             user = M.User.by_username('test-user')
             user.set_tool_data('AuthPasswordReset',
@@ -2308,8 +2308,8 @@ class TestPasswordExpire(TestController):
                                hash_expiry="04-08-2020")
             hash = user.get_tool_data('AuthPasswordReset', 'hash')
             hash_expiry = user.get_tool_data('AuthPasswordReset', 'hash_expiry')
-            assert_equal(hash, 'generated_hash_value')
-            assert_equal(hash_expiry, '04-08-2020')
+            assert hash == 'generated_hash_value'
+            assert hash_expiry == '04-08-2020'
             session(user).flush(user)
 
             # Change expired password
@@ -2319,14 +2319,14 @@ class TestPasswordExpire(TestController):
             f['pw'] = 'qwerty'
             f['pw2'] = 'qwerty'
             r = f.submit(extra_environ={'username': 'test-user'}, status=302)
-            assert_equal(r.location, 'http://localhost/')
+            assert r.location == 'http://localhost/'
 
             user = M.User.by_username('test-user')
             hash = user.get_tool_data('AuthPasswordReset', 'hash')
             hash_expiry = user.get_tool_data('AuthPasswordReset', 'hash_expiry')
 
-            assert_equal(hash, '')
-            assert_equal(hash_expiry, '')
+            assert hash == ''
+            assert hash_expiry == ''
 
     def check_validation(self, oldpw, pw, pw2):
         user = M.User.by_username('test-user')
@@ -2338,32 +2338,32 @@ class TestPasswordExpire(TestController):
         f['pw'] = pw
         f['pw2'] = pw2
         r = f.submit(extra_environ={'username': 'test-user'})
-        assert_true(self.expired(r))
+        assert self.expired(r)
         user = M.User.by_username('test-user')
-        assert_equal(user.last_password_updated, old_update_time)
-        assert_equal(user.password, old_password)
+        assert user.last_password_updated == old_update_time
+        assert user.password == old_password
         return r
 
     def test_change_pwd_validation(self):
         self.set_expire_for_user()
         with h.push_config(config, **{'auth.pwdexpire.days': 90}):
             r = self.login()
-            assert_true(self.expired(r))
+            assert self.expired(r)
             self.assert_redirects()
 
             r = self.check_validation('', '', '')
-            assert_in('Please enter a value', r)
+            assert 'Please enter a value' in r
             r = self.check_validation('', 'qwe', 'qwerty')
-            assert_in('Enter a value 6 characters long or more', r)
+            assert 'Enter a value 6 characters long or more' in r
             r = self.check_validation('bad', 'qwerty1', 'qwerty')
-            assert_in('Passwords must match', r)
+            assert 'Passwords must match' in r
             r = self.check_validation('bad', 'qwerty', 'qwerty')
-            assert_in('Incorrect password', self.webflash(r))
-            assert_equal(r.location, 'http://localhost/auth/pwd_expired?return_to=')
+            assert 'Incorrect password' in self.webflash(r)
+            assert r.location == 'http://localhost/auth/pwd_expired?return_to='
 
             with h.push_config(config, **{'auth.min_password_len': 3}):
                 r = self.check_validation('foo', 'foo', 'foo')
-                assert_in('Your old and new password should not be the same', r)
+                assert 'Your old and new password should not be the same' in r
 
     def test_return_to(self):
         return_to = '/p/test/tickets/?milestone=1.0&page=2'
@@ -2371,7 +2371,7 @@ class TestPasswordExpire(TestController):
         with h.push_config(config, **{'auth.pwdexpire.days': 90}):
             r = self.login(query_string='?' + urlencode({'return_to': return_to}))
             # don't go to the return_to yet
-            assert_equal(r.location, 'http://localhost/auth/pwd_expired?' + urlencode({'return_to': return_to}))
+            assert r.location == 'http://localhost/auth/pwd_expired?' + urlencode({'return_to': return_to})
 
             # but if user tries to go directly there anyway, intercept and redirect back
             self.assert_redirects(where=return_to)
@@ -2383,7 +2383,7 @@ class TestPasswordExpire(TestController):
             f['pw2'] = 'qwerty'
             f['return_to'] = return_to
             r = f.submit(extra_environ={'username': 'test-user'}, status=302)
-            assert_equal(r.location, 'http://localhost/p/test/tickets/?milestone=1.0&page=2')
+            assert r.location == 'http://localhost/p/test/tickets/?milestone=1.0&page=2'
 
 
 class TestCSRFProtection(TestController):
@@ -2402,13 +2402,13 @@ class TestCSRFProtection(TestController):
         # regular form submit
         r = self.app.get('/admin/overview')
         r = r.form.submit()
-        assert_equal(r.location, 'http://localhost/admin/overview')
+        assert r.location == 'http://localhost/admin/overview'
 
         # invalid form submit
         r = self.app.get('/admin/overview')
         r.form['_session_id'] = 'bogus'
         r = r.form.submit()
-        assert_equal(r.location, 'http://localhost/auth/')
+        assert r.location == 'http://localhost/auth/'
 
     def test_blocks_invalid_on_login(self):
         r = self.app.get('/auth/')
@@ -2417,7 +2417,7 @@ class TestCSRFProtection(TestController):
 
     def test_token_present_on_first_request(self):
         r = self.app.get('/auth/')
-        assert_true(r.form['_session_id'].value)
+        assert r.form['_session_id'].value
 
 
 class TestTwoFactor(TestController):
@@ -2457,13 +2457,13 @@ class TestTwoFactor(TestController):
     def test_user_disabled(self):
         r = self.app.get('/auth/preferences/')
         info_html = str(r.html.find(attrs={'class': 'preferences multifactor'}))
-        assert_in('disabled', info_html)
+        assert 'disabled' in info_html
 
     def test_user_enabled(self):
         self._init_totp()
         r = self.app.get('/auth/preferences/')
         info_html = str(r.html.find(attrs={'class': 'preferences multifactor'}))
-        assert_in('enabled', info_html)
+        assert 'enabled' in info_html
 
     def test_reconfirm_auth(self):
         from datetime import datetime as real_datetime
@@ -2473,22 +2473,22 @@ class TestTwoFactor(TestController):
             # reconfirm required at first
             datetime.utcnow.return_value = real_datetime(2016, 1, 1, 0, 0, 0)
             r = self.app.get('/auth/preferences/totp_new')
-            assert_in('Password Confirmation', r)
+            assert 'Password Confirmation' in r
 
             # submit form, and its not required
             r.form['password'] = 'foo'
             r = r.form.submit()
-            assert_not_in('Password Confirmation', r)
+            assert 'Password Confirmation' not in r
 
             # still not required
             datetime.utcnow.return_value = real_datetime(2016, 1, 1, 0, 1, 45)
             r = self.app.get('/auth/preferences/totp_new')
-            assert_not_in('Password Confirmation', r)
+            assert 'Password Confirmation' not in r
 
             # required later
             datetime.utcnow.return_value = real_datetime(2016, 1, 1, 0, 2, 3)
             r = self.app.get('/auth/preferences/totp_new')
-            assert_in('Password Confirmation', r)
+            assert 'Password Confirmation' in r
 
     def test_enable_totp(self):
         # create a separate session, for later use in the test
@@ -2498,13 +2498,13 @@ class TestTwoFactor(TestController):
 
         with out_audits(user=True):
             r = self.app.get('/auth/preferences/totp_new')
-            assert_in('Password Confirmation', r)
+            assert 'Password Confirmation' in r
 
         with audits('Visited multifactor new TOTP page', user=True):
             r.form['password'] = 'foo'
             r = r.form.submit()
-            assert_in('Scan this', r)
-            assert_in('Or enter setup key: ', r)
+            assert 'Scan this' in r
+            assert 'Or enter setup key: ' in r
 
         first_key_shown = r.session['totp_new_key']
 
@@ -2512,9 +2512,9 @@ class TestTwoFactor(TestController):
             form = r.forms['totp_set']
             form['code'] = ''
             r = form.submit()
-            assert_in('Invalid', r)
-            assert_in(f'Or enter setup key: {b32encode(first_key_shown).decode()}', r)
-            assert_equal(first_key_shown, r.session['totp_new_key'])  # different keys on each pageload would be bad!
+            assert 'Invalid' in r
+            assert f'Or enter setup key: {b32encode(first_key_shown).decode()}' in r
+            assert first_key_shown == r.session['totp_new_key']  # different keys on each pageload would be bad!
 
         new_totp = TotpService().Totp(r.session['totp_new_key'])
         code = new_totp.generate(time_time())
@@ -2522,20 +2522,19 @@ class TestTwoFactor(TestController):
         form['code'] = code
         with audits('Set up multifactor TOTP', user=True):
             r = form.submit()
-            assert_equal('Two factor authentication has now been set up.', json.loads(self.webflash(r))['message'],
-                         self.webflash(r))
+            assert 'Two factor authentication has now been set up.' == json.loads(self.webflash(r))['message'], self.webflash(r)
 
         tasks = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendsimplemail')).all()
-        assert_equal(len(tasks), 1)
-        assert_equal(tasks[0].kwargs['subject'], 'Two-Factor Authentication Enabled')
-        assert_in('new two-factor authentication', tasks[0].kwargs['text'])
+        assert len(tasks) == 1
+        assert tasks[0].kwargs['subject'] == 'Two-Factor Authentication Enabled'
+        assert 'new two-factor authentication' in tasks[0].kwargs['text']
 
         r = r.follow()
-        assert_in('Recovery Codes', r)
+        assert 'Recovery Codes' in r
 
         # Confirm any pre-existing sessions have to re-authenticate
         r = other_session.app.get('/auth/preferences/')
-        assert_in('/auth/?return_to', r.headers['Location'])
+        assert '/auth/?return_to' in r.headers['Location']
         other_session.tearDown()
 
     def test_reset_totp(self):
@@ -2543,28 +2542,28 @@ class TestTwoFactor(TestController):
 
         # access page
         r = self.app.get('/auth/preferences/totp_new')
-        assert_in('Password Confirmation', r)
+        assert 'Password Confirmation' in r
 
         # reconfirm password to get to it
         r.form['password'] = 'foo'
         r = r.form.submit()
 
         # confirm warning message, and key is not changed yet
-        assert_in('Scan this', r)
-        assert_in('Or enter setup key: ', r)
-        assert_in('this will invalidate your previous', r)
+        assert 'Scan this' in r
+        assert 'Or enter setup key: ' in r
+        assert 'this will invalidate your previous' in r
         current_key = TotpService.get().get_secret_key(M.User.query.get(username='test-admin'))
-        assert_equal(self.sample_key, current_key)
+        assert self.sample_key == current_key
 
         # incorrect submission
         form = r.forms['totp_set']
         form['code'] = ''
         r = form.submit()
-        assert_in('Invalid', r)
+        assert 'Invalid' in r
 
         # still unchanged key
         current_key = TotpService.get().get_secret_key(M.User.query.get(username='test-admin'))
-        assert_equal(self.sample_key, current_key)
+        assert self.sample_key == current_key
 
         # valid submission
         new_key = r.session['totp_new_key']
@@ -2573,13 +2572,12 @@ class TestTwoFactor(TestController):
         form = r.forms['totp_set']
         form['code'] = code
         r = form.submit()
-        assert_equal('Two factor authentication has now been set up.', json.loads(self.webflash(r))['message'],
-                     self.webflash(r))
+        assert 'Two factor authentication has now been set up.' == json.loads(self.webflash(r))['message'], self.webflash(r)
 
         # new key in place
         current_key = TotpService.get().get_secret_key(M.User.query.get(username='test-admin'))
-        assert_equal(new_key, current_key)
-        assert_not_equal(self.sample_key, current_key)
+        assert new_key == current_key
+        assert self.sample_key != current_key
 
     def test_disable(self):
         self._init_totp()
@@ -2592,26 +2590,25 @@ class TestTwoFactor(TestController):
         r = form.submit()
 
         # confirm first, no change
-        assert_in('Password Confirmation', r)
+        assert 'Password Confirmation' in r
         user = M.User.query.get(username='test-admin')
-        assert_equal(user.get_pref('multifactor'), True)
+        assert user.get_pref('multifactor') == True
 
         # confirm submit, everything goes off
         r.form['password'] = 'foo'
         with audits('Disabled multifactor TOTP', user=True):
             r = r.form.submit()
-            assert_equal('Multifactor authentication has now been disabled.', json.loads(self.webflash(r))['message'],
-                         self.webflash(r))
+            assert 'Multifactor authentication has now been disabled.' == json.loads(self.webflash(r))['message'], self.webflash(r)
         user = M.User.query.get(username='test-admin')
-        assert_equal(user.get_pref('multifactor'), False)
-        assert_equal(TotpService().get().get_secret_key(user), None)
-        assert_equal(RecoveryCodeService().get().get_codes(user), [])
+        assert user.get_pref('multifactor') == False
+        assert TotpService().get().get_secret_key(user) == None
+        assert RecoveryCodeService().get().get_codes(user) == []
 
         # email confirmation
         tasks = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendsimplemail')).all()
-        assert_equal(len(tasks), 1)
-        assert_equal(tasks[0].kwargs['subject'], 'Two-Factor Authentication Disabled')
-        assert_in('disabled two-factor authentication', tasks[0].kwargs['text'])
+        assert len(tasks) == 1
+        assert tasks[0].kwargs['subject'] == 'Two-Factor Authentication Disabled'
+        assert 'disabled two-factor authentication' in tasks[0].kwargs['text']
 
     def test_login_totp(self):
         self._init_totp()
@@ -2636,7 +2633,7 @@ class TestTwoFactor(TestController):
         r.form['code'] = 'invalid-code'
         with audits('Multifactor login - invalid code', user=True):
             r = r.form.submit()
-        assert_in('Invalid code', r)
+        assert 'Invalid code' in r
         assert not r.session.get('username')
 
         # use a valid code
@@ -2647,7 +2644,7 @@ class TestTwoFactor(TestController):
             r = r.form.submit()
 
         # confirm login and final page
-        assert_equal(r.session['username'], 'test-admin')
+        assert r.session['username'] == 'test-admin'
         assert r.location.endswith('/p/foo'), r
 
     def test_login_rate_limit(self):
@@ -2669,7 +2666,7 @@ class TestTwoFactor(TestController):
         for i in range(3):
             r.form['code'] = 'invalid-code'
             r = r.form.submit()
-            assert_in('Invalid code', r)
+            assert 'Invalid code' in r
 
         # use a valid code, but it'll hit rate limit
         totp = TotpService().Totp(self.sample_key)
@@ -2678,7 +2675,7 @@ class TestTwoFactor(TestController):
         with audits('Multifactor login - rate limit', user=True):
             r = r.form.submit()
 
-        assert_in('rate limit exceeded', r)
+        assert 'rate limit exceeded' in r
         assert not r.session.get('username')
 
     def test_login_totp_disrupted(self):
@@ -2705,11 +2702,10 @@ class TestTwoFactor(TestController):
         r = r.form.submit()
 
         # sent back to regular login
-        assert_equal('Your multifactor login was disrupted, please start over.',
-                     json.loads(self.webflash(r))['message'],
-                     self.webflash(r))
+        assert ('Your multifactor login was disrupted, please start over.' ==
+                     json.loads(self.webflash(r))['message']), self.webflash(r)
         r = r.follow()
-        assert_in('Password Login', r)
+        assert 'Password Login' in r
 
     def test_login_recovery_code(self):
         self._init_totp()
@@ -2735,7 +2731,7 @@ class TestTwoFactor(TestController):
         # try an invalid code
         r.form['code'] = 'invalid-code'
         r = r.form.submit()
-        assert_in('Invalid code', r)
+        assert 'Invalid code' in r
         assert not r.session.get('username')
 
         # use a valid code
@@ -2748,11 +2744,11 @@ class TestTwoFactor(TestController):
             r = r.form.submit()
 
         # confirm login and final page
-        assert_equal(r.session['username'], 'test-admin')
+        assert r.session['username'] == 'test-admin'
         assert r.location.endswith('/p/foo'), r
 
         # confirm code used up
-        assert_not_in(recovery_code, RecoveryCodeService().get().get_codes(user))
+        assert recovery_code not in RecoveryCodeService().get().get_codes(user)
 
     @patch('allura.lib.plugin.AuthenticationProvider.hibp_password_check_enabled', Mock(return_value=True))
     def test_login_totp_with_hibp(self):
@@ -2785,7 +2781,7 @@ class TestTwoFactor(TestController):
             r = r.form.submit()
 
         # confirm login and final page
-        assert_equal(r.session['username'], 'test-admin')
+        assert r.session['username'] == 'test-admin'
         assert r.location.endswith('/p/foo'), r
 
     def test_view_key(self):
@@ -2793,13 +2789,13 @@ class TestTwoFactor(TestController):
 
         with out_audits(user=True):
             r = self.app.get('/auth/preferences/totp_view')
-            assert_in('Password Confirmation', r)
+            assert 'Password Confirmation' in r
 
         with audits('Viewed multifactor TOTP config page', user=True):
             r.form['password'] = 'foo'
             r = r.form.submit()
-            assert_in('Scan this', r)
-            assert_in(f'Or enter setup key: {self.sample_b32}', r)
+            assert 'Scan this' in r
+            assert f'Or enter setup key: {self.sample_b32}' in r
 
     def test_view_recovery_codes_and_regen(self):
         self._init_totp()
@@ -2807,14 +2803,14 @@ class TestTwoFactor(TestController):
         # reconfirm password
         with out_audits(user=True):
             r = self.app.get('/auth/preferences/multifactor_recovery')
-            assert_in('Password Confirmation', r)
+            assert 'Password Confirmation' in r
 
         # actual visit
         with audits('Viewed multifactor recovery codes', user=True):
             r.form['password'] = 'foo'
             r = r.form.submit()
-            assert_in('Download', r)
-            assert_in('Print', r)
+            assert 'Download' in r
+            assert 'Print' in r
 
         # regenerate codes
         with audits('Regenerated multifactor recovery codes', user=True):
@@ -2822,9 +2818,9 @@ class TestTwoFactor(TestController):
 
         # email confirmation
         tasks = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendsimplemail')).all()
-        assert_equal(len(tasks), 1)
-        assert_equal(tasks[0].kwargs['subject'], 'Two-Factor Recovery Codes Regenerated')
-        assert_in('regenerated', tasks[0].kwargs['text'])
+        assert len(tasks) == 1
+        assert tasks[0].kwargs['subject'] == 'Two-Factor Recovery Codes Regenerated'
+        assert 'regenerated' in tasks[0].kwargs['text']
 
     def test_send_links(self):
         r = self.app.get('/auth/preferences/totp_new')
@@ -2834,7 +2830,7 @@ class TestTwoFactor(TestController):
         r = r.forms['totp_send_link'].submit()
 
         tasks = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendsimplemail')).all()
-        assert_equal(len(tasks), 1)
-        assert_equal(tasks[0].kwargs['subject'], 'Two-Factor Authentication Apps')
-        assert_in('itunes.apple.com', tasks[0].kwargs['text'])
-        assert_in('play.google.com', tasks[0].kwargs['text'])
+        assert len(tasks) == 1
+        assert tasks[0].kwargs['subject'] == 'Two-Factor Authentication Apps'
+        assert 'itunes.apple.com' in tasks[0].kwargs['text']
+        assert 'play.google.com' in tasks[0].kwargs['text']
diff --git a/Allura/allura/tests/functional/test_discuss.py b/Allura/allura/tests/functional/test_discuss.py
index 948a7af93..8dd2934cc 100644
--- a/Allura/allura/tests/functional/test_discuss.py
+++ b/Allura/allura/tests/functional/test_discuss.py
@@ -55,16 +55,16 @@ class TestDiscuss(TestDiscussBase):
         # remove tool-wide subscription, so it doesn't interfere
         M.Mailbox.query.remove(dict(user_id=user._id, app_config_id=thread.app_config_id))
 
-        assert_false(self._is_subscribed(user, thread))
+        assert not self._is_subscribed(user, thread)
         link = self._thread_link()
         params = {
             'threads-0._id': thread_id,
             'threads-0.subscription': 'on'}
         r = self.app.post('/wiki/_discuss/subscribe', params=params)
-        assert_true(self._is_subscribed(user, thread))
+        assert self._is_subscribed(user, thread)
         params = {'threads-0._id': thread_id}
         r = self.app.post('/wiki/_discuss/subscribe', params=params)
-        assert_false(self._is_subscribed(user, thread))
+        assert not self._is_subscribed(user, thread)
 
     def _make_post(self, text):
         thread_link = self._thread_link()
@@ -90,7 +90,7 @@ class TestDiscuss(TestDiscussBase):
         thread_link = self._thread_link()
         r = self._make_post('This is a post')
         assert 'This is a post' in r, r
-        assert_equal(check_spam.call_args[0][0], 'This is a post')
+        assert check_spam.call_args[0][0] == 'This is a post'
 
         post_link = str(
             r.html.find('div', {'class': 'edit_post_form reply'}).find('form')['action'])
@@ -289,7 +289,7 @@ class TestDiscuss(TestDiscussBase):
         post_link = str(
             r.html.find('div', {'class': 'edit_post_form reply'}).find('form')['action'])
         r = self.app.post(post_link + 'moderate', params=dict(spam='spam'))
-        assert_equal(r.json, {"result": "success"})
+        assert r.json == {"result": "success"}
         post = M.Post.query.find().first()
         post_username = post.author().username
         moderate_link = '/p/test/wiki/_discuss/moderate'
@@ -343,15 +343,15 @@ class TestDiscuss(TestDiscussBase):
         post_link = str(
             r.html.find('div', {'class': 'edit_post_form reply'}).find('form')['action'])
         post = M.Post.query.find().first()
-        assert_equal(post.status, 'pending')
+        assert post.status == 'pending'
         r = self.app.get('/wiki/feed.rss')
-        assert_not_in('Post needs moderation!', r)
+        assert 'Post needs moderation!' not in r
 
         self.app.post(post_link + 'moderate', params=dict(approve='approve'))
         post = M.Post.query.find().first()
-        assert_equal(post.status, 'ok')
+        assert post.status == 'ok'
         r = self.app.get('/wiki/feed.rss')
-        assert_in('Post needs moderation!', r)
+        assert 'Post needs moderation!' in r
 
     def test_post_paging(self):
         thread_link = self._thread_link()
diff --git a/Allura/allura/tests/functional/test_gravatar.py b/Allura/allura/tests/functional/test_gravatar.py
index c0155c0bf..f6738e03e 100644
--- a/Allura/allura/tests/functional/test_gravatar.py
+++ b/Allura/allura/tests/functional/test_gravatar.py
@@ -51,7 +51,7 @@ class TestGravatar(TestController):
         email = 'Wolf@example.com'
         url = urlparse(gravatar.url(email=email, rating='x'))
         query = parse_qs(url.query)
-        assert_equal(query,
+        assert (query ==
                      {'rating': ['x']})
 
     @patch.dict(tg.config, {'default_avatar_image': 'https://example.com/img/icon.png'})
@@ -59,5 +59,5 @@ class TestGravatar(TestController):
         email = 'Wolf@example.com'
         url = urlparse(gravatar.url(email=email))
         query = parse_qs(url.query)
-        assert_equal(query,
+        assert (query ==
                      {'r': ['pg'], 'd': ['https://example.com/img/icon.png']})
diff --git a/Allura/allura/tests/functional/test_home.py b/Allura/allura/tests/functional/test_home.py
index 11af5d674..4096a5add 100644
--- a/Allura/allura/tests/functional/test_home.py
+++ b/Allura/allura/tests/functional/test_home.py
@@ -39,22 +39,22 @@ class TestProjectHome(TestController):
                          str(root.html)), 'Missing Server comment'
         nav_links = root.html.find('div', dict(id='top_nav')).findAll('a')
         nav_links = [nl for nl in nav_links if 'add-tool-toggle' not in nl['class']]
-        assert_equal(len(nav_links), len(response.json['menu']))
+        assert len(nav_links) == len(response.json['menu'])
         for nl, entry in zip(nav_links, response.json['menu']):
             assert nl['href'] == entry['url']
 
     @td.with_wiki
     def test_project_nav_with_admin_options(self):
         r = self.app.get('/p/test/_nav.json?admin_options=1')
-        assert_in({
+        assert {
             "text": "Wiki",
             "href": "/p/test/admin/install_tool?tool_name=wiki",
             "tooltip":
                 "Documentation is key to your project and the wiki tool helps make it easy for anyone to contribute."
-        }, r.json['installable_tools'])
+        } in r.json['installable_tools']
         for m in r.json['menu']:
             if m['mount_point'] == 'sub1':
-                assert_equal(m['admin_options'],
+                assert (m['admin_options'] ==
                              [{'className': None,
                                'text': 'Subproject Admin',
                                'href': '/p/test/sub1/admin',
@@ -64,18 +64,18 @@ class TestProjectHome(TestController):
             raise AssertionError('Did not find sub1 subproject in menu results: {}'.format(r.json['menu']))
         for m in r.json['menu']:
             if m['mount_point'] == 'wiki':
-                assert_in({'className': 'admin_modal',
+                assert {'className': 'admin_modal',
                            'text': 'Set Home',
                            'href': '/p/test/admin/wiki/home',
-                           }, m['admin_options'])
-                assert_in({'className': None,
+                           } in m['admin_options']
+                assert {'className': None,
                            'text': 'Permissions',
                            'href': '/p/test/admin/wiki/permissions',
-                           }, m['admin_options'])
-                assert_in({'className': 'admin_modal',
+                           } in m['admin_options']
+                assert {'className': 'admin_modal',
                            'text': 'Delete Everything',
                            'href': '/p/test/admin/wiki/delete',
-                           }, m['admin_options'])
+                           } in m['admin_options']
                 break
         else:
             raise AssertionError('Did not find wiki in menu results: {}'.format(r.json['menu']))
@@ -92,13 +92,13 @@ class TestProjectHome(TestController):
         menu = response.json['menu']
         wiki_group = menu[-2]
         wikis = wiki_group.pop('children')
-        assert_equal({'url': '/p/test/_list/wiki', 'name': 'Wiki \u25be', 'mount_point': None,
-                      'icon': 'tool-wiki', 'tool_name': 'wiki', 'is_anchored': False}, wiki_group)
-        assert_equal(len(wikis), 2)
-        assert_in({'url': '/p/test/wiki/', 'name': 'Wiki', 'mount_point': 'wiki',
-                   'icon': 'tool-wiki', 'tool_name': 'wiki', 'is_anchored': False}, wikis)
-        assert_in({'url': '/p/test/wiki2/', 'name': 'wiki2', 'mount_point': 'wiki2',
-                   'icon': 'tool-wiki', 'tool_name': 'wiki', 'is_anchored': False}, wikis)
+        assert {'url': '/p/test/_list/wiki', 'name': 'Wiki \u25be', 'mount_point': None,
+                      'icon': 'tool-wiki', 'tool_name': 'wiki', 'is_anchored': False} == wiki_group
+        assert len(wikis) == 2
+        assert {'url': '/p/test/wiki/', 'name': 'Wiki', 'mount_point': 'wiki',
+                   'icon': 'tool-wiki', 'tool_name': 'wiki', 'is_anchored': False} in wikis
+        assert {'url': '/p/test/wiki2/', 'name': 'wiki2', 'mount_point': 'wiki2',
+                   'icon': 'tool-wiki', 'tool_name': 'wiki', 'is_anchored': False} in wikis
 
     def test_sitemap_limit_per_tool(self):
         """Test that sitemap is limited to max of 10 items per tool type."""
@@ -112,7 +112,7 @@ class TestProjectHome(TestController):
         response = self.app.get('/p/test/_nav.json')
         menu = response.json['menu']
         wikis = menu[-2]['children']
-        assert_equal(len(wikis), 10)
+        assert len(wikis) == 10
 
     @td.with_wiki
     def test_project_group_nav_more_than_ten(self):
@@ -126,9 +126,9 @@ class TestProjectHome(TestController):
         response = self.app.get('/p/test/_nav.json')
         menu = response.json['menu']
         wiki_menu = [m for m in menu if m['tool_name'] == 'wiki'][0]
-        assert_equal(len(wiki_menu['children']), 10)
-        assert_in({'url': '/p/test/_list/wiki', 'name': 'More...', 'mount_point': None,
-                   'icon': 'tool-wiki', 'tool_name': 'wiki', 'is_anchored': False}, wiki_menu['children'])
+        assert len(wiki_menu['children']) == 10
+        assert {'url': '/p/test/_list/wiki', 'name': 'More...', 'mount_point': None,
+                   'icon': 'tool-wiki', 'tool_name': 'wiki', 'is_anchored': False} in wiki_menu['children']
 
     @td.with_wiki
     def test_neighborhood_home(self):
@@ -144,7 +144,7 @@ class TestProjectHome(TestController):
 
         r = self.app.get('/u/test-admin/sub1/')
         assert r.location.endswith('admin/'), r.location
-        assert_not_in('Profile', r.follow().text)
+        assert 'Profile' not in r.follow().text
 
     def test_user_icon_missing(self):
         r = self.app.get('/u/test-user/user_icon', status=302)
@@ -162,7 +162,7 @@ class TestProjectHome(TestController):
                 short_description='A Test Project'),
                 upload_files=[upload])
         r = self.app.get('/u/test-admin/user_icon')
-        assert_equal(r.content_type, 'image/png')
+        assert r.content_type == 'image/png'
 
     def test_user_search(self):
         r = self.app.get('/p/test/user_search?term=test', status=200)
@@ -190,7 +190,7 @@ class TestProjectHome(TestController):
             'value': 'test-admin',
             'label': 'Test Admin (test-admin)'
         }]
-        assert_equal(j['options'], expected)
+        assert j['options'] == expected
 
     def test_members(self):
         nbhd = M.Neighborhood.query.get(name='Projects')
@@ -246,7 +246,7 @@ class TestProjectHome(TestController):
         pr.install_app(ep_name='Wiki', mount_point='test-sub', mount_label='Test Sub', ordinal='1')
         r = self.app.get('/p/test/test-mount/test-sub/').follow()
         active_link = r.html.findAll('li', {'class': 'selected'})
-        assert_equal(len(active_link), 1)
+        assert len(active_link) == 1
         assert active_link[0].contents[1]['href'] == '/p/test/test-mount/test-sub/'
         assert 'Welcome to your wiki!' in r
 
@@ -271,6 +271,6 @@ class TestProjectHome(TestController):
         # Check if the tool is accessed and not the subproject.
         r = self.app.get('/p/test/test-mount/').follow()
         active_link = r.html.findAll('li', {'class': 'selected'})
-        assert_equal(len(active_link), 1)
+        assert len(active_link) == 1
         assert active_link[0].contents[1]['href'] == '/p/test/test-mount/'
         assert 'Welcome to your wiki!' in r
diff --git a/Allura/allura/tests/functional/test_neighborhood.py b/Allura/allura/tests/functional/test_neighborhood.py
index 038fb21c8..7384dde8f 100644
--- a/Allura/allura/tests/functional/test_neighborhood.py
+++ b/Allura/allura/tests/functional/test_neighborhood.py
@@ -174,21 +174,21 @@ class TestNeighborhood(TestController):
                                       anchored_tools='w!iki:Wiki, tickets:Ticket'),
                           extra_environ=dict(username='root'))
         assert 'error' in self.webflash(r)
-        assert_equal(neighborhood.anchored_tools, 'wiki:Wiki, tickets:Ticket')
+        assert neighborhood.anchored_tools == 'wiki:Wiki, tickets:Ticket'
 
         r = self.app.post('/p/_admin/update',
                           params=dict(name='Projects',
                                       anchored_tools='wiki:Wiki,'),
                           extra_environ=dict(username='root'))
         assert 'error' in self.webflash(r)
-        assert_equal(neighborhood.anchored_tools, 'wiki:Wiki, tickets:Ticket')
+        assert neighborhood.anchored_tools == 'wiki:Wiki, tickets:Ticket'
 
         r = self.app.post('/p/_admin/update',
                           params=dict(name='Projects',
                                       anchored_tools='badname,'),
                           extra_environ=dict(username='root'))
         assert 'error' in self.webflash(r)
-        assert_equal(neighborhood.anchored_tools, 'wiki:Wiki, tickets:Ticket')
+        assert neighborhood.anchored_tools == 'wiki:Wiki, tickets:Ticket'
 
         r = self.app.get('/p/test/admin/overview')
         top_nav = r.html.find(id='top_nav')
@@ -769,10 +769,10 @@ class TestNeighborhood(TestController):
         assert "My home text!" in r
         # check tool options
         opts = p.app_config('wiki').options
-        assert_equal(False, opts.show_discussion)
-        assert_equal(False, opts.show_left_bar)
-        assert_equal(False, opts.show_right_bar)
-        assert_equal("http://foo.com/testtemp/", opts.some_url)
+        assert False == opts.show_discussion
+        assert False == opts.show_left_bar
+        assert False == opts.show_right_bar
+        assert "http://foo.com/testtemp/" == opts.some_url
         # check that custom groups/perms/users were setup correctly
         roles = p.named_roles
         for group in test_groups:
@@ -846,15 +846,15 @@ class TestNeighborhood(TestController):
         for name in ('My+Moz', 'Te%st!', 'ab', 'a' * 16):
             r = self.app.get(
                 '/p/check_names?neighborhood=Projects&project_unixname=%s' % name)
-            assert_equal(
-                r.json,
+            assert (
+                r.json ==
                 {'project_unixname': 'Please use 3-15 small letters, numbers, and dashes.'})
         r = self.app.get(
             '/p/check_names?neighborhood=Projects&project_unixname=mymoz')
-        assert_equal(r.json, {})
+        assert r.json == {}
         r = self.app.get(
             '/p/check_names?neighborhood=Projects&project_unixname=test')
-        assert_equal(r.json,
+        assert (r.json ==
                      {'project_unixname': 'This project name is taken.'})
 
     @td.with_tool('test/sub1', 'Wiki', 'wiki')
@@ -914,8 +914,8 @@ class TestNeighborhood(TestController):
                       extra_environ=dict(username='root'))
         r = self.app.get('/adobe/_admin/accolades',
                          extra_environ=dict(username='root'))
-        assert_in('Winner!', r)
-        assert_in('http://award.org', r)
+        assert 'Winner!' in r
+        assert 'http://award.org' in r
         self.app.get('/adobe/_admin/awards/%s/adobe-1' %
                      foo_id, extra_environ=dict(username='root'))
         self.app.post('/adobe/_admin/awards/%s/adobe-1/revoke' % foo_id,
@@ -991,11 +991,11 @@ class TestPhoneVerificationOnProjectRegistration(TestController):
             r = self.app.get('/p/verify_phone', {'number': '1234567890'})
             expected = {'status': 'error',
                         'error': 'Phone service is not configured'}
-            assert_equal(r.json, expected)
+            assert r.json == expected
             rid = r.session.get('phone_verification.request_id')
             hash = r.session.get('phone_verification.number_hash')
-            assert_equal(rid, None)
-            assert_equal(hash, None)
+            assert rid == None
+            assert hash == None
 
     @patch.object(g, 'phone_service', autospec=True)
     def test_verify_phone(self, phone_service):
@@ -1004,11 +1004,11 @@ class TestPhoneVerificationOnProjectRegistration(TestController):
                 'request_id': 'request-id', 'status': 'ok'}
             r = self.app.get('/p/verify_phone', {'number': '1-555-444-3333'})
             phone_service.verify.assert_called_once_with('15554443333')
-            assert_equal(r.json, {'status': 'ok'})
+            assert r.json == {'status': 'ok'}
             rid = r.session.get('phone_verification.request_id')
             hash = r.session.get('phone_verification.number_hash')
-            assert_equal(rid, 'request-id')
-            assert_equal(hash, 'f9ac49faef45d18746ced08d001e23b179107940')
+            assert rid == 'request-id'
+            assert hash == 'f9ac49faef45d18746ced08d001e23b179107940'
 
     @patch.object(g, 'phone_service', autospec=True)
     def test_verify_phone_escapes_error(self, phone_service):
@@ -1022,7 +1022,7 @@ class TestPhoneVerificationOnProjectRegistration(TestController):
             'status': 'error',
             'error': '&lt;script&gt;alert(&#34;hacked&#34;);&lt;/script&gt;',
         }
-        assert_equal(r.json, expected)
+        assert r.json == expected
 
     @patch.object(g, 'phone_service', autospec=True)
     def test_verify_phone_already_used(self, phone_service):
@@ -1032,10 +1032,10 @@ class TestPhoneVerificationOnProjectRegistration(TestController):
             session(u).flush(u)
             phone_service.verify.return_value = {'request_id': 'request-id', 'status': 'ok'}
             r = self.app.get('/p/verify_phone', {'number': '1-555-444-9999'})
-            assert_equal(r.json, {
+            assert r.json == {
                 'status': 'error',
                 'error': 'That phone number has already been used.'
-            })
+            }
 
     def test_check_phone_verification_no_params(self):
         with h.push_config(config, **{'project.verify_phone': 'true'}):
@@ -1053,12 +1053,12 @@ class TestPhoneVerificationOnProjectRegistration(TestController):
             r = self.app.get('/p/verify_phone', {'number': '1234567890'})
 
             r = self.app.get('/p/check_phone_verification', {'pin': '1234'})
-            assert_equal(r.json, {'status': 'error'})
+            assert r.json == {'status': 'error'}
             phone_service.check.assert_called_once_with(req_id, '1234')
 
             user = M.User.by_username('test-admin')
             hash = user.get_tool_data('phone_verification', 'number_hash')
-            assert_equal(hash, None)
+            assert hash == None
 
     @patch.object(g, 'phone_service', autospec=True)
     def test_check_phone_verification_ok(self, phone_service):
@@ -1072,12 +1072,12 @@ class TestPhoneVerificationOnProjectRegistration(TestController):
             r = self.app.get('/p/verify_phone', {'number': '11234567890'})
 
             r = self.app.get('/p/check_phone_verification', {'pin': '1234'})
-            assert_equal(r.json, {'status': 'ok'})
+            assert r.json == {'status': 'ok'}
             phone_service.check.assert_called_once_with(req_id, '1234')
 
             user = M.User.by_username('test-admin')
             hash = user.get_tool_data('phone_verification', 'number_hash')
-            assert_equal(hash, '54c61c96d5d5aea5254c2d4f41508a938e5501b4')
+            assert hash == '54c61c96d5d5aea5254c2d4f41508a938e5501b4'
 
     @patch.object(g, 'phone_service', autospec=True)
     def test_check_phone_verification_escapes_error(self, phone_service):
@@ -1091,7 +1091,7 @@ class TestPhoneVerificationOnProjectRegistration(TestController):
             'status': 'error',
             'error': '&lt;script&gt;alert(&#34;hacked&#34;);&lt;/script&gt;',
         }
-        assert_equal(r.json, expected)
+        assert r.json == expected
 
     def test_register_phone_not_verified(self):
         with h.push_config(config, **{'project.verify_phone': 'true'}):
@@ -1105,11 +1105,11 @@ class TestPhoneVerificationOnProjectRegistration(TestController):
                 extra_environ=dict(username='test-user'),
                 antispam=True)
             overlay = r.html.find('div', {'id': 'phone_verification_overlay'})
-            assert_not_equal(overlay, None)
+            assert overlay != None
             header = overlay.find('h2')
             iframe = overlay.find('iframe')
-            assert_equal(header.getText(), 'Phone Verification Required')
-            assert_equal(iframe.get('src'), '/p/phone_verification_fragment')
+            assert header.getText() == 'Phone Verification Required'
+            assert iframe.get('src') == '/p/phone_verification_fragment'
 
 
 class TestProjectImport(TestController):
diff --git a/Allura/allura/tests/functional/test_personal_dashboard.py b/Allura/allura/tests/functional/test_personal_dashboard.py
index 411704195..ea28f2ff0 100644
--- a/Allura/allura/tests/functional/test_personal_dashboard.py
+++ b/Allura/allura/tests/functional/test_personal_dashboard.py
@@ -36,12 +36,12 @@ class TestPersonalDashboard(TestController):
 
     def test_dashboard(self):
         r = self.app.get('/dashboard')
-        assert_equal('Test Admin / Dashboard', r.html.find('h1', 'project_title').text.strip())
+        assert 'Test Admin / Dashboard' == r.html.find('h1', 'project_title').text.strip()
         sections = {c for s in r.html.findAll(None, 'profile-section') for c in s['class']}
-        assert_in('tickets', sections)
-        assert_in('projects', sections)
-        assert_in('merge_requests', sections)
-        assert_in('activity', sections)
+        assert 'tickets' in sections
+        assert 'projects' in sections
+        assert 'merge_requests' in sections
+        assert 'activity' in sections
 
     def test_dashboard_sections(self):
         def ep(n):
@@ -55,17 +55,17 @@ class TestPersonalDashboard(TestController):
             with mock.patch.dict(tg.config, order):
                 iep.return_value = eps
                 sections = SectionsUtil.load_sections('personal_dashboard')
-                assert_equal(sections, [
+                assert sections == [
                     eps[1].load(),
                     eps[3].load(),
                     eps[2].load(),
-                    eps[0].load()])
+                    eps[0].load()]
                 r = self.app.get('/dashboard')
-                assert_in('Section a', r.text)
-                assert_in('Section b', r.text)
-                assert_in('Section c', r.text)
-                assert_in('Section d', r.text)
-                assert_not_in('Section f', r.text)
+                assert 'Section a' in r.text
+                assert 'Section b' in r.text
+                assert 'Section c' in r.text
+                assert 'Section d' in r.text
+                assert 'Section f' not in r.text
 
 
 class TestTicketsSection(TrackerTestController):
@@ -80,7 +80,7 @@ class TestTicketsSection(TrackerTestController):
     def test_tickets_section(self):
         response = self.app.get('/dashboard')
         ticket_rows = response.html.find('tbody')
-        assert_in('foo', str(ticket_rows))
+        assert 'foo' in str(ticket_rows)
 
 
 class TestMergeRequestsSection(TestController):
@@ -122,4 +122,4 @@ class TestMergeRequestsSection(TestController):
     def test_merge_requests_section(self):
         r = self.app.get('/dashboard')
         merge_req_rows = r.html.find('tbody')
-        assert_in('test request', str(merge_req_rows))
+        assert 'test request' in str(merge_req_rows)
diff --git a/Allura/allura/tests/functional/test_rest.py b/Allura/allura/tests/functional/test_rest.py
index 94b009fd5..294c0d60e 100644
--- a/Allura/allura/tests/functional/test_rest.py
+++ b/Allura/allura/tests/functional/test_rest.py
@@ -91,7 +91,7 @@ class TestRestHome(TestRestApiBase):
         request.scheme = 'https'
         request.path = '/rest/p/test/wiki'
         r = self.api_post('/rest/p/test/wiki', access_token='foo')
-        assert_equal(r.status_int, 200)
+        assert r.status_int == 200
 
     @mock.patch('allura.controllers.rest.M.OAuthAccessToken')
     @mock.patch('allura.controllers.rest.request')
@@ -181,13 +181,13 @@ class TestRestHome(TestRestApiBase):
 
     def test_project_data(self):
         r = self.api_get('/rest/p/test/')
-        assert_equal(r.json['shortname'], 'test')
-        assert_equal(r.json['name'], 'Test Project')
-        assert_equal(len(r.json['developers']), 1)
+        assert r.json['shortname'] == 'test'
+        assert r.json['name'] == 'Test Project'
+        assert len(r.json['developers']) == 1
         admin_dev = r.json['developers'][0]
-        assert_equal(admin_dev['username'], 'test-admin')
-        assert_equal(admin_dev['name'], 'Test Admin')
-        assert_equal(admin_dev['url'], 'http://localhost/u/test-admin/')
+        assert admin_dev['username'] == 'test-admin'
+        assert admin_dev['name'] == 'Test Admin'
+        assert admin_dev['url'] == 'http://localhost/u/test-admin/'
 
     @td.with_tool('test', 'Tickets', 'bugs')
     @td.with_tool('test', 'Tickets', 'private-bugs')
@@ -202,18 +202,18 @@ class TestRestHome(TestRestApiBase):
 
         # admin sees both 'Tickets' tools
         r = self.api_get('/rest/p/test/')
-        assert_equal(r.json['shortname'], 'test')
+        assert r.json['shortname'] == 'test'
         tool_mounts = [t['mount_point'] for t in r.json['tools']]
-        assert_in('bugs', tool_mounts)
-        assert_in('private-bugs', tool_mounts)
+        assert 'bugs' in tool_mounts
+        assert 'private-bugs' in tool_mounts
 
         # anonymous sees only non-private tool
         r = self.app.get('/rest/p/test/',
                          extra_environ={'username': '*anonymous'})
-        assert_equal(r.json['shortname'], 'test')
+        assert r.json['shortname'] == 'test'
         tool_mounts = [t['mount_point'] for t in r.json['tools']]
-        assert_in('bugs', tool_mounts)
-        assert_not_in('private-bugs', tool_mounts)
+        assert 'bugs' in tool_mounts
+        assert 'private-bugs' not in tool_mounts
 
     def test_neighborhood_has_access_no_params(self):
         r = self.api_get('/rest/p/has_access', status=404)
@@ -225,13 +225,13 @@ class TestRestHome(TestRestApiBase):
         r = self.api_get(
             '/rest/p/has_access?user=babadook&perm=read',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], False)
+        assert r.status_int == 200
+        assert r.json['result'] == False
         r = self.api_get(
             '/rest/p/has_access?user=test-admin&perm=jump',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], False)
+        assert r.status_int == 200
+        assert r.json['result'] == False
 
     def test_neighborhood_has_access_not_admin(self):
         """
@@ -247,26 +247,26 @@ class TestRestHome(TestRestApiBase):
         r = self.api_get(
             '/rest/p/has_access?user=root&perm=update',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], True)
+        assert r.status_int == 200
+        assert r.json['result'] == True
         r = self.api_get(
             '/rest/p/has_access?user=test-user&perm=update',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], False)
+        assert r.status_int == 200
+        assert r.json['result'] == False
 
     def test_neighborhood(self):
         self.api_get('/rest/p/', status=404)
 
     def test_neighborhood_tools(self):
         r = self.api_get('/rest/p/wiki/Home/')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['title'], 'Home')
+        assert r.status_int == 200
+        assert r.json['title'] == 'Home'
 
         r = self.api_get('/rest/p/admin/installable_tools', status=403)
 
         r = self.api_get('/rest/p/admin/installable_tools', user='root')
-        assert_equal(r.status_int, 200)
+        assert r.status_int == 200
         assert [t for t in r.json['tools'] if t['tool_label'] == 'Wiki'], r.json
 
     def test_project_has_access_no_params(self):
@@ -279,13 +279,13 @@ class TestRestHome(TestRestApiBase):
         r = self.api_get(
             '/rest/p/test/has_access?user=babadook&perm=read',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], False)
+        assert r.status_int == 200
+        assert r.json['result'] == False
         r = self.api_get(
             '/rest/p/test/has_access?user=test-admin&perm=jump',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], False)
+        assert r.status_int == 200
+        assert r.json['result'] == False
 
     def test_project_has_access_not_admin(self):
         """
@@ -301,20 +301,20 @@ class TestRestHome(TestRestApiBase):
         r = self.api_get(
             '/rest/p/test/has_access?user=test-admin&perm=update',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], True)
+        assert r.status_int == 200
+        assert r.json['result'] == True
         r = self.api_get(
             '/rest/p/test/has_access?user=test-user&perm=update',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], False)
+        assert r.status_int == 200
+        assert r.json['result'] == False
 
     def test_subproject_has_access(self):
         r = self.api_get(
             '/rest/p/test/sub1/has_access?user=test-admin&perm=update',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], True)
+        assert r.status_int == 200
+        assert r.json['result'] == True
 
     def test_unicode(self):
         self.app.post(
@@ -357,13 +357,13 @@ class TestRestHome(TestRestApiBase):
         }
         with mock.patch.dict(g.entry_points, eps):
             response = self.app.get('/rest/')
-            assert_equal(response.json, {
+            assert response.json == {
                 'site_stats': {
                     'foo_24hr': 42,
                     'bar_24hr': 84,
                     'qux_24hr': 0,
                 },
-            })
+            }
 
     def test_name_validation(self):
         r = self.api_get('/rest/p/test/')
@@ -442,7 +442,7 @@ class TestRestNbhdAddProject(TestRestApiBase):
                           params=json.dumps(project_data),
                           user='root',
                           status=400)
-        assert_in('Required', r.json['error'])
+        assert 'Required' in r.json['error']
 
     def test_add_project_bad_data(self):
         project_data = {
@@ -455,7 +455,7 @@ class TestRestNbhdAddProject(TestRestApiBase):
                           params=json.dumps(project_data),
                           user='root',
                           status=400)
-        assert_in('is not a valid trove category', r.json['error'])
+        assert 'is not a valid trove category' in r.json['error']
 
         # local icon paths are not allowed through web (have to use icon_url)
         project_data = {
@@ -468,7 +468,7 @@ class TestRestNbhdAddProject(TestRestApiBase):
                           params=json.dumps(project_data),
                           user='root',
                           status=400)
-        assert_in('Unrecognized keys in mapping', r.json['error'])
+        assert 'Unrecognized keys in mapping' in r.json['error']
 
     def test_add_project_name_error(self):
         project_data = {
@@ -478,7 +478,7 @@ class TestRestNbhdAddProject(TestRestApiBase):
                           params=json.dumps(project_data),
                           user='root',
                           status=400)
-        assert_equal('This project name is taken.', r.json['error'])
+        assert 'This project name is taken.' == r.json['error']
 
         project_data = {
             "shortname": "/?xyz",
@@ -487,7 +487,7 @@ class TestRestNbhdAddProject(TestRestApiBase):
                           params=json.dumps(project_data),
                           user='root',
                           status=400)
-        assert_in('Please use', r.json['error'])
+        assert 'Please use' in r.json['error']
 
     def test_add_project_create_error(self):
         project_data = {
@@ -500,7 +500,7 @@ class TestRestNbhdAddProject(TestRestApiBase):
                           params=json.dumps(project_data),
                           user='root',
                           status=400)
-        assert_equal("You can't create private projects in the Projects neighborhood", r.json['error'])
+        assert "You can't create private projects in the Projects neighborhood" == r.json['error']
 
     def test_add_project(self):
         project_data = {
@@ -527,18 +527,18 @@ class TestRestNbhdAddProject(TestRestApiBase):
                           params=json.dumps(project_data),
                           user='root',
                           status=201)
-        assert_equal(r.json, {
+        assert r.json == {
             'status': 'success',
             'html_url': 'http://localhost/p/my-new-proj/',
             'url': 'http://localhost/rest/p/my-new-proj/',
-        })
+        }
         p = M.Project.query.get(shortname='my-new-proj')
-        assert_equal(p.name, 'My New Project')
-        assert_equal(len(p.trove_license), 2)
+        assert p.name == 'My New Project'
+        assert len(p.trove_license) == 2
         assert isinstance(p.trove_license[0], ObjectId), p.trove_license[0]
         # these are sensitive fields only admins should be able to set:
-        assert_equal(p.get_tool_data('allura', 'grouping_threshold'), 5)
-        assert_equal(p.admins()[0].username, 'test-admin')
+        assert p.get_tool_data('allura', 'grouping_threshold') == 5
+        assert p.admins()[0].username == 'test-admin'
 
     def test_add_project_automatic_shortname(self):
         # no shortname given, and name "Test" would conflict with existing "test" project
@@ -550,11 +550,11 @@ class TestRestNbhdAddProject(TestRestApiBase):
                           params=json.dumps(project_data),
                           user='root',
                           status=201)
-        assert_equal(r.json, {
+        assert r.json == {
             'status': 'success',
             'html_url': 'http://localhost/p/test1/',
             'url': 'http://localhost/rest/p/test1/',
-        })
+        }
 
 
 class TestDoap(TestRestApiBase):
@@ -571,22 +571,22 @@ class TestDoap(TestRestApiBase):
         project.short_description = 'A Short Description'
         ThreadLocalODMSession.flush_all()
         r = self.app.get('/rest/p/test?doap')
-        assert_equal(r.content_type, 'application/rdf+xml')
+        assert r.content_type == 'application/rdf+xml'
         p = r.xml.find(self.ns + 'Project')
-        assert_equal(p.attrib[self.rdf + 'about'], 'http://localhost/rest/p/test?doap#')
-        assert_equal(p.find(self.ns + 'name').text, 'test')
-        assert_equal(p.find(self.dc + 'title').text, 'Test Project')
-        assert_equal(p.find(self.ns_sf + 'private').text, '0')
-        assert_equal(p.find(self.ns + 'shortdesc').text, 'A Summary')
-        assert_equal(p.find(self.ns + 'description').text, 'A Short Description')
-        assert_equal(p.find(self.ns + 'created').text, project._id.generation_time.strftime('%Y-%m-%d'))
+        assert p.attrib[self.rdf + 'about'] == 'http://localhost/rest/p/test?doap#'
+        assert p.find(self.ns + 'name').text == 'test'
+        assert p.find(self.dc + 'title').text == 'Test Project'
+        assert p.find(self.ns_sf + 'private').text == '0'
+        assert p.find(self.ns + 'shortdesc').text == 'A Summary'
+        assert p.find(self.ns + 'description').text == 'A Short Description'
+        assert p.find(self.ns + 'created').text == project._id.generation_time.strftime('%Y-%m-%d')
 
         maintainers = p.findall(self.ns + 'maintainer')
-        assert_equal(len(maintainers), 1)
+        assert len(maintainers) == 1
         user = maintainers[0].find(self.foaf + 'Person')
-        assert_equal(user.find(self.foaf + 'name').text, 'Test Admin')
-        assert_equal(user.find(self.foaf + 'nick').text, 'test-admin')
-        assert_equal(list(user.find(self.foaf + 'homepage').items())[0][1],
+        assert user.find(self.foaf + 'name').text == 'Test Admin'
+        assert user.find(self.foaf + 'nick').text == 'test-admin'
+        assert (list(user.find(self.foaf + 'homepage').items())[0][1] ==
                      'http://localhost/u/test-admin/')
 
     @td.with_tool('test', 'Tickets', 'bugs')
@@ -607,8 +607,8 @@ class TestDoap(TestRestApiBase):
         tools = [(t.find(self.ns_sf + 'Feature').find(self.ns + 'name').text,
                   list(t.find(self.ns_sf + 'Feature').find(self.foaf + 'page').items())[0][1])
                  for t in tools]
-        assert_in(('Tickets', 'http://localhost/p/test/bugs/'), tools)
-        assert_in(('Tickets', 'http://localhost/p/test/private-bugs/'), tools)
+        assert ('Tickets', 'http://localhost/p/test/bugs/') in tools
+        assert ('Tickets', 'http://localhost/p/test/private-bugs/') in tools
 
         # anonymous sees only non-private tool
         r = self.app.get('/rest/p/test?doap',
@@ -618,25 +618,25 @@ class TestDoap(TestRestApiBase):
         tools = [(t.find(self.ns_sf + 'Feature').find(self.ns + 'name').text,
                   list(t.find(self.ns_sf + 'Feature').find(self.foaf + 'page').items())[0][1])
                  for t in tools]
-        assert_in(('Tickets', 'http://localhost/p/test/bugs/'), tools)
-        assert_not_in(('Tickets', 'http://localhost/p/test/private-bugs/'), tools)
+        assert ('Tickets', 'http://localhost/p/test/bugs/') in tools
+        assert ('Tickets', 'http://localhost/p/test/private-bugs/') not in tools
 
 
 class TestUserProfile(TestRestApiBase):
     @td.with_user_project('test-admin')
     def test_profile_data(self):
         r = self.app.get('/rest/u/test-admin/profile/')
-        assert_equal(r.content_type, 'application/json')
+        assert r.content_type == 'application/json'
         json = r.json
-        assert_equal(json['username'], 'test-admin')
-        assert_equal(json['name'], 'Test Admin')
-        assert_in('availability', json)
-        assert_in('joined', json)
-        assert_in('localization', json)
-        assert_in('projects', json)
-        assert_in('sex', json)
-        assert_in('skills', json)
-        assert_in('skypeaccount', json)
-        assert_in('socialnetworks', json)
-        assert_in('telnumbers', json)
-        assert_in('webpages', json)
+        assert json['username'] == 'test-admin'
+        assert json['name'] == 'Test Admin'
+        assert 'availability' in json
+        assert 'joined' in json
+        assert 'localization' in json
+        assert 'projects' in json
+        assert 'sex' in json
+        assert 'skills' in json
+        assert 'skypeaccount' in json
+        assert 'socialnetworks' in json
+        assert 'telnumbers' in json
+        assert 'webpages' in json
diff --git a/Allura/allura/tests/functional/test_root.py b/Allura/allura/tests/functional/test_root.py
index 83eadf9c5..47d6d23a0 100644
--- a/Allura/allura/tests/functional/test_root.py
+++ b/Allura/allura/tests/functional/test_root.py
@@ -55,15 +55,15 @@ class TestRootController(TestController):
 
     def test_index(self):
         response = self.app.get('/', extra_environ=dict(username='*anonymous'))
-        assert_equal(response.location, 'http://localhost/neighborhood')
+        assert response.location == 'http://localhost/neighborhood'
 
         response = self.app.get('/')
-        assert_equal(response.location, 'http://localhost/dashboard')
+        assert response.location == 'http://localhost/dashboard'
 
     def test_neighborhood(self):
         response = self.app.get('/neighborhood')
-        assert_equal(response.html.find('h2', {'class': 'dark title'}).find('span').contents[
-                     0].strip(), 'All Neighborhoods')
+        assert response.html.find('h2', {'class': 'dark title'}).find('span').contents[
+                     0].strip() == 'All Neighborhoods'
         nbhds = response.html.findAll('div', {'class': 'nbhd_name'})
         assert nbhds[0].find('a').get('href') == '/adobe/'
         cat_links = response.html.find('div', {'id': 'sidebar'}).findAll('li')
@@ -136,7 +136,7 @@ class TestRootController(TestController):
 
         response = self.app.get('/adobe/')
         projects = response.html.findAll('div', {'class': 'list card proj_icon'})
-        assert_equal(len(projects), 2)
+        assert len(projects) == 2
         cat_links = response.html.find('div', {'id': 'sidebar'}).findAll('ul')[1].findAll('li')
         assert len(cat_links) == 3, cat_links
         assert cat_links[0].find('a').get('href') == '/adobe/browse/clustering'
@@ -178,7 +178,7 @@ class TestRootController(TestController):
             callable_name.return_value = 'foo'
             self.app.get('/p/')
             arg = callable_name.call_args[0][0]
-            assert_equal(arg.__wrapped__,
+            assert (arg.__wrapped__ ==
                          NeighborhoodController.index.__wrapped__)
             set_transaction_name.assert_called_with('foo', priority=2)
 
diff --git a/Allura/allura/tests/functional/test_site_admin.py b/Allura/allura/tests/functional/test_site_admin.py
index 819353de0..a68420a43 100644
--- a/Allura/allura/tests/functional/test_site_admin.py
+++ b/Allura/allura/tests/functional/test_site_admin.py
@@ -93,20 +93,20 @@ class TestSiteAdmin(TestController):
         ThreadLocalORMSession.flush_all()
         r = self.app.get('/nf/admin/new_projects', extra_environ=dict(
             username='root'))
-        assert_equal(len(r.html.find('table').findAll('tr')), count - 1)
+        assert len(r.html.find('table').findAll('tr')) == count - 1
 
     def test_new_projects_daterange_filtering(self):
         r = self.app.get('/nf/admin/new_projects', extra_environ=dict(
             username='root'))
         count = len(r.html.find('table').findAll('tr'))
-        assert_equal(count, 7)
+        assert count == 7
 
         filtr = r.forms[0]
         filtr['start-dt'] = '2000/01/01 10:10:10'
         filtr['end-dt'] = '2000/01/01 09:09:09'
         r = filtr.submit()
         count = len(r.html.find('table').findAll('tr'))
-        assert_equal(count, 1)  # only row with headers - no results
+        assert count == 1  # only row with headers - no results
 
     def test_reclone_repo_access(self):
         r = self.app.get('/nf/admin/reclone_repo', extra_environ=dict(
@@ -375,9 +375,9 @@ class TestProjectsSearch(TestController):
         search.site_admin_search.return_value = self.TEST_HIT
         r = self.app.get('/nf/admin/search_projects?q=fake&f=shortname')
         options = [o['value'] for o in r.html.findAll('option')]
-        assert_equal(options, ['shortname', 'name', '__custom__'])
+        assert options == ['shortname', 'name', '__custom__']
         ths = [th.text for th in r.html.findAll('th')]
-        assert_equal(ths, ['Short name', 'Full name', 'Registered', 'Deleted?', 'Details'])
+        assert ths == ['Short name', 'Full name', 'Registered', 'Deleted?', 'Details']
 
     @patch('allura.controllers.site_admin.search')
     def test_additional_fields(self, search):
@@ -386,9 +386,9 @@ class TestProjectsSearch(TestController):
                                       'search.project.additional_display_fields': 'url'}):
             r = self.app.get('/nf/admin/search_projects?q=fake&f=shortname')
         options = [o['value'] for o in r.html.findAll('option')]
-        assert_equal(options, ['shortname', 'name', 'private', 'url', '__custom__'])
+        assert options == ['shortname', 'name', 'private', 'url', '__custom__']
         ths = [th.text for th in r.html.findAll('th')]
-        assert_equal(ths, ['Short name', 'Full name', 'Registered', 'Deleted?', 'url', 'Details'])
+        assert ths == ['Short name', 'Full name', 'Registered', 'Deleted?', 'url', 'Details']
 
 
 class TestUsersSearch(TestController):
@@ -428,10 +428,10 @@ class TestUsersSearch(TestController):
         site_admin_search.return_value = self.TEST_HIT
         r = self.app.get('/nf/admin/search_users?q=fake&f=username')
         options = [o['value'] for o in r.html.findAll('option')]
-        assert_equal(options, ['username', 'display_name', '__custom__'])
+        assert options == ['username', 'display_name', '__custom__']
         ths = [th.text for th in r.html.findAll('th')]
-        assert_equal(ths, ['Username', 'Display name', 'Email', 'Registered',
-                           'Status', 'Details'])
+        assert ths == ['Username', 'Display name', 'Email', 'Registered',
+                           'Status', 'Details']
 
     @patch('allura.controllers.site_admin.search.site_admin_search')
     def test_additional_fields(self, site_admin_search):
@@ -440,10 +440,10 @@ class TestUsersSearch(TestController):
                                       'search.user.additional_display_fields': 'url'}):
             r = self.app.get('/nf/admin/search_users?q=fake&f=username')
         options = [o['value'] for o in r.html.findAll('option')]
-        assert_equal(options, ['username', 'display_name', 'email_addresses', 'url', '__custom__'])
+        assert options == ['username', 'display_name', 'email_addresses', 'url', '__custom__']
         ths = [th.text for th in r.html.findAll('th')]
-        assert_equal(ths, ['Username', 'Display name', 'Email', 'Registered',
-                           'Status', 'url', 'Details'])
+        assert ths == ['Username', 'Display name', 'Email', 'Registered',
+                           'Status', 'url', 'Details']
 
 
 class TestUserDetails(TestController):
@@ -462,22 +462,22 @@ class TestUserDetails(TestController):
                             'session_ip': '7.7.7.7'}
         r = self.app.get('/nf/admin/user/test-admin')
         # general info
-        assert_in('Username: test-admin', r)
-        assert_in('Full name: Test Admin', r)
-        assert_in('Registered: 2014-09-01 09:09:09', r)
+        assert 'Username: test-admin' in r
+        assert 'Full name: Test Admin' in r
+        assert 'Registered: 2014-09-01 09:09:09' in r
         # session info
-        assert_in('Date: 2014-09-02 06:06:06', r)
-        assert_in('IP: 8.8.8.8', r)
-        assert_in('UA: browser of the future 1.0', r)
-        assert_in('Date: 2014-09-12', r)
-        assert_in('IP: 7.7.7.7', r)
-        assert_in('UA: browser of the future 1.1', r)
+        assert 'Date: 2014-09-02 06:06:06' in r
+        assert 'IP: 8.8.8.8' in r
+        assert 'UA: browser of the future 1.0' in r
+        assert 'Date: 2014-09-12' in r
+        assert 'IP: 7.7.7.7' in r
+        assert 'UA: browser of the future 1.1' in r
         # list of projects
         projects = r.html.findAll('fieldset')[-1]
         projects = [e.getText() for e in projects.findAll('li')]
-        assert_in('Test 2\n\u2013\nAdmin\n', projects)
-        assert_in('Test Project\n\u2013\nAdmin\n', projects)
-        assert_in('Adobe project 1\n\u2013\nAdmin\n', projects)
+        assert 'Test 2\n\u2013\nAdmin\n' in projects
+        assert 'Test Project\n\u2013\nAdmin\n' in projects
+        assert 'Adobe project 1\n\u2013\nAdmin\n' in projects
 
     @patch('allura.model.auth.request')
     @patch('allura.lib.helpers.request')
@@ -487,162 +487,162 @@ class TestUserDetails(TestController):
         h.auditlog_user('test activity user 1')
         h.auditlog_user('test activity user 2', user=M.User.by_username('test-user-2'))
         r = self.app.get('/nf/admin/user/test-admin')
-        assert_in('Add comment', r)
-        assert_not_in('test activity', r)
+        assert 'Add comment' in r
+        assert 'test activity' not in r
         r = self.app.get('/nf/admin/user/test-user-1')
-        assert_in('test activity user 1', r)
-        assert_not_in('test activity user 2', r)
+        assert 'test activity user 1' in r
+        assert 'test activity user 2' not in r
         r = self.app.get('/nf/admin/user/test-user-2')
-        assert_not_in('test activity user 1', r)
-        assert_in('test activity user 2', r)
+        assert 'test activity user 1' not in r
+        assert 'test activity user 2' in r
 
     def test_add_audit_trail_entry_access(self):
         self.app.get('/nf/admin/user/add_audit_log_entry', status=404)  # GET is not allowed
         r = self.app.post('/nf/admin/user/add_audit_log_entry',
                           extra_environ={'username': '*anonymous'},
                           status=302)
-        assert_equal(r.location, 'http://localhost/auth/')
+        assert r.location == 'http://localhost/auth/'
 
     def test_add_comment(self):
         r = self.app.get('/nf/admin/user/test-user')
-        assert_not_in('Comment by test-admin: I was hêre!', r)
+        assert 'Comment by test-admin: I was hêre!' not in r
         form = [f for f in r.forms.values() if f.action.endswith('add_audit_trail_entry')][0]
-        assert_equal(form['username'].value, 'test-user')
+        assert form['username'].value == 'test-user'
         form['comment'] = 'I was hêre!'
         r = form.submit()
-        assert_in('Comment added', self.webflash(r))
+        assert 'Comment added' in self.webflash(r)
         r = self.app.get('/nf/admin/user/test-user')
-        assert_in('Comment by test-admin: I was hêre!', r)
+        assert 'Comment by test-admin: I was hêre!' in r
 
     def test_disable_user(self):
         # user was not pending
-        assert_equal(M.User.by_username('test-user-3').disabled, False)
-        assert_equal(M.User.by_username('test-user-3').pending, False)
+        assert M.User.by_username('test-user-3').disabled == False
+        assert M.User.by_username('test-user-3').pending == False
         r = self.app.get('/nf/admin/user/test-user-3')
         form = r.forms[0]
-        assert_equal(form['username'].value, 'test-user-3')
-        assert_equal(form['status'].value, 'enable')
+        assert form['username'].value == 'test-user-3'
+        assert form['status'].value == 'enable'
         form['status'].value = 'disable'
         with td.audits('Account disabled', user=True):
             r = form.submit()
-            assert_equal(M.AuditLog.query.find().count(), 1)
-        assert_in('User disabled', self.webflash(r))
-        assert_equal(M.User.by_username('test-user-3').disabled, True)
-        assert_equal(M.User.by_username('test-user-3').pending, False)
+            assert M.AuditLog.query.find().count() == 1
+        assert 'User disabled' in self.webflash(r)
+        assert M.User.by_username('test-user-3').disabled == True
+        assert M.User.by_username('test-user-3').pending == False
 
         # user was pending
         user = M.User.by_username('test-user-3')
         user.disabled = False
         user.pending = True
         ThreadLocalORMSession.flush_all()
-        assert_equal(M.User.by_username('test-user-3').disabled, False)
-        assert_equal(M.User.by_username('test-user-3').pending, True)
+        assert M.User.by_username('test-user-3').disabled == False
+        assert M.User.by_username('test-user-3').pending == True
         r = self.app.get('/nf/admin/user/test-user-3')
         form = r.forms[0]
-        assert_equal(form['username'].value, 'test-user-3')
-        assert_equal(form['status'].value, 'pending')
+        assert form['username'].value == 'test-user-3'
+        assert form['status'].value == 'pending'
         form['status'].value = 'disable'
         with td.audits('Account disabled', user=True):
             r = form.submit()
-            assert_equal(M.AuditLog.query.find().count(), 1)
-        assert_in('User disabled', self.webflash(r))
-        assert_equal(M.User.by_username('test-user-3').disabled, True)
-        assert_equal(M.User.by_username('test-user-3').pending, True)
+            assert M.AuditLog.query.find().count() == 1
+        assert 'User disabled' in self.webflash(r)
+        assert M.User.by_username('test-user-3').disabled == True
+        assert M.User.by_username('test-user-3').pending == True
 
     def test_enable_user(self):
         # user was not pending
         user = M.User.by_username('test-user-3')
         user.disabled = True
         ThreadLocalORMSession.flush_all()
-        assert_equal(M.User.by_username('test-user-3').disabled, True)
-        assert_equal(M.User.by_username('test-user-3').pending, False)
+        assert M.User.by_username('test-user-3').disabled == True
+        assert M.User.by_username('test-user-3').pending == False
         r = self.app.get('/nf/admin/user/test-user-3')
         form = r.forms[0]
-        assert_equal(form['username'].value, 'test-user-3')
-        assert_equal(form['status'].value, 'disable')
+        assert form['username'].value == 'test-user-3'
+        assert form['status'].value == 'disable'
         form['status'].value = 'enable'
         with td.audits('Account enabled', user=True):
             r = form.submit()
-            assert_equal(M.AuditLog.query.find().count(), 1)
-        assert_in('User enabled', self.webflash(r))
-        assert_equal(M.User.by_username('test-user-3').disabled, False)
-        assert_equal(M.User.by_username('test-user-3').pending, False)
+            assert M.AuditLog.query.find().count() == 1
+        assert 'User enabled' in self.webflash(r)
+        assert M.User.by_username('test-user-3').disabled == False
+        assert M.User.by_username('test-user-3').pending == False
 
         # user was pending
         user = M.User.by_username('test-user-3')
         user.disabled = False
         user.pending = True
         ThreadLocalORMSession.flush_all()
-        assert_equal(M.User.by_username('test-user-3').disabled, False)
-        assert_equal(M.User.by_username('test-user-3').pending, True)
+        assert M.User.by_username('test-user-3').disabled == False
+        assert M.User.by_username('test-user-3').pending == True
         r = self.app.get('/nf/admin/user/test-user-3')
         form = r.forms[0]
-        assert_equal(form['username'].value, 'test-user-3')
-        assert_equal(form['status'].value, 'pending')
+        assert form['username'].value == 'test-user-3'
+        assert form['status'].value == 'pending'
         form['status'].value = 'enable'
         with td.audits('Account activated', user=True):
             r = form.submit()
-            assert_equal(M.AuditLog.query.find().count(), 1)
-        assert_in('User enabled', self.webflash(r))
-        assert_equal(M.User.by_username('test-user-3').disabled, False)
-        assert_equal(M.User.by_username('test-user-3').pending, False)
+            assert M.AuditLog.query.find().count() == 1
+        assert 'User enabled' in self.webflash(r)
+        assert M.User.by_username('test-user-3').disabled == False
+        assert M.User.by_username('test-user-3').pending == False
 
         # user was pending and disabled
         user = M.User.by_username('test-user-3')
         user.disabled = True
         user.pending = True
         ThreadLocalORMSession.flush_all()
-        assert_equal(M.User.by_username('test-user-3').disabled, True)
-        assert_equal(M.User.by_username('test-user-3').pending, True)
+        assert M.User.by_username('test-user-3').disabled == True
+        assert M.User.by_username('test-user-3').pending == True
         r = self.app.get('/nf/admin/user/test-user-3')
         form = r.forms[0]
-        assert_equal(form['username'].value, 'test-user-3')
-        assert_equal(form['status'].value, 'disable')
+        assert form['username'].value == 'test-user-3'
+        assert form['status'].value == 'disable'
         form['status'].value = 'enable'
         with td.audits('Account enabled', user=True):
             r = form.submit()
-            assert_equal(M.AuditLog.query.find().count(), 1)
-        assert_in('User enabled', self.webflash(r))
-        assert_equal(M.User.by_username('test-user-3').disabled, False)
-        assert_equal(M.User.by_username('test-user-3').pending, False)
+            assert M.AuditLog.query.find().count() == 1
+        assert 'User enabled' in self.webflash(r)
+        assert M.User.by_username('test-user-3').disabled == False
+        assert M.User.by_username('test-user-3').pending == False
 
     def test_set_pending(self):
         # user was disabled
         user = M.User.by_username('test-user-3')
         user.disabled = True
         ThreadLocalORMSession.flush_all()
-        assert_equal(M.User.by_username('test-user-3').disabled, True)
-        assert_equal(M.User.by_username('test-user-3').pending, False)
+        assert M.User.by_username('test-user-3').disabled == True
+        assert M.User.by_username('test-user-3').pending == False
         r = self.app.get('/nf/admin/user/test-user-3')
         form = r.forms[0]
-        assert_equal(form['username'].value, 'test-user-3')
-        assert_equal(form['status'].value, 'disable')
+        assert form['username'].value == 'test-user-3'
+        assert form['status'].value == 'disable'
         form['status'].value = 'pending'
         with td.audits('Account changed to pending', user=True):
             r = form.submit()
-            assert_equal(M.AuditLog.query.find().count(), 1)
-        assert_in('Set user status to pending', self.webflash(r))
-        assert_equal(M.User.by_username('test-user-3').disabled, False)
-        assert_equal(M.User.by_username('test-user-3').pending, True)
+            assert M.AuditLog.query.find().count() == 1
+        assert 'Set user status to pending' in self.webflash(r)
+        assert M.User.by_username('test-user-3').disabled == False
+        assert M.User.by_username('test-user-3').pending == True
 
         # user was enabled
         user = M.User.by_username('test-user-3')
         user.pending = False
         user.disabled = False
         ThreadLocalORMSession.flush_all()
-        assert_equal(M.User.by_username('test-user-3').disabled, False)
-        assert_equal(M.User.by_username('test-user-3').pending, False)
+        assert M.User.by_username('test-user-3').disabled == False
+        assert M.User.by_username('test-user-3').pending == False
         r = self.app.get('/nf/admin/user/test-user-3')
         form = r.forms[0]
-        assert_equal(form['username'].value, 'test-user-3')
-        assert_equal(form['status'].value, 'enable')
+        assert form['username'].value == 'test-user-3'
+        assert form['status'].value == 'enable'
         form['status'].value = 'pending'
         with td.audits('Account changed to pending', user=True):
             r = form.submit()
-            assert_equal(M.AuditLog.query.find().count(), 1)
-        assert_in('Set user status to pending', self.webflash(r))
-        assert_equal(M.User.by_username('test-user-3').disabled, False)
-        assert_equal(M.User.by_username('test-user-3').pending, True)
+            assert M.AuditLog.query.find().count() == 1
+        assert 'Set user status to pending' in self.webflash(r)
+        assert M.User.by_username('test-user-3').disabled == False
+        assert M.User.by_username('test-user-3').pending == True
 
     def test_emails(self):
         # add test@example.com
@@ -654,11 +654,11 @@ class TestUserDetails(TestController):
                 'primary_addr': 'test@example.com'},
                 extra_environ=dict(username='test-admin'))
         r = self.app.get('/nf/admin/user/test-user')
-        assert_in('test@example.com', r)
+        assert 'test@example.com' in r
         em = M.EmailAddress.get(email='test@example.com')
-        assert_equal(em.confirmed, True)
+        assert em.confirmed == True
         user = M.User.query.get(username='test-user')
-        assert_equal(user.get_pref('email_address'), 'test@example.com')
+        assert user.get_pref('email_address') == 'test@example.com'
 
         # add test2@example.com
         with td.audits('New email address: test2@example.com', user=True):
@@ -669,11 +669,11 @@ class TestUserDetails(TestController):
                 'primary_addr': 'test@example.com'},
                 extra_environ=dict(username='test-admin'))
         r = self.app.get('/nf/admin/user/test-user')
-        assert_in('test2@example.com', r)
+        assert 'test2@example.com' in r
         em = M.EmailAddress.get(email='test2@example.com')
-        assert_equal(em.confirmed, True)
+        assert em.confirmed == True
         user = M.User.query.get(username='test-user')
-        assert_equal(user.get_pref('email_address'), 'test@example.com')
+        assert user.get_pref('email_address') == 'test@example.com'
 
         # change primary: test -> test2
         with td.audits('Primary email changed: test@example.com => test2@example.com', user=True):
@@ -684,7 +684,7 @@ class TestUserDetails(TestController):
                 extra_environ=dict(username='test-admin'))
         r = self.app.get('/nf/admin/user/test-user')
         user = M.User.query.get(username='test-user')
-        assert_equal(user.get_pref('email_address'), 'test2@example.com')
+        assert user.get_pref('email_address') == 'test2@example.com'
 
         # remove test2@example.com
         with td.audits('Email address deleted: test2@example.com', user=True):
@@ -700,14 +700,14 @@ class TestUserDetails(TestController):
         r = self.app.get('/nf/admin/user/test-user')
         user = M.User.query.get(username='test-user')
         # test@example.com set as primary since test2@example.com is deleted
-        assert_equal(user.get_pref('email_address'), 'test-user@allura.local')
+        assert user.get_pref('email_address') == 'test-user@allura.local'
 
     @patch.object(LocalAuthenticationProvider, 'set_password')
     def test_set_random_password(self, set_password):
         with td.audits('Set random password', user=True, actor='test-admin'):
             r = self.app.post('/nf/admin/user/set_random_password', params={'username': 'test-user'})
-        assert_in('Password is set', self.webflash(r))
-        assert_equal(set_password.call_count, 1)
+        assert 'Password is set' in self.webflash(r)
+        assert set_password.call_count == 1
 
     @patch('allura.tasks.mail_tasks.sendsimplemail')
     @patch('allura.lib.helpers.gen_message_id')
@@ -738,7 +738,7 @@ To update your password on %s, please visit the following URL:
             r = self.app.post('/nf/admin/user/make_password_reset_url', params={'username': 'test-user'})
         user = M.User.by_username('test-user')
         hash = user.get_tool_data('AuthPasswordReset', 'hash')
-        assert_in(hash, r.text)
+        assert hash in r.text
 
 
 class TestDeleteProjects(TestController):
@@ -751,14 +751,14 @@ class TestDeleteProjects(TestController):
 
     def test_projects_populated_from_get_params(self):
         r = self.app.get('/nf/admin/delete_projects/')
-        assert_equal(self.delete_form(r)['projects'].value, '')
+        assert self.delete_form(r)['projects'].value == ''
         link = '/nf/admin/delete_projects/?projects=/p/test/++++%23+comment%0A/adobe/adobe-1/%0A/p/test2/'
         link += '&reason=The%0AReason&disable_users=True'
         r = self.app.get(link)
         form = self.delete_form(r)
-        assert_equal(form['projects'].value, '/p/test/    # comment\n/adobe/adobe-1/\n/p/test2/')
-        assert_equal(form['reason'].value, 'The\nReason')
-        assert_equal(form['disable_users'].value, 'on')
+        assert form['projects'].value == '/p/test/    # comment\n/adobe/adobe-1/\n/p/test2/'
+        assert form['reason'].value == 'The\nReason'
+        assert form['disable_users'].value == 'on'
 
     def test_confirm_step_values(self):
         r = self.app.get('/nf/admin/delete_projects/')
@@ -769,16 +769,16 @@ class TestDeleteProjects(TestController):
         r = form.submit()
         confirm_form = self.confirm_form(r)
         for f in ['reason', 'disable_users']:
-            assert_equal(confirm_form[f].value, form[f].value)
-        assert_equal(confirm_form['projects'].value, 'p/test    # OK: /p/test/\ndne/dne    # Neighborhood not found')
+            assert confirm_form[f].value == form[f].value
+        assert confirm_form['projects'].value == 'p/test    # OK: /p/test/\ndne/dne    # Neighborhood not found'
 
         confirm_data = r.html.find('table').findAll('td')
-        assert_equal(len(confirm_data), 4)  # 2 projects == 2 rows (2 columns each)
-        assert_equal(confirm_data[0].getText(), 'p/test')
-        assert_equal(confirm_data[1].find('a').get('href'), '/p/test/')
-        assert_equal(confirm_data[1].getText().strip(), '/p/test/')
-        assert_equal(confirm_data[2].getText().strip(), 'dne/dne')
-        assert_equal(confirm_data[3].getText().strip(), 'Neighborhood not found')
+        assert len(confirm_data) == 4  # 2 projects == 2 rows (2 columns each)
+        assert confirm_data[0].getText() == 'p/test'
+        assert confirm_data[1].find('a').get('href') == '/p/test/'
+        assert confirm_data[1].getText().strip() == '/p/test/'
+        assert confirm_data[2].getText().strip() == 'dne/dne'
+        assert confirm_data[3].getText().strip() == 'Neighborhood not found'
 
     def test_confirm_step_edit_link(self):
         r = self.app.get('/nf/admin/delete_projects/')
diff --git a/Allura/allura/tests/functional/test_trovecategory.py b/Allura/allura/tests/functional/test_trovecategory.py
index fef314e54..c6a903833 100644
--- a/Allura/allura/tests/functional/test_trovecategory.py
+++ b/Allura/allura/tests/functional/test_trovecategory.py
@@ -39,25 +39,25 @@ class TestTroveCategory(TestController):
             r = self.app.post('/categories/create/', params=dict(categoryname='test'))
 
         category_id = post_event.call_args[0][1]
-        assert_true(isinstance(category_id, int))
-        assert_equals(post_event.call_args[0][0], 'trove_category_created')
+        assert isinstance(category_id, int)
+        assert post_event.call_args[0][0] == 'trove_category_created'
         category = M.TroveCategory.query.get(trove_cat_id=category_id)
 
         # Update event
         category.fullname = 'test2'
         session(M.TroveCategory).flush()
         edited_category_id = post_event.call_args[0][1]
-        assert_true(isinstance(edited_category_id, int))
-        assert_equals(edited_category_id, category_id)
-        assert_equals(post_event.call_args[0][0], 'trove_category_updated')
+        assert isinstance(edited_category_id, int)
+        assert edited_category_id == category_id
+        assert post_event.call_args[0][0] == 'trove_category_updated'
 
         # Delete event
         M.TroveCategory.delete(category)
         session(M.TroveCategory).flush()
         deleted_category_id = post_event.call_args[0][1]
-        assert_true(isinstance(deleted_category_id, int))
-        assert_equals(deleted_category_id, category_id)
-        assert_equals(post_event.call_args[0][0], 'trove_category_deleted')
+        assert isinstance(deleted_category_id, int)
+        assert deleted_category_id == category_id
+        assert post_event.call_args[0][0] == 'trove_category_deleted'
 
     def test_enableediting_setting(self):
         def check_access(username=None, status=None):
@@ -122,7 +122,7 @@ class TestTroveCategoryController(TestController):
             </ul>
         </ul>
         """.strip(), 'html.parser')
-        assert_equals(str(expected), str(rendered_tree))
+        assert str(expected) == str(rendered_tree)
 
     @td.with_tool('test2', 'admin_main', 'admin')
     def test_trove_empty_hierarchy(self):
@@ -132,24 +132,24 @@ class TestTroveCategoryController(TestController):
         <ul>
         </ul>
         """.strip(), 'html.parser')
-        assert_equals(str(expected), str(rendered_tree))
+        assert str(expected) == str(rendered_tree)
 
     def test_delete(self):
         self.create_some_cats()
         session(M.TroveCategory).flush()
-        assert_equals(5, M.TroveCategory.query.find().count())
+        assert 5 == M.TroveCategory.query.find().count()
 
         r = self.app.get('/categories/1')
         form = r.forms[0]
         r = form.submit()
-        assert_in("This category contains at least one sub-category, therefore it can't be removed",
+        assert ("This category contains at least one sub-category, therefore it can't be removed" in
                   self.webflash(r))
 
         r = self.app.get('/categories/2')
         form = r.forms[0]
         r = form.submit()
-        assert_in("Category removed", self.webflash(r))
-        assert_equals(4, M.TroveCategory.query.find().count())
+        assert "Category removed" in self.webflash(r)
+        assert 4 == M.TroveCategory.query.find().count()
 
     def test_create_parent(self):
         self.create_some_cats()
@@ -161,9 +161,9 @@ class TestTroveCategoryController(TestController):
         form.submit()
 
         possible = M.TroveCategory.query.find(dict(fullname='New Category')).all()
-        assert_equal(len(possible), 1)
-        assert_equal(possible[0].fullname, 'New Category')
-        assert_equal(possible[0].shortname, 'new-category')
+        assert len(possible) == 1
+        assert possible[0].fullname == 'New Category'
+        assert possible[0].shortname == 'new-category'
 
     def test_create_child(self):
         self.create_some_cats()
@@ -175,10 +175,10 @@ class TestTroveCategoryController(TestController):
         form.submit()
 
         possible =M.TroveCategory.query.find(dict(fullname='New Child')).all()
-        assert_equal(len(possible), 1)
-        assert_equal(possible[0].fullname, 'New Child')
-        assert_equal(possible[0].shortname, 'new-child')
-        assert_equal(possible[0].trove_parent_id, 2)
+        assert len(possible) == 1
+        assert possible[0].fullname == 'New Child'
+        assert possible[0].shortname == 'new-child'
+        assert possible[0].trove_parent_id == 2
 
         # test slugify with periods. the relevant form becomes the third, after a child has been created above.
         r = self.app.get('/categories/2')
@@ -186,7 +186,7 @@ class TestTroveCategoryController(TestController):
         form['categoryname'].value = "New Child.io"
         form.submit()
         possible = M.TroveCategory.query.find(dict(fullname='New Child.io')).all()
-        assert_equal(possible[0].shortname, 'new-child.io')
+        assert possible[0].shortname == 'new-child.io'
 
     def test_create_child_bad_upper(self):
         self.create_some_cats()
diff --git a/Allura/allura/tests/functional/test_user_profile.py b/Allura/allura/tests/functional/test_user_profile.py
index d8f6724c1..c3ec9f7e9 100644
--- a/Allura/allura/tests/functional/test_user_profile.py
+++ b/Allura/allura/tests/functional/test_user_profile.py
@@ -30,18 +30,18 @@ class TestUserProfile(TestController):
     @td.with_user_project('test-admin')
     def test_profile(self):
         r = self.app.get('/u/test-admin/profile/')
-        assert_equal('Test Admin',
+        assert ('Test Admin' ==
                      r.html.find('h1', 'project_title').find('a').text)
         sections = {c for s in r.html.findAll(None, 'profile-section') for c in s['class']}
-        assert_in('personal-data', sections)
-        assert_in('Username:\ntest-admin', r.html.find(None, 'personal-data').getText().replace(' ', ''))
-        assert_in('projects', sections)
-        assert_in('Test Project', r.html.find(None, 'projects').getText())
-        assert_in('Last Updated:', r.html.find(None, 'projects').getText())
-        assert_in('tools', sections)
-        assert_in('Admin', r.html.find(None, 'tools').getText())
-        assert_in('skills', sections)
-        assert_in('No skills entered', r.html.find(None, 'skills').getText())
+        assert 'personal-data' in sections
+        assert 'Username:\ntest-admin' in r.html.find(None, 'personal-data').getText().replace(' ', '')
+        assert 'projects' in sections
+        assert 'Test Project' in r.html.find(None, 'projects').getText()
+        assert 'Last Updated:' in r.html.find(None, 'projects').getText()
+        assert 'tools' in sections
+        assert 'Admin' in r.html.find(None, 'tools').getText()
+        assert 'skills' in sections
+        assert 'No skills entered' in r.html.find(None, 'skills').getText()
 
     @td.with_user_project('test-admin')
     @mock.patch.dict(tg.config, {'use_gravatar': 'true'})
@@ -80,9 +80,9 @@ class TestUserProfile(TestController):
 
         # and accessing it by "-" which was the previous way, will redirect
         response = self.app.get('/u/foo-bar/', status=302)
-        assert_equal(response.location, 'http://localhost/u/foo_bar/')
+        assert response.location == 'http://localhost/u/foo_bar/'
         response = self.app.get('/u/foo-bar/profile/xyz?a=b', status=302)
-        assert_equal(response.location, 'http://localhost/u/foo_bar/profile/xyz?a=b')
+        assert response.location == 'http://localhost/u/foo_bar/profile/xyz?a=b'
 
     def test_differing_profile_proj_shortname_rest_api(self):
         User.upsert('foo_bar')
@@ -246,21 +246,21 @@ class TestUserProfile(TestController):
             with mock.patch.dict(tg.config, order):
                 iep.return_value = eps
                 sections = app.profile_sections
-                assert_equal(sections, [
+                assert sections == [
                     eps[1].load(),
                     eps[3].load(),
                     eps[2].load(),
-                    eps[0].load()])
+                    eps[0].load()]
         r = self.app.get('/u/test-user/profile')
-        assert_in('Section a', r.text)
-        assert_in('Section b', r.text)
-        assert_in('Section c', r.text)
-        assert_in('Section d', r.text)
-        assert_not_in('Section f', r.text)
+        assert 'Section a' in r.text
+        assert 'Section b' in r.text
+        assert 'Section c' in r.text
+        assert 'Section d' in r.text
+        assert 'Section f' not in r.text
 
     def test_no_index_tag_in_empty_profile(self):
         r = self.app.get('/u/test-user/profile/')
-        assert_in('content="noindex, follow"', r.text)
+        assert 'content="noindex, follow"' in r.text
 
     def test_remove_no_index_tag_profile(self):
         r = self.app.get('/u/test-admin/profile/')
@@ -284,13 +284,13 @@ class TestUserProfileHasAccessAPI(TestRestApiBase):
         r = self.api_get(
             '/rest/u/test-admin/profile/has_access?user=babadook&perm=read',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], False)
+        assert r.status_int == 200
+        assert r.json['result'] == False
         r = self.api_get(
             '/rest/u/test-admin/profile/has_access?user=test-user&perm=jump',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], False)
+        assert r.status_int == 200
+        assert r.json['result'] == False
 
     @td.with_user_project('test-admin')
     def test_has_access_not_admin(self):
@@ -308,10 +308,10 @@ class TestUserProfileHasAccessAPI(TestRestApiBase):
         r = self.api_get(
             '/rest/u/test-admin/profile/has_access?user=test-admin&perm=admin',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], True)
+        assert r.status_int == 200
+        assert r.json['result'] == True
         r = self.api_get(
             '/rest/u/test-admin/profile/has_access?user=test-user&perm=admin',
             user='root')
-        assert_equal(r.status_int, 200)
-        assert_equal(r.json['result'], False)
+        assert r.status_int == 200
+        assert r.json['result'] == False
diff --git a/Allura/allura/tests/model/test_artifact.py b/Allura/allura/tests/model/test_artifact.py
index 530f7c7c0..b851bb8f3 100644
--- a/Allura/allura/tests/model/test_artifact.py
+++ b/Allura/allura/tests/model/test_artifact.py
@@ -203,7 +203,7 @@ def test_last_updated(_datetime):
     _datetime.utcnow.return_value = datetime(2014, 1, 2)
     WM.Page(title='TestPage1')
     ThreadLocalORMSession.flush_all()
-    assert_equal(c.project.last_updated, datetime(2014, 1, 2))
+    assert c.project.last_updated == datetime(2014, 1, 2)
 
 
 @with_setup(setUp, tearDown)
@@ -215,7 +215,7 @@ def test_last_updated_disabled(_datetime):
         M.artifact_orm_session._get().skip_last_updated = True
         WM.Page(title='TestPage1')
         ThreadLocalORMSession.flush_all()
-        assert_equal(c.project.last_updated, datetime(2014, 1, 1))
+        assert c.project.last_updated == datetime(2014, 1, 1)
     finally:
         M.artifact_orm_session._get().skip_last_updated = False
 
@@ -235,12 +235,12 @@ def test_get_discussion_thread_dupe():
     thr4 = M.Thread.new(ref_id=thr1.ref_id)
 
     thread_q = M.Thread.query.find(dict(ref_id=artif.index_id()))
-    assert_equal(thread_q.count(), 4)
+    assert thread_q.count() == 4
 
     thread = artif.get_discussion_thread()[0]  # force cleanup
     threads = thread_q.all()
-    assert_equal(len(threads), 1)
-    assert_equal(len(thread.posts), 6)
+    assert len(threads) == 1
+    assert len(thread.posts) == 6
     assert not any(p.deleted for p in thread.posts)  # normal thread deletion propagates to children, make sure that doesn't happen
 
 
@@ -249,11 +249,11 @@ def test_snapshot_clear_user_data():
                            'display_name': 'John Doe',
                            'logged_ip': '1.2.3.4'})
     s.clear_user_data()
-    assert_equal(s.author, {'username': '',
+    assert s.author == {'username': '',
                             'display_name': '',
                             'logged_ip': None,
                             'id': None,
-                            })
+                            }
 
 
 @with_setup(setUp, tearDown)
@@ -265,7 +265,7 @@ def test_snapshot_from_username():
                            'display_name': 'John Doe',
                            'logged_ip': '1.2.3.4'})
     ThreadLocalORMSession.flush_all()
-    assert_equal(len(M.Snapshot.from_username('johndoe')), 1)
+    assert len(M.Snapshot.from_username('johndoe')) == 1
 
 
 def test_feed_clear_user_data():
@@ -273,17 +273,17 @@ def test_feed_clear_user_data():
                author_link='/u/johndoe/',
                title='Something')
     f.clear_user_data()
-    assert_equal(f.author_name, '')
-    assert_equal(f.author_link, '')
-    assert_equal(f.title, 'Something')
+    assert f.author_name == ''
+    assert f.author_link == ''
+    assert f.title == 'Something'
 
     f = M.Feed(author_name='John Doe',
                author_link='/u/johndoe/',
                title='Home Page modified by John Doe')
     f.clear_user_data()
-    assert_equal(f.author_name, '')
-    assert_equal(f.author_link, '')
-    assert_equal(f.title, 'Home Page modified by <REDACTED>')
+    assert f.author_name == ''
+    assert f.author_link == ''
+    assert f.title == 'Home Page modified by <REDACTED>'
 
 
 @with_setup(setUp, tearDown)
@@ -295,7 +295,7 @@ def test_feed_from_username():
            author_link='/u/johnsmith/',
            title='Something')
     ThreadLocalORMSession.flush_all()
-    assert_equal(len(M.Feed.from_username('johndoe')), 1)
+    assert len(M.Feed.from_username('johndoe')) == 1
 
 
 @with_setup(setUp, tearDown)
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index 90e39884d..6250d650e 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -77,42 +77,42 @@ def test_email_address_lookup_helpers():
     addr = M.EmailAddress.create('TEST@DOMAIN.NET')
     nobody = M.EmailAddress.create('nobody@example.com')
     ThreadLocalORMSession.flush_all()
-    assert_equal(addr.email, 'TEST@domain.net')
+    assert addr.email == 'TEST@domain.net'
 
-    assert_equal(M.EmailAddress.get(email='TEST@DOMAIN.NET'), addr)
-    assert_equal(M.EmailAddress.get(email='TEST@domain.net'), addr)
-    assert_equal(M.EmailAddress.get(email='test@domain.net'), None)
-    assert_equal(M.EmailAddress.get(email=None), None)
-    assert_equal(M.EmailAddress.get(email='nobody@example.com'), nobody)
+    assert M.EmailAddress.get(email='TEST@DOMAIN.NET') == addr
+    assert M.EmailAddress.get(email='TEST@domain.net') == addr
+    assert M.EmailAddress.get(email='test@domain.net') == None
+    assert M.EmailAddress.get(email=None) == None
+    assert M.EmailAddress.get(email='nobody@example.com') == nobody
     # invalid email returns None, but not nobody@example.com as before
-    assert_equal(M.EmailAddress.get(email='invalid'), None)
+    assert M.EmailAddress.get(email='invalid') == None
 
-    assert_equal(M.EmailAddress.find(dict(email='TEST@DOMAIN.NET')).all(), [addr])
-    assert_equal(M.EmailAddress.find(dict(email='TEST@domain.net')).all(), [addr])
-    assert_equal(M.EmailAddress.find(dict(email='test@domain.net')).all(), [])
-    assert_equal(M.EmailAddress.find(dict(email=None)).all(), [])
-    assert_equal(M.EmailAddress.find(dict(email='nobody@example.com')).all(), [nobody])
+    assert M.EmailAddress.find(dict(email='TEST@DOMAIN.NET')).all() == [addr]
+    assert M.EmailAddress.find(dict(email='TEST@domain.net')).all() == [addr]
+    assert M.EmailAddress.find(dict(email='test@domain.net')).all() == []
+    assert M.EmailAddress.find(dict(email=None)).all() == []
+    assert M.EmailAddress.find(dict(email='nobody@example.com')).all() == [nobody]
     # invalid email returns empty query, but not nobody@example.com as before
-    assert_equal(M.EmailAddress.find(dict(email='invalid')).all(), [])
+    assert M.EmailAddress.find(dict(email='invalid')).all() == []
 
 
 @with_setup(setUp)
 def test_email_address_canonical():
-    assert_equal(M.EmailAddress.canonical('nobody@EXAMPLE.COM'),
+    assert (M.EmailAddress.canonical('nobody@EXAMPLE.COM') ==
                  'nobody@example.com')
-    assert_equal(M.EmailAddress.canonical('nobody@example.com'),
+    assert (M.EmailAddress.canonical('nobody@example.com') ==
                  'nobody@example.com')
-    assert_equal(M.EmailAddress.canonical('I Am Nobody <no...@example.com>'),
+    assert (M.EmailAddress.canonical('I Am Nobody <no...@example.com>') ==
                  'nobody@example.com')
-    assert_equal(M.EmailAddress.canonical('  nobody@example.com\t'),
+    assert (M.EmailAddress.canonical('  nobody@example.com\t') ==
                  'nobody@example.com')
-    assert_equal(M.EmailAddress.canonical('I Am@Nobody <no...@example.com> '),
+    assert (M.EmailAddress.canonical('I Am@Nobody <no...@example.com> ') ==
                  'nobody@example.com')
-    assert_equal(M.EmailAddress.canonical(' No@body <no...@example.com> '),
+    assert (M.EmailAddress.canonical(' No@body <no...@example.com> ') ==
                  'no@body@example.com')
-    assert_equal(M.EmailAddress.canonical('no@body@example.com'),
+    assert (M.EmailAddress.canonical('no@body@example.com') ==
                  'no@body@example.com')
-    assert_equal(M.EmailAddress.canonical('invalid'), None)
+    assert M.EmailAddress.canonical('invalid') == None
 
 @with_setup(setUp)
 def test_email_address_send_verification_link():
@@ -124,7 +124,7 @@ def test_email_address_send_verification_link():
     with patch('allura.tasks.mail_tasks.smtp_client._client') as _client:
         M.MonQTask.run_ready()
     return_path, rcpts, body = _client.sendmail.call_args[0]
-    assert_equal(rcpts, ['test_admin@domain.net'])
+    assert rcpts == ['test_admin@domain.net']
 
 
 @with_setup(setUp)
@@ -132,19 +132,19 @@ def test_email_address_send_verification_link():
 def test_user():
     assert c.user.url() .endswith('/u/test-admin/')
     assert c.user.script_name .endswith('/u/test-admin/')
-    assert_equal({p.shortname for p in c.user.my_projects()},
+    assert ({p.shortname for p in c.user.my_projects()} ==
                  {'test', 'test2', 'u/test-admin', 'adobe-1', '--init--'})
     # delete one of the projects and make sure it won't appear in my_projects()
     p = M.Project.query.get(shortname='test2')
     p.deleted = True
     ThreadLocalORMSession.flush_all()
-    assert_equal({p.shortname for p in c.user.my_projects()},
+    assert ({p.shortname for p in c.user.my_projects()} ==
                  {'test', 'u/test-admin', 'adobe-1', '--init--'})
     u = M.User.register(dict(
         username='nosetest-user'))
     ThreadLocalORMSession.flush_all()
     assert u.reg_date
-    assert_equal(u.private_project().shortname, 'u/nosetest-user')
+    assert u.private_project().shortname == 'u/nosetest-user'
     roles = g.credentials.user_roles(
         u._id, project_id=u.private_project().root_project._id)
     assert len(roles) == 3, roles
@@ -208,40 +208,40 @@ def test_user_by_email_address(log):
     # both users are disabled
     u1.disabled, u2.disabled = True, True
     ThreadLocalORMSession.flush_all()
-    assert_equal(M.User.by_email_address('abc123@abc.me'), None)
-    assert_equal(log.warn.call_count, 0)
+    assert M.User.by_email_address('abc123@abc.me') == None
+    assert log.warn.call_count == 0
 
     # only u2 is active
     u1.disabled, u2.disabled = True, False
     ThreadLocalORMSession.flush_all()
-    assert_equal(M.User.by_email_address('abc123@abc.me'), u2)
-    assert_equal(log.warn.call_count, 0)
+    assert M.User.by_email_address('abc123@abc.me') == u2
+    assert log.warn.call_count == 0
 
     # both are active
     u1.disabled, u2.disabled = False, False
     ThreadLocalORMSession.flush_all()
-    assert_in(M.User.by_email_address('abc123@abc.me'), [u1, u2])
-    assert_equal(log.warn.call_count, 1)
+    assert M.User.by_email_address('abc123@abc.me') in [u1, u2]
+    assert log.warn.call_count == 1
 
     # invalid email returns None, but not user which claimed
     # nobody@example.com as before
     nobody = M.EmailAddress(email='nobody@example.com', confirmed=True,
                             claimed_by_user_id=u1._id)
     ThreadLocalORMSession.flush_all()
-    assert_equal(M.User.by_email_address('nobody@example.com'), u1)
-    assert_equal(M.User.by_email_address('invalid'), None)
+    assert M.User.by_email_address('nobody@example.com') == u1
+    assert M.User.by_email_address('invalid') == None
 
 
 def test_user_equality():
-    assert_equal(M.User.by_username('test-user'), M.User.by_username('test-user'))
-    assert_equal(M.User.anonymous(), M.User.anonymous())
-    assert_equal(M.User.by_username('*anonymous'), M.User.anonymous())
+    assert M.User.by_username('test-user') == M.User.by_username('test-user')
+    assert M.User.anonymous() == M.User.anonymous()
+    assert M.User.by_username('*anonymous') == M.User.anonymous()
 
-    assert_not_equal(M.User.by_username('test-user'), M.User.by_username('test-admin'))
-    assert_not_equal(M.User.by_username('test-user'), M.User.anonymous())
-    assert_not_equal(M.User.anonymous(), None)
-    assert_not_equal(M.User.anonymous(), 12345)
-    assert_not_equal(M.User.anonymous(), M.User())
+    assert M.User.by_username('test-user') != M.User.by_username('test-admin')
+    assert M.User.by_username('test-user') != M.User.anonymous()
+    assert M.User.anonymous() != None
+    assert M.User.anonymous() != 12345
+    assert M.User.anonymous() != M.User()
 
 
 def test_user_hash():
@@ -300,9 +300,9 @@ def test_email_address_claimed_by_user():
 @with_setup(setUp)
 @td.with_user_project('test-admin')
 def test_user_projects_by_role():
-    assert_equal({p.shortname for p in c.user.my_projects()},
+    assert ({p.shortname for p in c.user.my_projects()} ==
                  {'test', 'test2', 'u/test-admin', 'adobe-1', '--init--'})
-    assert_equal({p.shortname for p in c.user.my_projects_by_role_name('Admin')},
+    assert ({p.shortname for p in c.user.my_projects_by_role_name('Admin')} ==
                  {'test', 'test2', 'u/test-admin', 'adobe-1', '--init--'})
     # Remove admin access from c.user to test2 project
     project = M.Project.query.get(shortname='test2')
@@ -313,9 +313,9 @@ def test_user_projects_by_role():
     user_role.roles.append(developer_role._id)
     ThreadLocalORMSession.flush_all()
     g.credentials.clear()
-    assert_equal({p.shortname for p in c.user.my_projects()},
+    assert ({p.shortname for p in c.user.my_projects()} ==
                  {'test', 'test2', 'u/test-admin', 'adobe-1', '--init--'})
-    assert_equal({p.shortname for p in c.user.my_projects_by_role_name('Admin')},
+    assert ({p.shortname for p in c.user.my_projects_by_role_name('Admin')} ==
                  {'test', 'u/test-admin', 'adobe-1', '--init--'})
 
 
@@ -333,8 +333,8 @@ def test_user_projects_unnamed():
         project_id=sub1._id)
     ThreadLocalORMSession.flush_all()
     project_names = [p.shortname for p in c.user.my_projects()]
-    assert_not_in('test/sub1', project_names)
-    assert_in('test', project_names)
+    assert 'test/sub1' not in project_names
+    assert 'test' in project_names
 
 
 @patch.object(g, 'user_message_max_messages', 3)
@@ -345,7 +345,7 @@ def test_check_sent_user_message_times():
     time3 = datetime.utcnow() - timedelta(minutes=70)
     user1.sent_user_message_times = [time1, time2, time3]
     assert user1.can_send_user_message()
-    assert_equal(len(user1.sent_user_message_times), 2)
+    assert len(user1.sent_user_message_times) == 2
     user1.sent_user_message_times.append(
         datetime.utcnow() - timedelta(minutes=15))
     assert not user1.can_send_user_message()
@@ -358,40 +358,40 @@ def test_user_track_active():
     setup_functional_test()
     c.user = M.User.by_username('test-admin')
 
-    assert_equal(c.user.last_access['session_date'], None)
-    assert_equal(c.user.last_access['session_ip'], None)
-    assert_equal(c.user.last_access['session_ua'], None)
+    assert c.user.last_access['session_date'] == None
+    assert c.user.last_access['session_ip'] == None
+    assert c.user.last_access['session_ua'] == None
 
     req = Mock(headers={'User-Agent': 'browser'}, remote_addr='addr')
     c.user.track_active(req)
     c.user = M.User.by_username(c.user.username)
-    assert_not_equal(c.user.last_access['session_date'], None)
-    assert_equal(c.user.last_access['session_ip'], 'addr')
-    assert_equal(c.user.last_access['session_ua'], 'browser')
+    assert c.user.last_access['session_date'] != None
+    assert c.user.last_access['session_ip'] == 'addr'
+    assert c.user.last_access['session_ua'] == 'browser'
 
     # ensure that session activity tracked with a whole-day granularity
     prev_date = c.user.last_access['session_date']
     c.user.track_active(req)
     c.user = M.User.by_username(c.user.username)
-    assert_equal(c.user.last_access['session_date'], prev_date)
+    assert c.user.last_access['session_date'] == prev_date
     yesterday = datetime.utcnow() - timedelta(1)
     c.user.last_access['session_date'] = yesterday
     session(c.user).flush(c.user)
     c.user.track_active(req)
     c.user = M.User.by_username(c.user.username)
-    assert_true(c.user.last_access['session_date'] > yesterday)
+    assert c.user.last_access['session_date'] > yesterday
 
     # ...or if IP or User Agent has changed
     req.remote_addr = 'new addr'
     c.user.track_active(req)
     c.user = M.User.by_username(c.user.username)
-    assert_equal(c.user.last_access['session_ip'], 'new addr')
-    assert_equal(c.user.last_access['session_ua'], 'browser')
+    assert c.user.last_access['session_ip'] == 'new addr'
+    assert c.user.last_access['session_ua'] == 'browser'
     req.headers['User-Agent'] = 'new browser'
     c.user.track_active(req)
     c.user = M.User.by_username(c.user.username)
-    assert_equal(c.user.last_access['session_ip'], 'new addr')
-    assert_equal(c.user.last_access['session_ua'], 'new browser')
+    assert c.user.last_access['session_ip'] == 'new addr'
+    assert c.user.last_access['session_ua'] == 'new browser'
 
 
 @with_setup(setUp)
@@ -399,35 +399,35 @@ def test_user_index():
     c.user.email_addresses = ['email1', 'email2']
     c.user.set_pref('email_address', 'email2')
     idx = c.user.index()
-    assert_equal(idx['id'], c.user.index_id())
-    assert_equal(idx['title'], 'User test-admin')
-    assert_equal(idx['type_s'], 'User')
-    assert_equal(idx['username_s'], 'test-admin')
-    assert_equal(idx['email_addresses_t'], 'email1 email2')
-    assert_equal(idx['email_address_s'], 'email2')
-    assert_in('last_password_updated_dt', idx)
-    assert_equal(idx['disabled_b'], False)
-    assert_in('results_per_page_i', idx)
-    assert_in('email_format_s', idx)
-    assert_in('disable_user_messages_b', idx)
-    assert_equal(idx['display_name_t'], 'Test Admin')
-    assert_equal(idx['sex_s'], 'Unknown')
-    assert_in('birthdate_dt', idx)
-    assert_in('localization_s', idx)
-    assert_in('timezone_s', idx)
-    assert_in('socialnetworks_t', idx)
-    assert_in('telnumbers_t', idx)
-    assert_in('skypeaccount_s', idx)
-    assert_in('webpages_t', idx)
-    assert_in('skills_t', idx)
-    assert_in('last_access_login_date_dt', idx)
-    assert_in('last_access_login_ip_s', idx)
-    assert_in('last_access_login_ua_t', idx)
-    assert_in('last_access_session_date_dt', idx)
-    assert_in('last_access_session_ip_s', idx)
-    assert_in('last_access_session_ua_t', idx)
+    assert idx['id'] == c.user.index_id()
+    assert idx['title'] == 'User test-admin'
+    assert idx['type_s'] == 'User'
+    assert idx['username_s'] == 'test-admin'
+    assert idx['email_addresses_t'] == 'email1 email2'
+    assert idx['email_address_s'] == 'email2'
+    assert 'last_password_updated_dt' in idx
+    assert idx['disabled_b'] == False
+    assert 'results_per_page_i' in idx
+    assert 'email_format_s' in idx
+    assert 'disable_user_messages_b' in idx
+    assert idx['display_name_t'] == 'Test Admin'
+    assert idx['sex_s'] == 'Unknown'
+    assert 'birthdate_dt' in idx
+    assert 'localization_s' in idx
+    assert 'timezone_s' in idx
+    assert 'socialnetworks_t' in idx
+    assert 'telnumbers_t' in idx
+    assert 'skypeaccount_s' in idx
+    assert 'webpages_t' in idx
+    assert 'skills_t' in idx
+    assert 'last_access_login_date_dt' in idx
+    assert 'last_access_login_ip_s' in idx
+    assert 'last_access_login_ua_t' in idx
+    assert 'last_access_session_date_dt' in idx
+    assert 'last_access_session_ip_s' in idx
+    assert 'last_access_session_ua_t' in idx
     # provided bby auth provider
-    assert_in('user_registration_date_dt', idx)
+    assert 'user_registration_date_dt' in idx
 
 
 @with_setup(setUp)
@@ -436,9 +436,9 @@ def test_user_index_none_values():
     c.user.set_pref('telnumbers', [None])
     c.user.set_pref('webpages', [None])
     idx = c.user.index()
-    assert_equal(idx['email_addresses_t'], '')
-    assert_equal(idx['telnumbers_t'], '')
-    assert_equal(idx['webpages_t'], '')
+    assert idx['email_addresses_t'] == ''
+    assert idx['telnumbers_t'] == ''
+    assert idx['webpages_t'] == ''
 
 
 @with_setup(setUp)
@@ -461,22 +461,22 @@ def test_user_backfill_login_details():
     c.user.backfill_login_details(auth_provider)
 
     details = M.UserLoginDetails.query.find({'user_id': c.user._id}).sort('ua').all()
-    assert_equal(len(details), 2, details)
-    assert_equal(details[0].ip, '127.0.0.1')
-    assert_equal(details[0].ua, 'TestBrowser/56')
-    assert_equal(details[1].ip, '127.0.0.1')
-    assert_equal(details[1].ua, 'TestBrowser/57')
+    assert len(details) == 2, details
+    assert details[0].ip == '127.0.0.1'
+    assert details[0].ua == 'TestBrowser/56'
+    assert details[1].ip == '127.0.0.1'
+    assert details[1].ua == 'TestBrowser/57'
 
 
 class TestAuditLog:
 
     def test_message_html(self):
         al = h.auditlog_user('our message <script>alert(1)</script>')
-        assert_equal(al.message, textwrap.dedent('''\
+        assert al.message == textwrap.dedent('''\
             IP Address: 127.0.0.1
             User-Agent: None
-            our message <script>alert(1)</script>'''))
-        assert_equal(al.message_html, textwrap.dedent('''\
+            our message <script>alert(1)</script>''')
+        assert al.message_html == textwrap.dedent('''\
             IP Address: 127.0.0.1<br>
             User-Agent: None<br>
-            <strong>our message &lt;script&gt;alert(1)&lt;/script&gt;</strong>'''))
+            <strong>our message &lt;script&gt;alert(1)&lt;/script&gt;</strong>''')
diff --git a/Allura/allura/tests/model/test_discussion.py b/Allura/allura/tests/model/test_discussion.py
index 124c916e6..8ef7d1cb7 100644
--- a/Allura/allura/tests/model/test_discussion.py
+++ b/Allura/allura/tests/model/test_discussion.py
@@ -104,7 +104,7 @@ def test_thread_methods():
     assert t.post_count == 3
     jsn = t.__json__()
     assert '_id' in jsn
-    assert_equals(len(jsn['posts']), 3)
+    assert len(jsn['posts']) == 3
     (p.approve() for p in (p0, p1))
     ThreadLocalORMSession.flush_all()
     assert t.num_replies == 3
@@ -127,10 +127,10 @@ def test_thread_new():
         session(t2).expunge(t2)
         t1_2 = M.Thread.query.get(_id=t1._id)
         t2_2 = M.Thread.query.get(_id=t2._id)
-        assert_equals(t1._id, 'deadbeef')
-        assert_equals(t2._id, 'beefdead')
-        assert_equals(t1_2.subject, 'Test Thread One')
-        assert_equals(t2_2.subject, 'Test Thread Two')
+        assert t1._id == 'deadbeef'
+        assert t2._id == 'beefdead'
+        assert t1_2.subject == 'Test Thread One'
+        assert t2_2.subject == 'Test Thread Two'
 
 
 @with_setup(setUp, tearDown)
@@ -145,7 +145,7 @@ def test_post_methods():
     p.commit()
     assert p.parent is None
     assert p.subject == 'Test Thread'
-    assert_equals(p.attachments, [])
+    assert p.attachments == []
     assert 'wiki/_discuss' in p.url()
     assert p.reply_subject() == 'Re: Test Thread'
     assert p.link_text() == p.subject
@@ -203,9 +203,9 @@ def test_attachment_methods():
     n = M.Notification.query.get(
         subject='[test:wiki] Test comment notification')
     url = h.absurl(f'{p.url()}attachment/{fs.filename}')
-    assert_in(
+    assert (
         '\nAttachments:\n\n'
-        '- [fake.txt]({}) (37 Bytes; text/plain)'.format(url),
+        '- [fake.txt]({}) (37 Bytes; text/plain)'.format(url) in
         n.text)
 
 
@@ -226,7 +226,7 @@ def test_multiple_attachments():
     test_post = t.post('test post')
     test_post.add_multiple_attachments([test_file1, test_file2])
     ThreadLocalORMSession.flush_all()
-    assert_equals(len(test_post.attachments), 2)
+    assert len(test_post.attachments) == 2
     attaches = test_post.attachments
     assert 'test1.txt' in [attaches[0].filename, attaches[1].filename]
     assert 'test2.txt' in [attaches[0].filename, attaches[1].filename]
@@ -244,7 +244,7 @@ def test_add_attachment():
     test_post = t.post('test post')
     test_post.add_attachment(test_file)
     ThreadLocalORMSession.flush_all()
-    assert_equals(len(test_post.attachments), 1)
+    assert len(test_post.attachments) == 1
     attach = test_post.attachments[0]
     assert attach.filename == 'test.txt', attach.filename
     assert attach.content_type == 'text/plain', attach.content_type
@@ -268,10 +268,10 @@ def test_notification_two_attaches():
     n = M.Notification.query.get(
         subject='[test:wiki] Test comment notification')
     base_url = h.absurl(f'{p.url()}attachment/')
-    assert_in(
+    assert (
         '\nAttachments:\n\n'
         '- [fake.txt]({0}fake.txt) (37 Bytes; text/plain)\n'
-        '- [fake2.txt]({0}fake2.txt) (37 Bytes; text/plain)'.format(base_url),
+        '- [fake2.txt]({0}fake2.txt) (37 Bytes; text/plain)'.format(base_url) in
         n.text)
 
 
@@ -289,7 +289,7 @@ def test_discussion_delete():
     ThreadLocalORMSession.flush_all()
     d.delete()
     ThreadLocalORMSession.flush_all()
-    assert_equals(M.ArtifactReference.query.find(dict(_id=rid)).count(), 0)
+    assert M.ArtifactReference.query.find(dict(_id=rid)).count() == 0
 
 
 @with_setup(setUp, tearDown)
@@ -395,7 +395,7 @@ def test_post_url_paginated():
         if page > 0:
             url += '&page=%s' % page
         url += '#' + _p.slug
-        assert_equal(_p.url_paginated(), url)
+        assert _p.url_paginated() == url
 
 
 @with_setup(setUp, tearDown)
@@ -406,7 +406,7 @@ def test_post_url_paginated_with_artifact():
     thread = page.discussion_thread
     comment = thread.post('Comment')
     url = page.url() + '?limit=25#' + comment.slug
-    assert_equals(comment.url_paginated(), url)
+    assert comment.url_paginated() == url
 
 
 @with_setup(setUp, tearDown)
@@ -466,7 +466,7 @@ def test_not_spam_and_has_unmoderated_post_permission(spam_checker):
     t.acl.append(unmoderated_post_permission)
     with h.push_config(c, user=M.User.anonymous()):
         post = t.post('Hey')
-    assert_equal(post.status, 'ok')
+    assert post.status == 'ok'
 
 
 @with_setup(setUp, tearDown)
@@ -481,8 +481,8 @@ def test_not_spam_but_has_no_unmoderated_post_permission(notify_moderators, spam
     t.acl.append(post_permission)
     with h.push_config(c, user=M.User.anonymous()):
         post = t.post('Hey')
-    assert_equal(post.status, 'pending')
-    assert_equal(notify_moderators.call_count, 1)
+    assert post.status == 'pending'
+    assert notify_moderators.call_count == 1
 
 
 @with_setup(setUp, tearDown)
@@ -499,8 +499,8 @@ def test_spam_and_has_unmoderated_post_permission(notify_moderators, spam_checke
     t.acl.append(unmoderated_post_permission)
     with h.push_config(c, user=M.User.anonymous()):
         post = t.post('Hey')
-    assert_equal(post.status, 'pending')
-    assert_equal(notify_moderators.call_count, 1)
+    assert post.status == 'pending'
+    assert notify_moderators.call_count == 1
 
 
 @with_setup(setUp, tearDown)
@@ -510,8 +510,8 @@ def test_thread_subject_not_included_in_text_checked(spam_checker):
     d = M.Discussion(shortname='test', name='test')
     t = M.Thread(discussion_id=d._id, subject='Test Thread')
     t.post('Hello')
-    assert_equal(spam_checker.check.call_count, 1)
-    assert_equal(spam_checker.check.call_args[0][0], 'Hello')
+    assert spam_checker.check.call_count == 1
+    assert spam_checker.check.call_args[0][0] == 'Hello'
 
 
 def test_post_count():
@@ -521,7 +521,7 @@ def test_post_count():
     M.Post(discussion_id=d._id, thread_id=t._id, status='ok')
     M.Post(discussion_id=d._id, thread_id=t._id, status='pending')
     ThreadLocalORMSession.flush_all()
-    assert_equal(t.post_count, 2)
+    assert t.post_count == 2
 
 
 @mock.patch('allura.controllers.discuss.g.spam_checker')
@@ -532,7 +532,7 @@ def test_spam_num_replies(spam_checker):
     ThreadLocalORMSession.flush_all()
     p1 = M.Post(discussion_id=d._id, thread_id=t._id, status='spam')
     p1.spam()
-    assert_equal(t.num_replies, 1)
+    assert t.num_replies == 1
 
 
 def test_deleted_thread_index():
diff --git a/Allura/allura/tests/model/test_filesystem.py b/Allura/allura/tests/model/test_filesystem.py
index 60e78a837..17eb472ae 100644
--- a/Allura/allura/tests/model/test_filesystem.py
+++ b/Allura/allura/tests/model/test_filesystem.py
@@ -133,8 +133,8 @@ class TestFile(TestCase):
             response_body = list(f.serve())
             etag_cache.assert_called_once_with('{}?{}'.format(f.filename,
                                                                f._id.generation_time).encode('utf-8'))
-            assert_equal([b'test1'], response_body)
-            assert_equal(response.content_type, f.content_type)
+            assert [b'test1'] == response_body
+            assert response.content_type == f.content_type
             assert 'Content-Disposition' not in response.headers
 
     def test_serve_embed_false(self):
@@ -146,9 +146,9 @@ class TestFile(TestCase):
             response_body = list(f.serve(embed=False))
             etag_cache.assert_called_once_with('{}?{}'.format(f.filename,
                                                                f._id.generation_time).encode('utf-8'))
-            assert_equal([b'test1'], response_body)
-            assert_equal(response.content_type, f.content_type)
-            assert_equal(response.headers['Content-Disposition'],
+            assert [b'test1'] == response_body
+            assert response.content_type == f.content_type
+            assert (response.headers['Content-Disposition'] ==
                          'attachment;filename="te%20s%E0%AD%AE1.txt"')
 
     def test_image(self):
@@ -199,8 +199,8 @@ class TestFile(TestCase):
         attachment = M.BaseAttachment.save_attachment('user.png', fp,
                                                       save_original=True)
         assert not isinstance(attachment, tuple)   # tuple is for (img, thumb) pairs
-        assert_equal(attachment.length, 500)
-        assert_equal(attachment.filename, 'user.png')
+        assert attachment.length == 500
+        assert attachment.filename == 'user.png'
 
     def test_attachment_name_encoding(self):
         path = os.path.join(os.path.dirname(__file__),
@@ -211,7 +211,7 @@ class TestFile(TestCase):
             'Strukturpr\xfcfung.dvi', fp,
             save_original=True)
         assert not isinstance(attachment, tuple)   # tuple is for (img, thumb) pairs
-        assert_equal(attachment.filename, 'Strukturpr\xfcfung.dvi')
+        assert attachment.filename == 'Strukturpr\xfcfung.dvi'
 
     def _assert_content(self, f, content):
         result = f.rfile().read()
diff --git a/Allura/allura/tests/model/test_notification.py b/Allura/allura/tests/model/test_notification.py
index 5ad0aa6d3..922e1fff2 100644
--- a/Allura/allura/tests/model/test_notification.py
+++ b/Allura/allura/tests/model/test_notification.py
@@ -118,7 +118,7 @@ class TestNotification(unittest.TestCase):
         )
         notification.footer = lambda: ' footer'
         notification.send_direct(c.user._id)
-        assert_equal(sendmail.post.call_count, 0)
+        assert sendmail.post.call_count == 0
 
     @mock.patch('allura.tasks.mail_tasks.sendmail')
     def test_send_direct_wrong_project_context(self, sendmail):
@@ -133,7 +133,7 @@ class TestNotification(unittest.TestCase):
         """
         project1 = c.project
         project2 = M.Project.query.get(shortname='test2')
-        assert_equal(project1.shortname, 'test')
+        assert project1.shortname == 'test'
         c.user = M.User.query.get(username='test-user')
         wiki = project1.app_instance('wiki')
         page = WM.Page.query.get(app_config_id=wiki.config._id)
@@ -188,7 +188,7 @@ class TestPostNotifications(unittest.TestCase):
         ThreadLocalORMSession.flush_all()
         M.MonQTask.list()
         t = M.MonQTask.get()
-        assert_equal(t.args[1], [self.pg.index_id()])
+        assert t.args[1] == [self.pg.index_id()]
 
     def test_post_user_notification(self):
         u = M.User.query.get(username='test-admin')
@@ -220,34 +220,34 @@ class TestPostNotifications(unittest.TestCase):
         self._post_notification()
         ThreadLocalORMSession.flush_all()
 
-        assert_equal(M.Notification.query.get()
-                     ['from_address'], '"Test Admin" <te...@users.localhost>')
-        assert_equal(M.Mailbox.query.find().count(), 2)
+        assert (M.Notification.query.get()
+                     ['from_address'] == '"Test Admin" <te...@users.localhost>')
+        assert M.Mailbox.query.find().count() == 2
 
         # sends the notification out into "mailboxes", and from mailboxes into
         # email tasks
         M.MonQTask.run_ready()
         mboxes = M.Mailbox.query.find().all()
-        assert_equal(len(mboxes), 2)
-        assert_equal(len(mboxes[0].queue), 1)
+        assert len(mboxes) == 2
+        assert len(mboxes[0].queue) == 1
         assert not mboxes[0].queue_empty
-        assert_equal(len(mboxes[1].queue), 1)
+        assert len(mboxes[1].queue) == 1
         assert not mboxes[1].queue_empty
 
         email_tasks = M.MonQTask.query.find({'state': 'ready'}).all()
         # make sure both subscribers will get an email
-        assert_equal(len(email_tasks), 2)
+        assert len(email_tasks) == 2
 
         first_destinations = [e.kwargs['destinations'][0] for e in email_tasks]
-        assert_in(str(c.user._id), first_destinations)
-        assert_in(str(user2._id), first_destinations)
-        assert_equal(email_tasks[0].kwargs['fromaddr'],
+        assert str(c.user._id) in first_destinations
+        assert str(user2._id) in first_destinations
+        assert (email_tasks[0].kwargs['fromaddr'] ==
                      '"Test Admin" <te...@users.localhost>')
-        assert_equal(email_tasks[1].kwargs['fromaddr'],
+        assert (email_tasks[1].kwargs['fromaddr'] ==
                      '"Test Admin" <te...@users.localhost>')
-        assert_equal(email_tasks[0].kwargs['sender'],
+        assert (email_tasks[0].kwargs['sender'] ==
                      'wiki@test.p.in.localhost')
-        assert_equal(email_tasks[1].kwargs['sender'],
+        assert (email_tasks[1].kwargs['sender'] ==
                      'wiki@test.p.in.localhost')
         assert email_tasks[0].kwargs['text'].startswith(
             'Home modified by Test Admin')
@@ -441,14 +441,14 @@ class TestSubscriptionTypes(unittest.TestCase):
         count = M.MonQTask.query.find(dict(
             task_name='allura.tasks.mail_tasks.sendmail',
             state='ready')).count()
-        assert_equal(count, 0)
+        assert count == 0
         user.disabled = False
         ThreadLocalORMSession.flush_all()
         notification.send_direct(user._id)
         count = M.MonQTask.query.find(dict(
             task_name='allura.tasks.mail_tasks.sendmail',
             state='ready')).count()
-        assert_equal(count, 1)
+        assert count == 1
 
     @mock.patch('allura.model.notification.Notification.ref')
     def test_send_digest_disabled_user(self, ref):
@@ -464,7 +464,7 @@ class TestSubscriptionTypes(unittest.TestCase):
         count = M.MonQTask.query.find(dict(
             task_name='allura.tasks.mail_tasks.sendmail',
             state='ready')).count()
-        assert_equal(count, 0)
+        assert count == 0
         user.disabled = False
         ThreadLocalORMSession.flush_all()
         M.Notification.send_digest(
@@ -472,7 +472,7 @@ class TestSubscriptionTypes(unittest.TestCase):
         count = M.MonQTask.query.find(dict(
             task_name='allura.tasks.mail_tasks.sendmail',
             state='ready')).count()
-        assert_equal(count, 1)
+        assert count == 1
 
 
 class TestSiteNotification(unittest.TestCase):
diff --git a/Allura/allura/tests/model/test_oauth.py b/Allura/allura/tests/model/test_oauth.py
index 9f7b7f00c..7179bcd75 100644
--- a/Allura/allura/tests/model/test_oauth.py
+++ b/Allura/allura/tests/model/test_oauth.py
@@ -38,6 +38,6 @@ def test_upsert():
     token1 = M.OAuthConsumerToken.upsert(name, admin)
     token2 = M.OAuthConsumerToken.upsert(name, admin)
     token3 = M.OAuthConsumerToken.upsert(name, user)
-    assert_equal(M.OAuthConsumerToken.query.find().count(), 2)
-    assert_equal(token1._id, token2._id)
-    assert_not_equal(token1._id, token3._id)
+    assert M.OAuthConsumerToken.query.find().count() == 2
+    assert token1._id == token2._id
+    assert token1._id != token3._id
diff --git a/Allura/allura/tests/model/test_project.py b/Allura/allura/tests/model/test_project.py
index 7dc696da7..161df7680 100644
--- a/Allura/allura/tests/model/test_project.py
+++ b/Allura/allura/tests/model/test_project.py
@@ -42,29 +42,29 @@ def setup_with_tools():
 
 
 def test_project():
-    assert_equals(type(c.project.sidebar_menu()), list)
-    assert_in(c.project.script_name, c.project.url())
+    assert type(c.project.sidebar_menu()) == list
+    assert c.project.script_name in c.project.url()
     old_proj = c.project
     h.set_context('test/sub1', neighborhood='Projects')
-    assert_equals(type(c.project.sidebar_menu()), list)
-    assert_equals(type(c.project.sitemap()), list)
-    assert_equals(c.project.sitemap()[1].label, 'Admin')
-    assert_in(old_proj, list(c.project.parent_iter()))
+    assert type(c.project.sidebar_menu()) == list
+    assert type(c.project.sitemap()) == list
+    assert c.project.sitemap()[1].label == 'Admin'
+    assert old_proj in list(c.project.parent_iter())
     h.set_context('test', 'wiki', neighborhood='Projects')
     adobe_nbhd = M.Neighborhood.query.get(name='Adobe')
     p = M.Project.query.get(
         shortname='adobe-1', neighborhood_id=adobe_nbhd._id)
     # assert 'http' in p.url() # We moved adobe into /adobe/, not
     # http://adobe....
-    assert_in(p.script_name, p.url())
-    assert_equals(c.project.shortname, 'test')
-    assert_in('<p>', c.project.description_html)
+    assert p.script_name in p.url()
+    assert c.project.shortname == 'test'
+    assert '<p>' in c.project.description_html
     c.project.uninstall_app('hello-test-mount-point')
     ThreadLocalORMSession.flush_all()
 
     c.project.install_app('Wiki', 'hello-test-mount-point')
     c.project.support_page = 'hello-test-mount-point'
-    assert_equals(c.project.app_config('wiki').tool_name, 'wiki')
+    assert c.project.app_config('wiki').tool_name == 'wiki'
     ThreadLocalORMSession.flush_all()
     with td.raises(ToolError):
         # already installed
@@ -104,10 +104,10 @@ def test_install_app_validates_options():
         for v in [None, '', 'bad@email']:
             with td.raises(ToolError):
                 c.project.install_app('Tickets', 'test-tickets', **{name: v})
-            assert_equals(c.project.app_instance('test-tickets'), None)
+            assert c.project.app_instance('test-tickets') == None
         c.project.install_app('Tickets', 'test-tickets', **{name: 'e@e.com'})
         app = c.project.app_instance('test-tickets')
-        assert_equals(app.config.options[name], 'e@e.com')
+        assert app.config.options[name] == 'e@e.com'
 
 
 def test_project_index():
@@ -142,9 +142,9 @@ def test_subproject():
 def test_anchored_tools():
     c.project.neighborhood.anchored_tools = 'wiki:Wiki, tickets:Ticket'
     c.project.install_app = MagicMock()
-    assert_equals(c.project.sitemap()[0].label, 'Wiki')
-    assert_equals(c.project.install_app.call_args[0][0], 'tickets')
-    assert_equals(c.project.ordered_mounts()[0]['ac'].tool_name, 'wiki')
+    assert c.project.sitemap()[0].label == 'Wiki'
+    assert c.project.install_app.call_args[0][0] == 'tickets'
+    assert c.project.ordered_mounts()[0]['ac'].tool_name == 'wiki'
 
 
 def test_set_ordinal_to_admin_tool():
@@ -152,7 +152,7 @@ def test_set_ordinal_to_admin_tool():
                        user=M.User.by_username('test-admin'),
                        project=M.Project.query.get(shortname='test')):
         sm = c.project.sitemap()
-        assert_equals(sm[-1].tool_name, 'admin')
+        assert sm[-1].tool_name == 'admin'
 
 
 @with_setup(setUp)
diff --git a/Allura/allura/tests/model/test_repo.py b/Allura/allura/tests/model/test_repo.py
index aa85e06b3..2ceccdef2 100644
--- a/Allura/allura/tests/model/test_repo.py
+++ b/Allura/allura/tests/model/test_repo.py
@@ -36,10 +36,10 @@ class TestGitLikeTree:
         tree = M.GitLikeTree()
         tree.set_blob('/dir/dir2/file', 'file-oid')
 
-        assert_equal(tree.blobs, {})
-        assert_equal(tree.get_tree('dir').blobs, {})
-        assert_equal(tree.get_tree('dir').get_tree('dir2')
-                     .blobs, {'file': 'file-oid'})
+        assert tree.blobs == {}
+        assert tree.get_tree('dir').blobs == {}
+        assert (tree.get_tree('dir').get_tree('dir2')
+                     .blobs == {'file': 'file-oid'})
 
     def test_hex(self):
         tree = M.GitLikeTree()
@@ -47,24 +47,24 @@ class TestGitLikeTree:
         hex = tree.hex()
 
         # check the reprs. In case hex (below) fails, this'll be useful
-        assert_equal(repr(tree.get_tree('dir').get_tree('dir2')),
+        assert (repr(tree.get_tree('dir').get_tree('dir2')) ==
                      'b file-oid file')
-        assert_equal(repr(tree),
+        assert (repr(tree) ==
                      't 96af1772ecce1e6044e6925e595d9373ffcd2615 dir')
         # the hex() value shouldn't change, it's an important key
-        assert_equal(hex, '4abba29a43411b9b7cecc1a74f0b27920554350d')
+        assert hex == '4abba29a43411b9b7cecc1a74f0b27920554350d'
 
         # another one should be the same
         tree2 = M.GitLikeTree()
         tree2.set_blob('/dir/dir2/file', 'file-oid')
         hex2 = tree2.hex()
-        assert_equal(hex, hex2)
+        assert hex == hex2
 
     def test_hex_with_unicode(self):
         tree = M.GitLikeTree()
         tree.set_blob('/dir/f•º£', 'file-oid')
         # the hex() value shouldn't change, it's an important key
-        assert_equal(tree.hex(), '51ce65bead2f6452da61d4f6f2e42f8648bf9e4b')
+        assert tree.hex() == '51ce65bead2f6452da61d4f6f2e42f8648bf9e4b'
 
 
 class RepoImplTestBase:
@@ -104,28 +104,28 @@ class RepoTestBase(unittest.TestCase):
         c.app = mock.Mock(**{'config._id': 'deadbeef'})
         repo = M.repository.Repository(tool='git')
         cmd_cats = repo.clone_command_categories(anon=False)
-        assert_equal(cmd_cats, [
+        assert cmd_cats == [
             {'key': 'file', 'name': 'File', 'title': 'Filesystem'}
-        ])
+        ]
 
         cmd_cats = repo.clone_command_categories(anon=True)
-        assert_equal(cmd_cats, [
+        assert cmd_cats == [
             {'key': 'file', 'name': 'File', 'title': 'Filesystem'}
-        ])
+        ]
 
         repo = M.repository.Repository(tool='something-else')  # no "something-else" in config so will use defaults
         cmd_cats = repo.clone_command_categories(anon=False)
-        assert_equal(cmd_cats, [
+        assert cmd_cats == [
             {'key': 'rw', 'name': 'RW', 'title': 'Read/Write'},
             {'key': 'ro', 'name': 'RO', 'title': 'Read Only'},
             {'key': 'https', 'name': 'HTTPS', 'title': 'HTTPS'}
-        ])
+        ]
 
         cmd_cats = repo.clone_command_categories(anon=True)
-        assert_equal(cmd_cats, [
+        assert cmd_cats == [
             {'key': 'ro', 'name': 'RO', 'title': 'Read Only'},
             {'key': 'https_anon', 'name': 'HTTPS', 'title': 'HTTPS'}
-        ])
+        ]
 
 
 class TestLastCommit(unittest.TestCase):
@@ -365,13 +365,13 @@ class TestLastCommit(unittest.TestCase):
         commit2 = self._add_commit('Commit 2', ['file2'])
         commit2.changed_paths = []
         result = self.repo.last_commit_ids(commit2, ['file2'])
-        assert_equal(result, {'file2': commit2._id})
+        assert result == {'file2': commit2._id}
 
     def test_missing_add_record_first_commit(self):
         commit1 = self._add_commit('Commit 1', ['file1'])
         commit1.changed_paths = []
         result = self.repo.last_commit_ids(commit1, ['file1'])
-        assert_equal(result, {'file1': commit1._id})
+        assert result == {'file1': commit1._id}
 
     def test_timeout(self):
         commit1 = self._add_commit('Commit 1', ['file1'])
@@ -704,31 +704,31 @@ class TestMergeRequest:
 
     def test_can_merge_cache_key(self):
         key = self.mr.can_merge_cache_key()
-        assert_equal(key, '12345-09876')
+        assert key == '12345-09876'
 
     def test_get_can_merge_cache(self):
         key = self.mr.can_merge_cache_key()
-        assert_equal(self.mr.get_can_merge_cache(), None)
+        assert self.mr.get_can_merge_cache() == None
         self.mr.can_merge_cache[key] = True
-        assert_equal(self.mr.get_can_merge_cache(), True)
+        assert self.mr.get_can_merge_cache() == True
 
         self.mr.can_merge_cache_key = lambda: '123-123'
         self.mr.can_merge_cache['123-123'] = False
-        assert_equal(self.mr.get_can_merge_cache(), False)
+        assert self.mr.get_can_merge_cache() == False
 
     def test_set_can_merge_cache(self):
         key = self.mr.can_merge_cache_key()
-        assert_equal(self.mr.can_merge_cache, {})
+        assert self.mr.can_merge_cache == {}
         self.mr.set_can_merge_cache(True)
-        assert_equal(self.mr.can_merge_cache, {key: True})
+        assert self.mr.can_merge_cache == {key: True}
 
         self.mr.can_merge_cache_key = lambda: '123-123'
         self.mr.set_can_merge_cache(False)
-        assert_equal(self.mr.can_merge_cache, {key: True, '123-123': False})
+        assert self.mr.can_merge_cache == {key: True, '123-123': False}
 
     def test_can_merge_merged(self):
         self.mr.status = 'merged'
-        assert_equal(self.mr.can_merge(), True)
+        assert self.mr.can_merge() == True
 
     @mock.patch('allura.tasks.repo_tasks.can_merge', autospec=True)
     def test_can_merge_cached(self, can_merge_task):
@@ -738,23 +738,23 @@ class TestMergeRequest:
 
         self.mr.set_can_merge_cache(False)
         self.mr = self._reload_mr_from_db(self.mr)
-        assert_equal(self.mr.can_merge(), False)
+        assert self.mr.can_merge() == False
 
         self.mr.set_can_merge_cache(True)
         self.mr = self._reload_mr_from_db(self.mr)
-        assert_equal(self.mr.can_merge(), True)
-        assert_equal(can_merge_task.post.call_count, 0)
+        assert self.mr.can_merge() == True
+        assert can_merge_task.post.call_count == 0
 
     @mock.patch('allura.tasks.repo_tasks.can_merge', autospec=True)
     def test_can_merge_not_cached(self, can_merge_task):
-        assert_equal(self.mr.can_merge(), None)
+        assert self.mr.can_merge() == None
         can_merge_task.post.assert_called_once_with(self.mr._id)
 
     @mock.patch('allura.tasks.repo_tasks.can_merge', autospec=True)
     def test_can_merge_disabled(self, can_merge_task):
         self.mr.merge_allowed.return_value = False
-        assert_equal(self.mr.can_merge(), None)
-        assert_equal(can_merge_task.post.call_count, 0)
+        assert self.mr.can_merge() == None
+        assert can_merge_task.post.call_count == 0
 
     @mock.patch('allura.tasks.repo_tasks.merge', autospec=True)
     def test_merge(self, merge_task):
@@ -765,21 +765,21 @@ class TestMergeRequest:
         merge_task.reset_mock()
         self.mr.merge_task_status = lambda: 'ready'
         self.mr.merge()
-        assert_equal(merge_task.post.called, False)
+        assert merge_task.post.called == False
 
     def test_merge_task_status(self):
         from allura.tasks import repo_tasks
-        assert_equal(self.mr.merge_task_status(), None)
+        assert self.mr.merge_task_status() == None
         repo_tasks.merge.post(self.mr._id)
-        assert_equal(self.mr.merge_task_status(), 'ready')
+        assert self.mr.merge_task_status() == 'ready'
         M.MonQTask.run_ready()
-        assert_equal(self.mr.merge_task_status(), 'complete')
+        assert self.mr.merge_task_status() == 'complete'
 
     def test_can_merge_task_status(self):
         from allura.tasks import repo_tasks
-        assert_equal(self.mr.can_merge_task_status(), None)
+        assert self.mr.can_merge_task_status() == None
         repo_tasks.can_merge.post(self.mr._id)
-        assert_equal(self.mr.can_merge_task_status(), 'ready')
+        assert self.mr.can_merge_task_status() == 'ready'
         with mock.patch('allura.model.repository.MergeRequest.set_can_merge_cache'):
             M.MonQTask.run_ready()
-        assert_equal(self.mr.can_merge_task_status(), 'complete')
+        assert self.mr.can_merge_task_status() == 'complete'
diff --git a/Allura/allura/tests/model/test_timeline.py b/Allura/allura/tests/model/test_timeline.py
index 067b71991..d60fea319 100644
--- a/Allura/allura/tests/model/test_timeline.py
+++ b/Allura/allura/tests/model/test_timeline.py
@@ -38,5 +38,5 @@ class TestActivityObject_Functional:
         wiki_app = p.app_instance('wiki')
         app_config = wiki_app.config
 
-        assert_equal(bool(app_config.has_activity_access('read', user=M.User.anonymous(), activity=None)),
+        assert (bool(app_config.has_activity_access('read', user=M.User.anonymous(), activity=None)) ==
                      True)
\ No newline at end of file
diff --git a/Allura/allura/tests/scripts/test_create_sitemap_files.py b/Allura/allura/tests/scripts/test_create_sitemap_files.py
index 31fa0bfd1..56e80a383 100644
--- a/Allura/allura/tests/scripts/test_create_sitemap_files.py
+++ b/Allura/allura/tests/scripts/test_create_sitemap_files.py
@@ -50,9 +50,9 @@ class TestCreateSitemapFiles:
             xml_index = ET.parse(os.path.join(tmpdir.path, 'sitemap.xml'))
             ns = {'ns0': 'http://www.sitemaps.org/schemas/sitemap/0.9'}
             locs = [loc.text for loc in xml_index.findall('ns0:sitemap/ns0:loc', ns)]
-            assert_in('http://localhost/allura_sitemap/sitemap-0.xml', locs)
+            assert 'http://localhost/allura_sitemap/sitemap-0.xml' in locs
 
             xml_0 = ET.parse(os.path.join(tmpdir.path, 'sitemap-0.xml'))
             urls = [loc.text for loc in xml_0.findall('ns0:url/ns0:loc', ns)]
-            assert_not_in('http://localhost/p/wiki/', urls)  # blank wiki pages omitted from sitemap
-            assert_in('http://localhost/p/test/sub1/', urls)
+            assert 'http://localhost/p/wiki/' not in urls  # blank wiki pages omitted from sitemap
+            assert 'http://localhost/p/test/sub1/' in urls
diff --git a/Allura/allura/tests/scripts/test_delete_projects.py b/Allura/allura/tests/scripts/test_delete_projects.py
index 6d3f1c3cf..c5af80d49 100644
--- a/Allura/allura/tests/scripts/test_delete_projects.py
+++ b/Allura/allura/tests/scripts/test_delete_projects.py
@@ -91,7 +91,7 @@ class TestDeleteProjects(TestController):
         things = self.things_related_to_project(pid)
         assert len(things) == 0, 'Not all things are deleted: %s' % things
         parent_things_after = self.things_related_to_project(parent_pid)
-        assert_equal(len(parent_things_before), len(parent_things_after))
+        assert len(parent_things_before) == len(parent_things_after)
 
     @patch('allura.lib.plugin.solr_del_project_artifacts', autospec=True)
     def test_solr_index_is_deleted(self, del_solr):
diff --git a/Allura/allura/tests/scripts/test_misc_scripts.py b/Allura/allura/tests/scripts/test_misc_scripts.py
index a20206f56..104ea9f84 100644
--- a/Allura/allura/tests/scripts/test_misc_scripts.py
+++ b/Allura/allura/tests/scripts/test_misc_scripts.py
@@ -38,8 +38,8 @@ class TestClearOldNotifications:
         n = M.Notification(app_config_id=ObjectId(), neighborhood_id=ObjectId(), project_id=ObjectId(),
                            tool_name='blah')
         session(n).flush(n)
-        assert_equal(M.Notification.query.find().count(), 1)
+        assert M.Notification.query.find().count() == 1
         self.run_script(['--back-days', '7'])
-        assert_equal(M.Notification.query.find().count(), 1)
+        assert M.Notification.query.find().count() == 1
         self.run_script(['--back-days', '0'])
-        assert_equal(M.Notification.query.find().count(), 0)
+        assert M.Notification.query.find().count() == 0
diff --git a/Allura/allura/tests/scripts/test_reindexes.py b/Allura/allura/tests/scripts/test_reindexes.py
index c2cdc2bbb..f5f58556c 100644
--- a/Allura/allura/tests/scripts/test_reindexes.py
+++ b/Allura/allura/tests/scripts/test_reindexes.py
@@ -45,7 +45,7 @@ class TestReindexProjects:
             self.run_script(['-n', '/p/', '-p', 'test', '--tasks'])
         assert_logmsg_and_no_warnings_or_errors(logs, 'Reindex project test')
         assert_logmsg_and_no_warnings_or_errors(logs, 'Reindex queued')
-        assert_equal(M.MonQTask.query.find({'task_name': 'allura.tasks.index_tasks.add_projects'}).count(), 1)
+        assert M.MonQTask.query.find({'task_name': 'allura.tasks.index_tasks.add_projects'}).count() == 1
 
 
 class TestReindexUsers:
@@ -71,4 +71,4 @@ class TestReindexUsers:
         assert_logmsg_and_no_warnings_or_errors(logs, 'Reindex user root')
         assert_logmsg_and_no_warnings_or_errors(logs, 'Reindex user test-user-1')
         assert_logmsg_and_no_warnings_or_errors(logs, 'Reindex queued')
-        assert_equal(M.MonQTask.query.find({'task_name': 'allura.tasks.index_tasks.add_users'}).count(), 1)
+        assert M.MonQTask.query.find({'task_name': 'allura.tasks.index_tasks.add_users'}).count() == 1
diff --git a/Allura/allura/tests/templates/jinja_master/test_lib.py b/Allura/allura/tests/templates/jinja_master/test_lib.py
index 9e73a0f54..0acf97104 100644
--- a/Allura/allura/tests/templates/jinja_master/test_lib.py
+++ b/Allura/allura/tests/templates/jinja_master/test_lib.py
@@ -45,7 +45,7 @@ class TestRelatedArtifacts(TemplateTest):
 
     def test_none(self):
         artifact = Mock(related_artifacts=lambda user: [])
-        assert_equal(self._render_related_artifacts(artifact), '')
+        assert self._render_related_artifacts(artifact) == ''
 
     def test_simple(self):
         other = Mock()
@@ -54,12 +54,12 @@ class TestRelatedArtifacts(TemplateTest):
         other.app_config.options.mount_label = 'Foo'
         other.link_text.return_value = 'Bar'
         artifact = Mock(related_artifacts=lambda user: [other])
-        assert_equal(self._render_related_artifacts(artifact), strip_space('''
+        assert self._render_related_artifacts(artifact) == strip_space('''
             <h4>Related</h4>
             <p>
             <a href="/p/test/foo/bar">Test Project: Foo: Bar</a><br>
             </p>
-        '''))
+        ''')
 
     def test_non_artifact(self):
         # e.g. a commit
@@ -73,9 +73,9 @@ class TestRelatedArtifacts(TemplateTest):
                 return '/p/test/code/ci/deadbeef'
 
         artifact = Mock(related_artifacts=lambda user: [CommitThing()])
-        assert_equal(self._render_related_artifacts(artifact), strip_space('''
+        assert self._render_related_artifacts(artifact) == strip_space('''
             <h4>Related</h4>
             <p>
             <a href="/p/test/code/ci/deadbeef">Commit: [deadbeef]</a><br>
             </p>
-        '''))
+        ''')
diff --git a/Allura/allura/tests/test_app.py b/Allura/allura/tests/test_app.py
index ceca74591..5448df2a5 100644
--- a/Allura/allura/tests/test_app.py
+++ b/Allura/allura/tests/test_app.py
@@ -58,27 +58,27 @@ def test_config_options():
 
 def test_config_options_render_attrs():
     opt = app.ConfigOption('test1', str, None, extra_attrs={'type': 'url'})
-    assert_equal(opt.render_attrs(), 'type="url"')
+    assert opt.render_attrs() == 'type="url"'
 
 
 def test_config_option_without_validator():
     opt = app.ConfigOption('test1', str, None)
-    assert_equal(opt.validate(None), None)
-    assert_equal(opt.validate(''), '')
-    assert_equal(opt.validate('val'), 'val')
+    assert opt.validate(None) == None
+    assert opt.validate('') == ''
+    assert opt.validate('val') == 'val'
 
 
 def test_config_option_with_validator():
     v = fev.NotEmpty()
     opt = app.ConfigOption('test1', str, None, validator=v)
-    assert_equal(opt.validate('val'), 'val')
+    assert opt.validate('val') == 'val'
     assert_raises(fev.Invalid, opt.validate, None)
     assert_raises(fev.Invalid, opt.validate, '')
 
 
 def test_options_on_install_default():
     a = app.Application(c.project, c.app.config)
-    assert_equal(a.options_on_install(), [])
+    assert a.options_on_install() == []
 
 
 def test_options_on_install():
@@ -91,7 +91,7 @@ def test_options_on_install():
         config_on_install = ['url', 'private']
 
     a = TestApp(c.project, c.app.config)
-    assert_equal(a.options_on_install(), opts)
+    assert a.options_on_install() == opts
 
 
 def test_main_menu():
@@ -105,8 +105,8 @@ def test_main_menu():
 
     a = TestApp(c.project, c.app.config)
     main_menu = a.main_menu()
-    assert_equal(len(main_menu), 1)
-    assert_equal(main_menu[0].children, [])  # default main_menu implementation should drop the children from sitemap()
+    assert len(main_menu) == 1
+    assert main_menu[0].children == []  # default main_menu implementation should drop the children from sitemap()
 
 
 def test_sitemap():
@@ -138,15 +138,15 @@ def test_handle_artifact_unicode(qg):
 
     msg = dict(payload='foo ƒ†©¥˙¨ˆ'.encode(), message_id=1, headers={})
     a.handle_artifact_message(ticket, msg)
-    assert_equal(post.attach.call_args[0][1].getvalue(), 'foo ƒ†©¥˙¨ˆ'.encode())
+    assert post.attach.call_args[0][1].getvalue() == 'foo ƒ†©¥˙¨ˆ'.encode()
 
     msg = dict(payload=b'foo', message_id=1, headers={})
     a.handle_artifact_message(ticket, msg)
-    assert_equal(post.attach.call_args[0][1].getvalue(), b'foo')
+    assert post.attach.call_args[0][1].getvalue() == b'foo'
 
     msg = dict(payload="\x94my quote\x94".encode(), message_id=1, headers={})
     a.handle_artifact_message(ticket, msg)
-    assert_equal(post.attach.call_args[0][1].getvalue(), '\x94my quote\x94'.encode())
+    assert post.attach.call_args[0][1].getvalue() == '\x94my quote\x94'.encode()
 
     # assert against prod example
     msg_raw = """Message-Id: <15...@webmail.messagingengine.com>
diff --git a/Allura/allura/tests/test_commands.py b/Allura/allura/tests/test_commands.py
index edb50b1d3..9f3f3f1bd 100644
--- a/Allura/allura/tests/test_commands.py
+++ b/Allura/allura/tests/test_commands.py
@@ -251,7 +251,7 @@ class TestEnsureIndexCommand:
         cmd = show_models.EnsureIndexCommand('ensure_index')
         cmd._update_indexes(collection, indexes)
 
-        assert_equal(collection.mock_calls, [
+        assert collection.mock_calls == [
             call.index_information(),
             call.ensure_index(
                 [('foo', 1), ('bar', 1), ('temporary_extra_field_for_indexing', 1)]),
@@ -265,7 +265,7 @@ class TestEnsureIndexCommand:
             call.drop_index('_foo_baz_temporary_extra_field_for_indexing'),
             call.ensure_index([('foo', 1), ('baz', 1)], unique=True, sparse=False),
             call.ensure_index([('foo', 1), ('bar', 1)], unique=False, sparse=False, background=True)
-        ])
+        ]
 
 
 class TestTaskCommand:
@@ -275,16 +275,16 @@ class TestTaskCommand:
 
     def test_commit(self):
         exit_code = taskd.TaskCommand('task').run([test_config, 'commit'])
-        assert_equal(M.MonQTask.query.find({'task_name': 'allura.tasks.index_tasks.commit'}).count(), 1)
-        assert_equal(exit_code, 0)
+        assert M.MonQTask.query.find({'task_name': 'allura.tasks.index_tasks.commit'}).count() == 1
+        assert exit_code == 0
 
     def test_list(self):
         exit_code = taskd.TaskCommand('task').run([test_config, 'list'])
-        assert_equal(exit_code, 0)
+        assert exit_code == 0
 
     def test_count(self):
         exit_code = taskd.TaskCommand('task').run([test_config, 'count'])
-        assert_equal(exit_code, 0)
+        assert exit_code == 0
 
     def test_retry(self):
         # self.test_commit()
@@ -293,24 +293,24 @@ class TestTaskCommand:
             '--filter-name-prefix', 'allura.tasks.index_tasks.',
             '--filter-result-regex', 'pysolr',
         ])
-        assert_equal(exit_code, 0)
+        assert exit_code == 0
 
     def test_purge(self):
         # create task
         self.test_commit()
-        assert_equal(M.MonQTask.query.find().count(), 1)
+        assert M.MonQTask.query.find().count() == 1
         M.MonQTask.query.update({'task_name': 'allura.tasks.index_tasks.commit'}, {'$set': {'state': 'complete'}})
         # run purge; verify 0 records
         exit_code = taskd.TaskCommand('task').run([
             test_config, 'purge',
         ])
-        assert_equal(exit_code, 0)
-        assert_equal(M.MonQTask.query.find().count(), 0)
+        assert exit_code == 0
+        assert M.MonQTask.query.find().count() == 0
 
     def test_purge_old_only(self):
         # create task
         self.test_commit()
-        assert_equal(M.MonQTask.query.find().count(), 1)
+        assert M.MonQTask.query.find().count() == 1
 
         # force task to be in complete state
         M.MonQTask.query.update({'task_name': 'allura.tasks.index_tasks.commit'}, {'$set': {'state': 'complete'}})
@@ -318,8 +318,8 @@ class TestTaskCommand:
         exit_code = taskd.TaskCommand('task').run([
             test_config, 'purge', '--filter-queued-days-ago', '180',
         ])
-        assert_equal(exit_code, 0)
-        assert_equal(M.MonQTask.query.find().count(), 1)
+        assert exit_code == 0
+        assert M.MonQTask.query.find().count() == 1
 
         # modify task to be old
         then = datetime.datetime.utcnow() - datetime.timedelta(days=200)
@@ -330,8 +330,8 @@ class TestTaskCommand:
         exit_code = taskd.TaskCommand('task').run([
             test_config, 'purge', '--filter-queued-days-ago', '180',
         ])
-        assert_equal(exit_code, 0)
-        assert_equal(M.MonQTask.query.find().count(), 0)
+        assert exit_code == 0
+        assert M.MonQTask.query.find().count() == 0
 
 
 class TestTaskdCleanupCommand:
@@ -454,10 +454,10 @@ class TestShowModels:
         cmd = show_models.ShowModelsCommand('models')
         with OutputCapture() as output:
             cmd.run([test_config])
-        assert_in('''allura.model.notification.SiteNotification
+        assert '''allura.model.notification.SiteNotification
          - <FieldProperty _id>
          - <FieldProperty content>
-        ''', output.captured)
+        ''' in output.captured
 
 class TestReindexAsTask:
 
@@ -467,12 +467,12 @@ class TestReindexAsTask:
     def test_command_post(self):
         show_models.ReindexCommand.post('-p "project 3"')
         tasks = M.MonQTask.query.find({'task_name': self.task_name}).all()
-        assert_equal(len(tasks), 1)
+        assert len(tasks) == 1
         task = tasks[0]
-        assert_equal(task.args, [self.cmd, '-p "project 3"'])
+        assert task.args == [self.cmd, '-p "project 3"']
 
     def test_command_doc(self):
-        assert_in('Usage:', show_models.ReindexCommand.__doc__)
+        assert 'Usage:' in show_models.ReindexCommand.__doc__
 
     @patch('allura.command.show_models.ReindexCommand')
     def test_run_command(self, command):
@@ -487,7 +487,7 @@ class TestReindexAsTask:
         try:
             with td.raises(Exception) as e:
                 M.MonQTask.run_ready()
-            assert_in('Error parsing args', str(e.exc))
+            assert 'Error parsing args' in str(e.exc)
         finally:
             # cleanup - remove bad MonQTask
             M.MonQTask.query.remove()
@@ -511,7 +511,7 @@ class TestReindexCommand:
         cmd.options, args = cmd.parser.parse_args([
             '-p', 'test', '--solr', '--solr-hosts=http://blah.com/solr/forge'])
         cmd._chunked_add_artifacts(list(range(10)))
-        assert_equal(Solr.call_args[0][0], 'http://blah.com/solr/forge')
+        assert Solr.call_args[0][0] == 'http://blah.com/solr/forge'
 
     @patch('pysolr.Solr')
     def test_solr_hosts_list(self, Solr):
@@ -520,11 +520,10 @@ class TestReindexCommand:
             '-p', 'test', '--solr', '--solr-hosts=http://blah.com/solr/forge,https://other.net/solr/forge'])
         cmd._chunked_add_artifacts(list(range(10)))
         # check constructors of first and second Solr() instantiations
-        assert_equal(
-            {Solr.call_args_list[0][0][0], Solr.call_args_list[1][0][0]},
+        assert (
+            {Solr.call_args_list[0][0][0], Solr.call_args_list[1][0][0]} ==
             {'http://blah.com/solr/forge',
-                 'https://other.net/solr/forge'}
-        )
+                 'https://other.net/solr/forge'})
 
     @patch('allura.command.show_models.utils')
     def test_project_regex(self, utils):
@@ -539,12 +538,12 @@ class TestReindexCommand:
         cmd.options = Mock(tasks=True, max_chunk=10 * 1000, ming_config=None)
         ref_ids = list(range(10 * 1000 * 2 + 20))
         cmd._chunked_add_artifacts(ref_ids)
-        assert_equal(len(add_artifacts.post.call_args_list), 3)
-        assert_equal(
-            len(add_artifacts.post.call_args_list[0][0][0]), 10 * 1000)
-        assert_equal(
-            len(add_artifacts.post.call_args_list[1][0][0]), 10 * 1000)
-        assert_equal(len(add_artifacts.post.call_args_list[2][0][0]), 20)
+        assert len(add_artifacts.post.call_args_list) == 3
+        assert (
+            len(add_artifacts.post.call_args_list[0][0][0]) == 10 * 1000)
+        assert (
+            len(add_artifacts.post.call_args_list[1][0][0]) == 10 * 1000)
+        assert len(add_artifacts.post.call_args_list[2][0][0]) == 20
 
     @patch('allura.command.show_models.add_artifacts')
     def test_post_add_artifacts_too_large(self, add_artifacts):
@@ -571,7 +570,7 @@ class TestReindexCommand:
             call([3], **kw),
             call([4], **kw)
         ]
-        assert_equal(expected, add_artifacts.post.call_args_list)
+        assert expected == add_artifacts.post.call_args_list
 
     @patch('allura.command.show_models.add_artifacts')
     def test_post_add_artifacts_other_error(self, add_artifacts):
diff --git a/Allura/allura/tests/test_decorators.py b/Allura/allura/tests/test_decorators.py
index 0935b7b70..40d68062e 100644
--- a/Allura/allura/tests/test_decorators.py
+++ b/Allura/allura/tests/test_decorators.py
@@ -74,10 +74,10 @@ class TestMemoize:
         const1 = remember_randomy(False)
         rand_kwargs1 = remember_randomy(True, foo='asdf')
         rand_kwargs2 = remember_randomy(True, foo='xyzzy')
-        assert_equal(rand1, rand2)
-        assert_equal(const1, "constant")
-        assert_not_equal(rand1, rand_kwargs1)
-        assert_not_equal(rand_kwargs1, rand_kwargs2)
+        assert rand1 == rand2
+        assert const1 == "constant"
+        assert rand1 != rand_kwargs1
+        assert rand_kwargs1 != rand_kwargs2
 
     def test_methods(self):
 
@@ -103,10 +103,10 @@ class TestMemoize:
         other1 = r.other(True)
         other2 = r.other(True)
 
-        assert_equal(rand1, rand2)
-        assert_equal(const1, "constant")
-        assert_not_equal(rand1, other1)
-        assert_equal(other1, other2)
+        assert rand1 == rand2
+        assert const1 == "constant"
+        assert rand1 != other1
+        assert other1 == other2
 
         r2 = Randomy()
         r2rand1 = r2.randomy(True)
@@ -115,10 +115,10 @@ class TestMemoize:
         r2other1 = r2.other(True)
         r2other2 = r2.other(True)
 
-        assert_not_equal(r2rand1, rand1)
-        assert_equal(r2rand1, r2rand2)
-        assert_not_equal(r2other1, other1)
-        assert_equal(r2other1, r2other2)
+        assert r2rand1 != rand1
+        assert r2rand1 == r2rand2
+        assert r2other1 != other1
+        assert r2other1 == r2other2
 
     def test_methods_garbage_collection(self):
 
diff --git a/Allura/allura/tests/test_globals.py b/Allura/allura/tests/test_globals.py
index 3b1334915..c37901c13 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -206,7 +206,7 @@ def test_macro_members():
     p_test.add_user(M.User.by_username('test-user-0'), ['Member'])
     ThreadLocalORMSession.flush_all()
     r = g.markdown_wiki.convert('[[members limit=2]]').replace('\t', '').replace('\n', '')
-    assert_equal(r,
+    assert (r ==
                  '<div class="markdown_content"><h6>Project Members:</h6>'
                  '<ul class="md-users-list">'
                  '<li><a href="/u/test-admin/">Test Admin</a> (admin)</li>'
@@ -221,7 +221,7 @@ def test_macro_members_escaping():
     user = M.User.by_username('test-admin')
     user.display_name = 'Test Admin <script>'
     r = g.markdown_wiki.convert('[[members]]')
-    assert_equal(r.replace('\n', '').replace('\t', ''),
+    assert (r.replace('\n', '').replace('\t', '') ==
                  '<div class="markdown_content"><h6>Project Members:</h6>'
                  '<ul class="md-users-list">'
                  '<li><a href="/u/test-admin/">Test Admin &lt;script&gt;</a> (admin)</li>'
@@ -234,7 +234,7 @@ def test_macro_project_admins():
     user.display_name = 'Test Ådmin <script>'
     with h.push_context('test', neighborhood='Projects'):
         r = g.markdown_wiki.convert('[[project_admins]]')
-    assert_equal(r.replace('\n', ''),
+    assert (r.replace('\n', '') ==
                  '<div class="markdown_content"><h6>Project Admins:</h6>'
                  '<ul class="md-users-list">'
                  '    <li><a href="/u/test-admin/">Test \xc5dmin &lt;script&gt;</a></li>'
@@ -283,7 +283,7 @@ def test_macro_include_no_extra_br():
 <div class="markdown_content"><p>included page 3</p></div>
 </div>
 <p></p></div>'''
-    assert_equal(squish_spaces(html), squish_spaces(expected_html))
+    assert squish_spaces(html) == squish_spaces(expected_html)
 
 
 @with_setup(setUp, tearDown)
@@ -315,9 +315,9 @@ def test_macro_include_permissions():
         c.user = M.User.anonymous()
         md = '[[include ref=CanRead]]\n[[include ref=wiki2:CanNotRead]]'
         html = g.markdown_wiki.convert(md)
-        assert_in('Can see this!', html)
-        assert_not_in('Can not see this!', html)
-        assert_in("[[include: you don't have a read permission for wiki2:CanNotRead]]", html)
+        assert 'Can see this!' in html
+        assert 'Can not see this!' not in html
+        assert "[[include: you don't have a read permission for wiki2:CanNotRead]]" in html
 
 
 @patch('oembed.OEmbedEndpoint.fetch')
@@ -328,8 +328,8 @@ def test_macro_embed(oembed_fetch):
         "title": "Nature's 3D Printer: MIND BLOWING Cocoon in Rainforest - Smarter Every Day 94",
     }
     r = g.markdown_wiki.convert('[[embed url=http://www.youtube.com/watch?v=kOLpSPEA72U]]')
-    assert_in('<p><iframe height="270" '
-              'src="https://www.youtube-nocookie.com/embed/kOLpSPEA72U?feature=oembed" width="480"></iframe></p>',
+    assert ('<p><iframe height="270" '
+              'src="https://www.youtube-nocookie.com/embed/kOLpSPEA72U?feature=oembed" width="480"></iframe></p>' in
               r.replace('\n', ''))
 
 
@@ -338,24 +338,24 @@ def test_macro_embed_video_gone():
     r = g.markdown_wiki.convert('[[embed url=https://www.youtube.com/watch?v=OWsFqPZ3v-0]]')
     r = str(r)  # convert away from Markup, to get better assertion diff output
     # either of these could happen depending on the mood of youtube's oembed API:
-    assert_in(r, [
+    assert r in [
         '<div class="markdown_content"><p>Video not available</p></div>',
         '<div class="markdown_content"><p>Could not embed: https://www.youtube.com/watch?v=OWsFqPZ3v-0</p></div>',
-    ])
+    ]
 
 
 @patch('oembed.OEmbedEndpoint.fetch')
 def test_macro_embed_video_error(oembed_fetch):
     oembed_fetch.side_effect = OEmbedError('Invalid mime-type in response...')
     r = g.markdown_wiki.convert('[[embed url=http://www.youtube.com/watch?v=6YbBmqUnoQM]]')
-    assert_equal(r, '<div class="markdown_content"><p>Could not embed: '
+    assert (r == '<div class="markdown_content"><p>Could not embed: '
                     'http://www.youtube.com/watch?v=6YbBmqUnoQM</p></div>')
 
 
 def test_macro_embed_notsupported():
     r = g.markdown_wiki.convert('[[embed url=http://vimeo.com/46163090]]')
-    assert_equal(
-        r, '<div class="markdown_content"><p>[[embed url=http://vimeo.com/46163090]]</p></div>')
+    assert (
+        r == '<div class="markdown_content"><p>[[embed url=http://vimeo.com/46163090]]</p></div>')
 
 
 def test_markdown_toc():
@@ -389,19 +389,19 @@ def test_wiki_artifact_links():
 def test_markdown_links():
     with patch.dict(tg.config, {'nofollow_exempt_domains': 'foobar.net'}):
         text = g.markdown.convert('Read [here](http://foobar.net/) about our project')
-        assert_in('class="" href="http://foobar.net/">here</a> about', text)
+        assert 'class="" href="http://foobar.net/">here</a> about' in text
 
     text = g.markdown.convert('Read [here](http://foobar.net/) about our project')
-    assert_in('class="" href="http://foobar.net/" rel="nofollow">here</a> about', text)
+    assert 'class="" href="http://foobar.net/" rel="nofollow">here</a> about' in text
 
     text = g.markdown.convert('Read [here](/p/foobar/blah) about our project')
-    assert_in('class="" href="/p/foobar/blah">here</a> about', text)
+    assert 'class="" href="/p/foobar/blah">here</a> about' in text
 
     text = g.markdown.convert('Read [here](/p/foobar/blah/) about our project')
-    assert_in('class="" href="/p/foobar/blah/">here</a> about', text)
+    assert 'class="" href="/p/foobar/blah/">here</a> about' in text
 
     text = g.markdown.convert('Read <http://foobar.net/> about our project')
-    assert_in('href="http://foobar.net/" rel="nofollow">http://foobar.net/</a> about', text)
+    assert 'href="http://foobar.net/" rel="nofollow">http://foobar.net/</a> about' in text
 
 
 def test_markdown_and_html():
@@ -413,7 +413,7 @@ def test_markdown_and_html():
 def test_markdown_within_html():
     with h.push_context('test', neighborhood='Projects'):
         r = g.markdown_wiki.convert('<div style="float:left" markdown>**blah**</div>')
-    assert_in('<div style="float: left;"><p><strong>blah</strong></p></div>',
+    assert ('<div style="float: left;"><p><strong>blah</strong></p></div>' in
               r.replace('\n', ''))
 
 
@@ -425,37 +425,37 @@ def test_markdown_with_html_comments():
 def test_markdown_big_text():
     '''If text is too big g.markdown.convert should return plain text'''
     text = 'a' * 40001
-    assert_equal(g.markdown.convert(text), '<pre>%s</pre>' % text)
-    assert_equal(g.markdown_wiki.convert(text), '<pre>%s</pre>' % text)
+    assert g.markdown.convert(text) == '<pre>%s</pre>' % text
+    assert g.markdown_wiki.convert(text) == '<pre>%s</pre>' % text
 
 
 @td.with_wiki
 def test_markdown_basics():
     with h.push_context('test', 'wiki', neighborhood='Projects'):
         text = g.markdown.convert('# Foo!\n[Home]')
-        assert_equal(text,
+        assert (text ==
                      '<div class="markdown_content"><h1 id="foo">Foo!</h1>\n'
                      '<p><a class="alink" href="/p/test/wiki/Home/">[Home]</a></p></div>')
         text = g.markdown.convert('# Foo!\n[Rooted]')
-        assert_equal(text,
+        assert (text ==
                      '<div class="markdown_content"><h1 id="foo">Foo!</h1>\n'
                      '<p><span>[Rooted]</span></p></div>')
 
-    assert_equal(
-        g.markdown.convert('Multi\nLine'),
+    assert (
+        g.markdown.convert('Multi\nLine') ==
         '<div class="markdown_content"><p>Multi<br/>\n'
         'Line</p></div>')
-    assert_equal(
-        g.markdown.convert('Multi\n\nLine'),
+    assert (
+        g.markdown.convert('Multi\n\nLine') ==
         '<div class="markdown_content"><p>Multi</p>\n'
         '<p>Line</p></div>')
 
     # should not raise an exception:
-    assert_equal(
-        g.markdown.convert("<class 'foo'>"),
+    assert (
+        g.markdown.convert("<class 'foo'>") ==
         '''<div class="markdown_content"><p>&lt;class 'foo'=""&gt;&lt;/class&gt;</p></div>''')
 
-    assert_equal(
+    assert (
         g.markdown.convert('''# Header
 
 Some text in a regular paragraph
@@ -463,29 +463,26 @@ Some text in a regular paragraph
     :::python
     for i in range(10):
         print i
-'''),
+''') ==
         # no <br
         '<div class="markdown_content"><h1 id="header">Header</h1>\n'
         '<p>Some text in a regular paragraph</p>\n'
         '<div class="codehilite"><pre><span></span><code><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>\n'
         '    <span class="nb">print</span> <span class="n">i</span>\n'
         '</code></pre></div>\n'
-        '</div>'
-    )
-    assert_equal(
-        g.forge_markdown(email=True).convert('[Home]'),
+        '</div>')
+    assert (
+        g.forge_markdown(email=True).convert('[Home]') ==
         # uses localhost:
-        '<div class="markdown_content"><p><a class="alink" href="http://localhost/p/test/wiki/Home/">[Home]</a></p></div>'
-    )
-    assert_equal(
+        '<div class="markdown_content"><p><a class="alink" href="http://localhost/p/test/wiki/Home/">[Home]</a></p></div>')
+    assert (
         g.markdown.convert('''
 ~~~~
 def foo(): pass
-~~~~'''),
+~~~~''') ==
         '<div class="markdown_content"><div class="codehilite"><pre><span></span><code>def foo(): pass\n'
         '</code></pre></div>\n'
-        '</div>'
-    )
+        '</div>')
 
 
 def test_markdown_list_without_break():
@@ -494,64 +491,60 @@ def test_markdown_list_without_break():
     # it is valid in the CommonMark spec https://spec.commonmark.org/0.30/#lists
     # TODO: try https://github.com/adamb70/mdx-breakless-lists
     #       or https://gitlab.com/ayblaq/prependnewline
-    assert_equal(
+    assert (
         g.markdown.convert('''\
 Regular text
 * first item
-* second item'''),
+* second item''') ==
         '<div class="markdown_content"><p>Regular text\n'  # no <br>
         '* first item\n'  # no <br>
-        '* second item</p></div>'
-    )
+        '* second item</p></div>')
 
-    assert_equal(
+    assert (
         g.markdown.convert('''\
 Regular text
 - first item
-- second item'''),
+- second item''') ==
         '<div class="markdown_content"><p>Regular text<br/>\n'
         '- first item<br/>\n'
-        '- second item</p></div>'
-    )
+        '- second item</p></div>')
 
-    assert_equal(
+    assert (
         g.markdown.convert('''\
 Regular text
 + first item
-+ second item'''),
++ second item''') ==
         '<div class="markdown_content"><p>Regular text<br/>\n'
         '+ first item<br/>\n'
-        '+ second item</p></div>'
-    )
+        '+ second item</p></div>')
 
-    assert_equal(
+    assert (
         g.markdown.convert('''\
 Regular text
 1. first item
-2. second item'''),
+2. second item''') ==
         '<div class="markdown_content"><p>Regular text<br/>\n'
         '1. first item<br/>\n'
-        '2. second item</p></div>'
-    )
+        '2. second item</p></div>')
 
 
 def test_markdown_autolink():
     tgt = 'http://everything2.com/?node=nate+oostendorp'
     s = g.markdown.convert('This is %s' % tgt)
-    assert_equal(
-        s, f'<div class="markdown_content"><p>This is <a href="{tgt}" rel="nofollow">{tgt}</a></p></div>')
+    assert (
+        s == f'<div class="markdown_content"><p>This is <a href="{tgt}" rel="nofollow">{tgt}</a></p></div>')
     assert '<a href=' in g.markdown.convert('This is http://domain.net')
     # beginning of doc
-    assert_in('<a href=', g.markdown.convert('http://domain.net abc'))
+    assert '<a href=' in g.markdown.convert('http://domain.net abc')
     # beginning of a line
-    assert_in('<br/>\n<a href="http://',
+    assert ('<br/>\n<a href="http://' in
               g.markdown.convert('foobar\nhttp://domain.net abc'))
     # no conversion of these urls:
-    assert_in('a blahttp://sdf.com z',
+    assert ('a blahttp://sdf.com z' in
               g.markdown.convert('a blahttp://sdf.com z'))
-    assert_in('literal <code>http://domain.net</code> literal',
+    assert ('literal <code>http://domain.net</code> literal' in
               g.markdown.convert('literal `http://domain.net` literal'))
-    assert_in('<pre><span></span><code>preformatted http://domain.net\n</code></pre>',
+    assert ('<pre><span></span><code>preformatted http://domain.net\n</code></pre>' in
               g.markdown.convert('    :::text\n'
                                  '    preformatted http://domain.net'))
 
@@ -565,31 +558,31 @@ def test_markdown_autolink_with_escape():
 
 def test_markdown_invalid_script():
     r = g.markdown.convert('<script>alert(document.cookies)</script>')
-    assert_equal('<div class="markdown_content">&lt;script&gt;alert(document.cookies)&lt;/script&gt;\n</div>', r)
+    assert '<div class="markdown_content">&lt;script&gt;alert(document.cookies)&lt;/script&gt;\n</div>' == r
 
 
 def test_markdown_invalid_onerror():
     r = g.markdown.convert('<img src=x onerror=alert(document.cookie)>')
-    assert_not_in('onerror', r)
+    assert 'onerror' not in r
 
 
 def test_markdown_invalid_tagslash():
     r = g.markdown.convert('<div/onload><img src=x onerror=alert(document.cookie)>')
-    assert_not_in('onerror', r)
+    assert 'onerror' not in r
 
 
 def test_markdown_invalid_script_in_link():
     r = g.markdown.convert('[xss](http://"><a onmouseover=prompt(document.domain)>xss</a>)')
-    assert_equal('<div class="markdown_content"><p><a class="" '
+    assert ('<div class="markdown_content"><p><a class="" '
                  '''href='http://"&gt;&lt;a%20onmouseover=prompt(document.domain)&gt;xss&lt;/a&gt;' '''
-                 'rel="nofollow">xss</a></p></div>', r)
+                 'rel="nofollow">xss</a></p></div>' == r)
 
 
 def test_markdown_invalid_script_in_link2():
     r = g.markdown.convert('[xss](http://"><img src=x onerror=alert(document.cookie)>)')
-    assert_equal('<div class="markdown_content"><p><a class="" '
+    assert ('<div class="markdown_content"><p><a class="" '
                  '''href='http://"&gt;&lt;img%20src=x%20onerror=alert(document.cookie)&gt;' '''
-                 'rel="nofollow">xss</a></p></div>', r)
+                 'rel="nofollow">xss</a></p></div>' == r)
 
 
 def test_markdown_extremely_slow():
@@ -706,7 +699,7 @@ def test_filtering():
         r = g.markdown_wiki.convert(
             '[[projects category="%s"]]' % random_trove.fullpath)
         project_names = get_project_names(r)
-        assert_equal([test_project.name], project_names)
+        assert [test_project.name] == project_names
 
 
 def test_projects_macro():
@@ -732,7 +725,7 @@ def test_myprojects_macro():
         if p.deleted or p.is_nbhd_project:
             continue
         proj_title = f'<h2><a href="{p.url()}">{p.name}</a></h2>'
-        assert_in(proj_title, r)
+        assert proj_title in r
 
     h.set_context('u/test-user-1', 'wiki', neighborhood='Users')
     user = M.User.query.get(username='test-user-1')
@@ -741,7 +734,7 @@ def test_myprojects_macro():
         if p.deleted or p.is_nbhd_project:
             continue
         proj_title = f'<h2><a href="{p.url()}">{p.name}</a></h2>'
-        assert_in(proj_title, r)
+        assert proj_title in r
 
 
 @td.with_wiki
@@ -768,12 +761,12 @@ def test_hideawards_macro():
 
     with h.push_context(p_nbhd.neighborhood_project._id):
         r = g.markdown_wiki.convert('[[projects]]')
-        assert_in('<div class="feature"> <a href="http://award.org" rel="nofollow" title="Winner!">'
-                  'Award short</a> </div>',
+        assert ('<div class="feature"> <a href="http://award.org" rel="nofollow" title="Winner!">'
+                  'Award short</a> </div>' in
                   squish_spaces(r))
 
         r = g.markdown_wiki.convert('[[projects show_awards_banner=False]]')
-        assert_not_in('Award short', r)
+        assert 'Award short' not in r
 
 
 @td.with_tool('test', 'Blog', 'blog')
@@ -792,11 +785,11 @@ def test_project_blog_posts_macro():
         )
 
         r = g.markdown_wiki.convert('[[project_blog_posts]]')
-        assert_in('Test title</a></h3>', r)
-        assert_in('Test title2</a></h3>', r)
-        assert_in('<div class="markdown_content"><p>test post</p></div>', r)
-        assert_in('<div class="markdown_content"><p>test post2</p></div>', r)
-        assert_in('by <em>Test Admin</em>', r)
+        assert 'Test title</a></h3>' in r
+        assert 'Test title2</a></h3>' in r
+        assert '<div class="markdown_content"><p>test post</p></div>' in r
+        assert '<div class="markdown_content"><p>test post2</p></div>' in r
+        assert 'by <em>Test Admin</em>' in r
 
 
 def test_project_screenshots_macro():
@@ -806,8 +799,8 @@ def test_project_screenshots_macro():
 
         r = g.markdown_wiki.convert('[[project_screenshots]]')
 
-        assert_in('href="/p/test/screenshot/test_file.jpg"', r)
-        assert_in('src="/p/test/screenshot/test_file.jpg/thumb"', r)
+        assert 'href="/p/test/screenshot/test_file.jpg"' in r
+        assert 'src="/p/test/screenshot/test_file.jpg/thumb"' in r
 
 
 def get_project_names(r):
@@ -953,35 +946,35 @@ class TestEmojis(unittest.TestCase):
 
     def test_markdown_emoji_atomic(self):
         output = g.markdown.convert(':smile:')
-        assert_in('<p>\U0001F604</p>', output)
+        assert '<p>\U0001F604</p>' in output
         output = g.markdown.convert(':+1:')
-        assert_in('<p>\U0001F44D</p>', output)
+        assert '<p>\U0001F44D</p>' in output
         output = g.markdown.convert(':Bosnia_&_Herzegovina:')
-        assert_in('<p>\U0001F1E7\U0001F1E6</p>', output)
+        assert '<p>\U0001F1E7\U0001F1E6</p>' in output
         output = g.markdown.convert(':Åland_Islands:')  # emoji code with non-ascii character
-        assert_in('<p>\U0001F1E6\U0001F1FD</p>', output)
+        assert '<p>\U0001F1E6\U0001F1FD</p>' in output
 
     def test_markdown_emoji_with_text(self):
         output = g.markdown.convert('Thumbs up emoji :+1: wow!')
-        assert_in('<p>Thumbs up emoji \U0001F44D wow!</p>', output)
+        assert '<p>Thumbs up emoji \U0001F44D wow!</p>' in output
         output = g.markdown.convert('More emojis :+1::camel::three_o’clock: wow!')
-        assert_in('<p>More emojis \U0001F44D\U0001F42B\U0001F552 wow!</p>', output)
+        assert '<p>More emojis \U0001F44D\U0001F42B\U0001F552 wow!</p>' in output
         output = g.markdown.convert(':man_bouncing_ball_medium-light_skin_tone:emoji:+1:')
-        assert_in('<p>\U000026F9\U0001F3FC\U0000200D\U00002642\U0000FE0Femoji\U0001F44D</p>', output)
+        assert '<p>\U000026F9\U0001F3FC\U0000200D\U00002642\U0000FE0Femoji\U0001F44D</p>' in output
 
     def test_markdown_emoji_in_code(self):
         output = g.markdown.convert('This will not become an emoji `:+1:`')
-        assert_in('<p>This will not become an emoji <code>:+1:</code></p>', output)
+        assert '<p>This will not become an emoji <code>:+1:</code></p>' in output
         output = g.markdown.convert('```html\n<p>:camel:</p>\n```')
-        assert_in(':camel:', output)
+        assert ':camel:' in output
         output = g.markdown.convert('~~~\n:camel:\n~~~')
-        assert_in('<pre><span></span><code>:camel:\n</code></pre>', output)
+        assert '<pre><span></span><code>:camel:\n</code></pre>' in output
 
     def test_markdown_commit_with_emojis(self):
         output = g.markdown_commit.convert('Thumbs up emoji :+1: wow!')
-        assert_in('Thumbs up emoji \U0001F44D wow!', output)
+        assert 'Thumbs up emoji \U0001F44D wow!' in output
         output = g.markdown.convert('More emojis :+1::camel::three_o’clock: wow!')
-        assert_in('More emojis \U0001F44D\U0001F42B\U0001F552 wow!', output)
+        assert 'More emojis \U0001F44D\U0001F42B\U0001F552 wow!' in output
 
 
 class TestUserMentions(unittest.TestCase):
@@ -1092,31 +1085,31 @@ class TestIconRender:
 
     def test_default(self):
         html = '<a class="icon" href="#" title="Edit"><i class="fa fa-edit"></i></a>'
-        assert_equal(html, self.i.render())
+        assert html == self.i.render()
 
     def test_show_title(self):
         html = '<a class="icon" href="#" title="Edit"><i class="fa fa-edit"></i>&nbsp;Edit</a>'
-        assert_equal(html, self.i.render(show_title=True))
+        assert html == self.i.render(show_title=True)
 
         html = '<a class="icon" href="#" title="&lt;script&gt;"><i class="fa fa-edit"></i>&nbsp;&lt;script&gt;</a>'
-        assert_equal(html, self.i.render(show_title=True, title="<script>"))
+        assert html == self.i.render(show_title=True, title="<script>")
 
     def test_extra_css(self):
         html = '<a class="icon reply btn" href="#" title="Edit"><i class="fa fa-edit"></i></a>'
-        assert_equal(html, self.i.render(extra_css='reply btn'))
+        assert html == self.i.render(extra_css='reply btn')
 
     def test_no_closing_tag(self):
         html = '<a class="icon" href="#" title="Edit"><i class="fa fa-edit"></i>'
-        assert_equal(html, self.i.render(closing_tag=False))
+        assert html == self.i.render(closing_tag=False)
 
     def test_tag(self):
         html = '<div class="icon" title="Edit"><i class="fa fa-edit"></i></div>'
-        assert_equal(html, self.i.render(tag='div'))
+        assert html == self.i.render(tag='div')
 
     def test_kwargs(self):
         html = '<a class="icon" data-id="123" href="#" title="Edit"><i class="fa fa-edit"></i></a>'
-        assert_equal(html, self.i.render(**{'data-id': '123'}))
+        assert html == self.i.render(**{'data-id': '123'})
 
     def test_escaping(self):
         html = '<a class="icon &#34;" data-url="&gt;" href="#" title="Edit"><i class="fa fa-edit"></i></a>'
-        assert_equal(html, self.i.render(extra_css='"', **{'data-url': '>'}))
+        assert html == self.i.render(extra_css='"', **{'data-url': '>'})
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 650ba023f..8f11145e1 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -80,14 +80,14 @@ def test_escape_json():
     inputdata = {"foo": "bar</script><img src=foobar onerror=alert(1)>"}
     outputsample = '{"foo": "bar\\u003C/script>\\u003Cimg src=foobar onerror=alert(1)>"}'
     outputdata = h.escape_json(inputdata)
-    assert_equals(outputdata, outputsample)
+    assert outputdata == outputsample
 
 
 def test_strip_bad_unicode():
     inputdata = 'Hello\x08World\t\n\rfoo bar\x1E'
     outputsample = 'HelloWorld\t\n\rfoo bar'
     outputdata = h.strip_bad_unicode(inputdata)
-    assert_equals(outputdata, outputsample)
+    assert outputdata == outputsample
 
 
 def test_really_unicode():
@@ -105,22 +105,22 @@ def test_really_unicode():
     s = h._attempt_encodings(b'foo', ['LKDJFLDK'])
     assert isinstance(s, str)
     # unicode stays the same
-    assert_equals(h.really_unicode('¬∂•°‹'), '¬∂•°‹')
+    assert h.really_unicode('¬∂•°‹') == '¬∂•°‹'
     # other types are handled too
-    assert_equals(h.really_unicode(1234), '1234')
-    assert_equals(h.really_unicode(datetime(2020, 1, 1)), '2020-01-01 00:00:00')
-    assert_equals(h.really_unicode(None), '')
+    assert h.really_unicode(1234) == '1234'
+    assert h.really_unicode(datetime(2020, 1, 1)) == '2020-01-01 00:00:00'
+    assert h.really_unicode(None) == ''
     # markup stays markup
     s = h.really_unicode(Markup('<b>test</b>'))
     assert isinstance(s, str)
     assert isinstance(s, Markup)
-    assert_equals(s, '<b>test</b>')
+    assert s == '<b>test</b>'
 
 
 def test_find_project():
     proj, rest = h.find_project('/p/test/foo')
-    assert_equals(proj.shortname, 'test')
-    assert_equals(proj.neighborhood.name, 'Projects')
+    assert proj.shortname == 'test'
+    assert proj.neighborhood.name == 'Projects'
     proj, rest = h.find_project('/p/testable/foo')
     assert proj is None
 
@@ -203,34 +203,34 @@ def test_encode_keys():
 
 
 def test_ago():
-    assert_equals(h.ago(datetime.utcnow() - timedelta(days=2)), '2 days ago')
-    assert_equals(h.ago(datetime.utcnow() + timedelta(days=2)), 'in 2 days')
-    assert_equals(h.ago_ts(time.time() - 60 * 60 * 2), '2 hours ago')
+    assert h.ago(datetime.utcnow() - timedelta(days=2)) == '2 days ago'
+    assert h.ago(datetime.utcnow() + timedelta(days=2)) == 'in 2 days'
+    assert h.ago_ts(time.time() - 60 * 60 * 2) == '2 hours ago'
     d_str = (datetime.utcnow() - timedelta(hours=3)).isoformat()
-    assert_equals(h.ago_string(d_str), '3 hours ago')
-    assert_equals(h.ago_string('bad format'), 'unknown')
-    assert_equals(h.ago_string(None), 'unknown')
+    assert h.ago_string(d_str) == '3 hours ago'
+    assert h.ago_string('bad format') == 'unknown'
+    assert h.ago_string(None) == 'unknown'
 
     monthish = datetime.utcnow() - timedelta(days=32)
     assert 'ago' not in h.ago(monthish)
-    assert_equals(h.ago(monthish, show_date_after=90), '1 month ago')
-    assert_equals(h.ago(monthish, show_date_after=None), '1 month ago')
+    assert h.ago(monthish, show_date_after=90) == '1 month ago'
+    assert h.ago(monthish, show_date_after=None) == '1 month ago'
 
     monthish = datetime.utcnow() + timedelta(days=32)
     assert 'in ' not in h.ago(monthish)
-    assert_equals(h.ago(monthish, show_date_after=90), 'in 1 month')
-    assert_equals(h.ago(monthish, show_date_after=None), 'in 1 month')
+    assert h.ago(monthish, show_date_after=90) == 'in 1 month'
+    assert h.ago(monthish, show_date_after=None) == 'in 1 month'
 
 
 def test_urlquote_unicode():
     # No exceptions please
-    assert_equals('%D0%90', h.urlquote('\u0410'))
-    assert_equals('%D0%90', h.urlquoteplus('\u0410'))
-    assert_equals('%D0%BF%D1%80%D0%B8%D0%B2%D1%96%D1%82.txt', h.urlquote('привіт.txt'))
+    assert '%D0%90' == h.urlquote('\u0410')
+    assert '%D0%90' == h.urlquoteplus('\u0410')
+    assert '%D0%BF%D1%80%D0%B8%D0%B2%D1%96%D1%82.txt' == h.urlquote('привіт.txt')
 
 
 def test_sharded_path():
-    assert_equals(h.sharded_path('foobar'), 'f/fo')
+    assert h.sharded_path('foobar') == 'f/fo'
 
 
 def test_paging_sanitizer():
@@ -254,19 +254,19 @@ def test_paging_sanitizer():
 
 
 def test_render_any_markup_empty():
-    assert_equals(h.render_any_markup('foo', ''), '<p><em>Empty File</em></p>')
+    assert h.render_any_markup('foo', '') == '<p><em>Empty File</em></p>'
 
 
 def test_render_any_markup_plain():
-    assert_equals(
+    assert (
         h.render_any_markup(
-            'readme.txt', '<b>blah</b>\n<script>alert(1)</script>\nfoo'),
+            'readme.txt', '<b>blah</b>\n<script>alert(1)</script>\nfoo') ==
         '<pre>&lt;b&gt;blah&lt;/b&gt;\n&lt;script&gt;alert(1)&lt;/script&gt;\nfoo</pre>')
 
 
 def test_render_any_markup_formatting():
-    assert_equals(str(h.render_any_markup('README.md', '### foo\n'
-                                          '    <script>alert(1)</script> bar')),
+    assert (str(h.render_any_markup('README.md', '### foo\n'
+                                          '    <script>alert(1)</script> bar')) ==
                   '<div class="markdown_content"><h3 id="foo">foo</h3>\n'
                   '<div class="codehilite"><pre><span></span><code><span class="nt">'
                   '&lt;script&gt;</span>alert(1)<span class="nt">'
@@ -275,7 +275,7 @@ def test_render_any_markup_formatting():
 
 def test_render_any_markdown_encoding():
     # send encoded content in, make sure it converts it to actual unicode object which Markdown lib needs
-    assert_equals(h.render_any_markup('README.md', 'Müller'.encode()),
+    assert (h.render_any_markup('README.md', 'Müller'.encode()) ==
                   '<div class="markdown_content"><p>Müller</p></div>')
 
 
@@ -311,29 +311,29 @@ def test_get_tool_packages():
 
 
 def test_get_first():
-    assert_equals(h.get_first({}, 'title'), None)
-    assert_equals(h.get_first({'title': None}, 'title'), None)
-    assert_equals(h.get_first({'title': 'Value'}, 'title'), 'Value')
-    assert_equals(h.get_first({'title': ['Value']}, 'title'), 'Value')
-    assert_equals(h.get_first({'title': []}, 'title'), None)
-    assert_equals(h.get_first({'title': ['Value']}, 'title'), 'Value')
+    assert h.get_first({}, 'title') == None
+    assert h.get_first({'title': None}, 'title') == None
+    assert h.get_first({'title': 'Value'}, 'title') == 'Value'
+    assert h.get_first({'title': ['Value']}, 'title') == 'Value'
+    assert h.get_first({'title': []}, 'title') == None
+    assert h.get_first({'title': ['Value']}, 'title') == 'Value'
 
 
 @patch('allura.lib.search.c')
 def test_inject_user(context):
     user = Mock(username='user01')
-    assert_equals(inject_user(None, user), None)
-    assert_equals(inject_user('', user), '')
-    assert_equals(inject_user('query', user), 'query')
+    assert inject_user(None, user) == None
+    assert inject_user('', user) == ''
+    assert inject_user('query', user) == 'query'
     result = inject_user('reported_by_s:$USER OR assigned_to_s:$USER', user)
-    assert_equals(result, 'reported_by_s:"user01" OR assigned_to_s:"user01"')
+    assert result == 'reported_by_s:"user01" OR assigned_to_s:"user01"'
     context.user = Mock(username='admin1')
     result = inject_user('reported_by_s:$USER OR assigned_to_s:$USER')
-    assert_equals(result, 'reported_by_s:"admin1" OR assigned_to_s:"admin1"')
+    assert result == 'reported_by_s:"admin1" OR assigned_to_s:"admin1"'
     context.user = Mock(username='*anonymous')
     result = inject_user('reported_by_s:$USER OR assigned_to_s:$USER')
-    assert_equals(
-        result, 'reported_by_s:"*anonymous" OR assigned_to_s:"*anonymous"')
+    assert (
+        result == 'reported_by_s:"*anonymous" OR assigned_to_s:"*anonymous"')
 
 
 def test_datetimeformat():
@@ -342,24 +342,24 @@ def test_datetimeformat():
 
 
 def test_nl2br_jinja_filter():
-    assert_equals(h.nl2br_jinja_filter('foo<script>alert(1)</script>\nbar\nbaz'),
+    assert (h.nl2br_jinja_filter('foo<script>alert(1)</script>\nbar\nbaz') ==
                   Markup('foo&lt;script&gt;alert(1)&lt;/script&gt;<br>\nbar<br>\nbaz'))
 
 
 def test_split_select_field_options():
-    assert_equals(h.split_select_field_options('"test message" test2'),
+    assert (h.split_select_field_options('"test message" test2') ==
                   ['test message', 'test2'])
-    assert_equals(h.split_select_field_options('"test message test2'),
+    assert (h.split_select_field_options('"test message test2') ==
                   ['test', 'message', 'test2'])
-    assert_equals(h.split_select_field_options('abc ƒå∂ ººº'),
+    assert (h.split_select_field_options('abc ƒå∂ ººº') ==
                   ['abc', 'ƒå∂', 'ººº'])
 
 
 def test_notifications_disabled():
     project = Mock(notifications_disabled=False)
     with h.notifications_disabled(project):
-        assert_equals(project.notifications_disabled, True)
-    assert_equals(project.notifications_disabled, False)
+        assert project.notifications_disabled == True
+    assert project.notifications_disabled == False
 
 
 @skipIf(module_not_available('html2text'), 'html2text required')
@@ -513,12 +513,12 @@ class TestUrlOpen(TestCase):
 
 
 def test_absurl():
-    assert_equals(h.absurl('/p/test/foobar'), 'http://localhost/p/test/foobar')
+    assert h.absurl('/p/test/foobar') == 'http://localhost/p/test/foobar'
 
 
 def test_daterange():
-    assert_equals(
-        list(h.daterange(datetime(2013, 1, 1), datetime(2013, 1, 4))),
+    assert (
+        list(h.daterange(datetime(2013, 1, 1), datetime(2013, 1, 4))) ==
         [datetime(2013, 1, 1), datetime(2013, 1, 2), datetime(2013, 1, 3)])
 
 
@@ -589,24 +589,24 @@ class TestIterEntryPoints(TestCase):
 
 def test_get_user_status():
     user = M.User.by_username('test-admin')
-    assert_equals(h.get_user_status(user), 'enabled')
+    assert h.get_user_status(user) == 'enabled'
 
     user = Mock(disabled=True, pending=False)
-    assert_equals(h.get_user_status(user), 'disabled')
+    assert h.get_user_status(user) == 'disabled'
 
     user = Mock(disabled=False, pending=True)
-    assert_equals(h.get_user_status(user), 'pending')
+    assert h.get_user_status(user) == 'pending'
 
     user = Mock(disabled=True, pending=True)  # not an expected combination
-    assert_equals(h.get_user_status(user), 'disabled')
+    assert h.get_user_status(user) == 'disabled'
 
 
 def test_convert_bools():
-    assert_equals(h.convert_bools({'foo': 'bar', 'baz': 'false', 'abc': 0, 'def': 1, 'ghi': True}),
+    assert (h.convert_bools({'foo': 'bar', 'baz': 'false', 'abc': 0, 'def': 1, 'ghi': True}) ==
                   {'foo': 'bar', 'baz': False, 'abc': 0, 'def': 1, 'ghi': True})
-    assert_equals(h.convert_bools({'foo': 'true', 'baz': ' TRUE '}),
+    assert (h.convert_bools({'foo': 'true', 'baz': ' TRUE '}) ==
                   {'foo': True, 'baz': True})
-    assert_equals(h.convert_bools({'foo': 'true', 'baz': ' TRUE '}, prefix='ba'),
+    assert (h.convert_bools({'foo': 'true', 'baz': ' TRUE '}, prefix='ba') ==
                   {'foo': 'true', 'baz': True})
 
 
@@ -621,21 +621,21 @@ def test_base64uri_img():
 
 def test_base64uri_text():
     b64txt = h.base64uri('blah blah blah\n123 456\nfoo bar baz', mimetype='text/plain')
-    assert_equals(b64txt, 'data:text/plain;base64,YmxhaCBibGFoIGJsYWgKMTIzIDQ1Ngpmb28gYmFyIGJheg==')
+    assert b64txt == 'data:text/plain;base64,YmxhaCBibGFoIGJsYWgKMTIzIDQ1Ngpmb28gYmFyIGJheg=='
 
     b64txt = h.base64uri('blah blah blah\n123 456\nfoo bar baz', mimetype='text/plain', windows_line_endings=True)
-    assert_equals(b64txt, 'data:text/plain;base64,YmxhaCBibGFoIGJsYWgNCjEyMyA0NTYNCmZvbyBiYXIgYmF6')
+    assert b64txt == 'data:text/plain;base64,YmxhaCBibGFoIGJsYWgNCjEyMyA0NTYNCmZvbyBiYXIgYmF6'
 
 
 def test_slugify():
-    assert_equals(h.slugify('Foo Bar Bat')[0], 'Foo-Bar-Bat')
-    assert_equals(h.slugify('Foo_Bar')[0], 'Foo_Bar')
-    assert_equals(h.slugify('Foo   ')[0], 'Foo')
-    assert_equals(h.slugify('    Foo   ')[0], 'Foo')
-    assert_equals(h.slugify('"    Foo   ')[0], 'Foo')
-    assert_equals(h.slugify('Fôö')[0], 'Foo')
-    assert_equals(h.slugify('Foo.Bar')[0], 'Foo-Bar')
-    assert_equals(h.slugify('Foo.Bar', True)[0], 'Foo.Bar')
+    assert h.slugify('Foo Bar Bat')[0] == 'Foo-Bar-Bat'
+    assert h.slugify('Foo_Bar')[0] == 'Foo_Bar'
+    assert h.slugify('Foo   ')[0] == 'Foo'
+    assert h.slugify('    Foo   ')[0] == 'Foo'
+    assert h.slugify('"    Foo   ')[0] == 'Foo'
+    assert h.slugify('Fôö')[0] == 'Foo'
+    assert h.slugify('Foo.Bar')[0] == 'Foo-Bar'
+    assert h.slugify('Foo.Bar', True)[0] == 'Foo.Bar'
 
 
 class TestRateLimit(TestCase):
@@ -671,26 +671,26 @@ class TestRateLimit(TestCase):
 
 
 def test_hide_private_info():
-    assert_equals(h.hide_private_info(None), None)
-    assert_equals(h.hide_private_info(''), '')
-    assert_equals(h.hide_private_info('foo bar baz@bing.com'), 'foo bar baz@...')
-    assert_equals(h.hide_private_info('some <1...@2.com>\nor asdf+asdf.f@g.f.x'), 'some <1...@...>\nor asdf+asdf.f@...')
+    assert h.hide_private_info(None) == None
+    assert h.hide_private_info('') == ''
+    assert h.hide_private_info('foo bar baz@bing.com') == 'foo bar baz@...'
+    assert h.hide_private_info('some <1...@2.com>\nor asdf+asdf.f@g.f.x') == 'some <1...@...>\nor asdf+asdf.f@...'
     safe_markup_converted = h.hide_private_info(Markup('foo bar baz@bing.com'))
-    assert_equals(type(safe_markup_converted), Markup)
-    assert_equals(safe_markup_converted, Markup('foo bar baz@...'))
+    assert type(safe_markup_converted) == Markup
+    assert safe_markup_converted == Markup('foo bar baz@...')
 
     with h.push_config(h.tg.config, hide_private_info=False):
-        assert_equals(h.hide_private_info('foo bar baz@bing.com'), 'foo bar baz@bing.com')
+        assert h.hide_private_info('foo bar baz@bing.com') == 'foo bar baz@bing.com'
 
 
 def test_emojize():
-    assert_equals(h.emojize(':smile:'), '😄')
+    assert h.emojize(':smile:') == '😄'
 
 
 def test_querystring():
     req = Request.blank('/p/test/foobar?page=1&limit=10&count=100', remote_addr='127.0.0.1',
                         base_url='https://mysite.com/p/test/foobar')
-    assert_equals(h.querystring(req, dict(page=2, limit=5)),
+    assert (h.querystring(req, dict(page=2, limit=5)) ==
                   'https://mysite.com/p/test/foobar/p/test/foobar?page=2&limit=5&count=100')
-    assert_equals(h.querystring(req, dict(page=5, limit=2, count=None)),
+    assert (h.querystring(req, dict(page=5, limit=2, count=None)) ==
                   'https://mysite.com/p/test/foobar/p/test/foobar?page=5&limit=2')
diff --git a/Allura/allura/tests/test_mail_util.py b/Allura/allura/tests/test_mail_util.py
index 1138c44e7..c0b15c264 100644
--- a/Allura/allura/tests/test_mail_util.py
+++ b/Allura/allura/tests/test_mail_util.py
@@ -79,9 +79,9 @@ class TestReactor(unittest.TestCase):
     def test_parse_address_good(self):
         topic, project, app = parse_address(
             'foo@wiki.test.p' + config.common_suffix)
-        assert_equal(topic, 'foo')
-        assert_equal(project.shortname, 'test')
-        assert_true(isinstance(app, Application))
+        assert topic == 'foo'
+        assert project.shortname == 'test'
+        assert isinstance(app, Application)
 
     def test_unicode_simple_message(self):
         charset = 'utf-8'
@@ -96,7 +96,7 @@ class TestReactor(unittest.TestCase):
         s_msg = msg1.as_string()
         msg2 = parse_message(s_msg)
         assert isinstance(msg2['payload'], str)
-        assert_in('всех', msg2['payload'])
+        assert 'всех' in msg2['payload']
 
     def test_more_encodings(self):
         # these are unicode strings to reflect behavior after loading 'route_email' tasks from mongo
@@ -115,7 +115,7 @@ IGZ0cCx0ZWxuZXQscGluZyBjYW4ndCB3b3JrICEKCgpXaHk/
 """
         msg = parse_message(s_msg)
         assert isinstance(msg['payload'], str)
-        assert_in('The Snap7 application', msg['payload'])
+        assert 'The Snap7 application' in msg['payload']
 
         s_msg = """Date: Sat, 25 May 2019 09:32:00 +1000
 From: <fo...@bar.com>
@@ -134,7 +134,7 @@ Content-Transfer-Encoding: 8bit
 """
         msg = parse_message(s_msg)
         assert isinstance(msg['payload'], str)
-        assert_in('• foo', msg['payload'])
+        assert '• foo' in msg['payload']
 
         s_msg = """Date: Sat, 25 May 2019 09:32:00 +1000
 From: <fo...@bar.com>
@@ -147,7 +147,7 @@ programmed or èrogrammed ?
 """
         msg = parse_message(s_msg)
         assert isinstance(msg['payload'], str)
-        assert_in('èrogrammed', msg['payload'])
+        assert 'èrogrammed' in msg['payload']
 
     def test_more_encodings_multipart(self):
         # these are unicode strings to reflect behavior after loading 'route_email' tasks from mongo
@@ -178,8 +178,8 @@ Content-Type: text/html; charset="utf-8"
         msg = parse_message(s_msg)
         assert isinstance(msg['parts'][1]['payload'], str)
         assert isinstance(msg['parts'][2]['payload'], str)
-        assert_in('• foo', msg['parts'][1]['payload'])
-        assert_in('• foo', msg['parts'][2]['payload'])
+        assert '• foo' in msg['parts'][1]['payload']
+        assert '• foo' in msg['parts'][2]['payload']
 
     def test_unicode_complex_message(self):
         charset = 'utf-8'
@@ -214,19 +214,19 @@ class TestHeader:
     @raises(TypeError)
     def test_bytestring(self):
         our_header = Header(b'[asdf2:wiki] Discussion for Home page')
-        assert_equal(our_header.encode(), '[asdf2:wiki] Discussion for Home page')
+        assert our_header.encode() == '[asdf2:wiki] Discussion for Home page'
 
     def test_ascii(self):
         our_header = Header('[asdf2:wiki] Discussion for Home page')
-        assert_equal(our_header.encode(), '[asdf2:wiki] Discussion for Home page')
+        assert our_header.encode() == '[asdf2:wiki] Discussion for Home page'
 
     def test_utf8(self):
         our_header = Header('теснятся')
-        assert_equal(our_header.encode(), '=?utf-8?b?0YLQtdGB0L3Rj9GC0YHRjw==?=')
+        assert our_header.encode() == '=?utf-8?b?0YLQtdGB0L3Rj9GC0YHRjw==?='
 
     def test_name_addr(self):
         our_header = Header('"теснятся"', '<da...@b.com>')
-        assert_equal(our_header.encode(),
+        assert (our_header.encode() ==
                      '=?utf-8?b?ItGC0LXRgdC90Y/RgtGB0Y8i?= <da...@b.com>')
 
 
@@ -236,44 +236,44 @@ class TestIsAutoreply:
         self.msg = {'headers': {}}
 
     def test_empty(self):
-        assert_false(is_autoreply(self.msg))
+        assert not is_autoreply(self.msg)
 
     def test_gmail(self):
         self.msg['headers']['Auto-Submitted'] = 'auto-replied'
         self.msg['headers']['Precedence'] = 'bulk'
         self.msg['headers']['X-Autoreply'] = 'yes'
-        assert_true(is_autoreply(self.msg))
+        assert is_autoreply(self.msg)
 
     def test_qmail(self):
         self.msg['headers']['Delivered-To'] = 'Autoresponder'
-        assert_true(is_autoreply(self.msg))
+        assert is_autoreply(self.msg)
 
     def test_mailtraq(self):
         self.msg['headers']['X-POST-MessageClass'] = '9; Autoresponder'
-        assert_true(is_autoreply(self.msg))
+        assert is_autoreply(self.msg)
 
     def test_firstclass(self):
         self.msg['headers']['X-FC-MachineGenerated'] = 'true'
-        assert_true(is_autoreply(self.msg))
+        assert is_autoreply(self.msg)
 
     def test_domain_technologies_control(self):
         self.msg['headers']['X-AutoReply-From'] = 'something'
         self.msg['headers']['X-Mail-Autoreply'] = 'something'
-        assert_true(is_autoreply(self.msg))
+        assert is_autoreply(self.msg)
 
     def test_communicate_pro(self):
         self.msg['headers']['X-Autogenerated'] = 'Forward'
-        assert_true(is_autoreply(self.msg))
+        assert is_autoreply(self.msg)
 
     def test_boxtrapper_cpanel(self):
         self.msg['headers']['Preference'] = 'auto_reply'
         self.msg['headers']['X-Precedence'] = 'auto_reply'
         self.msg['headers']['X-Autorespond'] = 'auto_reply'
-        assert_true(is_autoreply(self.msg))
+        assert is_autoreply(self.msg)
 
     def test_return_path(self):
         self.msg['headers']['Return-Path'] = '<>'
-        assert_true(is_autoreply(self.msg))
+        assert is_autoreply(self.msg)
 
 
 class TestIdentifySender:
@@ -283,7 +283,7 @@ class TestIdentifySender:
         EA.canonical = lambda e: e
         EA.get.side_effect = [
             mock.Mock(claimed_by_user_id=True, claimed_by_user=lambda:'user')]
-        assert_equal(identify_sender(None, 'arg', None, None), 'user')
+        assert identify_sender(None, 'arg', None, None) == 'user'
         EA.get.assert_called_once_with(email='arg', confirmed=True)
 
     @mock.patch('allura.model.EmailAddress')
@@ -291,9 +291,9 @@ class TestIdentifySender:
         EA.canonical = lambda e: e
         EA.get.side_effect = [
             None, mock.Mock(claimed_by_user_id=True, claimed_by_user=lambda:'user')]
-        assert_equal(
-            identify_sender(None, 'arg', {'From': 'from'}, None), 'user')
-        assert_equal(EA.get.call_args_list,
+        assert (
+            identify_sender(None, 'arg', {'From': 'from'}, None) == 'user')
+        assert (EA.get.call_args_list ==
                      [mock.call(email='arg', confirmed=True), mock.call(email='from')])
 
     @mock.patch('allura.model.User')
@@ -303,8 +303,8 @@ class TestIdentifySender:
         EA.canonical = lambda e: e
         EA.get.side_effect = [
             None, mock.Mock(claimed_by_user_id=True, claimed_by_user=lambda:'user')]
-        assert_equal(identify_sender(None, 'arg', {}, None), anon)
-        assert_equal(EA.get.call_args_list, [mock.call(email='arg', confirmed=True)])
+        assert identify_sender(None, 'arg', {}, None) == anon
+        assert EA.get.call_args_list == [mock.call(email='arg', confirmed=True)]
 
     @mock.patch('allura.model.User')
     @mock.patch('allura.model.EmailAddress')
@@ -312,17 +312,17 @@ class TestIdentifySender:
         anon = User.anonymous()
         EA.canonical = lambda e: e
         EA.get.side_effect = [None, None]
-        assert_equal(
-            identify_sender(None, 'arg', {'From': 'from'}, None), anon)
-        assert_equal(EA.get.call_args_list,
+        assert (
+            identify_sender(None, 'arg', {'From': 'from'}, None) == anon)
+        assert (EA.get.call_args_list ==
                      [mock.call(email='arg', confirmed=True), mock.call(email='from')])
 
 
 def test_parse_message_id():
-    assert_equal(_parse_message_id('<de...@libjpeg-turbo.p.domain.net>, </p...@libjpeg-turbo.p.domain.net>'), [
+    assert _parse_message_id('<de...@libjpeg-turbo.p.domain.net>, </p...@libjpeg-turbo.p.domain.net>') == [
         'de31888f6be2d87dc377d9e713876bb514548625.patches@libjpeg-turbo.p.domain.net',
         'de31888f6be2d87dc377d9e713876bb514548625.patches@libjpeg-turbo.p.domain.net',
-    ])
+    ]
 
 
 class TestMailServer:
@@ -336,5 +336,5 @@ class TestMailServer:
         mailserver = MailServer(listen_port, None)
         mailserver.process_message('127.0.0.1', 'foo@bar.com', ['1234@tickets.test.p.localhost'],
                                    'this is the email body with headers and everything Ο'.encode())
-        assert_equal([], log.exception.call_args_list)
+        assert [] == log.exception.call_args_list
         assert log.info.call_args[0][0].startswith('Msg passed along as task '), log.info.call_args
diff --git a/Allura/allura/tests/test_middlewares.py b/Allura/allura/tests/test_middlewares.py
index a428a10e8..60d4265b6 100644
--- a/Allura/allura/tests/test_middlewares.py
+++ b/Allura/allura/tests/test_middlewares.py
@@ -34,9 +34,9 @@ class TestCORSMiddleware:
 
     def test_init(self):
         cors = CORSMiddleware(self.app, ['get', 'post'], ['Some-Header'])
-        assert_equal(cors.app, self.app)
-        assert_equal(cors.allowed_methods, ['GET', 'POST'])
-        assert_equal(cors.allowed_headers, {'some-header'})
+        assert cors.app == self.app
+        assert cors.allowed_methods == ['GET', 'POST']
+        assert cors.allowed_headers == {'some-header'}
 
     def test_call_not_api_request(self):
         callback = MagicMock()
@@ -56,9 +56,9 @@ class TestCORSMiddleware:
                'HTTP_ORIGIN': 'my.site.com',
                'REQUEST_METHOD': 'GET'}
         self.cors(env, callback)
-        assert_equal(self.app.call_count, 1)
-        assert_equal(self.app.call_args_list[0][0][0], env)
-        assert_not_equal(self.app.call_args_list[0][0][1], callback)
+        assert self.app.call_count == 1
+        assert self.app.call_args_list[0][0][0] == env
+        assert self.app.call_args_list[0][0][1] != callback
 
     @patch('allura.lib.custom_middleware.exc', autospec=True)
     def test_handle_call_preflight_request(self, exc):
@@ -68,7 +68,7 @@ class TestCORSMiddleware:
                'REQUEST_METHOD': 'OPTIONS',
                'HTTP_ACCESS_CONTROL_REQUEST_METHOD': 'POST'}
         self.cors(env, callback)
-        assert_equal(self.app.call_count, 0)
+        assert self.app.call_count == 0
         exc.HTTPOk.assert_called_once_with(headers=[
             ('Access-Control-Allow-Origin', '*'),
             ('Access-Control-Allow-Methods', 'GET, POST, DELETE'),
@@ -78,21 +78,21 @@ class TestCORSMiddleware:
 
     def test_get_response_headers_simple(self):
         # Allow-Origin: * is crucial for security, since that prevents browsers from exposing results fetched withCredentials: true (aka cookies)
-        assert_equal(self.cors.get_response_headers(),
+        assert (self.cors.get_response_headers() ==
                      [('Access-Control-Allow-Origin', '*')])
-        assert_equal(self.cors.get_response_headers(preflight=False),
+        assert (self.cors.get_response_headers(preflight=False) ==
                      [('Access-Control-Allow-Origin', '*')])
 
     def test_get_response_headers_preflight(self):
-        assert_equal(
-            self.cors.get_response_headers(preflight=True),
+        assert (
+            self.cors.get_response_headers(preflight=True) ==
             [('Access-Control-Allow-Origin', '*'),
              ('Access-Control-Allow-Methods', 'GET, POST, DELETE'),
              ('Access-Control-Allow-Headers', 'accept, authorization')])
 
     def test_get_response_headers_preflight_with_cache(self):
         cors = CORSMiddleware(self.app, ['GET', 'PUT'], ['Accept'], 86400)
-        assert_equal(cors.get_response_headers(preflight=True),
+        assert (cors.get_response_headers(preflight=True) ==
                      [('Access-Control-Allow-Origin', '*'),
                       ('Access-Control-Allow-Methods', 'GET, PUT'),
                       ('Access-Control-Allow-Headers', 'accept'),
@@ -101,7 +101,7 @@ class TestCORSMiddleware:
     def test_get_access_control_request_headers(self):
         key = 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS'
         f = self.cors.get_access_control_request_headers
-        assert_equal(f({}), set())
-        assert_equal(f({key: ''}), set())
-        assert_equal(f({key: 'Authorization, Accept'}),
+        assert f({}) == set()
+        assert f({key: ''}) == set()
+        assert (f({key: 'Authorization, Accept'}) ==
                      {'authorization', 'accept'})
diff --git a/Allura/allura/tests/test_multifactor.py b/Allura/allura/tests/test_multifactor.py
index 2c76fc180..cfbef4d5e 100644
--- a/Allura/allura/tests/test_multifactor.py
+++ b/Allura/allura/tests/test_multifactor.py
@@ -54,25 +54,25 @@ class TestGoogleAuthenticatorFile:
 
     def test_parse(self):
         gaf = GoogleAuthenticatorFile.load(self.sample)
-        assert_equal(gaf.key, b'\xf8\x97\xbb/\xfd\xf2%\x01S\xa7\x8dZ\x07\x0c\\\xe4')
-        assert_equal(gaf.options['RATE_LIMIT'], '3 30')
-        assert_equal(gaf.options['DISALLOW_REUSE'], None)
-        assert_equal(gaf.options['TOTP_AUTH'], None)
-        assert_equal(gaf.recovery_codes, [
+        assert gaf.key == b'\xf8\x97\xbb/\xfd\xf2%\x01S\xa7\x8dZ\x07\x0c\\\xe4'
+        assert gaf.options['RATE_LIMIT'] == '3 30'
+        assert gaf.options['DISALLOW_REUSE'] == None
+        assert gaf.options['TOTP_AUTH'] == None
+        assert gaf.recovery_codes == [
             '43504045',
             '16951331',
             '16933944',
             '38009587',
             '49571579',
-        ])
+        ]
 
     def test_dump(self):
         gaf = GoogleAuthenticatorFile.load(self.sample)
-        assert_equal(gaf.dump(), self.sample)
+        assert gaf.dump() == self.sample
 
     def test_dump2(self):
         gaf = GoogleAuthenticatorFile.load(self.sample2)
-        assert_equal(gaf.dump(), self.sample2)
+        assert gaf.dump() == self.sample2
 
 
 class GenericTotpService(TotpService):
@@ -138,21 +138,21 @@ class TestAnyTotpServiceImplementation:
     def test_none(self):
         srv = self.Service()
         user = self.mock_user()
-        assert_equal(None, srv.get_secret_key(user))
+        assert None == srv.get_secret_key(user)
 
     def test_set_get(self):
         srv = self.Service()
         user = self.mock_user()
         srv.set_secret_key(user, self.sample_key)
-        assert_equal(self.sample_key, srv.get_secret_key(user))
+        assert self.sample_key == srv.get_secret_key(user)
 
     def test_delete(self):
         srv = self.Service()
         user = self.mock_user()
         srv.set_secret_key(user, self.sample_key)
-        assert_equal(self.sample_key, srv.get_secret_key(user))
+        assert self.sample_key == srv.get_secret_key(user)
         srv.set_secret_key(user, None)
-        assert_equal(None, srv.get_secret_key(user))
+        assert None == srv.get_secret_key(user)
 
     @patch('allura.lib.multifactor.time')
     def test_rate_limiting(self, time):
@@ -225,8 +225,8 @@ class TestRecoveryCodeService:
 
         recovery.regenerate_codes(user)
 
-        assert_equal(recovery.saved_user, user)
-        assert_equal(len(recovery.saved_codes), asint(config.get('auth.multifactor.recovery_code.count', 10)))
+        assert recovery.saved_user == user
+        assert len(recovery.saved_codes) == asint(config.get('auth.multifactor.recovery_code.count', 10))
 
 
 class TestAnyRecoveryCodeServiceImplementation:
@@ -239,7 +239,7 @@ class TestAnyRecoveryCodeServiceImplementation:
     def test_get_codes_none(self):
         recovery = self.Service()
         user = self.mock_user()
-        assert_equal(recovery.get_codes(user), [])
+        assert recovery.get_codes(user) == []
 
     def test_regen_get_codes(self):
         recovery = self.Service()
@@ -255,7 +255,7 @@ class TestAnyRecoveryCodeServiceImplementation:
             '67890'
         ]
         recovery.replace_codes(user, codes)
-        assert_equal(recovery.get_codes(user), codes)
+        assert recovery.get_codes(user) == codes
 
     def test_verify_fail(self):
         recovery = self.Service()
@@ -274,8 +274,8 @@ class TestAnyRecoveryCodeServiceImplementation:
         ]
         recovery.replace_codes(user, codes)
         result = recovery.verify_and_remove_code(user, '12345')
-        assert_equal(result, True)
-        assert_equal(recovery.get_codes(user), ['67890'])
+        assert result == True
+        assert recovery.get_codes(user) == ['67890']
 
     def test_rate_limiting(self):
         recovery = self.Service()
diff --git a/Allura/allura/tests/test_patches.py b/Allura/allura/tests/test_patches.py
index b86b95f95..0beb9ce96 100644
--- a/Allura/allura/tests/test_patches.py
+++ b/Allura/allura/tests/test_patches.py
@@ -35,7 +35,7 @@ def test_with_trailing_slash():
     patches.apply()
     with assert_raises(webob.exc.HTTPMovedPermanently) as raised:
         tg.decorators.with_trailing_slash(empty_func)()
-    assert_equal(raised.exception.location, 'http://localhost/foo/bar/')
+    assert raised.exception.location == 'http://localhost/foo/bar/'
 
 
 @patch.object(patches, 'request', webob.Request.blank('/foo/bar/?a=b'))
@@ -50,7 +50,7 @@ def test_with_trailing_slash_qs():
     patches.apply()
     with assert_raises(webob.exc.HTTPMovedPermanently) as raised:
         tg.decorators.with_trailing_slash(empty_func)()
-    assert_equal(raised.exception.location, 'http://localhost/foo/bar/?foo=bar&baz=bam')
+    assert raised.exception.location == 'http://localhost/foo/bar/?foo=bar&baz=bam'
 
 
 @patch.object(patches, 'request', webob.Request.blank('/foo/bar/'))
@@ -58,7 +58,7 @@ def test_without_trailing_slash():
     patches.apply()
     with assert_raises(webob.exc.HTTPMovedPermanently) as raised:
         tg.decorators.without_trailing_slash(empty_func)()
-    assert_equal(raised.exception.location, 'http://localhost/foo/bar')
+    assert raised.exception.location == 'http://localhost/foo/bar'
 
 
 @patch.object(patches, 'request', webob.Request.blank('/foo/bar?a=b'))
@@ -73,4 +73,4 @@ def test_without_trailing_slash_qs():
     patches.apply()
     with assert_raises(webob.exc.HTTPMovedPermanently) as raised:
         tg.decorators.without_trailing_slash(empty_func)()
-    assert_equal(raised.exception.location, 'http://localhost/foo/bar?foo=bar&baz=bam')
+    assert raised.exception.location == 'http://localhost/foo/bar?foo=bar&baz=bam'
diff --git a/Allura/allura/tests/test_plugin.py b/Allura/allura/tests/test_plugin.py
index 76133e0b5..4ae9d96fc 100644
--- a/Allura/allura/tests/test_plugin.py
+++ b/Allura/allura/tests/test_plugin.py
@@ -94,48 +94,48 @@ class TestProjectRegistrationProviderParseProjectFromUrl:
         self.parse = self.provider.project_from_url
 
     def test_empty_url(self):
-        assert_equal((None, 'Empty url'), self.parse(None))
-        assert_equal((None, 'Empty url'), self.parse(''))
-        assert_equal((None, 'Empty url'), self.parse('/'))
+        assert (None, 'Empty url') == self.parse(None)
+        assert (None, 'Empty url') == self.parse('')
+        assert (None, 'Empty url') == self.parse('/')
 
     def test_neighborhood_not_found(self):
-        assert_equal((None, 'Neighborhood not found'), self.parse('/nbhd/project'))
+        assert (None, 'Neighborhood not found') == self.parse('/nbhd/project')
 
     def test_project_not_found(self):
-        assert_equal((None, 'Project not found'), self.parse('/p/project'))
-        assert_equal((None, 'Project not found'), self.parse('project'))
+        assert (None, 'Project not found') == self.parse('/p/project')
+        assert (None, 'Project not found') == self.parse('project')
 
     def test_ok_full(self):
         p = M.Project.query.get(shortname='test')
         adobe = M.Project.query.get(shortname='adobe-1')
-        assert_equal((p, None), self.parse('p/test'))
-        assert_equal((p, None), self.parse('/p/test'))
-        assert_equal((p, None), self.parse('/p/test/tickets/1'))
-        assert_equal((p, None), self.parse('http://localhost:8080/p/test/tickets/1'))
-        assert_equal((adobe, None), self.parse('/adobe/adobe-1/'))
+        assert (p, None) == self.parse('p/test')
+        assert (p, None) == self.parse('/p/test')
+        assert (p, None) == self.parse('/p/test/tickets/1')
+        assert (p, None) == self.parse('http://localhost:8080/p/test/tickets/1')
+        assert (adobe, None) == self.parse('/adobe/adobe-1/')
 
     def test_only_shortname_multiple_projects_matched(self):
         adobe_n = M.Neighborhood.query.get(url_prefix='/adobe/')
         M.Project(shortname='test', neighborhood_id=adobe_n._id)
         ThreadLocalORMSession.flush_all()
-        assert_equal((None, 'Too many matches for project: 2'), self.parse('test'))
+        assert (None, 'Too many matches for project: 2') == self.parse('test')
 
     def test_only_shortname_ok(self):
         p = M.Project.query.get(shortname='test')
         adobe = M.Project.query.get(shortname='adobe-1')
-        assert_equal((p, None), self.parse('test'))
-        assert_equal((adobe, None), self.parse('adobe-1'))
+        assert (p, None) == self.parse('test')
+        assert (adobe, None) == self.parse('adobe-1')
 
     def test_subproject(self):
         p = M.Project.query.get(shortname='test/sub1')
-        assert_equal((p, None), self.parse('p/test/sub1'))
-        assert_equal((p, None), self.parse('p/test/sub1/something'))
-        assert_equal((p, None), self.parse('http://localhost:8080/p/test/sub1'))
-        assert_equal((p, None), self.parse('http://localhost:8080/p/test/sub1/something'))
+        assert (p, None) == self.parse('p/test/sub1')
+        assert (p, None) == self.parse('p/test/sub1/something')
+        assert (p, None) == self.parse('http://localhost:8080/p/test/sub1')
+        assert (p, None) == self.parse('http://localhost:8080/p/test/sub1/something')
 
     def test_subproject_not_found(self):
         p = M.Project.query.get(shortname='test')
-        assert_equal((p, None), self.parse('http://localhost:8080/p/test/not-a-sub'))
+        assert (p, None) == self.parse('http://localhost:8080/p/test/not-a-sub')
 
 
 class UserMock:
@@ -168,38 +168,38 @@ class TestProjectRegistrationProviderPhoneVerification:
 
     def test_phone_verified_disabled(self):
         with h.push_config(tg.config, **{'project.verify_phone': 'false'}):
-            assert_true(self.p.phone_verified(self.user, self.nbhd))
+            assert self.p.phone_verified(self.user, self.nbhd)
 
     @patch.object(plugin.security, 'has_access', autospec=True)
     def test_phone_verified_admin(self, has_access):
         has_access.return_value.return_value = True
         with h.push_config(tg.config, **{'project.verify_phone': 'true'}):
-            assert_true(self.p.phone_verified(self.user, self.nbhd))
+            assert self.p.phone_verified(self.user, self.nbhd)
 
     @patch.object(plugin.security, 'has_access', autospec=True)
     def test_phone_verified_project_admin(self, has_access):
         has_access.return_value.return_value = False
         with h.push_config(tg.config, **{'project.verify_phone': 'true'}):
             self.user.set_projects([Mock()])
-            assert_false(self.p.phone_verified(self.user, self.nbhd))
+            assert not self.p.phone_verified(self.user, self.nbhd)
             self.user.set_projects([Mock(neighborhood_id=self.nbhd._id)])
-            assert_true(self.p.phone_verified(self.user, self.nbhd))
+            assert self.p.phone_verified(self.user, self.nbhd)
 
     @patch.object(plugin.security, 'has_access', autospec=True)
     def test_phone_verified(self, has_access):
         has_access.return_value.return_value = False
         with h.push_config(tg.config, **{'project.verify_phone': 'true'}):
-            assert_false(self.p.phone_verified(self.user, self.nbhd))
+            assert not self.p.phone_verified(self.user, self.nbhd)
             self.user.set_tool_data('phone_verification', number_hash='123')
-            assert_true(self.p.phone_verified(self.user, self.nbhd))
+            assert self.p.phone_verified(self.user, self.nbhd)
 
     @patch.object(plugin, 'g')
     def test_verify_phone_disabled(self, g):
         g.phone_service = Mock(spec=phone.PhoneService)
         with h.push_config(tg.config, **{'project.verify_phone': 'false'}):
             result = self.p.verify_phone(self.user, '12345')
-            assert_false(g.phone_service.verify.called)
-            assert_equal(result, {'status': 'ok'})
+            assert not g.phone_service.verify.called
+            assert result == {'status': 'ok'}
 
     @patch.object(plugin, 'g')
     def test_verify_phone(self, g):
@@ -207,7 +207,7 @@ class TestProjectRegistrationProviderPhoneVerification:
         with h.push_config(tg.config, **{'project.verify_phone': 'true'}):
             result = self.p.verify_phone(self.user, '123 45 45')
             g.phone_service.verify.assert_called_once_with('1234545')
-            assert_equal(result, g.phone_service.verify.return_value)
+            assert result == g.phone_service.verify.return_value
 
     @patch.object(plugin, 'g')
     def test_check_phone_verification_disabled(self, g):
@@ -215,8 +215,8 @@ class TestProjectRegistrationProviderPhoneVerification:
         with h.push_config(tg.config, **{'project.verify_phone': 'false'}):
             result = self.p.check_phone_verification(
                 self.user, 'request-id', '1111', 'hash')
-            assert_false(g.phone_service.check.called)
-            assert_equal(result, {'status': 'ok'})
+            assert not g.phone_service.check.called
+            assert result == {'status': 'ok'}
 
     @patch.object(plugin.h, 'auditlog_user', autospec=True)
     @patch.object(plugin, 'g')
@@ -227,9 +227,9 @@ class TestProjectRegistrationProviderPhoneVerification:
                 self.user, 'request-id', '1111', 'hash')
             g.phone_service.check.assert_called_once_with(
                 'request-id', '1111')
-            assert_equal(result, g.phone_service.check.return_value)
-            assert_equal(
-                self.user.get_tool_data('phone_verification', 'number_hash'),
+            assert result == g.phone_service.check.return_value
+            assert (
+                self.user.get_tool_data('phone_verification', 'number_hash') ==
                 None)
             audit.assert_called_once_with(
                 'Phone verification failed. Hash: hash', user=self.user)
@@ -244,8 +244,8 @@ class TestProjectRegistrationProviderPhoneVerification:
                 self.user, 'request-id', '1111', 'hash')
             g.phone_service.check.assert_called_once_with(
                 'request-id', '1111')
-            assert_equal(
-                self.user.get_tool_data('phone_verification', 'number_hash'),
+            assert (
+                self.user.get_tool_data('phone_verification', 'number_hash') ==
                 'hash')
             audit.assert_called_once_with(
                 'Phone verification succeeded. Hash: hash', user=self.user)
@@ -258,8 +258,8 @@ class TestProjectRegistrationProviderPhoneVerification:
         with h.push_config(tg.config, **{'project.verify_phone': 'true', 'phone.attempts_limit': '5'}):
             for i in range(1, 3):
                 result = self.p.verify_phone(user, '123 45 45')
-                assert_equal(result, g.phone_service.verify.return_value)
-            assert_equal(2, g.phone_service.verify.call_count)
+                assert result == g.phone_service.verify.return_value
+            assert 2 == g.phone_service.verify.call_count
 
     @patch.object(plugin, 'g')
     def test_verify_phone_max_limit_reached(self, g):
@@ -270,10 +270,10 @@ class TestProjectRegistrationProviderPhoneVerification:
             for i in range(1, 7):
                 result = self.p.verify_phone(user, '123 45 45')
                 if i > 5:
-                    assert_equal(result, {'status': 'error', 'error': 'Maximum phone verification attempts reached.'})
+                    assert result == {'status': 'error', 'error': 'Maximum phone verification attempts reached.'}
                 else:
-                    assert_equal(result, g.phone_service.verify.return_value)
-            assert_equal(5, g.phone_service.verify.call_count)
+                    assert result == g.phone_service.verify.return_value
+            assert 5 == g.phone_service.verify.call_count
 
 class TestThemeProvider:
 
@@ -285,14 +285,14 @@ class TestThemeProvider:
                 24: 'images/testapp_24.png',
             }
         plugin_g.entry_points = {'tool': {'testapp': TestApp}}
-        assert_equals(ThemeProvider().app_icon_url('testapp', 24),
+        assert (ThemeProvider().app_icon_url('testapp', 24) ==
                       app_g.theme_href.return_value)
         app_g.theme_href.assert_called_with('images/testapp_24.png')
 
     @patch('allura.lib.plugin.g')
     def test_app_icon_str_invalid(self, g):
         g.entry_points = {'tool': {'testapp': Mock()}}
-        assert_equals(ThemeProvider().app_icon_url('invalid', 24),
+        assert (ThemeProvider().app_icon_url('invalid', 24) ==
                       None)
 
     @patch('allura.app.g')
@@ -302,7 +302,7 @@ class TestThemeProvider:
                 24: 'images/testapp_24.png',
             }
         app = TestApp(None, None)
-        assert_equals(ThemeProvider().app_icon_url(app, 24),
+        assert (ThemeProvider().app_icon_url(app, 24) ==
                       g.theme_href.return_value)
         g.theme_href.assert_called_with('images/testapp_24.png')
 
@@ -317,7 +317,7 @@ class TestThemeProvider_notifications:
     @patch('tg.request')
     def test_get_site_notification_no_note(self, request, response, SiteNotification):
         SiteNotification.actives.return_value = []
-        assert_is_none(self.Provider().get_site_notification())
+        assert self.Provider().get_site_notification() is None
         assert not response.set_cookie.called
 
     @patch('allura.lib.plugin.c', MagicMock())
@@ -332,7 +332,7 @@ class TestThemeProvider_notifications:
         note.page_tool_type = None
         SiteNotification.actives.return_value = [note]
         request.cookies = {'site-notification': 'deadbeef-1-true'}
-        assert_is_none(self.Provider().get_site_notification())
+        assert self.Provider().get_site_notification() is None
         assert not response.set_cookie.called
 
     @patch('allura.lib.plugin.c', MagicMock())
@@ -348,7 +348,7 @@ class TestThemeProvider_notifications:
         note.page_tool_type = None
         SiteNotification.actives.return_value = [note]
         request.cookies = {'site-notification': 'deadbeef-3-false'}
-        assert_is_none(self.Provider().get_site_notification())
+        assert self.Provider().get_site_notification() is None
         assert not response.set_cookie.called
 
     @patch('allura.lib.plugin.c', MagicMock())
@@ -366,7 +366,7 @@ class TestThemeProvider_notifications:
         request.cookies = {'site-notification': 'deadbeef-1-false'}
         request.environ['beaker.session'].secure = False
 
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
         response.set_cookie.assert_called_once_with(
             'site-notification', 'deadbeef-2-False', max_age=dt.timedelta(days=365), secure=False)
 
@@ -383,7 +383,7 @@ class TestThemeProvider_notifications:
         note.page_tool_type = None
         SiteNotification.actives.return_value = [note]
         request.cookies = {'site-notification': 'deadbeef-1000-false'}
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
@@ -400,7 +400,7 @@ class TestThemeProvider_notifications:
         request.cookies = {'site-notification': '0ddba11-1000-true'}
         request.environ['beaker.session'].secure = False
 
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
         response.set_cookie.assert_called_once_with(
             'site-notification', 'deadbeef-1-False', max_age=dt.timedelta(days=365), secure=False)
 
@@ -418,7 +418,7 @@ class TestThemeProvider_notifications:
         SiteNotification.actives.return_value = [note]
         request.cookies = {}
         request.environ['beaker.session'].secure = False
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
         response.set_cookie.assert_called_once_with(
             'site-notification', 'deadbeef-1-False', max_age=dt.timedelta(days=365), secure=False)
 
@@ -437,7 +437,7 @@ class TestThemeProvider_notifications:
         request.cookies = {'site-notification': 'deadbeef-1000-true-bad'}
         request.environ['beaker.session'].secure = False
 
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
         response.set_cookie.assert_called_once_with(
             'site-notification', 'deadbeef-1-False', max_age=dt.timedelta(days=365), secure=False)
 
@@ -455,21 +455,21 @@ class TestThemeProvider_notifications:
         projects = c.user.my_projects_by_role_name
 
         c.user.is_anonymous.return_value = True
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
         c.user.is_anonymous.return_value = False
         projects.return_value = []
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
         projects.return_value = [Mock()]
         projects.return_value[0].is_user_project = True
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
         projects.return_value[0].is_user_project = False
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
 
         projects.projects.return_value = [Mock(), Mock()]
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
@@ -482,7 +482,7 @@ class TestThemeProvider_notifications:
         note.page_tool_type = None
         note.impressions = 10
         SiteNotification.actives.return_value = [note]
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('re.search')
@@ -498,10 +498,10 @@ class TestThemeProvider_notifications:
         SiteNotification.actives.return_value = [note]
 
         search.return_value = True
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
 
         search.return_value = None
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
     @patch('allura.lib.plugin.c')
     @patch('allura.model.notification.SiteNotification')
@@ -516,13 +516,13 @@ class TestThemeProvider_notifications:
         SiteNotification.actives.return_value = [note]
         c.app = Mock()
         c.app.config.tool_name.lower.return_value = 'test1'
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
 
         c.app.config.tool_name.lower.return_value = 'test2'
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
         c.app = None
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
     @patch('allura.lib.plugin.c')
     @patch('tg.request')
@@ -539,23 +539,23 @@ class TestThemeProvider_notifications:
 
         request.path_qs = 'ttt'
         c.app.config.tool_name.lower.return_value = 'test2'
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
         request.path_qs = 'test'
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
         request.path_qs = 'ttt'
         c.app.config.tool_name.lower.return_value = 'test1'
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
         request.path_qs = 'test'
-        assert_is(self.Provider().get_site_notification(), note)
+        assert self.Provider().get_site_notification() is note
 
         c.app = None
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
         request.path_qs = 'ttt'
-        assert_is(self.Provider().get_site_notification(), None)
+        assert self.Provider().get_site_notification() is None
 
     @patch('allura.model.notification.SiteNotification')
     def test_get__site_notification(self, SiteNotification):
@@ -598,8 +598,8 @@ class TestThemeProvider_notifications:
 
         assert isinstance(get_note, tuple)
         assert len(get_note) == 2
-        assert_equal(get_note[0], note2)
-        assert_equal(get_note[1], 'test2-1-False')
+        assert get_note[0] == note2
+        assert get_note[1] == 'test2-1-False'
 
         # and with a cookie set
         get_note = self.Provider()._get_site_notification(
@@ -608,8 +608,8 @@ class TestThemeProvider_notifications:
 
         assert isinstance(get_note, tuple)
         assert len(get_note) == 2
-        assert_equal(get_note[0], note3)
-        assert_equal(get_note[1], 'test2-3-True_test3-1-False')
+        assert get_note[0] == note3
+        assert get_note[1] == 'test2-3-True_test3-1-False'
 
     @patch('allura.model.notification.SiteNotification')
     def test_get_site_notifications_with_api_cookie(self, SiteNotification):
@@ -641,7 +641,7 @@ class TestLocalAuthenticationProvider:
         ep = self.provider._encode_password
         assert ep('test_pass') != ep('test_pass')
         assert ep('test_pass', '0000') == ep('test_pass', '0000')
-        assert_equal(ep('test_pass', '0000'), 'sha2560000j7pRjKKZ5L8G0jScZKja9ECmYF2zBV82Mi+E3wkop30=')
+        assert ep('test_pass', '0000') == 'sha2560000j7pRjKKZ5L8G0jScZKja9ECmYF2zBV82Mi+E3wkop30='
 
     def test_set_password_with_old_password(self):
         user = Mock()
@@ -651,7 +651,7 @@ class TestLocalAuthenticationProvider:
         assert_raises(
             exc.HTTPUnauthorized,
             self.provider.set_password, user, 'old', 'new')
-        assert_equal(self.provider._encode_password.call_count, 0)
+        assert self.provider._encode_password.call_count == 0
 
         self.provider.validate_password = lambda u, p: True
         self.provider.set_password(user, 'old', 'new')
@@ -663,7 +663,7 @@ class TestLocalAuthenticationProvider:
         user.__ming__ = Mock()
         user.last_password_updated = None
         self.provider.set_password(user, None, 'new')
-        assert_equal(user.last_password_updated, dt_mock.utcnow.return_value)
+        assert user.last_password_updated == dt_mock.utcnow.return_value
 
     def test_get_last_password_updated_not_set(self):
         user = Mock()
@@ -673,13 +673,13 @@ class TestLocalAuthenticationProvider:
         upd = self.provider.get_last_password_updated(user)
         gen_time = dt.datetime.utcfromtimestamp(
             calendar.timegm(user._id.generation_time.utctimetuple()))
-        assert_equal(upd, gen_time)
+        assert upd == gen_time
 
     def test_get_last_password_updated(self):
         user = Mock()
         user.last_password_updated = dt.datetime(2014, 6, 4, 13, 13, 13)
         upd = self.provider.get_last_password_updated(user)
-        assert_equal(upd, user.last_password_updated)
+        assert upd == user.last_password_updated
 
     def test_enable_user(self):
         user = Mock(disabled=True, __ming__=Mock(), is_anonymous=lambda: False, _id=ObjectId())
@@ -687,7 +687,7 @@ class TestLocalAuthenticationProvider:
         with audits('Account enabled', user=True, actor='test-admin'):
             self.provider.enable_user(user)
             ThreadLocalORMSession.flush_all()
-        assert_equal(user.disabled, False)
+        assert user.disabled == False
 
     def test_disable_user(self):
         user = Mock(disabled=False, __ming__=Mock(), is_anonymous=lambda: False, _id=ObjectId())
@@ -695,51 +695,51 @@ class TestLocalAuthenticationProvider:
         with audits('Account disabled', user=True, actor='test-admin'):
             self.provider.disable_user(user)
             ThreadLocalORMSession.flush_all()
-        assert_equal(user.disabled, True)
+        assert user.disabled == True
 
     def test_login_details_from_auditlog(self):
         user = M.User(username='asfdasdf')
 
-        assert_equal(self.provider.login_details_from_auditlog(M.AuditLog(message='')),
+        assert (self.provider.login_details_from_auditlog(M.AuditLog(message='')) ==
                      None)
 
         detail = self.provider.login_details_from_auditlog(M.AuditLog(message='IP Address: 1.2.3.4\nFoo', user=user))
-        assert_equal(detail.user_id, user._id)
-        assert_equal(detail.ip, '1.2.3.4')
-        assert_equal(detail.ua, None)
+        assert detail.user_id == user._id
+        assert detail.ip == '1.2.3.4'
+        assert detail.ua == None
 
         detail = self.provider.login_details_from_auditlog(M.AuditLog(message='Foo\nIP Address: 1.2.3.4\nFoo', user=user))
-        assert_equal(detail.ip, '1.2.3.4')
-        assert_equal(detail.ua, None)
+        assert detail.ip == '1.2.3.4'
+        assert detail.ua == None
 
-        assert_equal(self.provider.login_details_from_auditlog(M.AuditLog(
-                        message='blah blah IP Address: 1.2.3.4\nFoo', user=user)),
+        assert (self.provider.login_details_from_auditlog(M.AuditLog(
+                        message='blah blah IP Address: 1.2.3.4\nFoo', user=user)) ==
                      None)
 
         detail = self.provider.login_details_from_auditlog(M.AuditLog(
                         message='User-Agent: Mozilla/Firefox\nFoo', user=user))
-        assert_equal(detail.ip, None)
-        assert_equal(detail.ua, 'Mozilla/Firefox')
+        assert detail.ip == None
+        assert detail.ua == 'Mozilla/Firefox'
 
         detail = self.provider.login_details_from_auditlog(M.AuditLog(
                         message='IP Address: 1.2.3.4\nUser-Agent: Mozilla/Firefox\nFoo', user=user))
-        assert_equal(detail.ip, '1.2.3.4')
-        assert_equal(detail.ua, 'Mozilla/Firefox')
+        assert detail.ip == '1.2.3.4'
+        assert detail.ua == 'Mozilla/Firefox'
 
     def test_get_login_detail(self):
         user = M.User(username='foobarbaz')
         detail = self.provider.get_login_detail(Request.blank('/'), user)
-        assert_equal(detail.user_id, user._id)
-        assert_equal(detail.ip, None)
-        assert_equal(detail.ua, None)
+        assert detail.user_id == user._id
+        assert detail.ip == None
+        assert detail.ua == None
 
         detail = self.provider.get_login_detail(Request.blank('/',
                                                               headers={'User-Agent': 'mybrowser'},
                                                               environ={'REMOTE_ADDR': '3.3.3.3'}),
                                                 user)
-        assert_equal(detail.user_id, user._id)
-        assert_equal(detail.ip, '3.3.3.3')
-        assert_equal(detail.ua, 'mybrowser')
+        assert detail.user_id == user._id
+        assert detail.ip == '3.3.3.3'
+        assert detail.ua == 'mybrowser'
 
 
 class TestAuthenticationProvider:
@@ -752,21 +752,21 @@ class TestAuthenticationProvider:
         self.user = Mock()
 
     def test_is_password_expired_disabled(self):
-        assert_false(self.provider.is_password_expired(self.user))
+        assert not self.provider.is_password_expired(self.user)
 
     def test_is_password_expired_days(self):
         with h.push_config(tg.config, **{'auth.pwdexpire.days': '180'}):
-            assert_false(self.provider.is_password_expired(self.user))
+            assert not self.provider.is_password_expired(self.user)
         with h.push_config(tg.config, **{'auth.pwdexpire.days': '90'}):
-            assert_true(self.provider.is_password_expired(self.user))
+            assert self.provider.is_password_expired(self.user)
 
     def test_is_password_expired_before(self):
         before = dt.datetime.utcnow() - dt.timedelta(days=180)
         before = calendar.timegm(before.timetuple())
         with h.push_config(tg.config, **{'auth.pwdexpire.before': str(before)}):
-            assert_false(self.provider.is_password_expired(self.user))
+            assert not self.provider.is_password_expired(self.user)
 
         before = dt.datetime.utcnow() - dt.timedelta(days=1)
         before = calendar.timegm(before.timetuple())
         with h.push_config(tg.config, **{'auth.pwdexpire.before': str(before)}):
-            assert_true(self.provider.is_password_expired(self.user))
+            assert self.provider.is_password_expired(self.user)
diff --git a/Allura/allura/tests/test_security.py b/Allura/allura/tests/test_security.py
index c94c924ce..54680e331 100644
--- a/Allura/allura/tests/test_security.py
+++ b/Allura/allura/tests/test_security.py
@@ -94,28 +94,28 @@ class TestSecurity(TestController):
         anon_role = M.ProjectRole.by_name('*anonymous')
         test_user = M.User.by_username('test-user')
 
-        assert_equal(all_allowed(wiki, admin_role), {
-            'configure', 'read', 'create', 'edit', 'unmoderated_post', 'post', 'moderate', 'admin', 'delete'})
-        assert_equal(all_allowed(wiki, dev_role), {
-            'read', 'create', 'edit', 'unmoderated_post', 'post', 'moderate', 'delete'})
-        assert_equal(all_allowed(wiki, member_role),
+        assert all_allowed(wiki, admin_role) == {
+            'configure', 'read', 'create', 'edit', 'unmoderated_post', 'post', 'moderate', 'admin', 'delete'}
+        assert all_allowed(wiki, dev_role) == {
+            'read', 'create', 'edit', 'unmoderated_post', 'post', 'moderate', 'delete'}
+        assert (all_allowed(wiki, member_role) ==
                      {'read', 'create', 'edit', 'unmoderated_post', 'post'})
-        assert_equal(all_allowed(wiki, auth_role),
+        assert (all_allowed(wiki, auth_role) ==
                      {'read', 'post', 'unmoderated_post'})
-        assert_equal(all_allowed(wiki, anon_role), {'read'})
-        assert_equal(all_allowed(wiki, test_user),
+        assert all_allowed(wiki, anon_role) == {'read'}
+        assert (all_allowed(wiki, test_user) ==
                      {'read', 'post', 'unmoderated_post'})
 
         _add_to_group(test_user, member_role)
 
-        assert_equal(all_allowed(wiki, test_user),
+        assert (all_allowed(wiki, test_user) ==
                      {'read', 'create', 'edit', 'unmoderated_post', 'post'})
 
         _deny(wiki, auth_role, 'unmoderated_post')
 
-        assert_equal(all_allowed(wiki, member_role),
+        assert (all_allowed(wiki, member_role) ==
                      {'read', 'create', 'edit', 'post'})
-        assert_equal(all_allowed(wiki, test_user),
+        assert (all_allowed(wiki, test_user) ==
                      {'read', 'create', 'edit', 'post'})
 
     @td.with_wiki
@@ -133,12 +133,12 @@ class TestSecurity(TestController):
         assert has_access(page, 'read', anon_role)()
         assert has_access(page, 'post', anon_role)()
         assert has_access(page, 'unmoderated_post', anon_role)()
-        assert_equal(all_allowed(page, anon_role), {'read'})
+        assert all_allowed(page, anon_role) == {'read'}
         # as well as an authenticated user
         assert has_access(page, 'read', test_user)()
         assert has_access(page, 'post', test_user)()
         assert has_access(page, 'unmoderated_post', test_user)()
-        assert_equal(all_allowed(page, test_user),
+        assert (all_allowed(page, test_user) ==
                      {'read', 'post', 'unmoderated_post'})
 
         _deny(page, auth_role, 'read')
@@ -154,7 +154,7 @@ class TestSecurity(TestController):
         assert has_access(wiki, 'read', test_user)()
         assert has_access(wiki, 'post', test_user)()
         assert has_access(wiki, 'unmoderated_post', test_user)()
-        assert_equal(all_allowed(wiki, test_user),
+        assert (all_allowed(wiki, test_user) ==
                      {'read', 'post', 'unmoderated_post'})
 
         _deny(wiki, anon_role, 'read')
@@ -184,7 +184,7 @@ class TestSecurity(TestController):
         page = WM.Page.query.get(app_config_id=wiki.config._id)
         test_user = M.User.by_username('test-user')
 
-        assert_equal(project1.shortname, 'test')
+        assert project1.shortname == 'test'
         assert has_access(page, 'read', test_user)()
         c.project = project2
         assert has_access(page, 'read', test_user)()
diff --git a/Allura/allura/tests/test_tasks.py b/Allura/allura/tests/test_tasks.py
index b1b2215ca..16815e600 100644
--- a/Allura/allura/tests/test_tasks.py
+++ b/Allura/allura/tests/test_tasks.py
@@ -63,9 +63,9 @@ class TestRepoTasks(unittest.TestCase):
         fake_traceback = 'fake_traceback'
         app.repo.init_as_clone.side_effect = Exception(fake_traceback)
         repo_tasks.clone(None, None, fake_source_url)
-        assert_equal(post_event.call_args[0][0], 'repo_clone_task_failed')
-        assert_equal(post_event.call_args[0][1], fake_source_url)
-        assert_equal(post_event.call_args[0][2], None)
+        assert post_event.call_args[0][0] == 'repo_clone_task_failed'
+        assert post_event.call_args[0][1] == fake_source_url
+        assert post_event.call_args[0][2] == None
         # ignore args[3] which is a traceback string
 
     @mock.patch('allura.tasks.repo_tasks.session', autospec=True)
@@ -76,7 +76,7 @@ class TestRepoTasks(unittest.TestCase):
         MR.query.get.return_value = mr
         repo_tasks.merge(mr._id)
         mr.app.repo.merge.assert_called_once_with(mr)
-        assert_equal(mr.status, 'merged')
+        assert mr.status == 'merged'
         session.assert_called_once_with(mr)
         session.return_value.flush.assert_called_once_with(mr)
 
@@ -146,12 +146,12 @@ class TestEventTasks(unittest.TestCase):
                 mock.patch.dict(tg.config, {'monq.raise_errors': False}):  # match normal non-test behavior
             t()
         # l.check() would be nice, but string is too detailed to check
-        assert_equal(l.records[0].name, 'allura.model.monq_model')
+        assert l.records[0].name == 'allura.model.monq_model'
         msg = l.records[0].getMessage()
-        assert_in("AssertionError('assert 0'", msg)
-        assert_in("AssertionError('assert 5'", msg)
-        assert_in(' on job <MonQTask ', msg)
-        assert_in(' (error) P:10 allura.tests.test_tasks.raise_exc ', msg)
+        assert "AssertionError('assert 0'" in msg
+        assert "AssertionError('assert 5'" in msg
+        assert ' on job <MonQTask ' in msg
+        assert ' (error) P:10 allura.tests.test_tasks.raise_exc ' in msg
         for x in range(10):
             assert ('assert %d' % x) in t.result
 
@@ -208,7 +208,7 @@ class TestIndexTasks(unittest.TestCase):
             M.main_orm_session.clear()
             t3 = _TestArtifact.query.get(_shorthand_id='t3')
             assert len(t3.backrefs) == 5, t3.backrefs
-            assert_equal(find_slinks.call_args_list,
+            assert (find_slinks.call_args_list ==
                          [mock.call(a.index().get('text')) for a in artifacts])
 
     @td.with_wiki
@@ -228,8 +228,8 @@ class TestIndexTasks(unittest.TestCase):
         assert old_shortlinks + 5 == new_shortlinks, 'Shortlinks not created'
         assert solr.add.call_count == 1
         sort_key = operator.itemgetter('id')
-        assert_equal(
-            sorted(solr.add.call_args[0][0], key=sort_key),
+        assert (
+            sorted(solr.add.call_args[0][0], key=sort_key) ==
             sorted((ref.artifact.solarize() for ref in arefs),
                    key=sort_key))
         index_tasks.del_artifacts(ref_ids)
@@ -261,19 +261,19 @@ class TestMailTasks(unittest.TestCase):
                 reply_to=g.noreply,
                 subject='Test subject',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
 
-            assert_equal(rcpts, [c.user.get_pref('email_address')])
-            assert_in('Reply-To: %s' % g.noreply, body)
-            assert_in('From: "Test Admin" <te...@users.localhost>', body)
-            assert_in('Subject: Test subject', body)
+            assert rcpts == [c.user.get_pref('email_address')]
+            assert 'Reply-To: %s' % g.noreply in body
+            assert 'From: "Test Admin" <te...@users.localhost>' in body
+            assert 'Subject: Test subject' in body
             # plain
-            assert_in('This is a test', body)
+            assert 'This is a test' in body
             # html
-            assert_in(
-                '<div class="markdown_content"><p>This is a test</p></div>', body)
+            assert (
+                '<div class="markdown_content"><p>This is a test</p></div>' in body)
 
     def test_send_email_nonascii(self):
         with mock.patch.object(mail_tasks.smtp_client, '_client') as _client:
@@ -284,12 +284,12 @@ class TestMailTasks(unittest.TestCase):
                 reply_to=g.noreply,
                 subject='По оживлённым берегам',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
 
-            assert_equal(rcpts, ['blah@blah.com'])
-            assert_in('Reply-To: %s' % g.noreply, body)
+            assert rcpts == ['blah@blah.com']
+            assert 'Reply-To: %s' % g.noreply in body
 
             # The address portion must not be encoded, only the name portion can be.
             # Also py2 and py3 vary in handling of double-quote separators when the name portion is encoded
@@ -297,11 +297,11 @@ class TestMailTasks(unittest.TestCase):
             quoted_cyrillic_No = '=?utf-8?b?ItCf0L4i?='  # "По"
             assert (f'From: {quoted_cyrillic_No} <fo...@bar.com>' in body or
                     f'From: {unquoted_cyrillic_No} <fo...@bar.com>' in body), body
-            assert_in(
-                'Subject: =?utf-8?b?0J/QviDQvtC20LjQstC70ZHQvdC90YvQvCDQsdC10YDQtdCz0LDQvA==?=', body)
-            assert_in('Content-Type: text/plain; charset="utf-8"', body)
-            assert_in('Content-Transfer-Encoding: base64', body)
-            assert_in(six.ensure_text(b64encode('Громады стройные теснятся'.encode())), body)
+            assert (
+                'Subject: =?utf-8?b?0J/QviDQvtC20LjQstC70ZHQvdC90YvQvCDQsdC10YDQtdCz0LDQvA==?=' in body)
+            assert 'Content-Type: text/plain; charset="utf-8"' in body
+            assert 'Content-Transfer-Encoding: base64' in body
+            assert six.ensure_text(b64encode('Громады стройные теснятся'.encode())) in body
 
     def test_send_email_with_disabled_user(self):
         c.user = M.User.by_username('test-admin')
@@ -317,10 +317,10 @@ class TestMailTasks(unittest.TestCase):
                 reply_to=g.noreply,
                 subject='Test subject',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
-            assert_in('From: %s' % g.noreply, body)
+            assert 'From: %s' % g.noreply in body
 
     def test_send_email_with_disabled_destination_user(self):
         c.user = M.User.by_username('test-admin')
@@ -336,7 +336,7 @@ class TestMailTasks(unittest.TestCase):
                 reply_to=g.noreply,
                 subject='Test subject',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 0)
+            assert _client.sendmail.call_count == 0
 
     def test_sendsimplemail_with_disabled_user(self):
         c.user = M.User.by_username('test-admin')
@@ -348,10 +348,10 @@ class TestMailTasks(unittest.TestCase):
                 reply_to=g.noreply,
                 subject='Test subject',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
-            assert_in('From: "Test Admin" <te...@users.localhost>', body)
+            assert 'From: "Test Admin" <te...@users.localhost>' in body
 
             c.user.disabled = True
             ThreadLocalORMSession.flush_all()
@@ -362,10 +362,10 @@ class TestMailTasks(unittest.TestCase):
                 reply_to=g.noreply,
                 subject='Test subject',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 2)
+            assert _client.sendmail.call_count == 2
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
-            assert_in('From: %s' % g.noreply, body)
+            assert 'From: %s' % g.noreply in body
 
     def test_email_sender_to_headers(self):
         c.user = M.User.by_username('test-admin')
@@ -378,12 +378,12 @@ class TestMailTasks(unittest.TestCase):
                 subject='Test subject',
                 sender='tickets@test.p.domain.net',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
-            assert_in('From: "Test Admin" <te...@users.localhost>', body)
-            assert_in('Sender: tickets@test.p.domain.net', body)
-            assert_in('To: test@mail.com', body)
+            assert 'From: "Test Admin" <te...@users.localhost>' in body
+            assert 'Sender: tickets@test.p.domain.net' in body
+            assert 'To: test@mail.com' in body
 
             _client.reset_mock()
             mail_tasks.sendmail(
@@ -394,12 +394,12 @@ class TestMailTasks(unittest.TestCase):
                 subject='Test subject',
                 sender='tickets@test.p.domain.net',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
-            assert_in('From: "Test Admin" <te...@users.localhost>', body)
-            assert_in('Sender: tickets@test.p.domain.net', body)
-            assert_in('To: 123@tickets.test.p.domain.net', body)
+            assert 'From: "Test Admin" <te...@users.localhost>' in body
+            assert 'Sender: tickets@test.p.domain.net' in body
+            assert 'To: 123@tickets.test.p.domain.net' in body
 
     def test_email_references_header(self):
         c.user = M.User.by_username('test-admin')
@@ -412,11 +412,11 @@ class TestMailTasks(unittest.TestCase):
                 subject='Test subject',
                 references=['a', 'b', 'c'],
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
-            assert_in('From: "Test Admin" <te...@users.localhost>', body)
-            assert_in('References: <a> <b> <c>', body)
+            assert 'From: "Test Admin" <te...@users.localhost>' in body
+            assert 'References: <a> <b> <c>' in body
 
             _client.reset_mock()
             mail_tasks.sendmail(
@@ -427,11 +427,11 @@ class TestMailTasks(unittest.TestCase):
                 subject='Test subject',
                 references='ref',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
-            assert_in('From: "Test Admin" <te...@users.localhost>', body)
-            assert_in('References: <ref>', body)
+            assert 'From: "Test Admin" <te...@users.localhost>' in body
+            assert 'References: <ref>' in body
 
     def test_cc(self):
         c.user = M.User.by_username('test-admin')
@@ -444,10 +444,10 @@ class TestMailTasks(unittest.TestCase):
                 subject='Test subject',
                 cc='someone@example.com',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
-            assert_in('CC: someone@example.com', body)
-            assert_in('someone@example.com', rcpts)
+            assert 'CC: someone@example.com' in body
+            assert 'someone@example.com' in rcpts
 
     def test_fromaddr_objectid_not_str(self):
         c.user = M.User.by_username('test-admin')
@@ -459,9 +459,9 @@ class TestMailTasks(unittest.TestCase):
                 reply_to=g.noreply,
                 subject='Test subject',
                 message_id=h.gen_message_id())
-            assert_equal(_client.sendmail.call_count, 1)
+            assert _client.sendmail.call_count == 1
             return_path, rcpts, body = _client.sendmail.call_args[0]
-            assert_in('From: "Test Admin" <te...@users.localhost>', body)
+            assert 'From: "Test Admin" <te...@users.localhost>' in body
 
     def test_send_email_long_lines_use_quoted_printable(self):
         with mock.patch.object(mail_tasks.smtp_client, '_client') as _client:
@@ -477,14 +477,14 @@ class TestMailTasks(unittest.TestCase):
             body = body.split('\n')
 
             for line in body:
-                assert_less_equal(len(line), MAX_MAIL_LINE_OCTETS)
+                assert len(line) <= MAX_MAIL_LINE_OCTETS
 
             # plain text
-            assert_in('012345678901234567890123456789012345678901234567890123456789012345678901234=', body)
-            assert_in('=D0=93=D1=80=D0=BE=D0=BC=D0=B0=D0=B4=D1=8B =D1=81=D1=82=D1=80=D0=BE =D0=93=', body)
+            assert '012345678901234567890123456789012345678901234567890123456789012345678901234=' in body
+            assert '=D0=93=D1=80=D0=BE=D0=BC=D0=B0=D0=B4=D1=8B =D1=81=D1=82=D1=80=D0=BE =D0=93=' in body
             # html
-            assert_in('<div class=3D"markdown_content"><p>0123456789012345678901234567890123456789=', body)
-            assert_in('<p>=D0=93=D1=80=D0=BE=D0=BC=D0=B0=D0=B4=D1=8B =D1=81=D1=82=D1=80=D0=BE =D0=', body)
+            assert '<div class=3D"markdown_content"><p>0123456789012345678901234567890123456789=' in body
+            assert '<p>=D0=93=D1=80=D0=BE=D0=BC=D0=B0=D0=B4=D1=8B =D1=81=D1=82=D1=80=D0=BE =D0=' in body
 
     @td.with_wiki
     def test_receive_email_ok(self):
@@ -519,7 +519,7 @@ I'm not here'''
                 c.user.email_addresses[0],
                 ['1@bugs.test.p.in.localhost'],
                 message)
-            assert_equal(hm.call_count, 0)
+            assert hm.call_count == 0
 
     @td.with_tool('test', 'Tickets', 'bugs')
     def test_email_posting_disabled(self):
@@ -533,7 +533,7 @@ I'm not here'''
                 c.user.email_addresses[0],
                 ['1@bugs.test.p.in.localhost'],
                 message)
-            assert_equal(hm.call_count, 0)
+            assert hm.call_count == 0
 
 
 class TestUserNotificationTasks(TestController):
@@ -556,15 +556,15 @@ class TestUserNotificationTasks(TestController):
         # check email notification
         tasks = M.MonQTask.query.find(
             dict(task_name='allura.tasks.mail_tasks.sendsimplemail')).all()
-        assert_equal(len(tasks), 1)
-        assert_equal(tasks[0].kwargs['subject'],
+        assert len(tasks) == 1
+        assert (tasks[0].kwargs['subject'] ==
                      '[test:wiki] Your name was mentioned')
-        assert_equal(tasks[0].kwargs['toaddr'], 'test-user-1@allura.local')
-        assert_equal(tasks[0].kwargs['reply_to'], g.noreply)
+        assert tasks[0].kwargs['toaddr'] == 'test-user-1@allura.local'
+        assert tasks[0].kwargs['reply_to'] == g.noreply
         text = tasks[0].kwargs['text']
-        assert_in('Your name was mentioned at [foo]', text)
-        assert_in('by Test Admin', text)
-        assert_in('auth/subscriptions#notifications', text)
+        assert 'Your name was mentioned at [foo]' in text
+        assert 'by Test Admin' in text
+        assert 'auth/subscriptions#notifications' in text
 
 
 class TestNotificationTasks(unittest.TestCase):
@@ -651,25 +651,25 @@ class TestExportTasks(unittest.TestCase):
         # check notification
         tasks = M.MonQTask.query.find(
             dict(task_name='allura.tasks.mail_tasks.sendsimplemail')).all()
-        assert_equal(len(tasks), 1)
-        assert_equal(tasks[0].kwargs['subject'],
+        assert len(tasks) == 1
+        assert (tasks[0].kwargs['subject'] ==
                      'Bulk export for project test completed')
-        assert_equal(tasks[0].kwargs['fromaddr'], '"Allura" <no...@localhost>')
-        assert_equal(tasks[0].kwargs['reply_to'], g.noreply)
+        assert tasks[0].kwargs['fromaddr'] == '"Allura" <no...@localhost>'
+        assert tasks[0].kwargs['reply_to'] == g.noreply
         text = tasks[0].kwargs['text']
-        assert_in('The bulk export for project test is completed.', text)
-        assert_in('The following tools were exported:\n- wiki', text)
-        assert_in('Sample instructions for test', text)
+        assert 'The bulk export for project test is completed.' in text
+        assert 'The following tools were exported:\n- wiki' in text
+        assert 'Sample instructions for test' in text
 
     def test_bulk_export_status(self):
-        assert_equal(c.project.bulk_export_status(), None)
+        assert c.project.bulk_export_status() == None
         export_tasks.bulk_export.post(['wiki'])
-        assert_equal(c.project.bulk_export_status(), 'busy')
+        assert c.project.bulk_export_status() == 'busy'
 
 
 class TestAdminTasks(unittest.TestCase):
 
     def test_install_app_docstring(self):
-        assert_in('ep_name, mount_point=None', admin_tasks.install_app.__doc__)
+        assert 'ep_name, mount_point=None' in admin_tasks.install_app.__doc__
 
 Mapper.compile_all()
diff --git a/Allura/allura/tests/test_utils.py b/Allura/allura/tests/test_utils.py
index 8a1231479..e82c529e3 100644
--- a/Allura/allura/tests/test_utils.py
+++ b/Allura/allura/tests/test_utils.py
@@ -93,9 +93,9 @@ class TestChunkedIterator(unittest.TestCase):
         assert len(chunks) == 2, chunks
         assert len(chunks[0]) == 2, chunks[0]
         assert len(chunks[1]) == 1, chunks[1]
-        assert_equal(chunks[0][0].username, 'sample-user-1')
-        assert_equal(chunks[0][1].username, 'sample-user-2')
-        assert_equal(chunks[1][0].username, 'sample-user-3')
+        assert chunks[0][0].username == 'sample-user-1'
+        assert chunks[0][1].username == 'sample-user-2'
+        assert chunks[1][0].username == 'sample-user-3'
 
 
 class TestChunkedList(unittest.TestCase):
@@ -228,10 +228,10 @@ class TestLineAnchorCodeHtmlFormatter(unittest.TestCase):
         assert '<div id="l1" class="code_block">' in hl_code
         try:
             # older pygments
-            assert_in('<span class="lineno">1 </span>', hl_code)
+            assert '<span class="lineno">1 </span>' in hl_code
         except AssertionError:
             # newer pygments
-            assert_in('<span class="linenos">1</span>', hl_code)
+            assert '<span class="linenos">1</span>' in hl_code
 
 
 class TestIsTextFile(unittest.TestCase):
@@ -285,40 +285,40 @@ class TestHTMLSanitizer(unittest.TestCase):
     def test_html_sanitizer_iframe(self):
         walker = self.walker_from_text('<div><iframe></iframe></div>')
         p = utils.ForgeHTMLSanitizerFilter(walker)
-        assert_equal(self.simple_tag_list(p), ['div', 'div'])
+        assert self.simple_tag_list(p) == ['div', 'div']
 
     def test_html_sanitizer_youtube_iframe(self):
         walker = self.walker_from_text(
             '<div><iframe src="https://www.youtube.com/embed/kOLpSPEA72U?feature=oembed"></iframe></div>')
         p = utils.ForgeHTMLSanitizerFilter(walker)
-        assert_equal(self.simple_tag_list(p), ['div', 'iframe', 'iframe', 'div'])
+        assert self.simple_tag_list(p) == ['div', 'iframe', 'iframe', 'div']
 
         walker = self.walker_from_text(
             '<div><iframe src="https://www.youtube-nocookie.com/embed/kOLpSPEA72U?feature=oembed"></iframe></div>')
         p = utils.ForgeHTMLSanitizerFilter(walker)
-        assert_equal(self.simple_tag_list(p), ['div', 'iframe', 'iframe', 'div'])
+        assert self.simple_tag_list(p) == ['div', 'iframe', 'iframe', 'div']
 
     def test_html_sanitizer_form_elements(self):
         walker = self.walker_from_text('<p>test</p><form method="post" action="http://localhost/foo.php"><input type=file><input type=text><textarea>asdf</textarea></form>')
         p = utils.ForgeHTMLSanitizerFilter(walker)
-        assert_equal(self.simple_tag_list(p), ['p', 'p'])
+        assert self.simple_tag_list(p) == ['p', 'p']
 
     def test_html_sanitizer_checkbox(self):
         walker = self.walker_from_text('<p><input type="checkbox" disabled/><input type="text" disabled/><input type="checkbox" disabled checked/></p>')
         p = utils.ForgeHTMLSanitizerFilter(walker)
-        assert_equal(self.simple_tag_list(p), ['p', 'input', 'input', 'p'])
+        assert self.simple_tag_list(p) == ['p', 'input', 'input', 'p']
 
     def test_html_sanitizer_summary(self):
         walker = self.walker_from_text('<details open="open"><summary>An Summary</summary><ul><li>Bullet Item</li></ul></details>')
         p = utils.ForgeHTMLSanitizerFilter(walker)
-        assert_equal(self.simple_tag_list(p), ['details', 'summary', 'summary', 'ul', 'li', 'li', 'ul', 'details'])
+        assert self.simple_tag_list(p) == ['details', 'summary', 'summary', 'ul', 'li', 'li', 'ul', 'details']
 
 
 def test_ip_address():
     req = Mock()
     req.remote_addr = '1.2.3.4'
     req.headers = {}
-    assert_equal(utils.ip_address(req),
+    assert (utils.ip_address(req) ==
                  '1.2.3.4')
 
 
@@ -327,7 +327,7 @@ def test_ip_address_header():
     req.remote_addr = '1.2.3.4'
     req.headers = {'X_FORWARDED_FOR': '5.6.7.8'}
     with h.push_config(config, **{'ip_address_header': 'X_FORWARDED_FOR'}):
-        assert_equal(utils.ip_address(req),
+        assert (utils.ip_address(req) ==
                      '5.6.7.8')
 
 
@@ -336,22 +336,22 @@ def test_ip_address_header_not_set():
     req.remote_addr = '1.2.3.4'
     req.headers = {}
     with h.push_config(config, **{'ip_address_header': 'X_FORWARDED_FOR'}):
-        assert_equal(utils.ip_address(req),
+        assert (utils.ip_address(req) ==
                      '1.2.3.4')
 
 
 def test_empty_cursor():
     """EmptyCursors conforms to specification of Ming's ODMCursor"""
     cursor = utils.EmptyCursor()
-    assert_equal(cursor.count(), 0)
-    assert_equal(cursor.first(), None)
-    assert_equal(cursor.all(), [])
-    assert_equal(cursor.limit(10), cursor)
-    assert_equal(cursor.skip(10), cursor)
-    assert_equal(cursor.sort('name', 1), cursor)
-    assert_equal(cursor.hint('index'), cursor)
-    assert_equal(cursor.extensions, [])
-    assert_equal(cursor.options(arg1='val1', arg2='val2'), cursor)
+    assert cursor.count() == 0
+    assert cursor.first() == None
+    assert cursor.all() == []
+    assert cursor.limit(10) == cursor
+    assert cursor.skip(10) == cursor
+    assert cursor.sort('name', 1) == cursor
+    assert cursor.hint('index') == cursor
+    assert cursor.extensions == []
+    assert cursor.options(arg1='val1', arg2='val2') == cursor
     assert_raises(ValueError, cursor.one)
     assert_raises(StopIteration, cursor.next)
     assert_raises(StopIteration, cursor._next_impl)
@@ -367,16 +367,16 @@ def test_DateJSONEncoder():
 
 def test_clean_phone_number():
     clean = utils.clean_phone_number
-    assert_equal(clean('123456789'), '123456789')
-    assert_equal(clean('+123 456:789'), '123456789')
-    assert_equal(clean('555-555-5555'), '5555555555')
-    assert_equal(clean('1-555-555-5555'), '15555555555')
+    assert clean('123456789') == '123456789'
+    assert clean('+123 456:789') == '123456789'
+    assert clean('555-555-5555') == '5555555555'
+    assert clean('1-555-555-5555') == '15555555555'
 
 
 def test_phone_number_hash():
     hash = utils.phone_number_hash
-    assert_equal(hash('1234567890'), hash('+123 456:7890'))
-    assert_not_equal(hash('1234567890'), hash('1234567891'))
+    assert hash('1234567890') == hash('+123 456:7890')
+    assert hash('1234567890') != hash('1234567891')
 
 
 def test_skip_mod_date():
@@ -395,8 +395,8 @@ class FakeAttachment:
 
 def unique_attachments():
     ua = utils.unique_attachments
-    assert_equal([], ua(None))
-    assert_equal([], ua([]))
+    assert [] == ua(None)
+    assert [] == ua([])
 
     pic1 = FakeAttachment('pic.png')
     pic2 = FakeAttachment('pic.png')
@@ -405,7 +405,7 @@ def unique_attachments():
     other = FakeAttachment('other')
     attachments = [pic1, file1, pic2, file2, pic2, other]
     expected = [file2, other, pic2]
-    assert_equal(expected, ua(attachments))
+    assert expected == ua(attachments)
 
 
 def test_is_nofollow_url():
@@ -432,8 +432,8 @@ def test_close_ipv4_addrs():
 
 def test_urlencode():
     # dict - a simple one so arbitrary ordering doesn't cause problems on py2
-    assert_equal(utils.urlencode({'a': 'hello'}),
+    assert (utils.urlencode({'a': 'hello'}) ==
                  'a=hello')
     # list of pairs - including unicode and bytes
-    assert_equal(utils.urlencode([('a', 1), ('b', 'ƒ'), ('c', 'ƒ'.encode())]),
+    assert (utils.urlencode([('a', 1), ('b', 'ƒ'), ('c', 'ƒ'.encode())]) ==
                  'a=1&b=%C6%92&c=%C6%92')
diff --git a/Allura/allura/tests/test_webhooks.py b/Allura/allura/tests/test_webhooks.py
index da3035ff2..84b758013 100644
--- a/Allura/allura/tests/test_webhooks.py
+++ b/Allura/allura/tests/test_webhooks.py
@@ -99,10 +99,10 @@ class TestValidators(TestWebhookBase):
         v = WebhookValidator(sender=sender, app=app, not_empty=True)
         with assert_raises(Invalid) as cm:
             v.to_python(None)
-        assert_equal(cm.exception.msg, 'Please enter a value')
+        assert cm.exception.msg == 'Please enter a value'
         with assert_raises(Invalid) as cm:
             v.to_python('invalid id')
-        assert_equal(cm.exception.msg, 'Invalid webhook')
+        assert cm.exception.msg == 'Invalid webhook'
 
         wh = M.Webhook(type='invalid type',
                        app_config_id=invalid_app.config._id,
@@ -112,19 +112,19 @@ class TestValidators(TestWebhookBase):
         # invalid type
         with assert_raises(Invalid) as cm:
             v.to_python(wh._id)
-        assert_equal(cm.exception.msg, 'Invalid webhook')
+        assert cm.exception.msg == 'Invalid webhook'
 
         wh.type = 'repo-push'
         session(wh).flush(wh)
         # invalild app
         with assert_raises(Invalid) as cm:
             v.to_python(wh._id)
-        assert_equal(cm.exception.msg, 'Invalid webhook')
+        assert cm.exception.msg == 'Invalid webhook'
 
         wh.app_config_id = app.config._id
         session(wh).flush(wh)
-        assert_equal(v.to_python(wh._id), wh)
-        assert_equal(v.to_python(str(wh._id)), wh)
+        assert v.to_python(wh._id) == wh
+        assert v.to_python(str(wh._id)) == wh
 
 
 class TestWebhookController(TestController):
@@ -162,8 +162,8 @@ class TestWebhookController(TestController):
         url = url or self.url
         r = self.app.post(url + '/repo-push/create', data)
         wf = json.loads(self.webflash(r))
-        assert_equal(wf['status'], 'ok')
-        assert_equal(wf['message'], 'Created successfully')
+        assert wf['status'] == 'ok'
+        assert wf['message'] == 'Created successfully'
         return r
 
     def find_error(self, r, field, msg, form_type='create'):
@@ -174,7 +174,7 @@ class TestWebhookController(TestController):
             error = form.find('input', attrs={'name': field})
             error = error.findNext('div', attrs={'class': 'error'})
         if error:
-            assert_in(msg, error.getText())
+            assert msg in error.getText()
         else:
             assert False, 'Validation error not found'
 
@@ -186,7 +186,7 @@ class TestWebhookController(TestController):
         r = self.app.get(self.url + '/repo-push/',
                          extra_environ={'username': '*anonymous'},
                          status=302)
-        assert_equal(r.location,
+        assert (r.location ==
                      'http://localhost/auth/'
                      '?return_to=%2Fadobe%2Fadobe-1%2Fadmin%2Fsrc%2Fwebhooks%2Frepo-push%2F')
 
@@ -194,52 +194,52 @@ class TestWebhookController(TestController):
         self.app.get(self.url + '/invalid-hook-type/', status=404)
 
     def test_create(self):
-        assert_equal(M.Webhook.query.find().count(), 0)
+        assert M.Webhook.query.find().count() == 0
         r = self.app.get(self.url)
-        assert_in('<h1>repo-push</h1>', r)
-        assert_not_in('http://httpbin.org/post', r)
+        assert '<h1>repo-push</h1>' in r
+        assert 'http://httpbin.org/post' not in r
         data = {'url': 'http://httpbin.org/post',
                 'secret': ''}
         msg = 'add webhook repo-push {} {}'.format(
             data['url'], self.git.config.url())
         with td.audits(msg):
             r = self.create_webhook(data).follow()
-        assert_in('http://httpbin.org/post', r)
+        assert 'http://httpbin.org/post' in r
 
         hooks = M.Webhook.query.find().all()
-        assert_equal(len(hooks), 1)
-        assert_equal(hooks[0].type, 'repo-push')
-        assert_equal(hooks[0].hook_url, 'http://httpbin.org/post')
-        assert_equal(hooks[0].app_config_id, self.git.config._id)
-        assert_equal(hooks[0].secret, 'super-secret')
+        assert len(hooks) == 1
+        assert hooks[0].type == 'repo-push'
+        assert hooks[0].hook_url == 'http://httpbin.org/post'
+        assert hooks[0].app_config_id == self.git.config._id
+        assert hooks[0].secret == 'super-secret'
 
         # Try to create duplicate
         with td.out_audits(msg):
             r = self.app.post(self.url + '/repo-push/create', data)
         self.find_error(r, '_the_form',
                         '"repo-push" webhook already exists for Git http://httpbin.org/post')
-        assert_equal(M.Webhook.query.find().count(), 1)
+        assert M.Webhook.query.find().count() == 1
 
     def test_create_limit_reached(self):
-        assert_equal(M.Webhook.query.find().count(), 0)
+        assert M.Webhook.query.find().count() == 0
         limit = json.dumps({'git': 1})
         with h.push_config(config, **{'webhook.repo_push.max_hooks': limit}):
             data = {'url': 'http://httpbin.org/post',
                     'secret': ''}
             r = self.create_webhook(data).follow()
-            assert_equal(M.Webhook.query.find().count(), 1)
+            assert M.Webhook.query.find().count() == 1
 
             r = self.app.post(self.url + '/repo-push/create', data)
             wf = json.loads(self.webflash(r))
-            assert_equal(wf['status'], 'error')
-            assert_equal(
-                wf['message'],
+            assert wf['status'] == 'error'
+            assert (
+                wf['message'] ==
                 'You have exceeded the maximum number of webhooks '
                 'you are allowed to create for this project/app')
-            assert_equal(M.Webhook.query.find().count(), 1)
+            assert M.Webhook.query.find().count() == 1
 
     def test_create_validation(self):
-        assert_equal(M.Webhook.query.find().count(), 0)
+        assert M.Webhook.query.find().count() == 0
         r = self.app.post(
             self.url + '/repo-push/create', {}, status=404)
 
@@ -270,13 +270,13 @@ class TestWebhookController(TestController):
                  'secret': 'secret2'}
         self.create_webhook(data1).follow()
         self.create_webhook(data2).follow()
-        assert_equal(M.Webhook.query.find().count(), 2)
+        assert M.Webhook.query.find().count() == 2
         wh1 = M.Webhook.query.get(hook_url=data1['url'])
         r = self.app.get(self.url + '/repo-push/%s' % wh1._id)
         form = r.forms[0]
-        assert_equal(form['url'].value, data1['url'])
-        assert_equal(form['secret'].value, data1['secret'])
-        assert_equal(form['webhook'].value, str(wh1._id))
+        assert form['url'].value == data1['url']
+        assert form['secret'].value == data1['secret']
+        assert form['webhook'].value == str(wh1._id)
         form['url'] = 'http://host.org/hook'
         form['secret'] = 'new secret'
         msg = 'edit webhook repo-push\n{} => {}\n{}'.format(
@@ -284,14 +284,14 @@ class TestWebhookController(TestController):
         with td.audits(msg):
             r = form.submit()
         wf = json.loads(self.webflash(r))
-        assert_equal(wf['status'], 'ok')
-        assert_equal(wf['message'], 'Edited successfully')
-        assert_equal(M.Webhook.query.find().count(), 2)
+        assert wf['status'] == 'ok'
+        assert wf['message'] == 'Edited successfully'
+        assert M.Webhook.query.find().count() == 2
         wh1 = M.Webhook.query.get(_id=wh1._id)
-        assert_equal(wh1.hook_url, 'http://host.org/hook')
-        assert_equal(wh1.app_config_id, self.git.config._id)
-        assert_equal(wh1.secret, 'new secret')
-        assert_equal(wh1.type, 'repo-push')
+        assert wh1.hook_url == 'http://host.org/hook'
+        assert wh1.app_config_id == self.git.config._id
+        assert wh1.secret == 'new secret'
+        assert wh1.type == 'repo-push'
 
         # Duplicates
         r = self.app.get(self.url + '/repo-push/%s' % wh1._id)
@@ -336,15 +336,15 @@ class TestWebhookController(TestController):
         data = {'url': 'http://httpbin.org/post',
                 'secret': 'secret'}
         self.create_webhook(data).follow()
-        assert_equal(M.Webhook.query.find().count(), 1)
+        assert M.Webhook.query.find().count() == 1
         wh = M.Webhook.query.get(hook_url=data['url'])
         data = {'webhook': str(wh._id)}
         msg = 'delete webhook repo-push {} {}'.format(
             wh.hook_url, self.git.config.url())
         with td.audits(msg):
             r = self.app.post(self.url + '/repo-push/delete', data)
-        assert_equal(r.json, {'status': 'ok'})
-        assert_equal(M.Webhook.query.find().count(), 0)
+        assert r.json == {'status': 'ok'}
+        assert M.Webhook.query.find().count() == 0
 
     def test_delete_validation(self):
         invalid = M.Webhook(
@@ -353,14 +353,14 @@ class TestWebhookController(TestController):
             hook_url='http://httpbin.org/post',
             secret='secret')
         session(invalid).flush(invalid)
-        assert_equal(M.Webhook.query.find().count(), 1)
+        assert M.Webhook.query.find().count() == 1
 
         data = {'webhook': ''}
         self.app.post(self.url + '/repo-push/delete', data, status=404)
 
         data = {'webhook': str(invalid._id)}
         self.app.post(self.url + '/repo-push/delete', data, status=404)
-        assert_equal(M.Webhook.query.find().count(), 1)
+        assert M.Webhook.query.find().count() == 1
 
     @with_git2
     def test_list_webhooks(self):
@@ -379,9 +379,9 @@ class TestWebhookController(TestController):
         wh2 = M.Webhook.query.get(hook_url=data2['url'])
 
         r = self.app.get(self.url)
-        assert_in('<h1>repo-push</h1>', r)
+        assert '<h1>repo-push</h1>' in r
         rows = r.html.find('table').findAll('tr')
-        assert_equal(len(rows), 2)
+        assert len(rows) == 2
         rows = sorted((self._format_row(row) for row in rows), key=lambda rows: rows[0]['text'])
         expected_rows = sorted([
             [{'text': wh1.hook_url},
@@ -397,10 +397,10 @@ class TestWebhookController(TestController):
              {'href': self.url + '/repo-push/delete',
               'data-id': str(wh2._id)}],
         ], key=lambda rows: rows[0]['text'])
-        assert_equal(rows, expected_rows)
+        assert rows == expected_rows
         # make sure webhooks for another app is not visible
-        assert_not_in('http://another-app.org/', r)
-        assert_not_in('secret3', r)
+        assert 'http://another-app.org/' not in r
+        assert 'secret3' not in r
 
     def _format_row(self, row):
         def link(td):
@@ -425,14 +425,14 @@ class TestSendWebhookHelper(TestWebhookBase):
         self.h = SendWebhookHelper(self.wh, self.payload)
 
     def test_timeout(self):
-        assert_equal(self.h.timeout, 30)
+        assert self.h.timeout == 30
         with h.push_config(config, **{'webhook.timeout': 10}):
-            assert_equal(self.h.timeout, 10)
+            assert self.h.timeout == 10
 
     def test_retries(self):
-        assert_equal(self.h.retries, [60, 120, 240])
+        assert self.h.retries == [60, 120, 240]
         with h.push_config(config, **{'webhook.retry': '1 2 3 4 5 6'}):
-            assert_equal(self.h.retries, [1, 2, 3, 4, 5, 6])
+            assert self.h.retries == [1, 2, 3, 4, 5, 6]
 
     def test_sign(self):
         json_payload = json.dumps(self.payload)
@@ -441,18 +441,18 @@ class TestSendWebhookHelper(TestWebhookBase):
             json_payload.encode('utf-8'),
             hashlib.sha1)
         signature = 'sha1=' + signature.hexdigest()
-        assert_equal(self.h.sign(json_payload), signature)
+        assert self.h.sign(json_payload) == signature
 
     def test_log_msg(self):
-        assert_equal(
-            self.h.log_msg('OK'),
+        assert (
+            self.h.log_msg('OK') ==
             'OK: repo-push http://httpbin.org/post /adobe/adobe-1/src/')
         response = Mock(
             status_code=500,
             text='that is why',
             headers={'Content-Type': 'application/json'})
-        assert_equal(
-            self.h.log_msg('Error', response=response),
+        assert (
+            self.h.log_msg('Error', response=response) ==
             "Error: repo-push http://httpbin.org/post /adobe/adobe-1/src/ 500 "
             "that is why {'Content-Type': 'application/json'}")
 
@@ -485,15 +485,15 @@ class TestSendWebhookHelper(TestWebhookBase):
     def test_send_error_response_status(self, log, requests, time):
         requests.post.return_value = Mock(status_code=500)
         self.h.send()
-        assert_equal(requests.post.call_count, 4)  # initial call + 3 retries
-        assert_equal(time.sleep.call_args_list,
+        assert requests.post.call_count == 4  # initial call + 3 retries
+        assert (time.sleep.call_args_list ==
                      [call(60), call(120), call(240)])
-        assert_equal(log.info.call_args_list, [
+        assert log.info.call_args_list == [
             call('Retrying webhook in: %s', [60, 120, 240]),
             call('Retrying webhook in %s seconds', 60),
             call('Retrying webhook in %s seconds', 120),
-            call('Retrying webhook in %s seconds', 240)])
-        assert_equal(log.error.call_count, 4)
+            call('Retrying webhook in %s seconds', 240)]
+        assert log.error.call_count == 4
         log.error.assert_called_with(
             'Webhook send error: {} {} {} {} {} {}'.format(
                 self.wh.type, self.wh.hook_url,
@@ -509,10 +509,10 @@ class TestSendWebhookHelper(TestWebhookBase):
         requests.post.return_value = Mock(status_code=500)
         with h.push_config(config, **{'webhook.retry': ''}):
             self.h.send()
-            assert_equal(requests.post.call_count, 1)
-            assert_equal(time.call_count, 0)
+            assert requests.post.call_count == 1
+            assert time.call_count == 0
             log.info.assert_called_once_with('Retrying webhook in: %s', [])
-            assert_equal(log.error.call_count, 1)
+            assert log.error.call_count == 1
             log.error.assert_called_with(
                 'Webhook send error: {} {} {} {} {} {}'.format(
                     self.wh.type, self.wh.hook_url,
@@ -540,10 +540,10 @@ class TestRepoPushWebhookSender(TestWebhookBase):
         self.wh.enforce_limit = Mock(return_value=True)
         with h.push_config(c, app=self.git):
             sender.send([dict(arg1=1, arg2=2), dict(arg1=3, arg2=4)])
-        assert_equal(send_webhook.post.call_count, 2)
-        assert_equal(send_webhook.post.call_args_list,
+        assert send_webhook.post.call_count == 2
+        assert (send_webhook.post.call_args_list ==
                      [call(self.wh._id, 1), call(self.wh._id, 2)])
-        assert_equal(self.wh.enforce_limit.call_count, 1)
+        assert self.wh.enforce_limit.call_count == 1
 
     @patch('allura.webhooks.log', autospec=True)
     @patch('allura.webhooks.send_webhook', autospec=True)
@@ -553,7 +553,7 @@ class TestRepoPushWebhookSender(TestWebhookBase):
         self.wh.enforce_limit = Mock(return_value=False)
         with h.push_config(c, app=self.git):
             sender.send(dict(arg1=1, arg2=2))
-        assert_equal(send_webhook.post.call_count, 0)
+        assert send_webhook.post.call_count == 0
         log.warn.assert_called_once_with(
             'Webhook fires too often: %s. Skipping', self.wh)
 
@@ -564,7 +564,7 @@ class TestRepoPushWebhookSender(TestWebhookBase):
         sender = RepoPushWebhookSender()
         with h.push_config(c, app=self.git):
             sender.send(dict(arg1=1, arg2=2))
-        assert_equal(send_webhook.post.call_count, 0)
+        assert send_webhook.post.call_count == 0
 
     def test_get_payload(self):
         sender = RepoPushWebhookSender()
@@ -584,7 +584,7 @@ class TestRepoPushWebhookSender(TestWebhookBase):
                 'url': 'http://localhost/adobe/adobe-1/src/',
             },
         }
-        assert_equal(result, expected_result)
+        assert result == expected_result
 
     def test_enforce_limit(self):
         def add_webhooks(suffix, n):
@@ -598,64 +598,64 @@ class TestRepoPushWebhookSender(TestWebhookBase):
 
         sender = RepoPushWebhookSender()
         # default
-        assert_equal(sender.enforce_limit(self.git), True)
+        assert sender.enforce_limit(self.git) == True
         add_webhooks('one', 3)
-        assert_equal(sender.enforce_limit(self.git), False)
+        assert sender.enforce_limit(self.git) == False
 
         # config
         limit = json.dumps({'git': 5})
         with h.push_config(config, **{'webhook.repo_push.max_hooks': limit}):
-            assert_equal(sender.enforce_limit(self.git), True)
+            assert sender.enforce_limit(self.git) == True
             add_webhooks('two', 3)
-            assert_equal(sender.enforce_limit(self.git), False)
+            assert sender.enforce_limit(self.git) == False
 
     def test_before(self):
         sender = RepoPushWebhookSender()
         with patch.object(self.git.repo, 'commit', autospec=True) as _ci:
-            assert_equal(sender._before(self.git.repo, ['3', '2', '1']), '')
+            assert sender._before(self.git.repo, ['3', '2', '1']) == ''
             _ci.return_value.parent_ids = ['0']
-            assert_equal(sender._before(self.git.repo, ['3', '2', '1']), '0')
+            assert sender._before(self.git.repo, ['3', '2', '1']) == '0'
 
     def test_after(self):
         sender = RepoPushWebhookSender()
-        assert_equal(sender._after([]), '')
-        assert_equal(sender._after(['3', '2', '1']), '3')
+        assert sender._after([]) == ''
+        assert sender._after(['3', '2', '1']) == '3'
 
     def test_convert_id(self):
         sender = RepoPushWebhookSender()
-        assert_equal(sender._convert_id(''), '')
-        assert_equal(sender._convert_id('a433fa9'), 'a433fa9')
-        assert_equal(sender._convert_id('a433fa9:13'), 'r13')
+        assert sender._convert_id('') == ''
+        assert sender._convert_id('a433fa9') == 'a433fa9'
+        assert sender._convert_id('a433fa9:13') == 'r13'
 
 
 class TestModels(TestWebhookBase):
     def test_webhook_url(self):
-        assert_equal(self.wh.url(),
+        assert (self.wh.url() ==
                      f'/adobe/adobe-1/admin/src/webhooks/repo-push/{self.wh._id}')
 
     def test_webhook_enforce_limit(self):
         self.wh.last_sent = None
-        assert_equal(self.wh.enforce_limit(), True)
+        assert self.wh.enforce_limit() == True
         # default value
         self.wh.last_sent = dt.datetime.utcnow() - dt.timedelta(seconds=31)
-        assert_equal(self.wh.enforce_limit(), True)
+        assert self.wh.enforce_limit() == True
         self.wh.last_sent = dt.datetime.utcnow() - dt.timedelta(seconds=15)
-        assert_equal(self.wh.enforce_limit(), False)
+        assert self.wh.enforce_limit() == False
         # value from config
         with h.push_config(config, **{'webhook.repo_push.limit': 100}):
             self.wh.last_sent = dt.datetime.utcnow() - dt.timedelta(seconds=101)
-            assert_equal(self.wh.enforce_limit(), True)
+            assert self.wh.enforce_limit() == True
             self.wh.last_sent = dt.datetime.utcnow() - dt.timedelta(seconds=35)
-            assert_equal(self.wh.enforce_limit(), False)
+            assert self.wh.enforce_limit() == False
 
     @patch('allura.model.webhook.dt', autospec=True)
     def test_update_limit(self, dt_mock):
         _now = dt.datetime(2015, 2, 2, 13, 39)
         dt_mock.datetime.utcnow.return_value = _now
-        assert_equal(self.wh.last_sent, None)
+        assert self.wh.last_sent == None
         self.wh.update_limit()
         session(self.wh).expunge(self.wh)
-        assert_equal(M.Webhook.query.get(_id=self.wh._id).last_sent, _now)
+        assert M.Webhook.query.get(_id=self.wh._id).last_sent == _now
 
     def test_json(self):
         expected = {
@@ -743,7 +743,7 @@ class TestWebhookRestController(TestRestApiBase):
         dd.assert_equal(r.json, expected)
 
     def test_create_validation(self):
-        assert_equal(M.Webhook.query.find().count(), len(self.webhooks))
+        assert M.Webhook.query.find().count() == len(self.webhooks)
         r = self.api_get(self.url + '/repo-push', status=405)
 
         r = self.api_post(self.url + '/repo-push', status=400)
@@ -751,7 +751,7 @@ class TestWebhookRestController(TestRestApiBase):
             'result': 'error',
             'error': {'url': 'Please enter a value'},
         }
-        assert_equal(r.json, expected)
+        assert r.json == expected
 
         data = {'url': 'qwer', 'secret': 'qwe'}
         r = self.api_post(self.url + '/repo-push', status=400, **data)
@@ -761,11 +761,11 @@ class TestWebhookRestController(TestRestApiBase):
                 'url': 'You must provide a full domain name (like qwer.com)'
             },
         }
-        assert_equal(r.json, expected)
-        assert_equal(M.Webhook.query.find().count(), len(self.webhooks))
+        assert r.json == expected
+        assert M.Webhook.query.find().count() == len(self.webhooks)
 
     def test_create(self):
-        assert_equal(M.Webhook.query.find().count(), len(self.webhooks))
+        assert M.Webhook.query.find().count() == len(self.webhooks)
         data = {'url': 'http://hook.slack.com/abcd'}
         limit = json.dumps({'git': 10})
         with h.push_config(config, **{'webhook.repo_push.max_hooks': limit}):
@@ -774,7 +774,7 @@ class TestWebhookRestController(TestRestApiBase):
             with td.audits(msg):
                 r = self.api_post(self.url + '/repo-push', status=201, **data)
         webhook = M.Webhook.query.get(hook_url=data['url'])
-        assert_equal(webhook.secret, 'super-secret')  # secret generated
+        assert webhook.secret == 'super-secret'  # secret generated
         expected = {
             '_id': str(webhook._id),
             'url': 'http://localhost/rest/adobe/adobe-1/admin'
@@ -784,10 +784,10 @@ class TestWebhookRestController(TestRestApiBase):
             'mod_date': str(webhook.mod_date),
         }
         dd.assert_equal(r.json, expected)
-        assert_equal(M.Webhook.query.find().count(), len(self.webhooks) + 1)
+        assert M.Webhook.query.find().count() == len(self.webhooks) + 1
 
     def test_create_duplicates(self):
-        assert_equal(M.Webhook.query.find().count(), len(self.webhooks))
+        assert M.Webhook.query.find().count() == len(self.webhooks)
         data = {'url': self.webhooks[0].hook_url}
         limit = json.dumps({'git': 10})
         with h.push_config(config, **{'webhook.repo_push.max_hooks': limit}):
@@ -795,11 +795,11 @@ class TestWebhookRestController(TestRestApiBase):
         expected = {'result': 'error',
                     'error': '_the_form: "repo-push" webhook already '
                               'exists for Git http://httpbin.org/post/0'}
-        assert_equal(r.json, expected)
-        assert_equal(M.Webhook.query.find().count(), len(self.webhooks))
+        assert r.json == expected
+        assert M.Webhook.query.find().count() == len(self.webhooks)
 
     def test_create_limit_reached(self):
-        assert_equal(M.Webhook.query.find().count(), len(self.webhooks))
+        assert M.Webhook.query.find().count() == len(self.webhooks)
         data = {'url': 'http://hook.slack.com/abcd'}
         r = self.api_post(self.url + '/repo-push', status=400, **data)
         expected = {
@@ -807,8 +807,8 @@ class TestWebhookRestController(TestRestApiBase):
             'limits': {'max': 3, 'used': 3},
             'error': 'You have exceeded the maximum number of webhooks '
                       'you are allowed to create for this project/app'}
-        assert_equal(r.json, expected)
-        assert_equal(M.Webhook.query.find().count(), len(self.webhooks))
+        assert r.json == expected
+        assert M.Webhook.query.find().count() == len(self.webhooks)
 
     def test_edit_validation(self):
         webhook = self.webhooks[0]
@@ -821,7 +821,7 @@ class TestWebhookRestController(TestRestApiBase):
                 'url': 'You must provide a full domain name (like qwe.com)'
             },
         }
-        assert_equal(r.json, expected)
+        assert r.json == expected
 
     def test_edit(self):
         webhook = self.webhooks[0]
@@ -833,8 +833,8 @@ class TestWebhookRestController(TestRestApiBase):
         with td.audits(msg):
             r = self.api_post(url, status=200, **data)
         webhook = M.Webhook.query.get(_id=webhook._id)
-        assert_equal(webhook.hook_url, data['url'])
-        assert_equal(webhook.secret, 'secret-0')
+        assert webhook.hook_url == data['url']
+        assert webhook.secret == 'secret-0'
         expected = {
             '_id': str(webhook._id),
             'url': 'http://localhost/rest/adobe/adobe-1/admin'
@@ -853,8 +853,8 @@ class TestWebhookRestController(TestRestApiBase):
         with td.audits(msg):
             r = self.api_post(url, status=200, **data)
         webhook = M.Webhook.query.get(_id=webhook._id)
-        assert_equal(webhook.hook_url, 'http://hook.slack.com/abcd')
-        assert_equal(webhook.secret, 'new-secret')
+        assert webhook.hook_url == 'http://hook.slack.com/abcd'
+        assert webhook.secret == 'new-secret'
         expected = {
             '_id': str(webhook._id),
             'url': 'http://localhost/rest/adobe/adobe-1/admin'
@@ -873,14 +873,14 @@ class TestWebhookRestController(TestRestApiBase):
         expected = {'result': 'error',
                     'error': '_the_form: "repo-push" webhook already '
                               'exists for Git http://httpbin.org/post/1'}
-        assert_equal(r.json, expected)
+        assert r.json == expected
 
     def test_delete_validation(self):
         url = f'{self.url}/repo-push/invalid'
         self.api_delete(url, status=404)
 
     def test_delete(self):
-        assert_equal(M.Webhook.query.find().count(), 3)
+        assert M.Webhook.query.find().count() == 3
         webhook = self.webhooks[0]
         url = f'{self.url}/repo-push/{webhook._id}'
         msg = 'delete webhook repo-push {} {}'.format(
@@ -888,8 +888,8 @@ class TestWebhookRestController(TestRestApiBase):
         with td.audits(msg):
             r = self.api_delete(url, status=200)
         dd.assert_equal(r.json, {'result': 'ok'})
-        assert_equal(M.Webhook.query.find().count(), 2)
-        assert_equal(M.Webhook.query.get(_id=webhook._id), None)
+        assert M.Webhook.query.find().count() == 2
+        assert M.Webhook.query.get(_id=webhook._id) == None
 
     def test_permissions(self):
         self.api_get(self.url, user='test-user', status=403)
diff --git a/Allura/allura/tests/unit/controllers/test_discussion_moderation_controller.py b/Allura/allura/tests/unit/controllers/test_discussion_moderation_controller.py
index c2c366c4e..6e3dda279 100644
--- a/Allura/allura/tests/unit/controllers/test_discussion_moderation_controller.py
+++ b/Allura/allura/tests/unit/controllers/test_discussion_moderation_controller.py
@@ -50,17 +50,17 @@ class TestWhenModerating(WithDatabase):
             assert mock_post_to_feed.call_count == 1
 
         post = self.get_post()
-        assert_equal(post.status, 'ok')
-        assert_equal(post.thread.last_post_date.strftime("%Y-%m-%d %H:%M:%S"),
+        assert post.status == 'ok'
+        assert (post.thread.last_post_date.strftime("%Y-%m-%d %H:%M:%S") ==
                      mod_date.strftime("%Y-%m-%d %H:%M:%S"))
 
     def test_that_it_can_mark_as_spam(self):
         self.moderate_post(spam=True)
-        assert_equal(self.get_post().status, 'spam')
+        assert self.get_post().status == 'spam'
 
     def test_that_it_can_be_deleted(self):
         self.moderate_post(delete=True)
-        assert_equal(self.get_post(), None)
+        assert self.get_post() == None
 
     def moderate_post(self, **kwargs):
         with patch('allura.controllers.discuss.flash'):
diff --git a/Allura/allura/tests/unit/phone/test_nexmo.py b/Allura/allura/tests/unit/phone/test_nexmo.py
index 32b861579..1a51b4455 100644
--- a/Allura/allura/tests/unit/phone/test_nexmo.py
+++ b/Allura/allura/tests/unit/phone/test_nexmo.py
@@ -38,44 +38,44 @@ class TestPhoneService:
                     'brand': 'Allura',
                     'api_key': 'test-api-key',
                     'api_secret': 'test-api-secret'}
-        assert_equal(expected, res)
+        assert expected == res
 
         self.phone.config['phone.lang'] = 'it-it'
         res = self.phone.add_common_params(params)
         expected['lg'] = 'it-it'
-        assert_equal(expected, res)
+        assert expected == res
 
     def test_error(self):
         res = self.phone.error()
         expected = {'status': 'error',
                     'error': 'Failed sending request to Nexmo'}
-        assert_equal(expected, res)
+        assert expected == res
         # not allowed code
         res = self.phone.error(code='2', msg='text')
-        assert_equal(expected, res)
+        assert expected == res
         # allowed code
         res = self.phone.error(code='15', msg='text')
         expected = {'status': 'error', 'error': 'text'}
-        assert_equal(expected, res)
+        assert expected == res
 
         # invalid format, possibly US
         res = self.phone.error(code='3', msg='Invalid value for parameter: number', number='8005551234')
-        assert_equal(res['status'], 'error')
-        assert_in('Invalid value for parameter: number', res['error'])
-        assert_in('country code', res['error'])
-        assert_in('US', res['error'])
+        assert res['status'] == 'error'
+        assert 'Invalid value for parameter: number' in res['error']
+        assert 'country code' in res['error']
+        assert 'US' in res['error']
 
         # invalid format, not US
         res = self.phone.error(code='3', msg='Invalid value for parameter: number', number='738005551234')
-        assert_equal(res['status'], 'error')
-        assert_in('Invalid value for parameter: number', res['error'])
-        assert_in('country code', res['error'])
-        assert_not_in('US', res['error'])
+        assert res['status'] == 'error'
+        assert 'Invalid value for parameter: number' in res['error']
+        assert 'country code' in res['error']
+        assert 'US' not in res['error']
 
     def test_ok(self):
         res = self.phone.ok(request_id='123', other='smth')
         expected = {'status': 'ok', 'request_id': '123', 'other': 'smth'}
-        assert_equal(expected, res)
+        assert expected == res
 
     @patch('allura.lib.phone.nexmo.requests', autospec=True)
     def test_verify(self, req):
@@ -93,7 +93,7 @@ class TestPhoneService:
 
         resp = self.phone.verify('1234567890')
         expected = {'status': 'ok', 'request_id': 'test-req-id'}
-        assert_equal(expected, resp)
+        assert expected == resp
         req.post.assert_called_once_with(
             'https://api.nexmo.com/verify/json',
             data=data,
@@ -106,7 +106,7 @@ class TestPhoneService:
         }
         resp = self.phone.verify('1234567890')
         expected = {'status': 'error', 'error': 'Something went wrong'}
-        assert_equal(expected, resp)
+        assert expected == resp
         req.post.assert_called_once_with(
             'https://api.nexmo.com/verify/json',
             data=data,
@@ -118,7 +118,7 @@ class TestPhoneService:
         resp = self.phone.verify('1234567890')
         expected = {'status': 'error',
                     'error': 'Failed sending request to Nexmo'}
-        assert_equal(expected, resp)
+        assert expected == resp
 
     @patch('allura.lib.phone.nexmo.requests', autospec=True)
     def test_check(self, req):
@@ -136,7 +136,7 @@ class TestPhoneService:
 
         resp = self.phone.check('test-req-id', '1234')
         expected = {'status': 'ok', 'request_id': 'test-req-id'}
-        assert_equal(expected, resp)
+        assert expected == resp
         req.post.assert_called_once_with(
             'https://api.nexmo.com/verify/check/json',
             data=data,
@@ -149,7 +149,7 @@ class TestPhoneService:
         }
         resp = self.phone.check('test-req-id', '1234')
         expected = {'status': 'error', 'error': 'Something went wrong'}
-        assert_equal(expected, resp)
+        assert expected == resp
         req.post.assert_called_once_with(
             'https://api.nexmo.com/verify/check/json',
             data=data,
@@ -161,4 +161,4 @@ class TestPhoneService:
         resp = self.phone.check('req-id', '1234')
         expected = {'status': 'error',
                     'error': 'Failed sending request to Nexmo'}
-        assert_equal(expected, resp)
+        assert expected == resp
diff --git a/Allura/allura/tests/unit/phone/test_phone_service.py b/Allura/allura/tests/unit/phone/test_phone_service.py
index 20f145b19..62dcbb4ec 100644
--- a/Allura/allura/tests/unit/phone/test_phone_service.py
+++ b/Allura/allura/tests/unit/phone/test_phone_service.py
@@ -36,22 +36,22 @@ class TestPhoneService:
         res = PhoneService({}).verify('1234567890')
         expected = {'status': 'error',
                     'error': 'Phone service is not configured'}
-        assert_equal(res, expected)
+        assert res == expected
 
     def test_check(self):
         res = PhoneService({}).check('test-req-id', '1111')
         expected = {'status': 'error',
                     'error': 'Phone service is not configured'}
-        assert_equal(res, expected)
+        assert res == expected
 
     def test_get_default(self):
         config = {}
         entry_points = None
         phone = PhoneService.get(config, entry_points)
-        assert_true(isinstance(phone, PhoneService))
+        assert isinstance(phone, PhoneService)
 
     def test_get_method(self):
         config = {'phone.method': 'mock'}
         entry_points = {'mock': MockPhoneService}
         phone = PhoneService.get(config, entry_points)
-        assert_true(isinstance(phone, MockPhoneService))
+        assert isinstance(phone, MockPhoneService)
diff --git a/Allura/allura/tests/unit/spam/test_spam_filter.py b/Allura/allura/tests/unit/spam/test_spam_filter.py
index f9a8f59a3..02582135b 100644
--- a/Allura/allura/tests/unit/spam/test_spam_filter.py
+++ b/Allura/allura/tests/unit/spam/test_spam_filter.py
@@ -88,9 +88,9 @@ class TestSpamFilterFunctional:
         ThreadLocalORMSession.flush_all()
 
         results = SpamCheckResult.query.find().all()
-        assert_equal(len(results), 1)
-        assert_equal(results[0].result, True)
-        assert_equal(results[0].user.username, 'test-user')
+        assert len(results) == 1
+        assert results[0].result == True
+        assert results[0].user.username == 'test-user'
 
 
 class TestChainedSpamFilter:
@@ -101,8 +101,8 @@ class TestChainedSpamFilter:
         checker = SpamFilter.get(config, entry_points)
         assert isinstance(checker, ChainedSpamFilter)
         assert len(checker.filters) == 2, checker.filters
-        assert_equal(checker.filters[0].config, {'spam.method': 'mock1', 'spam.settingA': 'bcd'})
-        assert_equal(checker.filters[1].config, {'spam.method': 'mock2', 'spam.settingA': 'bcd'})
+        assert checker.filters[0].config == {'spam.method': 'mock1', 'spam.settingA': 'bcd'}
+        assert checker.filters[1].config == {'spam.method': 'mock2', 'spam.settingA': 'bcd'}
 
         assert checker.check()  # first filter errors out (but ignored by `exceptionless`), and 2nd returns True
 
diff --git a/Allura/allura/tests/unit/spam/test_stopforumspam.py b/Allura/allura/tests/unit/spam/test_stopforumspam.py
index 2ed47ea18..19da2d2b5 100644
--- a/Allura/allura/tests/unit/spam/test_stopforumspam.py
+++ b/Allura/allura/tests/unit/spam/test_stopforumspam.py
@@ -43,10 +43,10 @@ class TestStopForumSpam:
     @mock.patch('allura.lib.spam.stopforumspamfilter.request')
     def test_check(self, request):
         request.remote_addr = '1.2.3.4'
-        assert_equal(True, self.sfs.check(self.content, artifact=self.artifact))
+        assert True == self.sfs.check(self.content, artifact=self.artifact)
 
         request.remote_addr = '1.1.1.1'
-        assert_equal(False, self.sfs.check(self.content, artifact=self.artifact))
+        assert False == self.sfs.check(self.content, artifact=self.artifact)
 
         request.remote_addr = None  # e.g. from background task processing inbound email
-        assert_equal(False, self.sfs.check(self.content, artifact=self.artifact))
+        assert False == self.sfs.check(self.content, artifact=self.artifact)
diff --git a/Allura/allura/tests/unit/test_app.py b/Allura/allura/tests/unit/test_app.py
index 47b5c2bee..d64eaf0c0 100644
--- a/Allura/allura/tests/unit/test_app.py
+++ b/Allura/allura/tests/unit/test_app.py
@@ -108,7 +108,7 @@ class TestAppDefaults(WithDatabase):
 
     def test_email_address(self):
         self.app.url = '/p/project/mount-point/'
-        assert_equal(self.app.email_address, 'mount-point@project.p.in.localhost')
+        assert self.app.email_address == 'mount-point@project.p.in.localhost'
 
 
 def install_app():
diff --git a/Allura/allura/tests/unit/test_discuss.py b/Allura/allura/tests/unit/test_discuss.py
index fc35f1370..a9b4a8acf 100644
--- a/Allura/allura/tests/unit/test_discuss.py
+++ b/Allura/allura/tests/unit/test_discuss.py
@@ -27,13 +27,13 @@ class TestThread(WithDatabase):
 
     def test_should_update_index(self):
         p = M.Thread()
-        assert_false(p.should_update_index({}, {}))
+        assert not p.should_update_index({}, {})
         old = {'num_views': 1}
         new = {'num_views': 2}
-        assert_false(p.should_update_index(old, new))
+        assert not p.should_update_index(old, new)
         old = {'num_views': 1, 'a': 1}
         new = {'num_views': 2, 'a': 1}
-        assert_false(p.should_update_index(old, new))
+        assert not p.should_update_index(old, new)
         old = {'num_views': 1, 'a': 1}
         new = {'num_views': 2, 'a': 2}
-        assert_true(p.should_update_index(old, new))
+        assert p.should_update_index(old, new)
diff --git a/Allura/allura/tests/unit/test_helpers/test_ago.py b/Allura/allura/tests/unit/test_helpers/test_ago.py
index 159d0c72d..2c3513109 100644
--- a/Allura/allura/tests/unit/test_helpers/test_ago.py
+++ b/Allura/allura/tests/unit/test_helpers/test_ago.py
@@ -99,7 +99,7 @@ class TestAgo:
         self.assertTimeSince('in 2 years', 2008, 6, 1, 0, 0, 0, show_date_after=None)
 
     def assertTimeSince(self, time_string, *time_components, **kwargs):
-        assert_equal(time_string, self.time_since(*time_components, **kwargs))
+        assert time_string == self.time_since(*time_components, **kwargs)
 
     def time_since(self, *time_components, **kwargs):
         end_time = datetime(*time_components)
diff --git a/Allura/allura/tests/unit/test_ldap_auth_provider.py b/Allura/allura/tests/unit/test_ldap_auth_provider.py
index e0633f597..021d2016a 100644
--- a/Allura/allura/tests/unit/test_ldap_auth_provider.py
+++ b/Allura/allura/tests/unit/test_ldap_auth_provider.py
@@ -46,10 +46,10 @@ class TestLdapAuthenticationProvider:
         # Note: OSX uses a crypt library with a known issue relating the hashing algorithms.
         if b'$6$rounds=' not in ep('pwd') and platform.system() == 'Darwin':
             raise SkipTest
-        assert_not_equal(ep('test_pass'), ep('test_pass'))
-        assert_equal(ep('test_pass', '0000'), ep('test_pass', '0000'))
+        assert ep('test_pass') != ep('test_pass')
+        assert ep('test_pass', '0000') == ep('test_pass', '0000')
         # Test password format
-        assert_true(ep('pwd').startswith(b'{CRYPT}$6$rounds=6000$'))
+        assert ep('pwd').startswith(b'{CRYPT}$6$rounds=6000$')
 
     @patch('allura.lib.plugin.ldap')
     def test_set_password(self, ldap):
@@ -65,7 +65,7 @@ class TestLdapAuthenticationProvider:
         connection.bind_s.called_once_with(dn, b'old-pass')
         connection.modify_s.assert_called_once_with(
             dn, [(ldap.MOD_REPLACE, 'userPassword', b'new-pass-hash')])
-        assert_equal(connection.unbind_s.call_count, 1)
+        assert connection.unbind_s.call_count == 1
 
     @patch('allura.lib.plugin.ldap')
     def test_login(self, ldap):
@@ -83,7 +83,7 @@ class TestLdapAuthenticationProvider:
         ldap.initialize.assert_called_once_with('ldaps://localhost/')
         connection = ldap.initialize.return_value
         connection.bind_s.called_once_with(dn, 'test-password')
-        assert_equal(connection.unbind_s.call_count, 1)
+        assert connection.unbind_s.call_count == 1
 
     @patch('allura.lib.plugin.ldap')
     def test_login_autoregister(self, ldap):
@@ -103,7 +103,7 @@ class TestLdapAuthenticationProvider:
 
         user = M.User.query.get(username=params['username'])
         assert user
-        assert_equal(user.display_name, 'åℒƒ')
+        assert user.display_name == 'åℒƒ'
 
     @patch('allura.lib.plugin.modlist')
     @patch('allura.lib.plugin.ldap')
@@ -116,11 +116,11 @@ class TestLdapAuthenticationProvider:
         ldap.dn.escape_dn_chars = lambda x: x
         self.provider._encode_password = Mock(return_value=b'new-password-hash')
 
-        assert_equal(M.User.query.get(username=user_doc['username']), None)
+        assert M.User.query.get(username=user_doc['username']) == None
         with h.push_config(config, **{'auth.ldap.autoregister': 'false'}):
             self.provider.register_user(user_doc)
         ThreadLocalORMSession.flush_all()
-        assert_not_equal(M.User.query.get(username=user_doc['username']), None)
+        assert M.User.query.get(username=user_doc['username']) != None
 
         dn = 'uid=%s,ou=people,dc=localdomain' % user_doc['username']
         ldap.initialize.assert_called_once_with('ldaps://localhost/')
@@ -129,7 +129,7 @@ class TestLdapAuthenticationProvider:
             'cn=admin,dc=localdomain',
             'admin-password')
         connection.add_s.assert_called_once_with(dn, modlist.addModlist.return_value)
-        assert_equal(connection.unbind_s.call_count, 1)
+        assert connection.unbind_s.call_count == 1
 
     @patch('allura.lib.plugin.ldap')
     @patch('allura.lib.plugin.datetime', autospec=True)
@@ -138,7 +138,7 @@ class TestLdapAuthenticationProvider:
         user.__ming__ = Mock()
         user.last_password_updated = None
         self.provider.set_password(user, None, 'new')
-        assert_equal(user.last_password_updated, dt_mock.utcnow.return_value)
+        assert user.last_password_updated == dt_mock.utcnow.return_value
 
     def test_get_last_password_updated_not_set(self):
         user = Mock()
@@ -148,10 +148,10 @@ class TestLdapAuthenticationProvider:
         upd = self.provider.get_last_password_updated(user)
         gen_time = datetime.utcfromtimestamp(
             calendar.timegm(user._id.generation_time.utctimetuple()))
-        assert_equal(upd, gen_time)
+        assert upd == gen_time
 
     def test_get_last_password_updated(self):
         user = Mock()
         user.last_password_updated = datetime(2014, 6, 4, 13, 13, 13)
         upd = self.provider.get_last_password_updated(user)
-        assert_equal(upd, user.last_password_updated)
+        assert upd == user.last_password_updated
diff --git a/Allura/allura/tests/unit/test_package_path_loader.py b/Allura/allura/tests/unit/test_package_path_loader.py
index c43118b6e..d00529918 100644
--- a/Allura/allura/tests/unit/test_package_path_loader.py
+++ b/Allura/allura/tests/unit/test_package_path_loader.py
@@ -43,19 +43,19 @@ class TestPackagePathLoader(TestCase):
 
         paths = PackagePathLoader()._load_paths()
 
-        assert_equal(paths, [
+        assert paths == [
             ['site-theme', None],
             ['ep0', 'path:eps.ep0'],
             ['ep1', 'path:eps.ep1'],
             ['ep2', 'path:eps.ep2'],
             ['allura', '/'],
-        ])
-        assert_equal(type(paths[0]), list)
-        assert_equal(resource_filename.call_args_list, [
+        ]
+        assert type(paths[0]) == list
+        assert resource_filename.call_args_list == [
             mock.call('eps.ep0', ''),
             mock.call('eps.ep1', ''),
             mock.call('eps.ep2', ''),
-        ])
+        ]
 
     @mock.patch('pkg_resources.iter_entry_points')
     def test_load_rules(self, iter_entry_points):
@@ -70,8 +70,8 @@ class TestPackagePathLoader(TestCase):
 
         order_rules, replacement_rules = PackagePathLoader()._load_rules()
 
-        assert_equal(order_rules, [('ep0', 'allura'), ('allura', 'ep2')])
-        assert_equal(replacement_rules, {'allura': 'ep1'})
+        assert order_rules == [('ep0', 'allura'), ('allura', 'ep2')]
+        assert replacement_rules == {'allura': 'ep1'}
 
         eps = iter_entry_points.return_value.__iter__.return_value = [
             mock.Mock(ep_name='ep0', rules=[('?', 'allura')]),
@@ -100,11 +100,11 @@ class TestPackagePathLoader(TestCase):
 
         ppl._replace_signposts(paths, rules)
 
-        assert_equal(paths, [
+        assert paths == [
             ['site-theme', '/ep1'],
             ['ep0', '/ep0'],
             ['allura', '/ep2'],
-        ])
+        ]
 
     def test_sort_paths(self):
         paths = [
@@ -125,14 +125,14 @@ class TestPackagePathLoader(TestCase):
 
         PackagePathLoader()._sort_paths(paths, rules)
 
-        assert_equal(paths, [
+        assert paths == [
             ['site-theme', None],
             ['ep2', '/ep2'],
             ['ep3', '/ep3'],
             ['ep1', '/ep1'],
             ['allura', '/'],
             ['ep0', '/ep0'],
-        ])
+        ]
 
     def test_init_paths(self):
         paths = [
@@ -153,7 +153,7 @@ class TestPackagePathLoader(TestCase):
         ppl._sort_paths.assert_called_once_with(paths, 'order_rules')
         ppl._replace_signposts.assert_called_once_with(paths, 'repl_rules')
 
-        assert_equal(output, ['/', '/tail'])
+        assert output == ['/', '/tail']
 
     @mock.patch('jinja2.FileSystemLoader')
     def test_fs_loader(self, FileSystemLoader):
@@ -166,7 +166,7 @@ class TestPackagePathLoader(TestCase):
 
         ppl.init_paths.assert_called_once_with()
         FileSystemLoader.assert_called_once_with(['path1', 'path2'])
-        assert_equal(output1, 'fs_loader')
+        assert output1 == 'fs_loader'
         assert output1 is output2
 
     @mock.patch.dict(config, {'disable_template_overrides': False})
@@ -179,7 +179,7 @@ class TestPackagePathLoader(TestCase):
         # override exists
         output = ppl.get_source('env', 'allura.ext.admin:templates/audit.html')
 
-        assert_equal(output, 'fs_load')
+        assert output == 'fs_load'
         fs_loader().get_source.assert_called_once_with(
             'env', 'override/allura/ext/admin/templates/audit.html')
 
@@ -195,8 +195,8 @@ class TestPackagePathLoader(TestCase):
             rf.assert_called_once_with(
                 'allura.ext.admin', 'templates/audit.html')
 
-        assert_equal(output, 'fs_load')
-        assert_equal(fs_loader().get_source.call_count, 2)
+        assert output == 'fs_load'
+        assert fs_loader().get_source.call_count == 2
         fs_loader().get_source.assert_called_with('env', 'resource')
 
         fs_loader().get_source.reset_mock()
@@ -206,8 +206,8 @@ class TestPackagePathLoader(TestCase):
         # no override, ':' not in template
         output = ppl.get_source('env', 'templates/audit.html')
 
-        assert_equal(output, 'fs_load')
-        assert_equal(fs_loader().get_source.call_count, 2)
+        assert output == 'fs_load'
+        assert fs_loader().get_source.call_count == 2
         fs_loader().get_source.assert_called_with(
             'env', 'templates/audit.html')
 
@@ -220,11 +220,11 @@ class TestPackagePathLoader(TestCase):
         assert_raises(
             jinja2.TemplateError,
             ppl.get_source, 'env', 'allura.ext.admin:templates/audit.html')
-        assert_equal(fs_loader().get_source.call_count, 1)
+        assert fs_loader().get_source.call_count == 1
         fs_loader().get_source.reset_mock()
 
         with mock.patch.dict(config, {'disable_template_overrides': False}):
             assert_raises(
                 jinja2.TemplateError,
                 ppl.get_source, 'env', 'allura.ext.admin:templates/audit.html')
-            assert_equal(fs_loader().get_source.call_count, 2)
+            assert fs_loader().get_source.call_count == 2
diff --git a/Allura/allura/tests/unit/test_repo.py b/Allura/allura/tests/unit/test_repo.py
index 648c330c7..15258ee5f 100644
--- a/Allura/allura/tests/unit/test_repo.py
+++ b/Allura/allura/tests/unit/test_repo.py
@@ -106,40 +106,40 @@ class TestBlob(unittest.TestCase):
 
     def test_pypeline_view(self):
         blob = M.repository.Blob(MagicMock(), 'INSTALL.mdown', 'blob1')
-        assert_equal(blob.has_pypeline_view, True)
+        assert blob.has_pypeline_view == True
 
     def test_has_html_view_text_mime(self):
         blob = M.repository.Blob(MagicMock(), 'INSTALL', 'blob1')
         blob.content_type = 'text/plain'
-        assert_equal(blob.has_html_view, True)
+        assert blob.has_html_view == True
 
     def test_has_html_view_text_ext(self):
         blob = M.repository.Blob(MagicMock(), 'INSTALL.txt', 'blob1')
         blob.content_type = 'foo/bar'
-        assert_equal(blob.has_html_view, True)
+        assert blob.has_html_view == True
 
     def test_has_html_view_text_contents(self):
         blob = M.repository.Blob(MagicMock(), 'INSTALL', 'blob1')
         blob.content_type = 'foo/bar'
         blob.text = b'hello world, this is text here'
-        assert_equal(blob.has_html_view, True)
+        assert blob.has_html_view == True
 
     def test_has_html_view_bin_ext(self):
         blob = M.repository.Blob(MagicMock(), 'INSTALL.zip', 'blob1')
-        assert_equal(blob.has_html_view, False)
+        assert blob.has_html_view == False
 
     def test_has_html_view_bin_content(self):
         blob = M.repository.Blob(MagicMock(), 'myfile', 'blob1')
         blob.content_type = 'whatever'
         blob.text = b'\0\0\0\0'
-        assert_equal(blob.has_html_view, False)
+        assert blob.has_html_view == False
 
     def test_has_html_view__local_setting_override_bin(self):
         blob = M.repository.Blob(MagicMock(), 'myfile.dat', 'blob1')
         blob.content_type = 'whatever'
         blob.text = b'\0\0\0\0'
         blob.repo._additional_viewable_extensions = ['.dat']
-        assert_equal(blob.has_html_view, True)
+        assert blob.has_html_view == True
 
 
 class TestCommit(unittest.TestCase):
@@ -169,19 +169,19 @@ class TestCommit(unittest.TestCase):
         tree = commit.get_tree(create=False)
         assert not commit.repo.compute_tree_new.called
         assert not c.model_cache.get.called
-        assert_equal(tree, None)
+        assert tree == None
 
         commit.tree_id = 'tree'
         tree = commit.get_tree(create=False)
         assert not commit.repo.compute_tree_new.called
         c.model_cache.get.assert_called_with(M.repository.Tree, dict(_id='tree'))
-        assert_equal(tree, None)
+        assert tree == None
 
         _tree = Mock()
         c.model_cache.get.return_value = _tree
         tree = commit.get_tree(create=False)
         _tree.set_context.assert_called_with(commit)
-        assert_equal(tree, _tree)
+        assert tree == _tree
 
     @patch.object(M.repository.Tree.query, 'get')
     def test_get_tree_create(self, tree_get):
@@ -196,7 +196,7 @@ class TestCommit(unittest.TestCase):
         commit.repo.compute_tree_new.assert_called_once_with(commit)
         assert not c.model_cache.get.called
         assert not tree_get.called
-        assert_equal(tree, None)
+        assert tree == None
 
         commit.repo.compute_tree_new.reset_mock()
         commit.repo.compute_tree_new.return_value = 'tree'
@@ -208,7 +208,7 @@ class TestCommit(unittest.TestCase):
         c.model_cache.get.assert_called_once_with(
             M.repository.Tree, dict(_id='tree'))
         _tree.set_context.assert_called_once_with(commit)
-        assert_equal(tree, _tree)
+        assert tree == _tree
 
         commit.repo.compute_tree_new.reset_mock()
         c.model_cache.get.reset_mock()
@@ -219,7 +219,7 @@ class TestCommit(unittest.TestCase):
         c.model_cache.get.assert_called_once_with(
             M.repository.Tree, dict(_id='tree2'))
         _tree.set_context.assert_called_once_with(commit)
-        assert_equal(tree, _tree)
+        assert tree == _tree
 
         commit.repo.compute_tree_new.reset_mock()
         c.model_cache.get.reset_mock()
@@ -229,12 +229,12 @@ class TestCommit(unittest.TestCase):
         c.model_cache.get.assert_called_once_with(
             M.repository.Tree, dict(_id='tree2'))
         commit.repo.compute_tree_new.assert_called_once_with(commit)
-        assert_equal(commit.tree_id, 'tree')
+        assert commit.tree_id == 'tree'
         tree_get.assert_called_once_with(_id='tree')
         c.model_cache.set.assert_called_once_with(
             M.repository.Tree, dict(_id='tree'), _tree)
         _tree.set_context.assert_called_once_with(commit)
-        assert_equal(tree, _tree)
+        assert tree == _tree
 
     def test_tree_create(self):
         commit = M.repository.Commit()
diff --git a/Allura/allura/tests/unit/test_solr.py b/Allura/allura/tests/unit/test_solr.py
index 5ef3492c8..8647aecef 100644
--- a/Allura/allura/tests/unit/test_solr.py
+++ b/Allura/allura/tests/unit/test_solr.py
@@ -36,14 +36,14 @@ class TestSolr(unittest.TestCase):
         solr = Solr(servers, commit=False, commitWithin='10000')
         calls = [mock.call('server1'), mock.call('server2')]
         pysolr.Solr.assert_has_calls(calls)
-        assert_equal(len(solr.push_pool), 2)
+        assert len(solr.push_pool) == 2
 
         pysolr.reset_mock()
         solr = Solr(servers, 'server3', commit=False, commitWithin='10000')
         calls = [mock.call('server1'), mock.call('server2'),
                  mock.call('server3')]
         pysolr.Solr.assert_has_calls(calls)
-        assert_equal(len(solr.push_pool), 2)
+        assert len(solr.push_pool) == 2
 
     @mock.patch('allura.lib.solr.pysolr')
     def test_add(self, pysolr):
@@ -124,21 +124,21 @@ class TestSearchIndexable(unittest.TestCase):
 
     def test_solarize_empty_index(self):
         self.obj.index = lambda: None
-        assert_equal(self.obj.solarize(), None)
+        assert self.obj.solarize() == None
 
     def test_solarize_doc_without_text(self):
         self.obj.index = lambda: dict()
-        assert_equal(self.obj.solarize(), dict(text=''))
+        assert self.obj.solarize() == dict(text='')
 
     def test_solarize_strips_markdown(self):
         self.obj.index = lambda: dict(text='# Header')
-        assert_equal(self.obj.solarize(), dict(text='Header'))
+        assert self.obj.solarize() == dict(text='Header')
 
     def test_solarize_html_in_text(self):
         self.obj.index = lambda: dict(text='<script>a(1)</script>')
-        assert_equal(self.obj.solarize(), dict(text='<script>a(1)</script>'))
+        assert self.obj.solarize() == dict(text='<script>a(1)</script>')
         self.obj.index = lambda: dict(text='&lt;script&gt;a(1)&lt;/script&gt;')
-        assert_equal(self.obj.solarize(), dict(text='<script>a(1)</script>'))
+        assert self.obj.solarize() == dict(text='<script>a(1)</script>')
 
 
 class TestSearch_app(unittest.TestCase):
@@ -156,7 +156,7 @@ class TestSearch_app(unittest.TestCase):
         url_fn.side_effect = ['the-score-url', 'the-date-url']
         with h.push_context('test', 'wiki', neighborhood='Projects'):
             resp = search_app(q='foo bar')
-        assert_equal(resp, dict(
+        assert resp == dict(
             q='foo bar',
             history=None,
             results=[],
@@ -167,7 +167,7 @@ class TestSearch_app(unittest.TestCase):
             sort_score_url='the-score-url',
             sort_date_url='the-date-url',
             sort_field='score',
-        ))
+        )
 
     @td.with_wiki
     @mock.patch('allura.lib.search.g.solr.search')
@@ -196,7 +196,7 @@ class TestSearch_app(unittest.TestCase):
         with h.push_context('test', 'wiki', neighborhood='Projects'):
             resp = search_app(q='foo bar')
 
-        assert_equal(resp, dict(
+        assert resp == dict(
             q='foo bar',
             history=None,
             count=2,
@@ -224,14 +224,14 @@ class TestSearch_app(unittest.TestCase):
                 'text_match': Markup('less scary but still dangerous &amp;lt;script&amp;gt;alert(1)&amp;lt;/script&amp;gt; blah <strong>bar</strong> foo foo'),
                 '_artifact': None,
             }]
-        ))
+        )
 
     def test_escape_solr_arg(self):
         text = 'some: weird "text" with symbols'
         escaped_text = escape_solr_arg(text)
-        assert_equal(escaped_text, r'some\: weird \"text\" with symbols')
+        assert escaped_text == r'some\: weird \"text\" with symbols'
 
     def test_escape_solr_arg_with_backslash(self):
         text = 'some: weird "text" with \\ backslash'
         escaped_text = escape_solr_arg(text)
-        assert_equal(escaped_text, r'some\: weird \"text\" with \\ backslash')
+        assert escaped_text == r'some\: weird \"text\" with \\ backslash'
diff --git a/requirements.in b/requirements.in
index 2d938e146..8f71e00ca 100644
--- a/requirements.in
+++ b/requirements.in
@@ -55,6 +55,7 @@ pyflakes
 #pylint -- disabled due to [#8346]  (also requires diff versions on py2 vs 3, including transitive deps which gets tricky with pip-compile)
 testfixtures
 WebTest
+pytest
 
 # deployment
 gunicorn
diff --git a/requirements.txt b/requirements.txt
index 840326b53..b0cffa15b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,6 +6,8 @@
 #
 activitystream==0.4.0
     # via -r requirements.in
+attrs==22.1.0
+    # via pytest
 beaker==1.11.0
     # via -r requirements.in
 beautifulsoup4==4.11.1
@@ -64,9 +66,14 @@ html5lib==1.1
 idna==3.3
     # via requests
 importlib-metadata==4.12.0
-    # via markdown
+    # via
+    #   markdown
+    #   pluggy
+    #   pytest
 inflection==0.5.1
     # via profanityfilter
+iniconfig==1.1.1
+    # via pytest
 iso8601==1.0.2
     # via colander
 jinja2==3.1.2
@@ -93,6 +100,8 @@ oauthlib==3.2.1
     # via
     #   -r requirements.in
     #   requests-oauthlib
+packaging==21.3
+    # via pytest
 paginate==0.5.6
     # via -r requirements.in
 paste==3.5.1
@@ -108,8 +117,12 @@ pastescript==3.2.1
     # via -r requirements.in
 pillow==9.2.0
     # via -r requirements.in
+pluggy==1.0.0
+    # via pytest
 profanityfilter==2.0.6
     # via -r requirements.in
+py==1.11.0
+    # via pytest
 pycparser==2.21
     # via cffi
 pyflakes==2.4.0
@@ -121,10 +134,15 @@ pymongo==3.11.4
     #   -r requirements.in
     #   activitystream
     #   ming
+pyparsing==2.4.7
+    # via
+    #   packaging
 pypeline[creole,markdown,rst,textile]==0.6.0
     # via -r requirements.in
 pysolr==3.9.0
     # via -r requirements.in
+pytest==7.1.3
+    # via -r requirements.in
 python-dateutil==2.8.2
     # via
     #   -r requirements.in
@@ -184,6 +202,8 @@ timermiddleware==0.6.2
     # via -r requirements.in
 tinycss2==1.1.1
     # via bleach
+tomli==2.0.1
+    # via pytest
 translationstring==1.4
     # via colander
 turbogears2==2.3.12