我正在尝试在一组文件上执行Google的cpplint.py,并将结果收集到一个日志文件中。但是,我还没有成功击败子进程模块。我目前的代码在这里:
import os, subprocess
rootdir = "C:/users/me/Documents/dev/"
srcdir = "project/src/"
with open(rootdir+srcdir+"log.txt", mode='w', encoding='utf-8') as logfile:
for subdir, dirs, files in os.walk(rootdir+srcdir):
for file in files:
if file.endswith(".h") or file.endswith(".cpp"):
filewithpath=os.path.join(subdir, file)
cmd=['c:/Python27/python.exe','C:/users/me/Documents/dev/cpplint.py','--filter=-whitespace,-legal,-build/include,-build/header_guard/', filewithpath]
output = subprocess.check_output(cmd)
logfile.write(output.decode('ascii'))
尝试运行上面的代码会引发错误:
File "C:\Python32\lib\site.py", line 159
file=sys.stderr)
^ SyntaxError: invalid syntax Traceback (most recent call last): File "C:\Users\me\Documents\dev\project\src\verifier.py", line 19, in <module>
output = subprocess.check_output(cmd) File "C:\Python32\lib\subprocess.py", line 511, in check_output
raise CalledProcessError(retcode, cmd, output=output) subprocess.CalledProcessError: Command '['c:/Python27/python.exe', 'C:/users/me/Documents/dev/cpplint.py', '--filter=-whitespace,-legal,-build/include,-build/header_guard/', 'C:/users/me/Documents/dev/project/src/aboutdialog.cpp']' returned non-zero exit status 1
如果我用简单的东西代替cmd:
cmd=['C:/WinAVR-20100110/bin/avr-gcc.exe','--version']
然后脚本按预期工作。
我还尝试使用单个命令字符串而不是字符串列表作为cmd,但结果是相同的。 在调试代码时,我从调试器复制了list-of-strings-turned-into-the-command-line-command并在Windows命令行中运行它,命令按预期运行。
运行我的脚本的Python解释器是Python 3.2。 任何提示都非常感谢。
答案 0 :(得分:11)
看起来cpplint.py
只是退出非零返回代码 - 例如,如果它在正在检查的源文件中发现错误或“lint”,它可能会这样做。
请参阅subprocess.check_output的文档。请注意,如果执行的命令返回非零退出代码,则会引发subprocess.CalledProcessError
。
你可以通过观察CalledProcessError
来解决这个问题,例如
try:
output = subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
# ack! cpplint.py failed... report an error to the user?
修改强>:
SyntaxError
似乎是关键所在,可能是由C:\Python32\lib
在你的PYTHONPATH中引起的(显式,或者,如果它是你当前的工作目录,可能会发生这种情况)。
Python解释器(大约1.5.2-ish)在启动时会自动运行import site
。因此,在这种情况下,您的脚本将执行:
c:/Python27/python.exe C:/users/me/Documents/dev/cpplint.py ...
然后 Python 2.7 解释器将首先找到C:\Python32\lib\site.py
,并尝试加载它,而不是C:\Python27\lib\site.py
处的那个(大概)。问题是Python 3的site.py
包含与Python 2不兼容的语法,因此subprocess.check_output
启动的进程在它甚至有机会运行cpplint
之前就会失败并出现一个SyntaxError,这会传播CalledProcessError
。
解决方案?确保Python2获得了真正的Python2“PYTHONPATH”,同样适用于Python3!换句话说,运行Python2解释器时,请确保C:\Python32\lib
不在PYTHONPATH搜索路径中。
在您的情况下执行此操作的一种方法是在启动流程时设置显式环境,例如:
python2_env = {"PYTHONPATH": "path/to/python2/stuff:..."}
output = subprocess.check_output(cmd, env=python2_env)
答案 1 :(得分:1)
我会要求你先运行
pipe = subprocess.Popen([cmd, options],stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = pipe.communicate()
您将了解其背后的错误究竟是什么,因为仅当退出代码为非零时才会引发CalledProcessError。
答案 2 :(得分:1)
我通过使用以下内容替换def main()来实现它(我编辑错误函数以获得正确的csv文件):
errorlog = sys.stderr
sys.stderr = open("errorlog.csv","w")
sys.stderr.write("File;Line;Message;Category;Confidence\n")
for filename in filenames:
ProcessFile(filename, _cpplint_state.verbose_level)
_cpplint_state.PrintErrorCounts()
sys.exit(_cpplint_state.error_count > 0)
sys.stdout = errorlog
sys.stderr.close()