如何调试ast.literal_eval中的错误?

sds*_*sds 5 python serialization abstract-syntax-tree python-2.7

我使用将数据写入文件,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
Run Code Online (Sandbox Code Playgroud)

如何修复此特定文件?

该文件的大小为17,000行/ 700kb。我将其加载到Emacs中-parens是平衡的。文件中没有非ASCII字符。我可以“分而治之”(将文件分成两半,然后尝试实现每一半)-但这很繁琐。有更好的吗?

我进行了修改,ast.literal_eval:_convert以打印出有问题的节点-原来是<_ast.UnaryOp object at 0x110696510>。不是很有帮助。

我如何确保将来不会发生这种情况?

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

我没有使用,JSON因为

  1. JSON无法处理非字符串字典键
  2. JSON插入的换行过多或完全没有

sds*_*sds 5

又快又脏

应用此补丁:

--- /...../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)
 
Run Code Online (Sandbox Code Playgroud)

重新加载ast

>>> reload(ast)
Run Code Online (Sandbox Code Playgroud)

重试加载有问题的文件

得到

ValueError: ('malformed string', 21161, 10)
Run Code Online (Sandbox Code Playgroud)

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

已提交错误报告

复杂的

将代码包裹在 中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))
Run Code Online (Sandbox Code Playgroud)

印刷

ERROR: ValueError('malformed string')
Error location: line=21933, col=15
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案。这确实应该是模块的默认行为 (2认同)