Skip to content
Foxipa
Code Completion 5 Challenges

Complete the ExitStack code

Practise entering dynamic synchronous and asynchronous resources, registering cleanup callbacks, handling partial acquisition, and transferring cleanup ownership.

Intermediate ~10 min read

Challenge 1

Enter the opened file through the ExitStack so it is closed when the stack exits.

python Your answer
from contextlib import ExitStack
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    path = Path(directory) / "note.txt"
    path.write_text("ready", encoding="utf-8")
    with ExitStack() as stack:
        file = 
        print(file.read())

Press Ctrl⌘Enter to check your answer

Challenge 2

Register events.append("released") to run when the stack closes.

python Your answer
from contextlib import ExitStack

events = []
with ExitStack() as stack:
    

assert events == ["released"]

Press Ctrl⌘Enter to check your answer

Challenge 3

Enter the file through the stack so a later failed open cannot leak it.

python Your answer
from contextlib import ExitStack
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    first_path = Path(directory) / "first.txt"
    first_path.write_text("ready", encoding="utf-8")
    first_file = None
    try:
        with ExitStack() as stack:
            first_file = 
            stack.enter_context((Path(directory) / "missing.txt").open(encoding="utf-8"))
    except FileNotFoundError:
        pass
    assert first_file.closed
    print(first_file.closed)

Press Ctrl⌘Enter to check your answer

Challenge 4

Transfer the registered cleanup operations to a separate stack without running them yet.

python Your answer
from contextlib import ExitStack

events = []

def cleanup_resource():
    events.append("released")

with ExitStack() as stack:
    stack.callback(cleanup_resource)
    owner = stack.()

assert events == []
owner.close()
assert events == ["released"]
print(events)

Press Ctrl⌘Enter to check your answer

Challenge 5

Enter the second asynchronous resource through the existing AsyncExitStack so its asynchronous cleanup is registered and runs in reverse acquisition order.

python Your answer
import asyncio
from contextlib import AsyncExitStack

events = []

class Lease:
    def __init__(self, name):
        self.name = name

    async def __aenter__(self):
        events.append(f"enter {self.name}")
        return self.name

    async def __aexit__(self, exc_type, exc_value, traceback):
        await asyncio.sleep(0)
        events.append(f"exit {self.name}")
        return False

async def main():
    async with AsyncExitStack() as stack:
        first = await stack.enter_async_context(Lease("first"))
        second = await stack.
        print(first, second)
    assert events == ["enter first", "enter second", "exit second", "exit first"]
    print(events)

asyncio.run(main())

Press Ctrl⌘Enter to check your answer