如何调试 `ast.literal_eval` 中的错误? [英] How do I debug an error in `ast.literal_eval`?

查看:31
本文介绍了如何调试 `ast.literal_eval` 中的错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 pprint.PrettyPrinter 将数据写入文件 我正在尝试使用 ast.literal_eval.这对我来说已经有一段时间了,我对生成的文本表示相当满意.

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

 文件/...mypath.../store.py",第 82 行,在 <lambda> 中reader=(lambda fd: ast.literal_eval(fd.read())),文件/usr/lib64/python2.7/ast.py",第 80 行,在literal_eval 中返回_convert(node_or_string)文件/usr/lib64/python2.7/ast.py",第 60 行,在 _convert返回列表(地图(_convert,node.elts))文件/usr/lib64/python2.7/ast.py",第 63 行,在 _convert在 zip(node.keys, node.values)) 中的文件/usr/lib64/python2.7/ast.py",第 62 行返回 dict((_convert(k), _convert(v)) for k, v文件/usr/lib64/python2.7/ast.py",第 63 行,在 _convert在 zip(node.keys, node.values)) 中的文件/usr/lib64/python2.7/ast.py",第 62 行返回 dict((_convert(k), _convert(v)) for k, v文件/usr/lib64/python2.7/ast.py",第 79 行,在 _convert引发 ValueError('格式错误的字符串')值错误:格式错误的字符串

如何修复此特定文件?

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

我修改了 ast.literal_eval:_convert 以打印违规节点 - 结果是 <_ast.UnaryOp 对象在 0x110696510>.不是很有帮助.

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

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

我没有使用 JSON 因为

  1. JSON 无法处理非字符串字典键
  2. JSON 插入的换行符过多或根本不插入

解决方案

又快又脏

应用此补丁:

---/...../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 @@ defliteral_eval(node_or_string):返回左 + 右别的:左右返回- 引发 ValueError('格式错误的字符串')+ raise ValueError('malformed string', node.lineno, node.col_offset)返回_convert(node_or_string)

重新加载ast:

<预><代码>>>>重新加载(AST)

重试加载有问题的文件

获取

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

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

已提交错误报告.

精致

将代码包裹在try/except,捕获错误并使用 inspect/traceback 访问<有问题的代码>节点:

尝试:ast.literal_eval(...)除了 ValueError 如:_exc_type, exc_value, exc_traceback = sys.exc_info()打印(错误:%r"%(exc_value))# traceback.print_tb(exc_traceback)last_tb = exc_traceback而 last_tb.tb_next:last_tb = last_tb.tb_next打印(错误位置:行=%d,列=%d"%(last_tb.tb_frame.f_locals[节点"].lineno,last_tb.tb_frame.f_locals[节点"].col_offset))

印刷品

错误:ValueError('格式错误的字符串')错误位置:line=21933, col=15

I wrote my data to a file using pprint.PrettyPrinter and I am trying to read it using ast.literal_eval. This has been working for me for quite some time, and I am reasonably satisfied with the text representation produced.

However, today I got this error on deserialization:

  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

How do I fix this specific file?

The file in question is 17k lines/700kb. I loaded it into Emacs -- the parens are balanced. There are no non-ASCII characters in the file. I can "divide and conquer" (split the file in half and try to real each half) - but this is rather tedious. Is there anything better?

I modified ast.literal_eval:_convert to print the offending node - it turned out to be <_ast.UnaryOp object at 0x110696510>. Not very helpful.

How do I ensure that this does not happen in the future?

I hope JSON is not the answer. ;-)

I am not using JSON because

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

解决方案

Quick and Dirty

Apply this patch:

--- /...../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)
 

Reload ast:

>>> reload(ast)

Retry loading the offending file

Get

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

then line 21161, column 10 is where the error is.

Bug report submitted.

Sophisticated

Wrap the code in try/except, catch the error and use inspect/traceback to access the node in question:

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))

prints

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

这篇关于如何调试 `ast.literal_eval` 中的错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