简体   繁体   English

在Bash调用中处理特定的Python错误?

[英]Handling specific Python error within Bash call?

I am using the line_profiler , which allows you to drop @profile decorators anywhere in a python codebase and returns line output. 我正在使用line_profiler ,它允许您在Py​​thon代码库中的任何位置放置@profile装饰器,并返回行输出。

However, if you try to execute python code that contains one such @profile decorator without loading this line_profiler module, the code will fail with a NameError, for such a decorator is defined and injected by this external library. 但是,如果您尝试执行包含一个此类@profile装饰器的python代码而不加载该line_profiler模块,则该代码将失败,并出现NameError,因为此类装饰器是由此外部库定义和注入的。

I'd like a bash command that attempts to run my python script with vanilla python. 我想要一个bash命令,尝试使用香草python运行我的python脚本。 Then, if and only if the error consists of NameError , I want to give it a second try. 然后,当且仅当错误包含NameError ,我才想再次尝试一下。 This is what I have got so far: 到目前为止,这是我得到的:

python -u $file || python -m kernprof -l -v --outfile=/dev/null $file"

The problem is of course that if my python code has ANY errors at all, be it ValueError or IndentationError or anything, it tries the profiler. 问题当然是,如果我的python代码根本没有任何错误,无论是ValueError还是IndentationError或其他任何错误,它都会尝试探查器。 I want to ONLY run the profiler if the error contains a string NameError: name 'profile' is not defined is found within stderr . 如果错误包含字符串NameError: name 'profile' is not defined我只想运行探查器NameError: name 'profile' is not definedstderr NameError: name 'profile' is not defined找到NameError: name 'profile' is not defined

Wouldn't be better to monkey patch profile when no line_profiles is present ? 没有line_profiles时,猴子补丁配置文件会更好吗?

Something like 就像是

try:
    import line_profiles
except:
    import warnings
    warnings.warn("Profile disabled")

    def profile(fn):
        def wrapper(*args, **kw):
            return fn(*args, **kw)
        return wrapper

This way your code runs in either case without complicating matters. 这样,无论哪种情况,您的代码都可以运行而不会使事情复杂化。

Here's a usable Bash solution that preserves stdout and stderr as separate streams (with the caveat that stderr appears after stdout ) and only checks stderr for the error message (which probably is overkill though). 这是一个可用的Bash解决方案,它将stdoutstderr保留为单独的流(带有警告, stderrstdout之后出现),并且仅检查stderr是否显示错误消息(尽管这可能是过大的)。

It goes the easy route and simply saves the stderr output to a file. 它很简单,只需将stderr输出保存到文件即可。 It also handles script names that contain spaces (by properly quoting variable expansions where needed) and/or start with - (by passing -- before the filename to switch off flag processing) as it's an OCD pet peeve of mine. 它还处理包含空格的脚本名称(通过在需要的地方适当地引用变量扩展名)和/或以-开头(通过在文件名前传递--以关闭标志处理),因为它是我的OCD petpeeve。

On success or if there is an error that is not the expected error, the stderr of the first python command is shown. 成功执行后,或者如果出现的错误不是预期的错误,则显示第一个python命令的stderr Otherwise (for the expected error), it is hidden. 否则(针对预期的错误)将被隐藏。

Usage is $ ./check <script> . 用法是$ ./check <script>

#!/bin/bash

if [[ $# -ne 1 ]]; then
    echo "Expected one argument: the script" >&2
    exit 1
fi

script=$1

if [[ ! -e $script ]]; then
    echo "'$script' does not exist or is not a regular file" >&2
    exit 1
fi

if ! python -- "$script" 2>saved_stderr &&
   grep -q "NameError: name 'profile' is not defined" saved_stderr; then

    # Try again with the kernprof module.
    python -m kernprof -l -v --outfile=/dev/null -- "$script"

else
    # Either success or an unexpected error. Show stderr.
    cat saved_stderr >&2
fi

rm saved_stderr
  • To check if the return status of a command is zero (ie, success), it suffices to do 要检查命令的返回状态是否为零(即成功),只需执行

     if <cmd>; then <if successful>; fi` 

    ! negates the exit status, so if ! <cmd> ... 否定退出状态,所以if ! <cmd> ... if ! <cmd> ... can be used to check for failure. if ! <cmd> ...可用于检查故障。 ! only applies to the python command above, not all of python ... && grep ... . 仅适用于上述python命令,不适用于python ... && grep ...

  • >&2 redirects stdout to stderr . >&2stdout重定向到stderr (It's the same as 1>&2 but saves a single character, which is a bit silly, but I included for illustrative purposes as it's a common idiom.) (它与1>&2相同,但是保存了一个字符,这有点愚蠢,但是出于说明目的,我将其包括在内是因为这是一个常见的习惯用法。)

Creating a simple Python wrapper would seem a lot more straightforward, because inside Python, you have access to the things which go wrong. 创建一个简单的Python包装器似乎要简单得多,因为在Python中,您可以访问出现问题的地方。

Assuming your $file uses the common __name__ == '__main__' idiom something like this: 假设您的$file使用通用的__name__ == '__main__'惯用法,如下所示:

if __name__ == '__main__':
    main()

you can create a wrapper something like 你可以创建一个包装像

import yourfile
try:
    file.main()
except NameError:
    import kernprof
    # hack hack, quickly constructed from looking at main() in kernprof.py
    prof = kernprof.ContextualProfile()
    execfile_ = execfile
    ns = locals()
    try:
        prof.runctx('execfile_(%r, globals())' % (yourfile,), ns, ns)
    finally:
        prof.print_stats()

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

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