【问题标题】:How to automatically generate assertion information?如何自动生成断言信息?
【发布时间】:2019-01-31 22:21:41
【问题描述】:

在python中,每当我使用断言并触发它时,我只会得到一个丑陋的信息:

AssertionError

我应该怎么做才能通过解析条件参数的 AST 来自动生成解释错误原因的消息?

例如:所以

assert 2 == 3

原因:

AssertionError: 2 != 3

【问题讨论】:

  • 只用pytest吗?
  • 我想,但我不确定 pytest 是否会支持 jupyter notebook :-
  • 如果 jupyter 支持是一个限制,你真的应该 在问题中

标签: python python-3.x assertion


【解决方案1】:

如果依赖是一个问题,您可以自己轻松解决。即:

def assert_eq(x, y):
  if x != y:
    print('error: {} != {}'.format(x, y))
  assert x == y

【讨论】:

    【解决方案2】:

    实现目标的一种简单方法是使用将断言条件作为字符串参数的包装函数,这样您就可以eval 它和assert 结果,同时将AssertionError 捕获在try 块,以便您可以使用给定字符串作为消息重新引发异常:

    def my_assert(condition):
        try:
            assert eval(condition)
        except AssertionError as e:
            e.args = condition,
            raise
    

    这样:

    my_assert('2 == 3')
    

    会提高:

    AssertionError: 2 == 3
    

    【讨论】:

    • 我认为需要更多细节来展示它如何与 x 和 y 一起工作。如果使用“x == y”调用,此函数将不知道这些变量`
    • 不需要。条件作为字符串传入,并且直接是eval'd,因此由 Python 编译器来解释它。这个答案没有做的是用与给定条件相反的条件引发错误(所以2 == 3 报告为2 != 3),这是 OP 所说的他/她想要的,但我不认为对于他/她的目的是必要的。
    • eval 具有安全隐患。请考虑使用ast.literal_eval。见stackoverflow.com/a/15197698/2958070
    • @Ben 除非您的所有断言都是针对常量的,否则ast.literal_eval 不适合此目的,因为变量名称可能涉及给定条件,ast.literal_eval 将无法解决。断言无论如何都是用于开发的,生产代码应该去掉断言,所以安全性首先不应该是一个问题。
    • @blhsing 我没有意识到变量与ast.literal_eval 搞混了,谢谢。
    【解决方案3】:

    由于AssertionError 是一个类,你可以派生出你自己的类来做你想做的事。棘手的部分是将它连接起来,以便解释器将它与assert statment 一起使用。

    这里有一些似乎可行,但我不知道与 jupyter notebook 结合使用时是否会出现这种情况。

    import builtins
    import traceback
    
    
    class MyAssertionError(builtins.AssertionError):
        def __init__(self, *args):
            super(MyAssertionError, self).__init__(*args)
            raw_tb = traceback.extract_stack()
            entries = traceback.format_list(raw_tb)
    
            # Remove the last two entries for the call to extract_stack(). Each
            # entry consists of single string with consisting of two lines, the
            # script file path then the line of source code making the call to this
            # function.
            del entries[-2:]
            self.lines = '\n'.join(entries)
    
        def __str__(self):
            return super(MyAssertionError, self).__str__() + '\n' + self.lines
    
    builtins.AssertionError = MyAssertionError  # Replace builtin.
    
    
    if __name__ == '__main__':
    
        assert 2 == 3
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-09
      • 2016-05-02
      相关资源
      最近更新 更多