From 6ec83e18dca497a8fbfca6caca5999984bd32f2e Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 26 Jan 2014 17:34:37 +0000 Subject: [PATCH] Added a workaround for a pypy bug in context managers --- flask/_compat.py | 24 ++++++++++++++++++++++++ flask/ctx.py | 7 +++++++ 2 files changed, 31 insertions(+) diff --git a/flask/_compat.py b/flask/_compat.py index e69dac45..86a87832 100644 --- a/flask/_compat.py +++ b/flask/_compat.py @@ -71,3 +71,27 @@ def with_metaclass(meta, *bases): return type.__new__(cls, name, (), d) return meta(name, bases, d) return metaclass('temporary_class', None, {}) + + +# Certain versions of pypy have a bug where clearing the exception stack +# breaks the __exit__ function in a very peculiar way. This is currently +# true for pypy 2.2.1 for instance. The second level of exception blocks +# is necessary because pypy seems to forget to check if an exception +# happend until the next bytecode instruction? +BROKEN_PYPY_CTXMGR_EXIT = False +if hasattr(sys, 'pypy_version_info'): + class _Mgr(object): + def __enter__(self): + return self + def __exit__(self, *args): + sys.exc_clear() + try: + try: + with _Mgr(): + raise AssertionError() + except: + raise + except TypeError: + BROKEN_PYPY_CTXMGR_EXIT = True + except AssertionError: + pass diff --git a/flask/ctx.py b/flask/ctx.py index 7f99dfb4..406d80c5 100644 --- a/flask/ctx.py +++ b/flask/ctx.py @@ -19,6 +19,7 @@ from werkzeug.exceptions import HTTPException from .globals import _request_ctx_stack, _app_ctx_stack from .module import blueprint_is_module from .signals import appcontext_pushed, appcontext_popped +from ._compat import BROKEN_PYPY_CTXMGR_EXIT class _AppCtxGlobals(object): @@ -187,6 +188,9 @@ class AppContext(object): def __exit__(self, exc_type, exc_value, tb): self.pop(exc_value) + if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None: + raise exc_type, exc_value, tb + class RequestContext(object): """The request context contains all request relevant information. It is @@ -390,6 +394,9 @@ class RequestContext(object): # See flask.testing for how this works. self.auto_pop(exc_value) + if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None: + raise exc_type, exc_value, tb + def __repr__(self): return '<%s \'%s\' [%s] of %s>' % ( self.__class__.__name__,