Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
357 views
in Technique[技术] by (71.8m points)

python - Re-raise exception with a different type and message, preserving existing information

I'm writing a module and want to have a unified exception hierarchy for the exceptions that it can raise (e.g. inheriting from a FooError abstract class for all the foo module's specific exceptions). This allows users of the module to catch those particular exceptions and handle them distinctly, if needed. But many of the exceptions raised from the module are raised because of some other exception; e.g. failing at some task because of an OSError on a file.

What I need is to “wrap” the exception caught such that it has a different type and message, so that information is available further up the propagation hierarchy by whatever catches the exception. But I don't want to lose the existing type, message, and stack trace; that's all useful information for someone trying to debug the problem. A top-level exception handler is no good, since I'm trying to decorate the exception before it makes its way further up the propagation stack, and the top-level handler is too late.

This is partly solved by deriving my module foo's specific exception types from the existing type (e.g. class FooPermissionError(OSError, FooError)), but that doesn't make it any easier to wrap the existing exception instance in a new type, nor modify the message.

Python's PEP 3134 “Exception Chaining and Embedded Tracebacks” discusses a change accepted in Python 3.0 for “chaining” exception objects, to indicate that a new exception was raised during the handling of an existing exception.

What I'm trying to do is related: I need it also working in earlier Python versions, and I need it not for chaining, but only for polymorphism. What is the right way to do this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Python 3 introduced exception chaining (as described in PEP 3134). This allows, when raising an exception, to cite an existing exception as the “cause”:

try:
    frobnicate()
except KeyError as exc:
    raise ValueError("Bad grape") from exc

The caught exception (exc, a KeyError) thereby becomes part of (is the “cause of”) the new exception, a ValueError. The “cause” is available to whatever code catches the new exception.

By using this feature, the __cause__ attribute is set. The built-in exception handler also knows how to report the exception's “cause” and “context” along with the traceback.


In Python 2, it appears this use case has no good answer (as described by Ian Bicking and Ned Batchelder). Bummer.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...