简体   繁体   English

如何从Python中的exec或execfile获取错误的行号

[英]how to get the line number of an error from exec or execfile in Python

Let's say I have the following multi-line string: 假设我有以下多行字符串:

cmd = """
    a = 1 + 1
    b = [
       2 + 2,
       4 + 4,
    ]
    bork bork bork
"""

and I want to execute it in a particular scope: 我想在特定范围内执行它:

scope = {}
exec( cmd, scope )
print scope[ 'b' ]

There's a SyntaxError at line 6 of the command, and I want to be able to report that to the user. 在命令的第6行有一个SyntaxError ,我希望能够向用户报告。 How do I get the line number? 我如何获得行号? I've tried this: 我试过这个:

try:
    exec( cmd, scope )  # <-- let's say this is on line 123 of the source file
except Exception, err:
    a, b, c = sys.exc_info()
    line_number = c.tb_lineno  # <-- this gets me 123,  not 6
    print "%s at line %d (%s)" % ( a, line_number, b.message )

...but I get the line number of the exec statement, not the line number within the multi-line command. ...但是我得到了exec语句的行号,而不是多行命令中的行号。

Update: it turns out the handling of the type of exception that I arbitrarily chose for this example, the SyntaxError , is different from the handling of any other type. 更新:事实证明,我为此示例任意选择的异常类型的处理, SyntaxError ,与处理任何其他类型不同。 To clarify, I'm looking a solution that copes with any kind of exception. 为了澄清,我正在寻找一种能够应对任何异常的解决方案。

For syntax errors, the source line number is available as the lineno flag on the exception object itself, in your case stored in err . 对于语法错误,源行号可用作异常对象本身的lineno标志,在您的情况下存储在err This is specific to syntax errors where the line number is an integral part of the error: 这特定于语法错误,其中行号是错误的组成部分:

>>> cmd = """
... 1 \ +
... 2 * "
... """
>>> try:
...   exec cmd
... except SyntaxError as err:
...   print err.lineno
... 
2

If you want to also handle other errors, add a new except block except Exception, err , and use the traceback module to compute the line number for the runtime error. 如果还要处理其他错误,请添加except Exception, err的新except块,并使用traceback模块计算运行时错误的行号。

import sys
import traceback

class InterpreterError(Exception): pass

def my_exec(cmd, globals=None, locals=None, description='source string'):
    try:
        exec(cmd, globals, locals)
    except SyntaxError as err:
        error_class = err.__class__.__name__
        detail = err.args[0]
        line_number = err.lineno
    except Exception as err:
        error_class = err.__class__.__name__
        detail = err.args[0]
        cl, exc, tb = sys.exc_info()
        line_number = traceback.extract_tb(tb)[-1][1]
    else:
        return
    raise InterpreterError("%s at line %d of %s: %s" % (error_class, line_number, description, detail))

Examples: 例子:

>>> my_exec("1+1")  # no exception
>>>
>>> my_exec("1+1\nbork")
...
InterpreterError: NameError at line 2 of source string: name 'bork' is not defined
>>>
>>> my_exec("1+1\nbork bork bork")
...
InterpreterError: SyntaxError at line 2 of source string: invalid syntax
>>>
>>> my_exec("1+1\n'''")
...
InterpreterError: SyntaxError at line 2 of source string: EOF while scanning triple-quoted string

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM