#python #python-3.x #subprocess
#python #python-3.x #подпроцесс
Вопрос:
Я пытаюсь выполнить 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:Python32libsite.py", line 159
file=sys.stderr)
^ SyntaxError: invalid syntax Traceback (most recent call last): File "C:UsersmeDocumentsdevprojectsrcverifier.py", line 19, in <module>
output = subprocess.check_output(cmd) File "C:Python32libsubprocess.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, превращенную в команду командной строки, из отладчика и запустил ее в командной строке Windows, и команда выполнялась, как и ожидалось.
Интерпретатор Python, выполняющий мой скрипт, — Python 3.2. Любые советы приветствуются.
Комментарии:
1. используете ли вы флаг shell=True при использовании одной командной строки?
2. Результат тот же, использую ли я shell= True, shell= False или вообще не определяю его.
3. Мне интересно, хорош ли этот способ использования интерпретатора Python 2.6 или нет. Использование
subprocess
— это верный способ выбора версии, но есть ли какой-либо другой способ доступа к полезным функциям этого модуля Python?4. Интересно то, что site.py модуль, на который ссылается исходный SyntaxError, имеет дело с импортом пакетов, что является странным местом для возникновения ошибки такого рода.
5. Используется ли смешанная версия python (cmd= [‘c:/Python27/python.exe ‘ …) вызывает проблему? Когда я запустил его с фиктивным cpplint.py (который просто печатает «привет»), он не получил синтаксическую ошибку, он просто остановился с «возвращенным ненулевым статусом выхода 2».
Ответ №1:
Похоже cpplint.py
, что он просто завершает работу с ненулевым кодом возврата, что он может сделать, например, если обнаружит ошибки или «ворсинки» в исходных файлах, которые он проверяет.
Смотрите Документацию для subprocess.check_output . Обратите внимание, что если выполняемая команда возвращает ненулевой код выхода, тогда subprocess.CalledProcessError
возникает a .
Вы можете обойти это, наблюдая CalledProcessError
, например
try:
output = subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
# ack! cpplint.py failed... report an error to the user?
Редактировать:
SyntaxError
Похоже, что это ключ здесь и, вероятно, вызвано тем C:Python32lib
, что он находится в вашем PYTHONPATH (либо явно, либо это может произойти, если это ваш текущий рабочий каталог).
Интерпретатор Python (начиная примерно с версии 1.5.2) автоматически запускается import site
при запуске. Итак, когда это так, и ваш скрипт переходит к выполнению:
c:/Python27/python.exe C:/users/me/Documents/dev/cpplint.py ...
тогда интерпретатор Python 2.7 найдет C:Python32libsite.py
первым и попытается загрузить его вместо того, который (предположительно) находится в C:Python27libsite.py
. Проблема в том, что Python 3 site.py
содержит синтаксис, несовместимый с Python 2, поэтому процесс, запущенный с помощью subprocess.check_output
, завершается ошибкой SyntaxError еще до того, как он получит возможность запуска cpplint
, что распространяет CalledProcessError
.
Решение? Убедитесь, что Python2 получает добросовестный Python2 «PYTHONPATH», а также для Python3! Другими словами, убедитесь C:Python32lib
, что его нет в пути поиска PYTHONPATH при запуске интерпретатора Python2.
Один из способов сделать это в вашем случае — установить явную среду при запуске процесса, например:
python2_env = {"PYTHONPATH": "path/to/python2/stuff:..."}
output = subprocess.check_output(cmd, env=python2_env)
Комментарии:
1. Я попытался перехватить как CalledProcessError, так и SyntaxError, но безуспешно : (
2. @Manjabes: ошибка синтаксиса любопытна. Что-то, что нужно попробовать: запустите
python -c "import site"
(где ‘python’ — это исполняемый файл Python 3.2, который вы используете для запуска своего скрипта, а не cpplint) и посмотрите, получаете ли вы SyntaxError. Если это так, ваша установка python3 может быть как-то испорчена?3. @Manjabes: я смог повторить ошибку SyntaxError, выполнив
site.py
из библиотек Python 3.2.2, но используя интерпретатор Python 2.x . So… Мне интересно, является ли это корнем ваших проблем? Что произойдет, если вы запустите свой скрипт, используяc:/Python27/python.exe
вместо Python3?4. Также: каков ваш текущий рабочий каталог при запуске этого? Если вы находитесь в
C:Python32lib
(по какой-то причине), python27 завершится ошибкой при попытке «импортировать сайт» (что интерпретатор делает автоматически), поскольку он находит asite.py
в WD перед тем, как на системном уровне. Обратите внимание, чтоC:Python32libsite.py
используется синтаксис, несовместимый с Python2.5. Да, так оно и было. Обычно я использую интерпретатор 3.2 в качестве своего Python по умолчанию и использую его в своем PATH (и его потомки в моем PYTHONPATH). После установки измененной среды для подпроцессов это сработало! Если вы могли бы опубликовать свой комментарий в качестве ответа, я приму его.
Ответ №2:
Я бы попросил вас сначала запустить это
pipe = subprocess.Popen([cmd, options],stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = pipe.communicate()
Вы узнаете, в чем именно заключается ошибка, стоящая за этим, поскольку CalledProcessError вызывается только в том случае, если код выхода отличен от нуля.
Комментарии:
1. stderr пуст, стандартный вывод аналогичен первой ошибке в моем исходном вопросе: File «C:Python32libsite.py «, строка 159 file=sys.stderr) ^ Ошибка синтаксиса: недопустимый синтаксис
2. вы уверены, что хотите ‘—filter=-пробел,-legal,-build / include,-build/ header_guard/’ в качестве одного параметра, или это несколько параметров для программы
3. Даже если я полностью удалю параметр —filter , результат будет тем же.
4. ‘—filter=-пробел’,’-legal’,’-build/include’,’-build/header_guard/’ … таким образом, все параметры будут обрабатываться как разные, а не как отдельные
5. Да, я понимаю, но сценарий, который я пытаюсь вызвать, Ожидает -пробел, -legal и т. Д. Как Часть параметра —filter . В любом случае, как я уже сказал, если я полностью удалю ‘—filter …’ из списка, это не избавит от ошибки.
Ответ №3:
Я сделал это, заменив def main() на следующее (я также отредактировал функцию errorfunction, чтобы получить правильный csv-файл):
errorlog = sys.stderr
sys.stderr = open("errorlog.csv","w")
sys.stderr.write("File;Line;Message;Category;Confidencen")
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()