Python Contextlib ExitStack

Python’s contextlib provides a ContextManager, ExitStack that makes managing other context managers driven by data.

ExitStack instance provides a method enter_context which registers a context manager and handles enter and exit special methods.

This method is useful when there are more than one context manager or nested context managers or to create context manager on the fly.

Example

from contextlib import ContextDecorator, ExitStack
from typing import Union
from pathlib import Path


class BackupFile(ContextDecorator):
    def __init__(self, name: Union[Path, str]):
        self.path = Path(name)

    def __enter__(self):
        print(f'-Creating backup file for {self.path}-')

    def __exit__(self, type, value, traceback):
        print(f'--Deleting the backup file for {self.path}--')


def get_filenames():
    # data from command line
    return ['destroy.txt', 'cant_create.txt']


def main():
    # This will not print any statement
    print('Calling the class outside of context manager')
    BackupFile("destroy.txt")

    print('Calling the class with ExitStack and should print statements')

    # This should print enter and exit print statement
    with ExitStack() as stack:
        filenames = get_filenames()
        files = [stack.enter_context(BackupFile(fname)) for fname in filenames]
        # edit file
        print('* Unit of Work *')
        # invoke some function and you can pass the stack



if __name__ == "__main__":
    main()

$python backup_file.py
Calling the class outside of context manager
Calling the class with ExitStack and should print statements
-Creating backup file for destroy.txt-
-Creating backup file for cant_create.txt-
* Unit of Work *
--Deleting the backup file for cant_create.txt--
--Deleting the backup file for destroy.txt--

Link to a sample usage from CPython source code.

Reference: