如何避免使用 sys.exc_clear
how to avoid to use sys.exc_clear
这是我的代码:
import sys
class App(object):
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, tb):
print sys.exc_info()
app = App()
with app:
try:
1/0
except:
print 'Caught you'
#sys.exc_clear()
另一个使用 Flask 应用上下文的例子:
from flask import Flask
app = Flask(__name__)
@app.teardown_appcontext
def teardown(exception):
print exception
with app.app_context():
try:
1 / 0
except:
pass
奇怪的是,如果我在处理异常时没有调用 sys.exc_clear,那么当退出应用程序时,sys.exc_info 仍然会 return 异常信息。
有什么办法可以避免这种情况吗?
在我基于flask的项目中,当出现异常时,我会回滚事务。虽然我处理了异常,但应用程序上下文仍然可以使用 sys.exc_info 获取它,如下面的代码所示:
#AppContext pop method
def pop(self, exc=None):
"""Pops the app context."""
self._refcnt -= 1
if self._refcnt <= 0:
if exc is None:
exc = sys.exc_info()[1]
self.app.do_teardown_appcontext(exc)
rv = _app_ctx_stack.pop()
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
% (rv, self)
appcontext_popped.send(self.app)
我不能要求团队中的每个人在处理每一个异常时都调用 sys.exc_info。
我应该怎么做才能避免这种情况?
这确实是 AppContext 处理您的情况的一个错误。
异常在当前帧退出时自动清除(因此在 with
语句之外)。如果您从 with
语句框架内调用另一个函数并在那里处理异常,则当另一个函数退出时,sys.exc_info()
信息将再次被清除。
AppContext.__exit__()
方法被正确通知您处理了异常并将异常值传递给 AppContext.pop()
方法。
因此,Flask AppContext.pop()
方法应该使用 不同的 标记值来检测没有传入异常;它可以检测到 None
不是作为默认值而是作为实际值传入的,表明没有引发异常或未正确处理。
我 filed an issue with the project requesting that this is implemented, with accompanying pull request。这已合并并将成为 Flask 未来版本的一部分。
您可以使用 monkeypatch 将其反向移植到当前的 Flask 版本:
from flask import app, ctx
import sys
if ctx.AppContext.pop.__defaults__ == (None,):
# unpatched
_sentinel = object()
def do_teardown_appcontext(self, exc=_sentinel):
if exc is _sentinel:
exc = sys.exc_info()[1]
for func in reversed(self.teardown_appcontext_funcs):
func(exc)
app.appcontext_tearing_down.send(self, exc=exc)
app.Flask.do_teardown_appcontext = do_teardown_appcontext
def pop(self, exc=_sentinel):
"""Pops the app context."""
self._refcnt -= 1
if self._refcnt <= 0:
if exc is _sentinel:
exc = sys.exc_info()[1]
self.app.do_teardown_appcontext(exc)
rv = ctx._app_ctx_stack.pop()
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
% (rv, self)
ctx.appcontext_popped.send(self.app)
ctx.AppContext.pop = pop
这是我的代码:
import sys
class App(object):
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, tb):
print sys.exc_info()
app = App()
with app:
try:
1/0
except:
print 'Caught you'
#sys.exc_clear()
另一个使用 Flask 应用上下文的例子:
from flask import Flask
app = Flask(__name__)
@app.teardown_appcontext
def teardown(exception):
print exception
with app.app_context():
try:
1 / 0
except:
pass
奇怪的是,如果我在处理异常时没有调用 sys.exc_clear,那么当退出应用程序时,sys.exc_info 仍然会 return 异常信息。
有什么办法可以避免这种情况吗?
在我基于flask的项目中,当出现异常时,我会回滚事务。虽然我处理了异常,但应用程序上下文仍然可以使用 sys.exc_info 获取它,如下面的代码所示:
#AppContext pop method
def pop(self, exc=None):
"""Pops the app context."""
self._refcnt -= 1
if self._refcnt <= 0:
if exc is None:
exc = sys.exc_info()[1]
self.app.do_teardown_appcontext(exc)
rv = _app_ctx_stack.pop()
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
% (rv, self)
appcontext_popped.send(self.app)
我不能要求团队中的每个人在处理每一个异常时都调用 sys.exc_info。
我应该怎么做才能避免这种情况?
这确实是 AppContext 处理您的情况的一个错误。
异常在当前帧退出时自动清除(因此在 with
语句之外)。如果您从 with
语句框架内调用另一个函数并在那里处理异常,则当另一个函数退出时,sys.exc_info()
信息将再次被清除。
AppContext.__exit__()
方法被正确通知您处理了异常并将异常值传递给 AppContext.pop()
方法。
因此,Flask AppContext.pop()
方法应该使用 不同的 标记值来检测没有传入异常;它可以检测到 None
不是作为默认值而是作为实际值传入的,表明没有引发异常或未正确处理。
我 filed an issue with the project requesting that this is implemented, with accompanying pull request。这已合并并将成为 Flask 未来版本的一部分。
您可以使用 monkeypatch 将其反向移植到当前的 Flask 版本:
from flask import app, ctx
import sys
if ctx.AppContext.pop.__defaults__ == (None,):
# unpatched
_sentinel = object()
def do_teardown_appcontext(self, exc=_sentinel):
if exc is _sentinel:
exc = sys.exc_info()[1]
for func in reversed(self.teardown_appcontext_funcs):
func(exc)
app.appcontext_tearing_down.send(self, exc=exc)
app.Flask.do_teardown_appcontext = do_teardown_appcontext
def pop(self, exc=_sentinel):
"""Pops the app context."""
self._refcnt -= 1
if self._refcnt <= 0:
if exc is _sentinel:
exc = sys.exc_info()[1]
self.app.do_teardown_appcontext(exc)
rv = ctx._app_ctx_stack.pop()
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
% (rv, self)
ctx.appcontext_popped.send(self.app)
ctx.AppContext.pop = pop