From 9c31fd86c5f3a2aecb2e20e40069f37c8a207b79 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 21 Nov 2023 11:13:08 +0000 Subject: [PATCH 1/4] testcase: Remove unnecessary try_import use These were removed in Python 3 and will never be present. Signed-off-by: Stephen Finucane --- testtools/testcase.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/testtools/testcase.py b/testtools/testcase.py index 004fdb5c..e9d86b99 100644 --- a/testtools/testcase.py +++ b/testtools/testcase.py @@ -60,8 +60,6 @@ class _UnexpectedSuccess(Exception): Note that this exception is private plumbing in testtools' testcase module. """ -_UnexpectedSuccess = try_import( - 'unittest.case._UnexpectedSuccess', _UnexpectedSuccess) class _ExpectedFailure(Exception): @@ -70,8 +68,6 @@ class _ExpectedFailure(Exception): Note that this exception is private plumbing in testtools' testcase module. """ -_ExpectedFailure = try_import( - 'unittest.case._ExpectedFailure', _ExpectedFailure) # Copied from unittest before python 3.4 release. Used to maintain From 59b890db3cb9f57d5a274757bab245c1ad941061 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 21 Nov 2023 11:21:58 +0000 Subject: [PATCH 2/4] testcase: Deprecate SkippedTest exception 'SkipTest' from the stdlib should be preferred for future compatibility. Signed-off-by: Stephen Finucane --- testtools/testcase.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/testtools/testcase.py b/testtools/testcase.py index e9d86b99..c45c5fc8 100644 --- a/testtools/testcase.py +++ b/testtools/testcase.py @@ -21,6 +21,7 @@ import sys import types import unittest +from unittest.case import SkipTest import warnings from testtools.compat import reraise @@ -49,9 +50,15 @@ ) -class TestSkipped(Exception): +class TestSkipped(SkipTest): """Raised within TestCase.run() when a test is skipped.""" -TestSkipped = try_import('unittest.case.SkipTest', TestSkipped) + def __init__(self, *args, **kwargs): + warnings.warn( + 'Use SkipTest from unittest instead.', + DeprecationWarning, + stacklevel=2, + ) + super().__init__(*args, **kwargs) class _UnexpectedSuccess(Exception): @@ -218,7 +225,7 @@ class TestCase(unittest.TestCase): and an optional list of exception handlers. """ - skipException = TestSkipped + skipException = SkipTest run_tests_with = RunTest @@ -597,7 +604,8 @@ def onException(self, exc_info, tb_label='traceback'): :seealso addOnException: """ if exc_info[0] not in [ - self.skipException, _UnexpectedSuccess, _ExpectedFailure]: + self.skipException, _UnexpectedSuccess, _ExpectedFailure, + ]: self._report_traceback(exc_info, tb_label=tb_label) for handler in self.__exception_handlers: handler(exc_info) From e0d56b7ce65ae5b3d9757d1074a6c34c1be6be5d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 21 Nov 2023 12:00:27 +0000 Subject: [PATCH 3/4] testcase: Deprecate legacy aliases These were removed in Python 3.12 released in October 2023. We should follow their lead in an attempt to keep in sync. The implementation is based on that used in Python (before 3.12) [1]. [1] https://github.com/python/cpython/blob/3.11/Lib/unittest/case.py#L1366-L1384 Signed-off-by: Stephen Finucane --- testtools/testcase.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/testtools/testcase.py b/testtools/testcase.py index c45c5fc8..a9b017bb 100644 --- a/testtools/testcase.py +++ b/testtools/testcase.py @@ -279,12 +279,24 @@ def __eq__(self, other): return False return self.__dict__ == getattr(other, '__dict__', None) + # We need to explicitly set this since we're overriding __eq__ + # https://docs.python.org/3/reference/datamodel.html#object.__hash__ __hash__ = unittest.TestCase.__hash__ def __repr__(self): # We add id to the repr because it makes testing testtools easier. return f"<{self.id()} id=0x{id(self):0x}>" + def _deprecate(original_func): + def deprecated_func(*args, **kwargs): + warnings.warn( + 'Please use {0} instead.'.format(original_func.__name__), + DeprecationWarning, + stacklevel=2, + ) + return original_func(*args, **kwargs) + return deprecated_func + def addDetail(self, name, content_object): """Add a detail to be reported with this test's outcome. @@ -397,7 +409,7 @@ def assertEqual(self, expected, observed, message=''): matcher = _FlippedEquals(expected) self.assertThat(observed, matcher, message) - failUnlessEqual = assertEquals = assertEqual + failUnlessEqual = assertEquals = _deprecate(assertEqual) def assertIn(self, needle, haystack, message=''): """Assert that needle is in haystack.""" @@ -471,7 +483,8 @@ def match(self, matchee): our_callable = Nullary(callableObj, *args, **kwargs) self.assertThat(our_callable, matcher) return capture.matchee - failUnlessRaises = assertRaises + + failUnlessRaises = _deprecate(assertRaises) def assertThat(self, matchee, matcher, message='', verbose=False): """Assert that matchee is matched by matcher. @@ -484,7 +497,8 @@ def assertThat(self, matchee, matcher, message='', verbose=False): if mismatch_error is not None: raise mismatch_error - assertItemsEqual = unittest.TestCase.assertCountEqual + assertItemsEqual = _deprecate(unittest.TestCase.assertCountEqual) + def addDetailUniqueName(self, name, content_object): """Add a detail to the test, but ensure it's name is unique. From 6aa2341189b7e55a776765293b74a7ebbf37685b Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 21 Nov 2023 12:17:03 +0000 Subject: [PATCH 4/4] tox: Remove unsupported Python versions, unnecessary deps We also bump to tox 4, which handles pyproject.toml files by default using its own build frontend. Signed-off-by: Stephen Finucane --- tox.ini | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tox.ini b/tox.ini index 5c529e86..68364d4a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,15 +1,11 @@ [tox] -envlist = py36,py37,py38,py39,py310,py311,py312,pypy3 -minversion = 1.6 +envlist = py37,py38,py39,py310,py311,py312,pypy3 +minversion = 4.2 [testenv] usedevelop = True -deps = - sphinx - setuptools>=61 - setuptools-scm extras = test twisted commands = - python -W once -m testtools.run testtools.tests.test_suite + python -W once -m testtools.run testtools.tests.test_suite {posargs}