Description
Feature or enhancement
Proposal:
The unittest.subTest
context (i.e. the object you get using with
's as
clause, currently None
) should get methods to manage cleanups:
addCleanup
enterContext
doCleanups
And similar ones for IsolatedAsyncIOTestCase
.
They should do the same thing as the same methods on TestCase
, but with subtest scope.
Example usage:
for param in 'a', 'b', 'c':
with self.subTest() as sub:
tempfile = make_tempfile()
sub.addCleanup(os.unlink, tempfile)
do_actual_test(tempfile, param)
See Discuss thread for motivation/discussion.
Has this already been discussed elsewhere?
I have already discussed this feature proposal on Discourse
Links to previous discussion of this feature:
https://discuss.python.org/t/unittest-add-addcleanup-to-subtest/91827
Linked PRs
Metadata
Metadata
Assignees
Projects
Status
Activity
encukou commentedon May 16, 2025
(If anyone wants to take it, go ahead! Otherwise I'll get to this eventually.)
StanFromIreland commentedon May 16, 2025
I can get to this in the evening:-) It's suprising that this was not implemented before!
ArunRawat404 commentedon May 17, 2025
If it's alright with you guys, I'd love to take on this issue.
StanFromIreland commentedon May 17, 2025
My implementation is not idea since _SubTest is a subclass and would therefore also expose asserts. I'd be interested to see what you have planned.
ArunRawat404 commentedon May 17, 2025
I'm thinking of creating a small helper class that only handles cleanup methods —
addCleanup
,enterContext
, anddoCleanups
— without inheriting fromTestCase
. That way, it avoids exposing any extra functionality likeassert*
methods and keeps things more contained. What are your thoughts on this?StanFromIreland commentedon May 17, 2025
I thought about that, but IMO it is pretty messy with a lot of duplicated code, so I don’t know. It is probably the only option.
ArunRawat404 commentedon May 17, 2025
Yes, it will be messy with duplicated code but I guess it's better than exposing unnecessary functionality. I also not able to think of any other way.
ArunRawat404 commentedon May 18, 2025
@encukou What are your thoughts on the implementation for this issue?
I’m considering creating a separate helper class
_SubTestCleanupHelper
with functionality similar to TestCase, but without exposing unnecessary features like_subTest
.The downside is that it would introduce some duplicated code.
Would love to hear your thoughts or suggestions.
picnixz commentedon May 18, 2025
My 2c:
_SubTest
as an opaque object with a documented interface. Let's not care about the extra methods that are added, let's only care about documenting those that should be public.__getattr__
that only returns a subset of allowed methods. The rest would raise RuntimeError if they are inherited from TestCase and not overloaded. We shouldn't expect_SubTest
to be a public class so we shouldn't worry about users subclassing this class and deal with this in our custom__getattr__
.The first solution would at least make any (CPython) code that is currently using
_SubTest
internally easier to maintain.encukou commentedon May 19, 2025
I think it's best to leave
_SubTest
for reporting, and add a new object for the context.Don't worry about duplicated code until the solution is working and tested. Then it's time to deduplicate.
addCleanup
,enterContext
anddoCleanups
tounittest.subTest
and tests #134318serhiy-storchaka commentedon Jun 4, 2025
Three ways to solve this issue was mentioned on the Discuss thread. With examples:
subTest
.But we need to add asynchronous variants to
subTest
inIsolatedAsyncIOTestCase
. This means two implementations ofsubTest
.It's unique advantage is that you can add callbacks for the outer scope and break strict LILO order. But I don't know how large a demand for it. The implementation will be complicated.
TestCase
.It may be easier to implement for
IsolatedAsyncIOTestCase
.addCleanup()
,doCleanups()
, etc will only work within a fence. All callbacks added in a fence will be called after leaving a fence. It may help to solve also other issues.But we will be able to fully understand the advantages and disadvantages only when we try to implement all three options.
2 remaining items