Skip to content

Warn about @contextlib.contextmanager without try/finally in generator functions #2832

@ghost

Description

Is your feature request related to a problem?

If you decorate a generator function with @contextlib.contextmanager and use the context manager cm inside a generator function, the context manager's __exit__ will not be always be called because the generator raises GeneratorExit, which ends the generator that defines cm.

Notice that cm exit never appears, as cm's __exit__ is never called.

from __future__ import generator_stop

import contextlib
import weakref
import sys


@contextlib.contextmanager
def cm():
    print("cm enter")
    a = yield
    print('cm exit')

def genfunc():
    with cm():
        print("stepping")
        yield

def main():
    gen = genfunc()
    ref = weakref.ref(gen, print)
    next(gen)


if __name__ == "__main__":
    main()

Output:

cm enter
stepping
<weakref at 0x7f4739e38e08; dead>

Describe the solution you'd like

Generator functions decorated with @contextlib.contextmanager should not be used in generators unless the context manager has finally:

@contextlib.contextmanager
def cm():
    try:
        yield
    finally:
        # cleanup code here
        ...

or specifically handles GeneratorExit:

@contextlib.contextmanager
def cm():
    try:
        yield
    except GeneratorExit:
        # cleanup code here
        ...

Additional context

Add any other context about the feature request here.

Metadata

Metadata

Assignees

Labels

Enhancement ✨Improvement to a componentNeeds PRThis issue is accepted, sufficiently specified and now needs an implementation

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions