Модулю подпроцесса не удается запустить команду

#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 завершится ошибкой при попытке «импортировать сайт» (что интерпретатор делает автоматически), поскольку он находит a site.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()