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

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

commit 7b3ac92adea10730d40271f8119f4fb0ed95778e
Author: Kenton Taylor <[email protected]>
AuthorDate: Tue Oct 29 18:05:23 2024 +0000

    py312 prep - Conversion of remaining unitest-style assertions
---
 Allura/allura/tests/model/test_filesystem.py       |   3 +-
 Allura/allura/tests/model/test_notification.py     |   8 +-
 Allura/allura/tests/model/test_repo.py             |   6 +-
 Allura/allura/tests/test_decorators.py             |   3 +-
 Allura/allura/tests/test_globals.py                |  28 +++---
 Allura/allura/tests/test_helpers.py                |   8 +-
 Allura/allura/tests/test_mail_util.py              |   2 +-
 Allura/allura/tests/test_scripttask.py             |   2 +-
 Allura/allura/tests/test_utils.py                  |  18 ++--
 Allura/allura/tests/test_validators.py             | 102 ++++++++++-----------
 Allura/allura/tests/unit/spam/test_spam_filter.py  |   2 +-
 Allura/allura/tests/unit/test_app.py               |  17 ++++
 Allura/allura/tests/unit/test_artifact.py          |   2 +-
 .../allura/tests/unit/test_package_path_loader.py  |   3 +-
 Allura/allura/tests/unit/test_project.py           |   4 +-
 Allura/allura/tests/unit/test_repo.py              |  17 ++--
 Allura/allura/tests/unit/test_session.py           |   5 +-
 Allura/allura/tests/unit/test_sitemapentry.py      |   6 +-
 Allura/allura/tests/unit/test_solr.py              |   6 +-
 AlluraTest/alluratest/tools.py                     |   4 +-
 ForgeGit/forgegit/tests/model/test_repository.py   |  17 ++--
 ForgeGit/forgegit/tests/test_git_app.py            |   2 +-
 ForgeGit/forgegit/tests/test_tasks.py              |   2 +-
 .../forgeimporters/github/tests/test_code.py       |  13 ++-
 .../forgeimporters/github/tests/test_oauth.py      |   3 +-
 .../forgeimporters/github/tests/test_tracker.py    |  11 +--
 .../forgeimporters/github/tests/test_wiki.py       |  19 ++--
 .../forgeimporters/tests/forge/test_discussion.py  |  11 +--
 .../forgeimporters/tests/forge/test_tracker.py     |  13 ++-
 .../tests/github/functional/test_github.py         |   3 +-
 .../forgeimporters/tests/github/test_extractor.py  |  64 ++++++-------
 .../forgeimporters/tests/github/test_tracker.py    |   5 +-
 ForgeImporters/forgeimporters/tests/test_base.py   |  25 +++--
 .../forgeimporters/trac/tests/test_tickets.py      |  16 ++--
 ForgeSVN/forgesvn/tests/model/test_repository.py   |  10 +-
 ForgeSVN/forgesvn/tests/test_svn_app.py            |   2 +-
 ForgeSVN/forgesvn/tests/test_tasks.py              |   2 +-
 .../tests/unit/test_root_controller.py             |   2 +-
 ForgeUserStats/forgeuserstats/tests/test_model.py  |   2 +-
 ForgeUserStats/forgeuserstats/tests/test_stats.py  |   2 +-
 pytest.ini                                         |   1 +
 41 files changed, 239 insertions(+), 232 deletions(-)

diff --git a/Allura/allura/tests/model/test_filesystem.py 
b/Allura/allura/tests/model/test_filesystem.py
index 3b2e54db1..60cd96aed 100644
--- a/Allura/allura/tests/model/test_filesystem.py
+++ b/Allura/allura/tests/model/test_filesystem.py
@@ -16,7 +16,6 @@
 #       under the License.
 
 import os
-from unittest import TestCase
 from io import BytesIO
 
 import ming
@@ -36,7 +35,7 @@ class File(M.File):
 Mapper.compile_all()
 
 
-class TestFile(TestCase):
+class TestFile:
 
     def setup_method(self, method):
         config = {
diff --git a/Allura/allura/tests/model/test_notification.py 
b/Allura/allura/tests/model/test_notification.py
index 557151de3..ba502823e 100644
--- a/Allura/allura/tests/model/test_notification.py
+++ b/Allura/allura/tests/model/test_notification.py
@@ -33,7 +33,7 @@ from allura.tests import decorators as td
 from forgewiki import model as WM
 
 
-class TestNotification(unittest.TestCase):
+class TestNotification:
 
     def setup_method(self, method):
         setup_basic_test()
@@ -164,7 +164,7 @@ class TestNotification(unittest.TestCase):
         )
 
 
-class TestPostNotifications(unittest.TestCase):
+class TestPostNotifications:
 
     def setup_method(self, method):
         setup_basic_test()
@@ -294,7 +294,7 @@ class TestPostNotifications(unittest.TestCase):
         return M.Notification.post(self.pg, 'metadata')
 
 
-class TestSubscriptionTypes(unittest.TestCase):
+class TestSubscriptionTypes:
 
     def setup_method(self, method):
         setup_basic_test()
@@ -468,7 +468,7 @@ class TestSubscriptionTypes(unittest.TestCase):
         assert count == 1
 
 
-class TestSiteNotification(unittest.TestCase):
+class TestSiteNotification:
     def setup_method(self, method):
         self.note = M.SiteNotification(
             active=True,
diff --git a/Allura/allura/tests/model/test_repo.py 
b/Allura/allura/tests/model/test_repo.py
index c9b872ae1..f1f57af8f 100644
--- a/Allura/allura/tests/model/test_repo.py
+++ b/Allura/allura/tests/model/test_repo.py
@@ -71,7 +71,7 @@ class RepoImplTestBase:
     pass
 
 
-class RepoTestBase(unittest.TestCase):
+class RepoTestBase:
     def setup_method(self, method):
         setup_basic_test()
 
@@ -128,7 +128,7 @@ class RepoTestBase(unittest.TestCase):
         ]
 
 
-class TestLastCommit(unittest.TestCase):
+class TestLastCommit:
     def setup_method(self, method):
         setup_basic_test()
         setup_global_objects()
@@ -400,7 +400,7 @@ class TestLastCommit(unittest.TestCase):
         assert lcd.by_name['file2'] == commit3._id
 
 
-class TestModelCache(unittest.TestCase):
+class TestModelCache:
     def setup_method(self, method):
         self.cache = M.repository.ModelCache()
 
diff --git a/Allura/allura/tests/test_decorators.py 
b/Allura/allura/tests/test_decorators.py
index fb700ba63..607833303 100644
--- a/Allura/allura/tests/test_decorators.py
+++ b/Allura/allura/tests/test_decorators.py
@@ -15,7 +15,6 @@
 #       specific language governing permissions and limitations
 #       under the License.
 import inspect
-from unittest import TestCase
 from mock import patch
 import random
 import gc
@@ -24,7 +23,7 @@ from allura.lib.decorators import task, memoize
 from alluratest.controller import setup_basic_test, setup_global_objects
 
 
-class TestTask(TestCase):
+class TestTask:
 
     def setup_method(self, method):
         setup_basic_test()
diff --git a/Allura/allura/tests/test_globals.py 
b/Allura/allura/tests/test_globals.py
index d139b1887..e8f349a73 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -762,7 +762,7 @@ class Test():
             assert 'src="/p/test/screenshot/test_file.jpg/thumb"' in r
 
 
-class TestCachedMarkdown(unittest.TestCase):
+class TestCachedMarkdown:
 
     def setup_method(self, method):
         setup()
@@ -815,7 +815,7 @@ class TestCachedMarkdown(unittest.TestCase):
         with patch.object(self.md, 'convert') as convert_func:
             html = self.md.cached_convert(self.post, 'text')
             assert html == self.expected_html
-            self.assertIsInstance(html, Markup)
+            assert isinstance(html, Markup)
             assert not convert_func.called
             self.post.text = "text [[include]] pass"
             html = self.md.cached_convert(self.post, 'text')
@@ -851,25 +851,25 @@ class TestCachedMarkdown(unittest.TestCase):
     def test_no_threshold_defined(self):
         html = self.md.cached_convert(self.post, 'text')
         assert html == self.expected_html
-        self.assertIsNone(self.post.text_cache.md5)
-        self.assertIsNone(self.post.text_cache.html)
-        self.assertIsNone(self.post.text_cache.render_time)
+        assert self.post.text_cache.md5 is None
+        assert self.post.text_cache.html is None
+        assert self.post.text_cache.render_time is None
 
     @patch.dict('allura.lib.app_globals.config', 
markdown_cache_threshold='foo')
     def test_invalid_threshold(self):
         html = self.md.cached_convert(self.post, 'text')
         assert html == self.expected_html
