aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYilei Yang <yileiyang@google.com>2022-07-14 15:59:50 -0700
committerCopybara-Service <copybara-worker@google.com>2022-07-14 16:00:17 -0700
commitf2a901edd64b8e863d3e1dfb3df4b7c91cf5507f (patch)
tree8dce130fc109495307ee065c5f4c4332a89de293
parentfea82554c370d78e9c9eb63e0d8cc85cac30ff15 (diff)
downloadabsl-py-f2a901edd64b8e863d3e1dfb3df4b7c91cf5507f.tar.gz
Make `TempFileCleanup.SUCCESS` work with Python 3.11 after https://github.com/python/cpython/pull/28180.
After the change, the errors from the test case were no longer buffered in `_Outcome`. Instead, we need to take a note of errors on the `TestResult` before, then compare errors after. PiperOrigin-RevId: 461070558 Change-Id: I7d9f769cd46143a886bc5edeb224804acd8dbaf9
-rw-r--r--CHANGELOG.md4
-rw-r--r--absl/testing/absltest.py43
-rw-r--r--absl/testing/tests/absltest_test.py19
-rw-r--r--absl/testing/tests/absltest_test_helper.py16
4 files changed, 70 insertions, 12 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3c36751..d083f61 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com).
## Unreleased
-Nothing notable unreleased.
+### Fixed
+
+* Fixed a crash in Python 3.11 when `TempFileCleanup.SUCCESS` is used.
## 1.1.0 (2022-06-01)
diff --git a/absl/testing/absltest.py b/absl/testing/absltest.py
index d3cf95a..b7a941b 100644
--- a/absl/testing/absltest.py
+++ b/absl/testing/absltest.py
@@ -787,24 +787,49 @@ class TestCase(unittest.TestCase):
elif cleanup == TempFileCleanup.ALWAYS:
self.addCleanup(_rmtree_ignore_errors, path)
elif cleanup == TempFileCleanup.SUCCESS:
- self._internal_cleanup_on_success(_rmtree_ignore_errors, path)
+ self._internal_add_cleanup_on_success(_rmtree_ignore_errors, path)
else:
raise AssertionError('Unexpected cleanup value: {}'.format(cleanup))
- def _internal_cleanup_on_success(self, function, *args, **kwargs):
- # type: (Callable[..., object], Any, Any) -> None
+ def _internal_add_cleanup_on_success(
+ self,
+ function: Callable[..., Any],
+ *args: Any,
+ **kwargs: Any,
+ ) -> None:
+ """Adds `function` as cleanup when the test case succeeds."""
+ outcome = self._outcome
+ previous_failure_count = (
+ len(outcome.result.failures)
+ + len(outcome.result.errors)
+ + len(outcome.result.unexpectedSuccesses)
+ )
def _call_cleaner_on_success(*args, **kwargs):
- if not self._ran_and_passed():
+ if not self._internal_ran_and_passed_when_called_during_cleanup(
+ previous_failure_count):
return
function(*args, **kwargs)
self.addCleanup(_call_cleaner_on_success, *args, **kwargs)
- def _ran_and_passed(self):
- # type: () -> bool
+ def _internal_ran_and_passed_when_called_during_cleanup(
+ self,
+ previous_failure_count: int,
+ ) -> bool:
+ """Returns whether test is passed. Expected to be called during cleanup."""
outcome = self._outcome
- result = self.defaultTestResult()
- self._feedErrorsToResult(result, outcome.errors) # pytype: disable=attribute-error
- return result.wasSuccessful()
+ if sys.version_info[:2] >= (3, 11):
+ current_failure_count = (
+ len(outcome.result.failures)
+ + len(outcome.result.errors)
+ + len(outcome.result.unexpectedSuccesses)
+ )
+ return current_failure_count == previous_failure_count
+ else:
+ # Before Python 3.11 https://github.com/python/cpython/pull/28180, errors
+ # were bufferred in _Outcome before calling cleanup.
+ result = self.defaultTestResult()
+ self._feedErrorsToResult(result, outcome.errors) # pytype: disable=attribute-error
+ return result.wasSuccessful()
def shortDescription(self):
# type: () -> Text
diff --git a/absl/testing/tests/absltest_test.py b/absl/testing/tests/absltest_test.py
index d941e07..43201bd 100644
--- a/absl/testing/tests/absltest_test.py
+++ b/absl/testing/tests/absltest_test.py
@@ -2145,6 +2145,11 @@ class TempFileTest(absltest.TestCase, HelperMixin):
'TempFileHelperTest/test_failure',
'TempFileHelperTest/test_failure/failure',
'TempFileHelperTest/test_success',
+ 'TempFileHelperTest/test_subtest_failure',
+ 'TempFileHelperTest/test_subtest_failure/parent',
+ 'TempFileHelperTest/test_subtest_failure/successful_child',
+ 'TempFileHelperTest/test_subtest_failure/failed_child',
+ 'TempFileHelperTest/test_subtest_success',
}
self.run_tempfile_helper('SUCCESS', expected)
@@ -2153,6 +2158,8 @@ class TempFileTest(absltest.TestCase, HelperMixin):
'TempFileHelperTest',
'TempFileHelperTest/test_failure',
'TempFileHelperTest/test_success',
+ 'TempFileHelperTest/test_subtest_failure',
+ 'TempFileHelperTest/test_subtest_success',
}
self.run_tempfile_helper('ALWAYS', expected)
@@ -2163,6 +2170,14 @@ class TempFileTest(absltest.TestCase, HelperMixin):
'TempFileHelperTest/test_failure/failure',
'TempFileHelperTest/test_success',
'TempFileHelperTest/test_success/success',
+ 'TempFileHelperTest/test_subtest_failure',
+ 'TempFileHelperTest/test_subtest_failure/parent',
+ 'TempFileHelperTest/test_subtest_failure/successful_child',
+ 'TempFileHelperTest/test_subtest_failure/failed_child',
+ 'TempFileHelperTest/test_subtest_success',
+ 'TempFileHelperTest/test_subtest_success/parent',
+ 'TempFileHelperTest/test_subtest_success/child0',
+ 'TempFileHelperTest/test_subtest_success/child1',
}
self.run_tempfile_helper('OFF', expected)
@@ -2172,8 +2187,8 @@ class SkipClassTest(absltest.TestCase):
def test_incorrect_decorator_call(self):
with self.assertRaises(TypeError):
- @absltest.skipThisClass # pylint: disable=unused-variable
- class Test(absltest.TestCase):
+ @absltest.skipThisClass
+ class Test(absltest.TestCase): # pylint: disable=unused-variable
pass
def test_incorrect_decorator_subclass(self):
diff --git a/absl/testing/tests/absltest_test_helper.py b/absl/testing/tests/absltest_test_helper.py
index e81a89b..89b6721 100644
--- a/absl/testing/tests/absltest_test_helper.py
+++ b/absl/testing/tests/absltest_test_helper.py
@@ -106,6 +106,8 @@ class HelperTest(absltest.TestCase):
class TempFileHelperTest(absltest.TestCase):
+ """Helper test case for tempfile cleanup tests."""
+
tempfile_cleanup = absltest.TempFileCleanup[os.environ.get(
'ABSLTEST_TEST_HELPER_TEMPFILE_CLEANUP', 'SUCCESS')]
@@ -116,6 +118,20 @@ class TempFileHelperTest(absltest.TestCase):
def test_success(self):
self.create_tempfile('success')
+ def test_subtest_failure(self):
+ self.create_tempfile('parent')
+ with self.subTest('success'):
+ self.create_tempfile('successful_child')
+ with self.subTest('failure'):
+ self.create_tempfile('failed_child')
+ self.fail('expected failure')
+
+ def test_subtest_success(self):
+ self.create_tempfile('parent')
+ for i in range(2):
+ with self.subTest(f'success{i}'):
+ self.create_tempfile(f'child{i}')
+
def main(argv):
del argv # Unused.