New submission from Antony Lee <anntzer....@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 <rep...@bugs.python.org> <https://bugs.python.org/issue37743> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com