【问题标题】:Using subprocess.check_output to run flake8使用 subprocess.check_output 运行 flake8
【发布时间】:2019-12-25 20:05:20
【问题描述】:

我正在尝试制作一个可以在当前目录中的 Python 文件上运行的基本 linter 脚本。到目前为止,我的脚本如下所示:

import subprocess
from os import listdir
from os.path import isfile, join

if __name__ == "__main__":
    subprocess.check_output(["black", "-l", "100", "./"])

    files = [f for f in listdir("./") if isfile(join("./", f))]
    for file in files:
        if file.endswith(".py"):
            subprocess.check_output(["flake8", file])

我想通过命令行运行代码,例如 main.py。 Black 执行良好,在当前目录中找到 .py 文件并毫无问题地对其进行格式化。但是,当尝试使用 flake8 运行类似命令时,它也会在目录的子目录上运行,例如我不感兴趣的 venv 文件夹。

因此,该脚本包含一个检查以获取当前目录中的文件,然后找到 .py 文件。但是,一旦获得这些文件,我似乎无法将 flake8 命令与 subprocess.check_output 一起使用。我得到的错误如下:

Traceback (most recent call last):
  File "linter.py", line 18, in <module>
    subprocess.check_output(["flake8", file], shell=False)
  File "C:\Users\calum\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 411, in check_output
    return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
  File "C:\Users\calum\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 512, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['flake8', 'flask_server_controller.py']' returned non-zero exit status 1.

有人可以解释错误和/或为我的问题提供解决方案吗?我还想在脚本中添加其他 linting 工具,例如 pylint,但是我担心如果没有正确理解会遇到同样的问题。

提前致谢。

【问题讨论】:

  • 在控制台自己运行'flake8 flask_server_controller.py',查看错误。我假设您需要将完整路径传递给 flake 并确保 flake 在您的 env/path 变量中
  • 您是否有理由不使用实际上适合此任务的工具,例如 shell 脚本?
  • @MauriceMeyer 感谢您的回复。如果我按照建议运行上面的命令 flake8 适用于文件。没有错误,因此,我认为这不是片状或 env 问题。
  • @tripleee 没有主要原因。我在其他一些帖子上看到说 shell 脚本不是一个好主意,但由于我的经验很少,请随时提供使用它的答案。我尝试将标志 shell=True 添加到 subprocess.check_output(["flake8", file], shell=True) 中,但是,这没有任何区别。
  • 检查flask_server_controller.py 的路径或查看stderr,如其中所述:stackoverflow.com/questions/16198546/…exit status 1 绝对是 flake8 的“回应”。

标签: python subprocess flake8


【解决方案1】:

subprocess.check_output 之所以给你是因为check_ 方面

这意味着当您运行的可执行文件返回非零时(例如,flake8 在检测到 lint 故障时返回非零)将引发异常

为避免这种行为,我建议改用subprocess.run,并沿返回码转发。像这样的:

import os
import subprocess
import sys


def main():
    ret = 0
    output = b''
    for filename in os.listdir('.'):
        if filename.endswith('.py'):
            proc_ret = subprocess.run(
                ('flake8', filename),
                stdout=subprocess.PIPE,
            )
            ret |= proc_ret.returncode
            output += proc_ret.stdout
    sys.stdout.buffer.write(output)
    return ret


if __name__ == '__main__':
    exit(main())

请注意,这会非常慢,您必须为每个文件承担flake8 的启动成本。

改善这一点的一种方法是一次将所有文件名传递给 flake8:

import os
import subprocess
import sys


def main():
    filenames = (fname for fname in os.listdir('.') if fname.endswith('.py'))
    proc_ret = subprocess.run(('flake8', *filenames), stdout=subprocess.PIPE)
    sys.stdout.buffer.write(proc_ret.stdout)
    return proc_ret.returncode


if __name__ == '__main__':
    exit(main())

但这也带来了另一个有趣的点,你为什么要收集输出?如果您让输出进入标准输出,它将自动打印:

import os
import subprocess


def main():
    filenames = (fname for fname in os.listdir('.') if fname.endswith('.py'))
    return subprocess.call(('flake8', *filenames))


if __name__ == '__main__':
    exit(main())

嗯,您可能根本不需要这样做,因为flake8 有自己的包含/排除代码——您可能只想正确配置exclude

# setup.cfg / tox.ini / .flake8
[flake8]
# for example, exclude recursing into the venv
exclude = venv

然后你就可以正常使用flake8 .

(免责声明:我是 flake8 的当前维护者)

【讨论】:

  • 感谢您的回复。我设法解决了查看不同帖子的问题,但您提出的一些观点我将更改和实施。感谢您的帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-16
  • 1970-01-01
  • 2021-04-04
  • 1970-01-01
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
相关资源
最近更新 更多