在Python中封装异常

时间:2014-11-02 10:47:07

标签: python python-2.7 exception pip

如何将应用程序与使用过的库依赖项中的异常分离?

[app] --uses--> [lib] --dependson--> [dependency]
                                           / /
  x- <-propagates--o <---throwsexception--' /
   \                                       /
    `-----needstohandle,soimports-----> --'

问题来自真正的pip代码:

  1. 模块A(req / req_set.py)depends on module B
  2. 模块B(下载)uses module C(请求)
  3. 模块A imports模块C to handle exception from C
  4. 如何在模块B中封装异常?要从模块A中删除对C的依赖?如何确保原始异常的原因和细节不会丢失?换句话说,如何用不同的名称重新引用异常?

    下面的代码片段可以满足需要,但它仅适用于Python 3:

     try:
         dependency_call()
     except DependencyError as exc:
         raise LibraryError from exc
    

    更新:我正在寻找与Python 2兼容的解决方案,Python 3添加了raise ... from ...,这种技巧几乎可以实现。

    UPDATE 2 :封装异常的目的是在[lib]中捕获它并重新抛出一个新的[app]来保留堆栈跟踪,以便调试工具可以仍然走上代码(对于仅限人类的解决方案the answer by Alex Thornton应该是好的)。

2 个答案:

答案 0 :(得分:3)

您可以通过引用Exception基类来捕获任意异常:

except Exception as exc:
    raise ApplicationError from exc

要让from成语在Python 2中运行,您将不得不破解自定义异常:

class ApplicationError(Exception):
    def __init__(self, cause, trace):
        self.cause = cause
        self.trace = trace
    def __str__(self):
        return '{origin}\nFrom {parent}'.format(origin=self.trace, 
                                                parent=self.cause)

然后像这样举起来:

 except Exception, exc:
     raise ApplicationError(exc)

然后它会在引发cause时打印出来,如果您决定捕获ApplicationError,也可以访问该属性。

答案 1 :(得分:0)

如果我确实让你做对了,你想更强烈地解耦并消除:

from pip._vendor import requests

except requests.HTTPError as exc:

你可以通过引入最后的回退处理程序来做到这一点 除了以下所有条款的最后except

try:...
except A:
...   # here all your other exceptions
except Exception as exc:    # the fall-back handler
    if "HTTPError" in repr(exc):
       # do whatever you want to do with the (assumed) request.HTTPError
       # any other Exception with HTTPError in it's repr-string will be
       # caught here

缺点是,它仍然紧密耦合,明显违反了 “得墨忒耳法则”,因为你需要知道一些物体的内部结构 在对象组成中甚至都没有。所以在某种意义上说现在更糟糕了。