[issue37743] How should contextmanager/ContextDecorator work with generators?

Antony Lee report at bugs.python.org
Thu Aug 1 19:33:04 EDT 2019


New submission from Antony Lee <anntzer.lee at gmail.com>:

The docs for ContextDecorator (of which contextmanager is a case) describe its semantics as:

    ... for any construct of the following form:

    def f():
        with cm():
            # Do stuff

    ContextDecorator lets you instead write:

    @cm()
    def f():
        # Do stuff

However, when decorating a generator, the equivalence is broken:

    from contextlib import contextmanager

    @contextmanager
    def cm():
        print("start")
        yield
        print("stop")

    def gen_using_with():
        with cm():
            yield from map(print, range(2))

    @cm()
    def gen_using_decorator():
        yield from map(print, range(2))

    print("using with")
    list(gen_using_with())
    print("==========")
    print("using decorator")
    list(gen_using_decorator())

results in

    using with
    start
    0
    1
    stop
    ==========
    using decorator
    start
    stop
    0
    1

i.e., when used as a decorator, the entire contextmanager is executed first before iterating over the generator (which is unsurprising given the implementation of ContextDecorator: ContextDecorator returns a function that executes the context manager and returns the generator, which is only iterated over later).

Should this be considered as a bug in ContextDecorator, and should ContextDecorator instead detect when it is used to decorate a generator (e.g. with inspect.isgeneratorfunction), and switch its implementation accordingly in that case?

----------
components: Library (Lib)
messages: 348878
nosy: Antony.Lee
priority: normal
severity: normal
status: open
title: How should contextmanager/ContextDecorator work with generators?
versions: Python 3.8

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue37743>
_______________________________________


More information about the Python-bugs-list mailing list