-        self.assertIsNone(self.post.text_cache.md5)
-        self.assertIsNone(self.post.text_cache.html)
-        self.assertIsNone(self.post.text_cache.render_time)
+        assert self.post.text_cache.md5 is None
+        assert self.post.text_cache.html is None
+        assert self.post.text_cache.render_time is None
 
     @patch.dict('allura.lib.app_globals.config', 
markdown_cache_threshold='99999')
     def test_render_time_below_threshold(self):
         html = self.md.cached_convert(self.post, 'text')
         assert html == self.expected_html
-        self.assertIsNone(self.post.text_cache.md5)
-        self.assertIsNone(self.post.text_cache.html)
-        self.assertIsNone(self.post.text_cache.render_time)
+        assert self.post.text_cache.md5 is None
+        assert self.post.text_cache.html is None
+        assert self.post.text_cache.render_time is None
 
     @patch.dict('allura.lib.app_globals.config', {})
     def test_all_expected_keys_exist_in_cache(self):
@@ -879,7 +879,7 @@ class TestCachedMarkdown(unittest.TestCase):
         assert required_keys == keys
 
 
-class TestEmojis(unittest.TestCase):
+class TestEmojis:
 
     def test_markdown_emoji_atomic(self):
         output = g.markdown.convert(':smile:')
@@ -914,7 +914,7 @@ class TestEmojis(unittest.TestCase):
         assert 'More emojis \U0001F44D\U0001F42B\U0001F552 wow!' in output
 
 
-class TestUserMentions(unittest.TestCase):
+class TestUserMentions:
 
     def test_markdown_user_mention_default(self):
         output = g.markdown.convert('Hello.. @nouser1, how are you?')
@@ -955,7 +955,7 @@ class TestUserMentions(unittest.TestCase):
         assert 'class="user-mention"' in output
 
 
-class TestHandlePaging(unittest.TestCase):
+class TestHandlePaging:
 
     def setup_method(self, method):
         prefs = {}
diff --git a/Allura/allura/tests/test_helpers.py 
b/Allura/allura/tests/test_helpers.py
index 07049ef6b..050de3239 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -16,7 +16,7 @@
 #       under the License.
 
 import io
-from unittest import TestCase, skipIf
+from unittest import  skipIf
 from os import path
 from datetime import datetime, timedelta
 import time
@@ -52,7 +52,7 @@ def setup_module():
     setup_basic_test()
 
 
-class TestMakeSafePathPortion(TestCase):
+class TestMakeSafePathPortion:
 
     def setup_method(self, method):
         self.f = h.make_safe_path_portion
@@ -580,7 +580,7 @@ def test_login_overlay():
         raise HTTPUnauthorized()
 
 
-class TestIterEntryPoints(TestCase):
+class TestIterEntryPoints:
 
     def _make_ep(self, name, cls):
         m = Mock()
@@ -683,7 +683,7 @@ def test_slugify():
     assert h.slugify('Foo.Bar', True)[0] == 'Foo.Bar'
 
 
-class TestRateLimit(TestCase):
+class TestRateLimit:
     rate_limits = '{"60": 1, "120": 3, "900": 5, "1800": 7, "3600": 10, 
"7200": 15, "86400": 20, "604800": 50, "2592000": 200}'
     key_comment = 'allura.rate_limits_per_user'
 
diff --git a/Allura/allura/tests/test_mail_util.py 
b/Allura/allura/tests/test_mail_util.py
index f5d1705be..f32b07387 100644
--- a/Allura/allura/tests/test_mail_util.py
+++ b/Allura/allura/tests/test_mail_util.py
@@ -46,7 +46,7 @@ config = ConfigProxy(
     return_path='forgemail.return_path')
 
 
-class TestReactor(unittest.TestCase):
+class TestReactor:
 
     def setup_method(self, method):
         setup_basic_test()
diff --git a/Allura/allura/tests/test_scripttask.py 
b/Allura/allura/tests/test_scripttask.py
index 9992498a5..edbfda5cf 100644
--- a/Allura/allura/tests/test_scripttask.py
+++ b/Allura/allura/tests/test_scripttask.py
@@ -21,7 +21,7 @@ import mock
 from allura.scripts.scripttask import ScriptTask
 
 
-class TestScriptTask(unittest.TestCase):
+class TestScriptTask:
 
     def setup_method(self, method):
         class TestScriptTask(ScriptTask):
diff --git a/Allura/allura/tests/test_utils.py 
b/Allura/allura/tests/test_utils.py
index 4497f9c3c..8878ea21a 100644
--- a/Allura/allura/tests/test_utils.py
+++ b/Allura/allura/tests/test_utils.py
@@ -42,7 +42,7 @@ from allura.lib import helpers as h
 
 
 @patch.dict('allura.lib.utils.tg.config', clear=True, foo='bar', baz='true')
-class TestConfigProxy(unittest.TestCase):
+class TestConfigProxy:
 
     def setup_method(self, method):
         self.cp = utils.ConfigProxy(mybaz="baz")
@@ -62,7 +62,7 @@ class TestConfigProxy(unittest.TestCase):
         assert self.cp.get_bool("fake") is False
 
 
-class TestChunkedIterator(unittest.TestCase):
+class TestChunkedIterator:
 
     def setup_method(self, method):
         setup_unit_test()
@@ -93,7 +93,7 @@ class TestChunkedIterator(unittest.TestCase):
         assert chunks[1][0].username == 'sample-user-3'
 
 
-class TestChunkedList(unittest.TestCase):
+class TestChunkedList:
 
     def test_chunked_list(self):
         l = list(range(10))
@@ -103,7 +103,7 @@ class TestChunkedList(unittest.TestCase):
         assert [el for sublist in chunks for el in sublist] == l
 
 
-class TestAntispam(unittest.TestCase):
+class TestAntispam:
 
     def setup_method(self, method):
         setup_unit_test()
@@ -168,7 +168,7 @@ class TestAntispam(unittest.TestCase):
         return encrypted_form
 
 
-class TestCaseInsensitiveDict(unittest.TestCase):
+class TestCaseInsensitiveDict:
 
     def test_everything(self):
         d = utils.CaseInsensitiveDict(Foo=5)
@@ -187,7 +187,7 @@ class TestCaseInsensitiveDict(unittest.TestCase):
         assert d == utils.CaseInsensitiveDict(Foo=1, bar=2)
 
 
-class TestLineAnchorCodeHtmlFormatter(unittest.TestCase):
+class TestLineAnchorCodeHtmlFormatter:
 
     def test_render(self):
         code = '#!/usr/bin/env python\n'\
@@ -207,7 +207,7 @@ class TestLineAnchorCodeHtmlFormatter(unittest.TestCase):
             assert '<span class="linenos">1</span>' in hl_code
 
 
-class TestIsTextFile(unittest.TestCase):
+class TestIsTextFile:
 
     def test_is_text_file(self):
         here_dir = path.dirname(__file__)
@@ -217,7 +217,7 @@ class TestIsTextFile(unittest.TestCase):
         assert not utils.is_text_file(open(bin_file, 'rb').read())
 
 
-class TestCodeStats(unittest.TestCase):
+class TestCodeStats:
 
     def setup_method(self, method):
         setup_unit_test()
@@ -241,7 +241,7 @@ class TestCodeStats(unittest.TestCase):
         assert stats['code_size'] == len(blob.text)
 
 
-class TestHTMLSanitizer(unittest.TestCase):
+class TestHTMLSanitizer:
 
     def walker_from_text(self, text):
         parsed = html5lib.parseFragment(text)
diff --git a/Allura/allura/tests/test_validators.py 
b/Allura/allura/tests/test_validators.py
index cf9bca102..d4ca3031b 100644
--- a/Allura/allura/tests/test_validators.py
+++ b/Allura/allura/tests/test_validators.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-import unittest
+import pytest
 import formencode as fe
 from mock import Mock, patch
 
@@ -35,7 +35,7 @@ def dummy_task(*args, **kw):
     pass
 
 
-class TestJsonConverter(unittest.TestCase):
+class TestJsonConverter:
     val = v.JsonConverter
 
     def setup_method(self, method):
@@ -45,13 +45,13 @@ class TestJsonConverter(unittest.TestCase):
         assert {} == self.val.to_python('{}')
 
     def test_invalid(self):
-        with self.assertRaises(fe.Invalid):
+        with pytest.raises(fe.Invalid):
             self.val.to_python('{')
-        with self.assertRaises(fe.Invalid):
+        with pytest.raises(fe.Invalid):
             self.val.to_python('3')
 
 
-class TestJsonFile(unittest.TestCase):
+class TestJsonFile:
 
     def setup_method(self, method):
         _setup_method()
@@ -67,11 +67,11 @@ class TestJsonFile(unittest.TestCase):
         assert {} == self.val.to_python(self.FieldStorage('{}'))
 
     def test_invalid(self):
-        with self.assertRaises(fe.Invalid):
+        with pytest.raises(fe.Invalid):
             self.val.to_python(self.FieldStorage('{'))
 
 
-class TestUserMapFile(unittest.TestCase):
+class TestUserMapFile:
     val = v.UserMapJsonFile()
 
     def setup_method(self, method):
@@ -87,7 +87,7 @@ class TestUserMapFile(unittest.TestCase):
             self.FieldStorage('{"user_old": "user_new"}'))
 
     def test_invalid(self):
-        with self.assertRaises(fe.Invalid):
+        with pytest.raises(fe.Invalid):
             self.val.to_python(self.FieldStorage('{"user_old": 1}'))
 
     def test_as_string(self):
@@ -96,7 +96,7 @@ class TestUserMapFile(unittest.TestCase):
             self.FieldStorage('{"user_old": "user_new"}'))
 
 
-class TestUserValidator(unittest.TestCase):
+class TestUserValidator:
     val = v.UserValidator
 
     def setup_method(self, method):
@@ -106,12 +106,12 @@ class TestUserValidator(unittest.TestCase):
         assert M.User.by_username('root') == self.val.to_python('root')
 
     def test_invalid(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('fakeuser')
-        assert str(cm.exception) == "Invalid username"
+        assert str(cm.value) == "Invalid username"
 
 
-class TestAnonymousValidator(unittest.TestCase):
+class TestAnonymousValidator:
     val = v.AnonymousValidator
 
     def setup_method(self, method):
@@ -125,12 +125,12 @@ class TestAnonymousValidator(unittest.TestCase):
     @patch('allura.lib.validators.c')
     def test_invalid(self, c):
         c.user = M.User.anonymous()
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python(True)
-        assert str(cm.exception) ==  "Log in to Mark as Private"
+        assert str(cm.value) ==  "Log in to Mark as Private"
 
 
-class TestMountPointValidator(unittest.TestCase):
+class TestMountPointValidator:
 
     def setup_method(self, method):
         _setup_method()
@@ -151,7 +151,7 @@ class TestMountPointValidator(unittest.TestCase):
         App.validate_mount_point.return_value = False
         c.project.app_instance.return_value = False
         val = v.MountPointValidator(App)
-        with self.assertRaises(fe.Invalid):
+        with pytest.raises(fe.Invalid):
             val.to_python('mymount')
 
     @patch('allura.lib.validators.c')
@@ -170,7 +170,7 @@ class TestMountPointValidator(unittest.TestCase):
         App.validate_mount_point.return_value = True
         c.project.app_instance.return_value = True
         val = v.MountPointValidator(App)
-        with self.assertRaises(fe.Invalid):
+        with pytest.raises(fe.Invalid):
             val.to_python('mymount')
 
     @patch('allura.lib.validators.c')
@@ -180,7 +180,7 @@ class TestMountPointValidator(unittest.TestCase):
         App.validate_mount_point.return_value = True
         c.project.app_instance.return_value = False
         val = v.MountPointValidator(App)
-        with self.assertRaises(fe.Invalid):
+        with pytest.raises(fe.Invalid):
             val.to_python('feed')
 
     @patch('allura.lib.validators.c')
@@ -193,7 +193,7 @@ class TestMountPointValidator(unittest.TestCase):
         assert 'wiki-0' == val.to_python(None)
 
 
-class TestTaskValidator(unittest.TestCase):
+class TestTaskValidator:
     val = v.TaskValidator
 
     def setup_method(self, method):
@@ -203,27 +203,27 @@ class TestTaskValidator(unittest.TestCase):
         assert dummy_task == 
self.val.to_python('allura.tests.test_validators.dummy_task')
 
     def test_invalid_name(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('badname')
-        assert str(cm.exception).startswith('Invalid task name')
+        assert str(cm.value).startswith('Invalid task name')
 
     def test_import_failure(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('allura.does.not.exist')
-        assert str(cm.exception) =='Could not import "allura.does.not.exist"'
+        assert str(cm.value) =='Could not import "allura.does.not.exist"'
 
     def test_attr_lookup_failure(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('allura.tests.test_validators.typo')
-        assert str(cm.exception) == 'Module has no attribute "typo"'
+        assert str(cm.value) == 'Module has no attribute "typo"'
 
     def test_not_a_task(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('allura.tests.test_validators._setup_method')
-        assert str(cm.exception) == 
'"allura.tests.test_validators._setup_method" is not a task.'
+        assert str(cm.value) == '"allura.tests.test_validators._setup_method" 
is not a task.'
 
 
-class TestPathValidator(unittest.TestCase):
+class TestPathValidator:
     val = v.PathValidator(strip=True, if_missing={}, if_empty={})
 
     def setup_method(self, method):
@@ -250,31 +250,31 @@ class TestPathValidator(unittest.TestCase):
         assert d['app'].config._id == app.config._id
 
     def test_invalid_format(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('test')
-        assert str(cm.exception).startswith(
+        assert str(cm.value).startswith(
             'You must specify at least a neighborhood and project')
 
     def test_invalid_neighborhood(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('/q/test')
-        assert str(cm.exception) == 'Invalid neighborhood: /q/'
+        assert str(cm.value) == 'Invalid neighborhood: /q/'
 
     def test_invalid_project(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('/p/badproject')
-        assert str(cm.exception) == 'Invalid project: badproject'
+        assert str(cm.value) == 'Invalid project: badproject'
 
     def test_invalid_app_mount_point(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('/p/test/badapp')
-        assert str(cm.exception) == 'Invalid app mount point: badapp'
+        assert str(cm.value) == 'Invalid app mount point: badapp'
 
     def test_no_input(self):
         assert {} == self.val.to_python('')
 
 
-class TestUrlValidator(unittest.TestCase):
+class TestUrlValidator:
     val = v.URL
 
     def setup_method(self, method):
@@ -285,17 +285,17 @@ class TestUrlValidator(unittest.TestCase):
         assert 'http://url' == self.val.to_python('url')
 
     def test_invalid_ip(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('192.168.0')
-        assert str(cm.exception) == 'That is not a valid URL'
+        assert str(cm.value) == 'That is not a valid URL'
 
     def test_invalid_url(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('u"rl')
-        assert str(cm.exception) == 'That is not a valid URL'
+        assert str(cm.value) == 'That is not a valid URL'
 
 
-class TestNonHttpUrlValidator(unittest.TestCase):
+class TestNonHttpUrlValidator:
     val = v.NonHttpUrl
 
     def setup_method(self, method):
@@ -306,17 +306,17 @@ class TestNonHttpUrlValidator(unittest.TestCase):
         assert 'ssh+git://url' == self.val.to_python('ssh+git://url')
 
     def test_invalid(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('http://u"rl')
-        assert str(cm.exception) == 'That is not a valid URL'
+        assert str(cm.value) == 'That is not a valid URL'
 
     def test_no_scheme(self):
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python('url')
-        assert str(cm.exception) == 'You must start your URL with a scheme'
+        assert str(cm.value) == 'You must start your URL with a scheme'
 
 
-class TestIconValidator(unittest.TestCase):
+class TestIconValidator:
     val = v.IconValidator
 
     def _mock(self, val):
@@ -339,11 +339,11 @@ class TestIconValidator(unittest.TestCase):
 
     def test_invalid(self):
         input = self._mock('foo.svg')
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             self.val.to_python(input)
-        assert str(cm.exception) == 'Project icons must be PNG, GIF, JPG, or 
BMP format.'
+        assert str(cm.value) == 'Project icons must be PNG, GIF, JPG, or BMP 
format.'
 
         input = self._mock('foogif.svg')
-        with self.assertRaises(fe.Invalid) as cm:
+        with pytest.raises(fe.Invalid) as cm:
             assert input == self.val.to_python(input)
-        assert str(cm.exception) == 'Project icons must be PNG, GIF, JPG, or 
BMP format.'
+        assert str(cm.value) == 'Project icons must be PNG, GIF, JPG, or BMP 
format.'
diff --git a/Allura/allura/tests/unit/spam/test_spam_filter.py 
b/Allura/allura/tests/unit/spam/test_spam_filter.py
index f7f8deefd..f2977fe8f 100644
--- a/Allura/allura/tests/unit/spam/test_spam_filter.py
+++ b/Allura/allura/tests/unit/spam/test_spam_filter.py
@@ -45,7 +45,7 @@ class MockFilter2(SpamFilter):
         return True
 
 
-class TestSpamFilter(unittest.TestCase):
+class TestSpamFilter:
 
     def test_check(self):
         # default no-op impl always returns False
diff --git a/Allura/allura/tests/unit/test_app.py 
b/Allura/allura/tests/unit/test_app.py
index ba31a5c9d..71b4e95f0 100644
--- a/Allura/allura/tests/unit/test_app.py
+++ b/Allura/allura/tests/unit/test_app.py
@@ -1,3 +1,20 @@
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
 import pytest
 
 from allura.app import Application
diff --git a/Allura/allura/tests/unit/test_artifact.py 
b/Allura/allura/tests/unit/test_artifact.py
index 590cb2d32..470d21034 100644
--- a/Allura/allura/tests/unit/test_artifact.py
+++ b/Allura/allura/tests/unit/test_artifact.py
@@ -20,7 +20,7 @@ import unittest
 from allura import model as M
 
 
-class TestArtifact(unittest.TestCase):
+class TestArtifact:
 
     def test_translate_query(self):
         fields = {'name_t': '', 'shortname_s': ''}
diff --git a/Allura/allura/tests/unit/test_package_path_loader.py 
b/Allura/allura/tests/unit/test_package_path_loader.py
index 40ed20fd0..4b6310532 100644
--- a/Allura/allura/tests/unit/test_package_path_loader.py
+++ b/Allura/allura/tests/unit/test_package_path_loader.py
@@ -17,7 +17,6 @@
 
 
 from collections import OrderedDict
-from unittest import TestCase
 
 import jinja2
 import mock
@@ -27,7 +26,7 @@ from tg import config
 from allura.lib.package_path_loader import PackagePathLoader
 
 
-class TestPackagePathLoader(TestCase):
+class TestPackagePathLoader:
 
     @mock.patch('pkg_resources.resource_filename')
     @mock.patch('pkg_resources.iter_entry_points')
diff --git a/Allura/allura/tests/unit/test_project.py 
b/Allura/allura/tests/unit/test_project.py
index 01113b2b5..125022e06 100644
--- a/Allura/allura/tests/unit/test_project.py
+++ b/Allura/allura/tests/unit/test_project.py
@@ -25,7 +25,7 @@ from allura.lib import helpers as h
 from allura.app import SitemapEntry
 
 
-class TestProject(unittest.TestCase):
+class TestProject:
 
     def test_grouped_navbar_entries(self):
         p = M.Project()
@@ -83,7 +83,7 @@ class TestProject(unittest.TestCase):
 
     def test_social_account(self):
         p = M.Project()
-        self.assertIsNone(p.social_account('Twitter'))
+        assert p.social_account('Twitter') is None
 
         p.set_social_account('Twitter', 'http://twitter.com/allura')
         assert p.social_account('Twitter').accounturl == 
'http://twitter.com/allura'
diff --git a/Allura/allura/tests/unit/test_repo.py 
b/Allura/allura/tests/unit/test_repo.py
index 2459ad032..e9983a580 100644
--- a/Allura/allura/tests/unit/test_repo.py
+++ b/Allura/allura/tests/unit/test_repo.py
@@ -18,6 +18,7 @@
 import datetime
 import unittest
 
+import pytest
 import six
 from mock import patch, Mock, MagicMock, call
 
@@ -31,7 +32,7 @@ from allura.model.repo_refresh import (
 )
 
 
-class TestTopoSort(unittest.TestCase):
+class TestTopoSort:
 
     def test_commit_dates_out_of_order(self):
         """Commits should be sorted by their parent/child relationships,
@@ -82,7 +83,7 @@ def blob(name, id):
     return b
 
 
-class TestTree(unittest.TestCase):
+class TestTree:
 
     @patch('allura.model.repository.Tree.__getitem__')
     def test_get_obj_by_path(self, getitem):
@@ -99,7 +100,7 @@ class TestTree(unittest.TestCase):
         getitem().__getitem__().__getitem__.assert_called_with('file.txt')
 
 
-class TestBlob(unittest.TestCase):
+class TestBlob:
 
     def test_pypeline_view(self):
         blob = M.repository.Blob(MagicMock(), 'INSTALL.mdown', 'blob1')
@@ -139,7 +140,7 @@ class TestBlob(unittest.TestCase):
         assert blob.has_html_view is True
 
 
-class TestCommit(unittest.TestCase):
+class TestCommit:
 
     def test_activity_extras(self):
         commit = M.repository.Commit()
@@ -240,7 +241,7 @@ class TestCommit(unittest.TestCase):
         commit.get_tree.assert_called_with(create=True)
 
 
-class TestZipDir(unittest.TestCase):
+class TestZipDir:
 
     @patch('allura.model.repository.Popen')
     @patch('allura.model.repository.tg')
@@ -271,9 +272,9 @@ class TestZipDir(unittest.TestCase):
         popen.return_value.returncode = 1
         src = '/fake/path/to/repo'
         zipfile = '/fake/zip/file.tmp'
-        with self.assertRaises(Exception) as cm:
+        with pytest.raises(Exception) as cm:
             zipdir(src, zipfile)
-        emsg = str(cm.exception)
+        emsg = str(cm.value)
         assert \
             "Command: " + \
             "['/bin/zip', '-y', '-q', '-r', '/fake/zip/file.tmp', b'repo'] " + 
\
@@ -282,7 +283,7 @@ class TestZipDir(unittest.TestCase):
         assert "STDERR: 2" in emsg
 
 
-class TestPrefixPathsUnion(unittest.TestCase):
+class TestPrefixPathsUnion:
 
     def test_disjoint(self):
         a = {'a1', 'a2', 'a3'}
diff --git a/Allura/allura/tests/unit/test_session.py 
b/Allura/allura/tests/unit/test_session.py
index bc3463f3e..e69e9737d 100644
--- a/Allura/allura/tests/unit/test_session.py
+++ b/Allura/allura/tests/unit/test_session.py
@@ -18,7 +18,6 @@
 import pymongo
 import mock
 
-from unittest import TestCase
 
 import allura
 from allura.tests import decorators as td
@@ -72,7 +71,7 @@ def test_extensions_cm_flush_raises():
     assert session._kwargs['extensions'] == []
 
 
-class TestSessionExtension(TestCase):
+class TestSessionExtension:
 
     def _mock_indexable(self, **kw):
         m = mock.Mock(**kw)
@@ -148,7 +147,7 @@ class TestArtifactSessionExtension(TestSessionExtension):
         assert index_tasks.add_artifacts.post.call_count == 0
 
 
-class TestBatchIndexer(TestCase):
+class TestBatchIndexer:
 
     def setup_method(self, method):
         session = mock.Mock()
diff --git a/Allura/allura/tests/unit/test_sitemapentry.py 
b/Allura/allura/tests/unit/test_sitemapentry.py
index 025b4bc62..73d4bbd8c 100644
--- a/Allura/allura/tests/unit/test_sitemapentry.py
+++ b/Allura/allura/tests/unit/test_sitemapentry.py
@@ -21,7 +21,7 @@ from mock import Mock
 from allura.app import SitemapEntry
 
 
-class TestSitemapEntry(unittest.TestCase):
+class TestSitemapEntry:
 
     def test_matches_url(self):
         request = Mock(upath_info='/p/project/tool/artifact')
@@ -29,6 +29,6 @@ class TestSitemapEntry(unittest.TestCase):
         s2 = SitemapEntry('tool2', url='/p/project/tool2')
         s3 = SitemapEntry('Tool', url='/p/project/_list/tool')
         s3.matching_urls.append('/p/project/tool')
-        self.assertTrue(s1.matches_url(request))
+        assert s1.matches_url(request)
         assert not s2.matches_url(request)
-        self.assertTrue(s3.matches_url(request))
+        assert s3.matches_url(request)
diff --git a/Allura/allura/tests/unit/test_solr.py 
b/Allura/allura/tests/unit/test_solr.py
index 7dd7328e6..54c2144e7 100644
--- a/Allura/allura/tests/unit/test_solr.py
+++ b/Allura/allura/tests/unit/test_solr.py
@@ -30,7 +30,7 @@ from allura.lib.solr import Solr, escape_solr_arg
 from allura.lib.search import search_app, SearchIndexable
 
 
-class TestSolr(unittest.TestCase):
+class TestSolr:
 
     def setup_method(self, method):
         # need to create the "test" project so @td.with_wiki works
@@ -140,7 +140,7 @@ class TestSolr(unittest.TestCase):
             
r'registration_ip:(2601\:404\:c300\:a560\:598f\:9336\:d2bb\:9e32)', fq=fq, 
ignore_errors=False, **{'q.op': 'AND'})
 
 
-class TestSearchIndexable(unittest.TestCase):
+class TestSearchIndexable:
 
     def setup_method(self, method):
         self.obj = SearchIndexable()
@@ -164,7 +164,7 @@ class TestSearchIndexable(unittest.TestCase):
         assert self.obj.solarize() == dict(text='<script>a(1)</script>')
 
 
-class TestSearch_app(unittest.TestCase):
+class TestSearch_app:
 
     def setup_method(self, method):
         # need to create the "test" project so @td.with_wiki works
diff --git a/AlluraTest/alluratest/tools.py b/AlluraTest/alluratest/tools.py
index c71c62e66..3f2c0eab8 100644
--- a/AlluraTest/alluratest/tools.py
+++ b/AlluraTest/alluratest/tools.py
@@ -15,10 +15,10 @@
 #       specific language governing permissions and limitations
 #       under the License.
 import functools
-import unittest
+import re
 
 from decorator import decorator
-
+import unittest
 testcase = unittest.TestCase(methodName='__init__')  # py2 needs a methodName 
that is a valid attr :/
 
 
diff --git a/ForgeGit/forgegit/tests/model/test_repository.py 
b/ForgeGit/forgegit/tests/model/test_repository.py
index aad27253f..7d0e97130 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -23,13 +23,14 @@ import unittest
 import pkg_resources
 import datetime
 import email.iterators
-
+import pytest
 import mock
 from tg import tmpl_context as c, app_globals as g
 import tg
 from ming.base import Object
 from ming.odm import ThreadLocalODMSession, session
 from testfixtures import TempDirectory
+import pytest
 
 from alluratest.controller import setup_basic_test, setup_global_objects
 from allura.lib import helpers as h
@@ -44,7 +45,7 @@ from forgegit.tests import with_git
 from forgewiki import model as WM
 
 
-class TestNewGit(unittest.TestCase):
+class TestNewGit:
 
     def setup_method(self, method):
         setup_basic_test()
@@ -122,7 +123,7 @@ class TestNewGit(unittest.TestCase):
                     'committer', 'added', 'removed', 'renamed', 'modified', 
'copied']))
 
 
-class TestGitRepo(unittest.TestCase, RepoImplTestBase):
+class TestGitRepo(RepoImplTestBase):
 
     def setup_method(self, method):
         setup_basic_test()
@@ -790,7 +791,7 @@ By Dave Brondsema''' in text_body
     def test_merge_raise_exception(self, git, shutil, tempfile):
         self.repo._impl._git.git = mock.Mock()
         git.Repo.clone_from.side_effect = ConnectionError
-        with self.assertRaises(ConnectionError):
+        with pytest.raises(ConnectionError):
             self.repo.merge(mock.Mock())
         assert shutil.rmtree.called
 
@@ -984,7 +985,7 @@ By Dave Brondsema''' in text_body
             assert rev.cached_tags == tags
 
 
-class TestGitImplementation(unittest.TestCase):
+class TestGitImplementation:
 
     def test_branches(self):
         repo_dir = pkg_resources.resource_filename(
@@ -1043,7 +1044,7 @@ class TestGitImplementation(unittest.TestCase):
             assert lcds == {}
 
 
-class TestGitCommit(unittest.TestCase):
+class TestGitCommit:
 
     def setup_method(self, method):
         setup_basic_test()
@@ -1119,7 +1120,7 @@ class TestGitCommit(unittest.TestCase):
         assert commits == []
 
 
-class TestGitHtmlView(unittest.TestCase):
+class TestGitHtmlView:
 
     def setup_method(self, method):
         setup_basic_test()
@@ -1150,7 +1151,7 @@ class TestGitHtmlView(unittest.TestCase):
         assert b.has_html_view
 
 
-class TestGitRename(unittest.TestCase):
+class TestGitRename:
 
     def setup_method(self, method):
         setup_basic_test()
diff --git a/ForgeGit/forgegit/tests/test_git_app.py 
b/ForgeGit/forgegit/tests/test_git_app.py
index 449c790fd..ee4df227f 100644
--- a/ForgeGit/forgegit/tests/test_git_app.py
+++ b/ForgeGit/forgegit/tests/test_git_app.py
@@ -25,7 +25,7 @@ from allura.lib import helpers as h
 from forgegit.tests import with_git
 
 
-class TestGitApp(unittest.TestCase):
+class TestGitApp:
 
     def setup_method(self, method):
         setup_basic_test()
diff --git a/ForgeGit/forgegit/tests/test_tasks.py 
b/ForgeGit/forgegit/tests/test_tasks.py
index c7b4cd900..48ea4828e 100644
--- a/ForgeGit/forgegit/tests/test_tasks.py
+++ b/ForgeGit/forgegit/tests/test_tasks.py
@@ -32,7 +32,7 @@ from forgegit.tests import with_git
 from forgegit.tests.functional.test_controllers import _TestCase as 
GitRealDataBaseTestCase
 
 
-class TestGitTasks(unittest.TestCase):
+class TestGitTasks:
 
     def setup_method(self, method):
         setup_basic_test()
diff --git a/ForgeImporters/forgeimporters/github/tests/test_code.py 
b/ForgeImporters/forgeimporters/github/tests/test_code.py
index 247edcf44..ca96746ff 100644
--- a/ForgeImporters/forgeimporters/github/tests/test_code.py
+++ b/ForgeImporters/forgeimporters/github/tests/test_code.py
@@ -15,7 +15,6 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from unittest import TestCase
 from mock import Mock, patch
 from ming.odm import ThreadLocalODMSession
 
@@ -33,7 +32,7 @@ test_project_with_repo = 'test2'
 with_git = with_tool(test_project_with_repo, 'git', 'src', 'git')
 
 
-class TestGitHubRepoImporter(TestCase):
+class TestGitHubRepoImporter:
 
     def setup_method(self, method):
         setup_unit_test()
@@ -67,16 +66,16 @@ class TestGitHubRepoImporter(TestCase):
         g.post_event.assert_called_once_with('project_updated')
 
 
-class TestGitHubImportController(TestController, TestCase):
+class TestGitHubImportController(TestController):
 
     @with_git
     def test_index(self):
         r = self.app.get(
             f'/p/{test_project_with_repo}/admin/ext/import/github-repo/')
-        self.assertIsNotNone(r.html.find(attrs=dict(name="gh_user_name")))
-        self.assertIsNotNone(r.html.find(attrs=dict(name="gh_project_name")))
-        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_label")))
-        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_point")))
+        assert r.html.find(attrs=dict(name="gh_user_name")) is not None
+        assert r.html.find(attrs=dict(name="gh_project_name")) is not None
+        assert r.html.find(attrs=dict(name="mount_label")) is not None
+        assert r.html.find(attrs=dict(name="mount_point")) is not None
 
     @with_git
     @patch('forgeimporters.github.requests')
diff --git a/ForgeImporters/forgeimporters/github/tests/test_oauth.py 
b/ForgeImporters/forgeimporters/github/tests/test_oauth.py
index 6d09017d8..83379f63b 100644
--- a/ForgeImporters/forgeimporters/github/tests/test_oauth.py
+++ b/ForgeImporters/forgeimporters/github/tests/test_oauth.py
@@ -15,7 +15,6 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from unittest import TestCase
 from alluratest.controller import setup_unit_test
 
 from mock import Mock, patch, MagicMock
@@ -25,7 +24,7 @@ from allura.tests import TestController
 from forgeimporters.github import GitHubOAuthMixin
 
 
-class TestGitHubOAuthMixin(TestController, TestCase):
+class TestGitHubOAuthMixin(TestController):
 
     def setup_method(self, method):
         super().setup_method(method)
diff --git a/ForgeImporters/forgeimporters/github/tests/test_tracker.py 
b/ForgeImporters/forgeimporters/github/tests/test_tracker.py
index ffd19e392..9620ab103 100644
--- a/ForgeImporters/forgeimporters/github/tests/test_tracker.py
+++ b/ForgeImporters/forgeimporters/github/tests/test_tracker.py
@@ -15,7 +15,6 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from unittest import TestCase
 from mock import patch
 from ming.odm import ThreadLocalODMSession
 
@@ -32,17 +31,17 @@ with_tracker = with_tool(test_project_with_tracker,
                          'tickets', 'spooky-issues', 'tickets')
 
 
-class TestGitHubTrackerImportController(TestController, TestCase):
+class TestGitHubTrackerImportController(TestController):
 
     url = '/p/%s/admin/ext/import/github-tracker/' % test_project_with_tracker
 
     @with_tracker
     def test_index(self):
         r = self.app.get(self.url)
-        self.assertIsNotNone(r.html.find(attrs=dict(name='gh_user_name')))
-        self.assertIsNotNone(r.html.find(attrs=dict(name='gh_project_name')))
-        self.assertIsNotNone(r.html.find(attrs=dict(name='mount_label')))
-        self.assertIsNotNone(r.html.find(attrs=dict(name='mount_point')))
+        assert r.html.find(attrs=dict(name='gh_user_name')) is not None
+        assert r.html.find(attrs=dict(name='gh_project_name')) is not None
+        assert r.html.find(attrs=dict(name='mount_label')) is not None
+        assert r.html.find(attrs=dict(name='mount_point')) is not None
 
     @with_tracker
     @patch('forgeimporters.github.requests')
diff --git a/ForgeImporters/forgeimporters/github/tests/test_wiki.py 
b/ForgeImporters/forgeimporters/github/tests/test_wiki.py
index 61b22f5d4..647b1b2d5 100644
--- a/ForgeImporters/forgeimporters/github/tests/test_wiki.py
+++ b/ForgeImporters/forgeimporters/github/tests/test_wiki.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from unittest import TestCase, skipIf
+from unittest import  skipIf
 from mock import Mock, patch, call
 from ming.odm import ThreadLocalODMSession
 import git
@@ -36,7 +36,7 @@ test_project_with_wiki = 'test2'
 with_wiki = with_tool(test_project_with_wiki, 'wiki', 'w', 'wiki')
 
 
-class TestGitHubWikiImporter(TestCase):
+class TestGitHubWikiImporter:
 
     def _make_project(self, gh_proj_name=None):
         project = Mock()
@@ -546,19 +546,18 @@ some text and **[Tips n\u2019 Tricks]**
         assert i.has_wiki_repo('fake url') is False
 
 
-class TestGitHubWikiImportController(TestController, TestCase):
+class TestGitHubWikiImportController(TestController):
 
     url = '/p/%s/admin/ext/import/github-wiki/' % test_project_with_wiki
 
     @with_wiki
     def test_index(self):
         r = self.app.get(self.url)
-        self.assertIsNotNone(r.html.find(attrs=dict(name='gh_user_name')))
-        self.assertIsNotNone(r.html.find(attrs=dict(name='gh_project_name')))
-        self.assertIsNotNone(r.html.find(attrs=dict(name='mount_label')))
-        self.assertIsNotNone(r.html.find(attrs=dict(name='mount_point')))
-        self.assertIsNotNone(
-            r.html.find(attrs=dict(name='tool_option', 
value='import_history')))
+        assert r.html.find(attrs=dict(name='gh_user_name')) is not None
+        assert r.html.find(attrs=dict(name='gh_project_name')) is not None
+        assert r.html.find(attrs=dict(name='mount_label')) is not None
+        assert r.html.find(attrs=dict(name='mount_point')) is not None
+        assert r.html.find(attrs=dict(name='tool_option', 
value='import_history')) is not None
 
     @with_wiki
     @patch('forgeimporters.github.requests')
@@ -593,7 +592,7 @@ class TestGitHubWikiImportController(TestController, 
TestCase):
             mount_label='GitHub Wiki'
         )
         r = self.app.post(self.url + 'create', params, status=302)
-        assert r.location, 'http://localhost/p/%s/admin/' % 
test_project_with_wiki
+        assert r.location == 'http://localhost/p/%s/admin/' % 
test_project_with_wiki
         args = import_tool.post.call_args[1]
         assert 'GitHub Wiki' == args['mount_label']
         assert 'gh-wiki' == args['mount_point']
diff --git a/ForgeImporters/forgeimporters/tests/forge/test_discussion.py 
b/ForgeImporters/forgeimporters/tests/forge/test_discussion.py
index cb694c200..70464f5e5 100644
--- a/ForgeImporters/forgeimporters/tests/forge/test_discussion.py
+++ b/ForgeImporters/forgeimporters/tests/forge/test_discussion.py
@@ -15,7 +15,6 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from unittest import TestCase
 import mock
 
 from dateutil.parser import parse
@@ -31,7 +30,7 @@ from forgeimporters.forge import discussion
 from forgediscussion import utils
 
 
-class TestDiscussionImporter(TestCase):
+class TestDiscussionImporter:
 
     def setup_method(self, method):
         self.patcher_g = mock.patch('forgeimporters.base.g', mock.MagicMock())
@@ -1268,7 +1267,7 @@ class TestDiscussionImporter(TestCase):
         g.post_event.assert_not_called()
 
 
-class TestForgeDiscussionController(TestController, TestCase):
+class TestForgeDiscussionController(TestController):
 
     def setup_method(self, method):
         super().setup_method(method)
@@ -1276,9 +1275,9 @@ class TestForgeDiscussionController(TestController, 
TestCase):
     @with_discussion
     def test_index(self):
         r = self.app.get('/p/test/admin/ext/import/forge-discussion/')
-        self.assertIsNotNone(r.html.find(attrs=dict(name="discussions_json")))
-        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_label")))
-        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_point")))
+        assert r.html.find(attrs=dict(name="discussions_json")) is not None
+        assert r.html.find(attrs=dict(name="mount_label")) is not None
+        assert r.html.find(attrs=dict(name="mount_point")) is not None
 
     @with_discussion
     @mock.patch('forgeimporters.forge.discussion.save_importer_upload')
diff --git a/ForgeImporters/forgeimporters/tests/forge/test_tracker.py 
b/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
index ad1df8b8d..7cb5e1741 100644
--- a/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
@@ -16,7 +16,6 @@
 #       under the License.
 
 from datetime import datetime
-from unittest import TestCase
 
 import mock
 import pytest
@@ -33,7 +32,7 @@ from forgeimporters.forge import tracker
 from forgeimporters.forge import alluraImporter
 
 
-class TestTrackerImporter(TestCase):
+class TestTrackerImporter:
 
     def setup_method(self, method):
         # every single test method here creates an importer and 
ToolImporterMeta uses 'g'
@@ -254,7 +253,7 @@ class TestTrackerImporter(TestCase):
         assert importer.get_user('foo') == 'bar'
         assert M.User.anonymous.call_count == 0
 
-        assert importer.get_user(None), 'anon'
+        assert importer.get_user(None) == 'anon'
         assert M.User.anonymous.call_count == 1
 
         M.User.by_username.return_value = None
@@ -335,7 +334,7 @@ class TestTrackerImporter(TestCase):
         ]
 
 
-class TestForgeTrackerImportController(TestController, TestCase):
+class TestForgeTrackerImportController(TestController):
 
     def setup_method(self, method):
         """Mount Allura importer on the Tracker admin controller"""
@@ -347,9 +346,9 @@ class TestForgeTrackerImportController(TestController, 
TestCase):
     @with_tracker
     def test_index(self):
         r = self.app.get('/p/test/admin/bugs/_importer/')
-        self.assertIsNotNone(r.html.find(attrs=dict(name="tickets_json")))
-        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_label")))
-        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_point")))
+        assert r.html.find(attrs=dict(name="tickets_json")) is not None
+        assert r.html.find(attrs=dict(name="mount_label")) is not None
+        assert r.html.find(attrs=dict(name="mount_point")) is not None
 
     @with_tracker
     @mock.patch('forgeimporters.forge.tracker.save_importer_upload')
diff --git 
a/ForgeImporters/forgeimporters/tests/github/functional/test_github.py 
b/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
index cc36dc5d8..d9ed29b8f 100644
--- a/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
+++ b/ForgeImporters/forgeimporters/tests/github/functional/test_github.py
@@ -17,13 +17,12 @@
 import requests
 import tg
 from mock import patch, call, Mock
-from unittest import TestCase
 
 from allura.tests import TestController
 from allura import model as M
 
 
-class TestGitHubImportController(TestController, TestCase):
+class TestGitHubImportController(TestController):
 
     def test_index(self):
         r = self.app.get('/p/import_project/github/')
diff --git a/ForgeImporters/forgeimporters/tests/github/test_extractor.py 
b/ForgeImporters/forgeimporters/tests/github/test_extractor.py
index 7c4c45332..d195f50a2 100644
--- a/ForgeImporters/forgeimporters/tests/github/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/github/test_extractor.py
@@ -15,7 +15,6 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-import pytest
 import json
 from io import BytesIO
 import six.moves.urllib.parse
@@ -26,6 +25,7 @@ from mock import patch, Mock
 
 from ... import github
 
+
 class TestGitHubProjectExtractor:
     PROJECT_INFO = {
         'description': 'project description',
@@ -82,58 +82,56 @@ class TestGitHubProjectExtractor:
         response.info = lambda: headers
         return response
 
-    @pytest.fixture
-    def extractor(self):  # Changed from setup_method to fixture
-        extractor = github.GitHubProjectExtractor('test_project')
-        extractor.urlopen = self.mocked_urlopen
-        return extractor
-
-    def test_get_next_page_url(self, extractor):
-        assert extractor.get_next_page_url(None) is None
-        assert extractor.get_next_page_url('') is None
+    def setup_method(self, method):
+        self.extractor = github.GitHubProjectExtractor('test_project')
+        self.extractor.urlopen = self.mocked_urlopen
 
+    def test_get_next_page_url(self):
+        assert self.extractor.get_next_page_url(None) is None
+        assert self.extractor.get_next_page_url('') is None
         link = 
'<https://api.github.com/repositories/8560576/issues?state=open&page=2>; 
rel="next", 
<https://api.github.com/repositories/8560576/issues?state=open&page=10>; 
rel="last"'
-        assert extractor.get_next_page_url(link) == 
'https://api.github.com/repositories/8560576/issues?state=open&page=2'
+        assert self.extractor.get_next_page_url(link) == 
'https://api.github.com/repositories/8560576/issues?state=open&page=2'
 
         link = 
'<https://api.github.com/repositories/8560576/issues?state=open&page=2>; 
rel="next"'
-        assert extractor.get_next_page_url(link) == 
'https://api.github.com/repositories/8560576/issues?state=open&page=2'
+        assert self.extractor.get_next_page_url(link) == 
'https://api.github.com/repositories/8560576/issues?state=open&page=2'
 
         link = 
'<https://api.github.com/repositories/8560576/issues?state=open&page=1>; 
rel="prev"'
-        assert extractor.get_next_page_url(link) is None
+        assert self.extractor.get_next_page_url(link) is None
 
-    def test_get_summary(self, extractor):
-        assert extractor.get_summary() == 'project description'
+    def test_get_summary(self):
+        assert self.extractor.get_summary() == 'project description'
 
-    def test_get_homepage(self, extractor):
-        assert extractor.get_homepage() == 'http://example.com'
+    def test_get_homepage(self):
+        assert self.extractor.get_homepage() == 'http://example.com'
 
-    def test_iter_issues(self, extractor):
-        issues = list(extractor.iter_issues())
+    def test_iter_issues(self):
+        issues = list(self.extractor.iter_issues())
         all_issues = list(zip((1, 2), self.CLOSED_ISSUES_LIST))
         all_issues += list(zip((3, 4, 5), self.OPENED_ISSUES_LIST))
         all_issues += list(zip((6, 7, 8), self.OPENED_ISSUES_LIST_PAGE2))
         assert issues == all_issues
 
-    def test_iter_comments(self, extractor):
+    def test_iter_comments(self):
         mock_issue = {'comments_url': '/issues/1/comments'}
-        comments = list(extractor.iter_comments(mock_issue))
+        comments = list(self.extractor.iter_comments(mock_issue))
         assert comments == self.ISSUE_COMMENTS + self.ISSUE_COMMENTS_PAGE2
 
-    def test_iter_events(self, extractor):
+    def test_iter_events(self):
         mock_issue = {'events_url': '/issues/1/events'}
-        events = list(extractor.iter_events(mock_issue))
+        events = list(self.extractor.iter_events(mock_issue))
         assert events == self.ISSUE_EVENTS + self.ISSUE_EVENTS_PAGE2[:1]
 
-    def test_has_wiki(self, extractor):
-        assert extractor.has_wiki()
+    def test_has_wiki(self):
+        assert self.extractor.has_wiki()
 
-    def test_get_wiki_url(self, extractor):
-        assert extractor.get_page_url('wiki_url') == 
'https://github.com/test_project.wiki'
+    def test_get_wiki_url(self):
+        assert self.extractor.get_page_url('wiki_url') == 
'https://github.com/test_project.wiki'
 
     @patch('forgeimporters.base.h.urlopen')
-    def test_urlopen(self, urlopen, extractor):
+    def test_urlopen(self, urlopen):
+        e = github.GitHubProjectExtractor('test_project')
         url = 'https://github.com/u/p/'
-        extractor.urlopen(url)
+        e.urlopen(url)
         request = urlopen.call_args[0][0]
         assert request.get_full_url() == url
 
@@ -149,7 +147,8 @@ class TestGitHubProjectExtractor:
     @patch('forgeimporters.base.h.urlopen')
     @patch('forgeimporters.github.time.sleep')
     @patch('forgeimporters.github.log')
-    def test_urlopen_rate_limit_403(self, log, sleep, urlopen, extractor):
+    def test_urlopen_rate_limit_403(self, log, sleep, urlopen):
+        '''Test that urlopen catches 403 which may happen if limit exceeded by 
previous fetches'''
         limit_exceeded_headers = {
             'X-RateLimit-Limit': '10',
             'X-RateLimit-Remaining': '0',
@@ -163,7 +162,8 @@ class TestGitHubProjectExtractor:
             raise six.moves.urllib.error.HTTPError(
                 'url', 403, 'msg', limit_exceeded_headers, BytesIO(b'{}'))
         urlopen.side_effect = urlopen_side_effect
-        extractor.get_page('http://example.com/')
+        e = github.GitHubProjectExtractor('test_project')
+        e.get_page('http://example.com/')
         assert sleep.call_count == 1
         assert urlopen.call_count == 2
         log.warning.assert_called_once_with(
@@ -176,4 +176,4 @@ class TestGitHubProjectExtractor:
         head.return_value.status_code = 200
         assert github.GitHubProjectExtractor('my-project').check_readable()
         head.return_value.status_code = 404
-        assert not github.GitHubProjectExtractor('my-project').check_readable()
\ No newline at end of file
+        assert not github.GitHubProjectExtractor('my-project').check_readable()
diff --git a/ForgeImporters/forgeimporters/tests/github/test_tracker.py 
b/ForgeImporters/forgeimporters/tests/github/test_tracker.py
index 0224925ec..70164494c 100644
--- a/ForgeImporters/forgeimporters/tests/github/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/github/test_tracker.py
@@ -17,7 +17,6 @@
 
 from datetime import datetime
 from operator import itemgetter
-from unittest import TestCase
 from urllib.error import HTTPError
 import mock
 
@@ -25,7 +24,7 @@ from ...github import tracker
 from forgeimporters.github.utils import GitHubMarkdownConverter
 
 
-class TestTrackerImporter(TestCase):
+class TestTrackerImporter:
 
     def setup_method(self, method):
         # every single test method here creates an importer and 
ToolImporterMeta uses 'g'
@@ -157,7 +156,7 @@ class TestTrackerImporter(TestCase):
         body = 'hello\n' \
             
'![cdbpzjc5ex4](https://f.cloud.github.com/assets/979771/1027411/a393ab5e-0e70-11e3-8a38-b93a3df904cf.jpg)\r\n'
         new_body, attachments = importer._get_attachments(extractor, body)
-        self.assertIsNotNone(attachments[0])
+        assert attachments[0] is not None
         assert not hasattr(attachments[0], 'file')
 
     def test_process_comments(self):
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py 
b/ForgeImporters/forgeimporters/tests/test_base.py
index f97efa390..7467613c9 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -15,7 +15,6 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from unittest import TestCase
 import errno
 
 from formencode import Invalid
@@ -32,7 +31,7 @@ from allura.lib import helpers as h
 from forgeimporters import base
 
 
-class TestProjectExtractor(TestCase):
+class TestProjectExtractor:
 
     @mock.patch('forgeimporters.base.h.urlopen')
     @mock.patch('urllib.request.Request')
@@ -142,7 +141,7 @@ def ep(name, source=None, importer=None, **kw):
     return mep
 
 
-class TestProjectImporter(TestCase):
+class TestProjectImporter:
 
     @mock.patch.object(base.h, 'iter_entry_points')
     def test_tool_importers(self, iep):
@@ -234,7 +233,7 @@ class TI3(base.ToolImporter):
     target_app = [TA2, TA2]
 
 
-class TestToolImporter(TestCase):
+class TestToolImporter:
 
     @mock.patch.object(base.h, 'iter_entry_points')
     def test_by_name(self, iep):
@@ -261,8 +260,8 @@ class TestToolImporter(TestCase):
             'importer2',
             'importer3',
         }
-        self.assertIsInstance(importers['importer2'], TI2)
-        self.assertIsInstance(importers['importer3'], TI3)
+        assert isinstance(importers['importer2'], TI2)
+        assert isinstance(importers['importer3'], TI3)
 
     def test_tool_label(self):
         assert TI1().tool_label == 'foo'
@@ -275,7 +274,7 @@ class TestToolImporter(TestCase):
         assert TI3().tool_description == 'qux_desc'
 
 
-class TestToolsValidator(TestCase):
+class TestToolsValidator:
 
     def setup_method(self, method):
         self.tv = base.ToolsValidator('good-source')
@@ -288,26 +287,26 @@ class TestToolsValidator(TestCase):
     @mock.patch.object(base.ToolImporter, 'by_name')
     def test_no_ep(self, by_name):
         eps = by_name.return_value = None
-        with self.assertRaises(Invalid) as cm:
+        with pytest.raises(Invalid) as cm:
             self.tv.to_python('my-value')
-        assert cm.exception.msg == 'Invalid tool selected: my-value'
+        assert cm.value.msg == 'Invalid tool selected: my-value'
         by_name.assert_called_once_with('my-value')
 
     @mock.patch.object(base.ToolImporter, 'by_name')
     def test_bad_source(self, by_name):
         eps = by_name.return_value = ep('ep1', 'bad-source').lv
-        with self.assertRaises(Invalid) as cm:
+        with pytest.raises(Invalid) as cm:
             self.tv.to_python('my-value')
-        assert cm.exception.msg == 'Invalid tool selected: my-value'
+        assert cm.value.msg == 'Invalid tool selected: my-value'
         by_name.assert_called_once_with('my-value')
 
     @mock.patch.object(base.ToolImporter, 'by_name')
     def test_multiple(self, by_name):
         eps = by_name.side_effect = [
             ep('ep1', 'bad-source').lv, ep('ep2', 'good-source').lv, ep('ep3', 
'bad-source').lv]
-        with self.assertRaises(Invalid) as cm:
+        with pytest.raises(Invalid) as cm:
             self.tv.to_python(['value1', 'value2', 'value3'])
-        assert cm.exception.msg == \
+        assert cm.value.msg == \
                          'Invalid tools selected: value1, value3'
         assert by_name.call_args_list == [
             mock.call('value1'),
diff --git a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py 
b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
index e95f586ac..daff4e392 100644
--- a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
@@ -18,7 +18,7 @@
 import json
 import os
 
-from unittest import TestCase, skipIf
+from unittest import  skipIf
 
 import pytest
 from mock import Mock, patch
@@ -40,7 +40,7 @@ from forgeimporters.trac.tickets import (
 )
 
 
-class TestTracTicketImporter(TestCase):
+class TestTracTicketImporter:
 
     def setup_method(self, method):
         setup_unit_test()
@@ -107,7 +107,7 @@ class TestTracTicketImporter(TestCase):
         h.make_app_admin_only.assert_called_once_with(app)
 
 
-class TestTracTicketImportController(TestController, TestCase):
+class TestTracTicketImportController(TestController):
 
     def setup_method(self, method):
         """Mount Trac import controller on the Tracker admin controller"""
@@ -118,9 +118,9 @@ class TestTracTicketImportController(TestController, 
TestCase):
     @with_tracker
     def test_index(self):
         r = self.app.get('/p/test/admin/bugs/_importer/')
-        self.assertIsNotNone(r.html.find(attrs=dict(name="trac_url")))
-        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_label")))
-        self.assertIsNotNone(r.html.find(attrs=dict(name="mount_point")))
+        assert r.html.find(attrs=dict(name="trac_url")) is not None
+        assert r.html.find(attrs=dict(name="mount_label")) is not None
+        assert r.html.find(attrs=dict(name="mount_point")) is not None
 
     @with_tracker
     @patch('forgeimporters.trac.requests.head')
@@ -192,7 +192,7 @@ class TestTracTicketImportController(TestController, 
TestCase):
         r = self.app.post('/p/test/admin/ext/import/trac-tickets/create', 
params, status=200)
         assert 'Invalid URL' in r.text
 
-class TestTracImportSupport(TestCase):
+class TestTracImportSupport:
 
     def test_link_processing(self):
         import_support = TracImportSupport()
@@ -224,7 +224,7 @@ class TestTracImportSupport(TestCase):
             assert actual == expected
 
 
-class TestTracImportSupportFunctional(TestRestApiBase, TestCase):
+class TestTracImportSupportFunctional(TestRestApiBase):
 
     @with_tracker
     def test_links(self):
diff --git a/ForgeSVN/forgesvn/tests/model/test_repository.py 
b/ForgeSVN/forgesvn/tests/model/test_repository.py
index 7c7affae7..6d3338f3c 100644
--- a/ForgeSVN/forgesvn/tests/model/test_repository.py
+++ b/ForgeSVN/forgesvn/tests/model/test_repository.py
@@ -49,7 +49,7 @@ from forgesvn.tests import with_svn
 from allura.tests.decorators import with_tool
 
 
-class TestNewRepo(unittest.TestCase):
+class TestNewRepo:
 
     def setup_method(self, method):
         setup_basic_test()
@@ -104,7 +104,7 @@ class TestNewRepo(unittest.TestCase):
                     'committer', 'added', 'removed', 'renamed', 'modified', 
'copied']))
 
 
-class TestSVNRepo(unittest.TestCase, RepoImplTestBase):
+class TestSVNRepo(RepoImplTestBase):
 
     def setup_method(self, method):
         setup_basic_test()
@@ -568,7 +568,7 @@ class TestSVNRepo(unittest.TestCase, RepoImplTestBase):
         assert payload == expected_payload
 
 
-class TestSVNRev(unittest.TestCase):
+class TestSVNRev:
 
     def setup_method(self, method):
         setup_basic_test()
@@ -645,7 +645,7 @@ class TestSVNRev(unittest.TestCase):
         assert 'Create readme' in n.text
 
 
-class _Test(unittest.TestCase):
+class _Test:
     idgen = ('obj_%d' % i for i in count())
 
     def _make_tree(self, object_id, **kwargs):
@@ -1016,7 +1016,7 @@ class TestCommit(_TestWithRepo):
         self.ci.context()
 
 
-class TestRename(unittest.TestCase):
+class TestRename:
 
     def setup_method(self, method):
         setup_basic_test()
diff --git a/ForgeSVN/forgesvn/tests/test_svn_app.py 
b/ForgeSVN/forgesvn/tests/test_svn_app.py
index f90b6e4be..1811445d7 100644
--- a/ForgeSVN/forgesvn/tests/test_svn_app.py
+++ b/ForgeSVN/forgesvn/tests/test_svn_app.py
@@ -25,7 +25,7 @@ from allura.lib import helpers as h
 from forgesvn.tests import with_svn
 
 
-class TestSVNApp(unittest.TestCase):
+class TestSVNApp:
 
     def setup_method(self, method):
         setup_basic_test()
diff --git a/ForgeSVN/forgesvn/tests/test_tasks.py 
b/ForgeSVN/forgesvn/tests/test_tasks.py
index f84d9dafe..a948a4f82 100644
--- a/ForgeSVN/forgesvn/tests/test_tasks.py
+++ b/ForgeSVN/forgesvn/tests/test_tasks.py
@@ -33,7 +33,7 @@ from allura.tasks import repo_tasks
 from forgesvn.tests import with_svn
 
 
-class TestRepoTasks(unittest.TestCase):
+class TestRepoTasks:
 
     def setup_method(self, method):
         setup_basic_test()
diff --git a/ForgeTracker/forgetracker/tests/unit/test_root_controller.py 
b/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
index dfc72a012..9f1a6950a 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
@@ -110,7 +110,7 @@ def create_ticket(summary, custom_fields):
     return ticket
 
 
-class test_change_text(unittest.TestCase):
+class test_change_text:
 
     def test_get_label(self):
         assert 'Milestone' == tracker_main.get_label('_milestone')
diff --git a/ForgeUserStats/forgeuserstats/tests/test_model.py 
b/ForgeUserStats/forgeuserstats/tests/test_model.py
index f6a6d7078..74703fa86 100644
--- a/ForgeUserStats/forgeuserstats/tests/test_model.py
+++ b/ForgeUserStats/forgeuserstats/tests/test_model.py
@@ -36,7 +36,7 @@ from forgeuserstats.model import stats as USM
 with_git = td.with_tool('test', 'Git', 'git-userstats-model', 'Git', 
type='git')
 
 
-class TestUserStats(unittest.TestCase):
+class TestUserStats:
 
     def setup_method(self, method):
         setup_basic_test()
diff --git a/ForgeUserStats/forgeuserstats/tests/test_stats.py 
b/ForgeUserStats/forgeuserstats/tests/test_stats.py
index cf206201b..9e4bb43ed 100644
--- a/ForgeUserStats/forgeuserstats/tests/test_stats.py
+++ b/ForgeUserStats/forgeuserstats/tests/test_stats.py
@@ -183,7 +183,7 @@ class TestStats(TestController):
             'modified'] == initial_tickets_artifacts['modified'] + 3
 
 
-class TestGitCommit(TestController, unittest.TestCase):
+class TestGitCommit(TestController):
 
     def setup_method(self, method):
         super().setup_method(method)
diff --git a/pytest.ini b/pytest.ini
index d6efbf3ef..34cbb2a3f 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -25,6 +25,7 @@ filterwarnings =
 
     # don't let us regress on this:
     error:tmpl_context.form_values:DeprecationWarning:tg.wsgiapp
+    error::pytest.PytestCollectionWarning
 
     # other packages' issues:
     ignore:Deprecated call to 
`pkg_resources.declare_namespace:DeprecationWarning:pkg_resources

Reply via email to