【问题标题】:How do I debug an error in `ast.literal_eval`?如何调试 `ast.literal_eval` 中的错误?
【发布时间】:2017-10-25 13:40:08
【问题描述】:

我使用pprint.PrettyPrinter 将我的数据写入文件,并尝试使用ast.literal_eval 读取它。 这已经为我工作了很长一段时间,我对生成的文本表示相当满意。

但是,今天我在反序列化时遇到了这个错误:

  File "/...mypath.../store.py", line 82, in <lambda>
    reader=(lambda fd: ast.literal_eval(fd.read())),
  File "/usr/lib64/python2.7/ast.py", line 80, in literal_eval
    return _convert(node_or_string)
  File "/usr/lib64/python2.7/ast.py", line 60, in _convert
    return list(map(_convert, node.elts))
  File "/usr/lib64/python2.7/ast.py", line 63, in _convert
    in zip(node.keys, node.values))
  File "/usr/lib64/python2.7/ast.py", line 62, in <genexpr>
    return dict((_convert(k), _convert(v)) for k, v
  File "/usr/lib64/python2.7/ast.py", line 63, in _convert
    in zip(node.keys, node.values))
  File "/usr/lib64/python2.7/ast.py", line 62, in <genexpr>
    return dict((_convert(k), _convert(v)) for k, v
  File "/usr/lib64/python2.7/ast.py", line 79, in _convert
    raise ValueError('malformed string')
ValueError: malformed string

如何修复这个特定文件?

有问题的文件是 17k 行/700kb。 我将它加载到 Emacs 中——括号是平衡的。 文件中没有非 ASCII 字符。 我可以“分而治之”(将文件分成两半并尝试真实每一半)——但这相当乏味。 有没有更好的?

我修改了ast.literal_eval:_convert 以打印有问题的节点 - 结果是&lt;_ast.UnaryOp object at 0x110696510&gt;。不是很有帮助。

如何确保以后不会发生这种情况?

我希望JSON 不是答案。 ;-)

我没有使用JSON,因为

  1. JSON cannot handle non-string dict keys
  2. JSON inserts either too many newlines or none at all

【问题讨论】:

  • 如果您能获得对违规节点的引用,请打印出其 linenocol_offset 属性 - 这应该可以告诉您问题的确切位置。
  • 您能展示一个(简化的)文件示例吗?
  • @SergeBallesta 问题是关于试图找出文件中的问题所在。该文件的简化版本可能根本不会出现错误。
  • 快速猜测,可能会也可能不会:在您的文件中搜索setast.literal_eval 无法处理空集。
  • @jasonharper:是的,做到了。谢谢!问题是我触发了一个已知的bug:ast.literal_eval(str(float("inf")))(请将您的评论转换为答案,我很乐意接受)

标签: python python-2.7 serialization abstract-syntax-tree


【解决方案1】:

又快又脏

应用此补丁:

--- /...../2.7/lib/python2.7/ast.py.old 2018-03-25 12:17:11.000000000 -0400
+++ /...../2.7/lib/python2.7/ast.py 2018-03-25 12:17:18.000000000 -0400
@@ -76,7 +76,7 @@ def literal_eval(node_or_string):
                 return left + right
             else:
                 return left - right
-        raise ValueError('malformed string')
+        raise ValueError('malformed string', node.lineno, node.col_offset)
     return _convert(node_or_string)
 

重新加载ast:

>>> reload(ast)

重试加载有问题的文件

获取

ValueError: ('malformed string', 21161, 10)

然后第 21161 行,第 10 列是错误所在。

Bug report submitted.

精致

将代码包装在try/except 中,捕获错误并使用inspect/traceback 访问有问题的node

try:
    ast.literal_eval(...)
except ValueError as ex:
    _exc_type, exc_value, exc_traceback = sys.exc_info()
    print("ERROR: %r" % (exc_value))
    # traceback.print_tb(exc_traceback)
    last_tb = exc_traceback
    while last_tb.tb_next:
        last_tb = last_tb.tb_next
    print("Error location: line=%d, col=%d" % (
        last_tb.tb_frame.f_locals["node"].lineno,
        last_tb.tb_frame.f_locals["node"].col_offset))

打印

ERROR: ValueError('malformed string')
Error location: line=21933, col=15

【讨论】:

  • 很好的答案。这应该是模块的默认行为
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-20
  • 2013-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-18
相关资源
最近更新 更多