使用subprocess.check_output运行 flake8



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

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:UserscalumAppDataLocalProgramsPythonPython38libsubprocess.py", line 411, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
File "C:UserscalumAppDataLocalProgramsPythonPython38libsubprocess.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,但是,我担心如果不正确理解它,我会遇到同样的问题。

提前谢谢。

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

但这也带来了另一个有趣的观点,你为什么要收集输出? 如果你让输出转到 stdout,它将自动打印:

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的当前维护者(

最新更新