-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
gh-134079: Add addCleanup
, enterContext
and doCleanups
to unittest.subTest
and tests
#134318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d12ab40
0edd1be
c9aad93
f09d6f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -559,10 +559,12 @@ def subTest(self, msg=_subtest_msg_sentinel, **params): | |||||||||||||||||||||
params_map = _OrderedChainMap(params) | ||||||||||||||||||||||
else: | ||||||||||||||||||||||
params_map = parent.params.new_child(params) | ||||||||||||||||||||||
self._subtest = _SubTest(self, msg, params_map) | ||||||||||||||||||||||
subtest = _SubTest(self, msg, params_map) | ||||||||||||||||||||||
self._subtest = subtest | ||||||||||||||||||||||
cleanup_helper = _SubTestCleanupHelper(subtest, self._outcome) | ||||||||||||||||||||||
try: | ||||||||||||||||||||||
with self._outcome.testPartExecutor(self._subtest, subTest=True): | ||||||||||||||||||||||
yield | ||||||||||||||||||||||
yield cleanup_helper | ||||||||||||||||||||||
if not self._outcome.success: | ||||||||||||||||||||||
result = self._outcome.result | ||||||||||||||||||||||
if result is not None and result.failfast: | ||||||||||||||||||||||
|
@@ -572,6 +574,7 @@ def subTest(self, msg=_subtest_msg_sentinel, **params): | |||||||||||||||||||||
# stop now and register the expected failure. | ||||||||||||||||||||||
raise _ShouldStop | ||||||||||||||||||||||
finally: | ||||||||||||||||||||||
cleanup_helper.doCleanups() | ||||||||||||||||||||||
self._subtest = parent | ||||||||||||||||||||||
|
||||||||||||||||||||||
def _addExpectedFailure(self, result, exc_info): | ||||||||||||||||||||||
|
@@ -1626,3 +1629,47 @@ def shortDescription(self): | |||||||||||||||||||||
|
||||||||||||||||||||||
def __str__(self): | ||||||||||||||||||||||
return "{} {}".format(self.test_case, self._subDescription()) | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
class _SubTestCleanupHelper: | ||||||||||||||||||||||
""" | ||||||||||||||||||||||
Helper class to manage cleanups and context managers inside subTest blocks, | ||||||||||||||||||||||
without exposing full TestCase functionality. | ||||||||||||||||||||||
""" | ||||||||||||||||||||||
Comment on lines
+1634
to
+1638
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: Perhaps
Suggested change
|
||||||||||||||||||||||
|
||||||||||||||||||||||
def __init__(self, subtest, outcome=None): | ||||||||||||||||||||||
self._cleanups = [] | ||||||||||||||||||||||
self._subtest = subtest | ||||||||||||||||||||||
self._outcome = outcome | ||||||||||||||||||||||
|
||||||||||||||||||||||
@staticmethod | ||||||||||||||||||||||
def _callCleanup(function, /, *args, **kwargs): | ||||||||||||||||||||||
function(*args, **kwargs) | ||||||||||||||||||||||
|
||||||||||||||||||||||
def addCleanup(self, function, /, *args, **kwargs): | ||||||||||||||||||||||
"""Add a function, with arguments, to be called when the test is | ||||||||||||||||||||||
completed. Functions added are called on a LIFO basis and are | ||||||||||||||||||||||
called after tearDown on test failure or success. | ||||||||||||||||||||||
|
||||||||||||||||||||||
Cleanup items are called even if setUp fails (unlike tearDown).""" | ||||||||||||||||||||||
self._cleanups.append((function, args, kwargs)) | ||||||||||||||||||||||
|
||||||||||||||||||||||
def enterContext(self, cm): | ||||||||||||||||||||||
"""Enters the supplied context manager. | ||||||||||||||||||||||
|
||||||||||||||||||||||
If successful, also adds its __exit__ method as a cleanup | ||||||||||||||||||||||
function and returns the result of the __enter__ method. | ||||||||||||||||||||||
""" | ||||||||||||||||||||||
return _enter_context(cm, self.addCleanup) | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add a flag argument to |
||||||||||||||||||||||
|
||||||||||||||||||||||
def doCleanups(self): | ||||||||||||||||||||||
"""Execute all cleanup functions registered for this subtest.""" | ||||||||||||||||||||||
outcome = self._outcome or _Outcome() | ||||||||||||||||||||||
while self._cleanups: | ||||||||||||||||||||||
function, args, kwargs = self._cleanups.pop() | ||||||||||||||||||||||
if hasattr(outcome, 'testPartExecutor'): | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any way the outcome would not have |
||||||||||||||||||||||
with outcome.testPartExecutor(self._subtest, subTest=True): | ||||||||||||||||||||||
self._callCleanup(function, *args, **kwargs) | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be |
||||||||||||||||||||||
else: | ||||||||||||||||||||||
self._callCleanup(function, *args, **kwargs) | ||||||||||||||||||||||
return outcome.success |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
unittest.subTest now supports addCleanup(), enterContext(), and doCleanups(), enabling resource management and cleanup inside subTest blocks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be no need for
_active_events_list
and_get_events
and_record_event
.