One of the changes in #7 is that TrioTestCase now has a stack member of type contextlib.AsyncExitStack, which you can use via await self.stack.enter_async_context(...) or self.stack.push_async_callback(...).
As it happens, I think we're only internally using the latter.
I think it'd be a good idea for TrioTestCase to look like other test classes. Upstream unittest.TestCase and more interestingly unittest.IsolatedAsyncioTestCase solve this problem in a different way: they have self.addCleanup(...) and await self.addAsyncCleanup(...) methods.
So, in theory, we could adopt that approach pretty straightforwardly.
However, upstream unittest is considering adding support for ExitStack/AsyncExitStack - see bpo-45046 and python/cpython#28045. The API is slightly different from ours - instead of exposing an actual stack member or even having such a private member, they just implement enterContext etc. and enterAsyncContext themselves, by (async) calling the enter function and adding an (async) cleanup for the exit function.
I have a vague feeling that context managers are a better approach than addAsyncCleanup/push_async_callback, but I'm not really sure.
For what it's worth, pytest-trio just has async fixtures which can cleanup post-yield, and are somewhat geared towards using context managers with a literal with statement. Their tutorial has this example:
@pytest.fixture
async def echo_client(nursery):
listeners = await nursery.start(
partial(trio.serve_tcp, echo_server_handler, port=0)
)
echo_client = await open_stream_to_socket_listener(listeners[0])
async with echo_client:
yield echo_client
I don't think there's any other way in pytest-trio to do cleanup.
(It's maybe also worth noting that pytest-trio's nursery fixture cancels the nursery's cancel scope when the test finishes, which is at least a little bit of what we're doing in our cleanups, but not all of it. So there may also be an argument for TrioTestCase to automatically provide a nursery, maybe....)
One of the changes in #7 is that TrioTestCase now has a
stackmember of typecontextlib.AsyncExitStack, which you can use viaawait self.stack.enter_async_context(...)orself.stack.push_async_callback(...).As it happens, I think we're only internally using the latter.
I think it'd be a good idea for
TrioTestCaseto look like other test classes. Upstreamunittest.TestCaseand more interestinglyunittest.IsolatedAsyncioTestCasesolve this problem in a different way: they haveself.addCleanup(...)andawait self.addAsyncCleanup(...)methods.So, in theory, we could adopt that approach pretty straightforwardly.
However, upstream unittest is considering adding support for
ExitStack/AsyncExitStack- see bpo-45046 and python/cpython#28045. The API is slightly different from ours - instead of exposing an actualstackmember or even having such a private member, they just implemententerContextetc. andenterAsyncContextthemselves, by (async) calling the enter function and adding an (async) cleanup for the exit function.I have a vague feeling that context managers are a better approach than
addAsyncCleanup/push_async_callback, but I'm not really sure.For what it's worth, pytest-trio just has async fixtures which can cleanup post-
yield, and are somewhat geared towards using context managers with a literalwithstatement. Their tutorial has this example:I don't think there's any other way in pytest-trio to do cleanup.
(It's maybe also worth noting that pytest-trio's
nurseryfixture cancels the nursery's cancel scope when the test finishes, which is at least a little bit of what we're doing in our cleanups, but not all of it. So there may also be an argument forTrioTestCaseto automatically provide a nursery, maybe....)