From 575d62de1058aa93aa5726890c51a95d9929aa03 Mon Sep 17 00:00:00 2001 From: Jonas Maurus Date: Fri, 5 Apr 2019 00:28:39 +0200 Subject: [PATCH 1/3] Fix generator support for Python 3. The wrapper should not yield itself. --- src/aspectlib/py3support.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aspectlib/py3support.py b/src/aspectlib/py3support.py index db9f907..864b5f8 100644 --- a/src/aspectlib/py3support.py +++ b/src/aspectlib/py3support.py @@ -36,7 +36,7 @@ def advising_generator_wrapper_py3(*args, **kwargs): kwargs = advice.kwargs gen = cutpoint_function(*args, **kwargs) try: - result = yield from gen + result = next(gen) except BaseException: advice = advisor.throw(*sys.exc_info()) else: From 8fe1359801c132d1aeda53696b53f4f04bc902a7 Mon Sep 17 00:00:00 2001 From: Jonas Maurus Date: Fri, 5 Apr 2019 16:05:40 +0200 Subject: [PATCH 2/3] Rewrite advising_generator_wrapper_py3 This is what I perceive to be the correct behavior for advising generators, where the advisor generator gets instantiated once per iteration on the cutpoint generator function --- src/aspectlib/py3support.py | 59 ++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/src/aspectlib/py3support.py b/src/aspectlib/py3support.py index 864b5f8..57d8538 100644 --- a/src/aspectlib/py3support.py +++ b/src/aspectlib/py3support.py @@ -20,38 +20,31 @@ def decorate_advising_generator_py3(advising_function, cutpoint_function, bind): assert isgeneratorfunction(cutpoint_function) def advising_generator_wrapper_py3(*args, **kwargs): - if bind: - advisor = advising_function(cutpoint_function, *args, **kwargs) - else: - advisor = advising_function(*args, **kwargs) - if not isgenerator(advisor): - raise ExpectedGenerator("advising_function %s did not return a generator." % advising_function) - try: + gen = cutpoint_function(*args, **kwargs) + while True: + if bind: + advisor = advising_function(cutpoint_function, *args, **kwargs) + else: + advisor = advising_function(*args, **kwargs) + + if not isgenerator(advisor): + raise ExpectedGenerator("advising_function %s did not return a generator." % advising_function) + advice = next(advisor) - while True: - logdebug('Got advice %r from %s', advice, advising_function) - if advice is Proceed or advice is None or isinstance(advice, Proceed): - if isinstance(advice, Proceed): - args = advice.args - kwargs = advice.kwargs - gen = cutpoint_function(*args, **kwargs) - try: - result = next(gen) - except BaseException: - advice = advisor.throw(*sys.exc_info()) - else: - try: - advice = advisor.send(result) - except StopIteration: - return result - finally: - gen.close() - elif advice is Return: - return - elif isinstance(advice, Return): - raise StopIteration(advice.value) - else: - raise UnacceptableAdvice("Unknown advice %s" % advice) - finally: - advisor.close() + logdebug('Got advice %r from %s', advice, advising_function) + if advice is Proceed or advice is None or isinstance(advice, Proceed): + try: + result = next(gen) + advice = advisor.send(result) + except StopIteration as e: + return e.value + except BaseException: + advice = advisor.throw(*sys.exc_info()) + + if advice is Return: + yield + elif isinstance(advice, Return): + yield advice.value + else: + raise UnacceptableAdvice("Unknown advice %s" % advice) return mimic(advising_generator_wrapper_py3, cutpoint_function) From 262c391ec892e335c4a95c470d1e3a805cdbcde7 Mon Sep 17 00:00:00 2001 From: Jonas Maurus Date: Sun, 7 Apr 2019 13:57:52 +0200 Subject: [PATCH 3/3] In this design Return without value should yield the last result --- src/aspectlib/py3support.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/aspectlib/py3support.py b/src/aspectlib/py3support.py index 57d8538..3a0d09f 100644 --- a/src/aspectlib/py3support.py +++ b/src/aspectlib/py3support.py @@ -32,6 +32,7 @@ def advising_generator_wrapper_py3(*args, **kwargs): advice = next(advisor) logdebug('Got advice %r from %s', advice, advising_function) + result = None if advice is Proceed or advice is None or isinstance(advice, Proceed): try: result = next(gen) @@ -42,7 +43,7 @@ def advising_generator_wrapper_py3(*args, **kwargs): advice = advisor.throw(*sys.exc_info()) if advice is Return: - yield + yield result elif isinstance(advice, Return): yield advice.value else: