Python вызывает подпроцесс, который не требует виртуальной среды - PullRequest
1 голос
/ 18 апреля 2019

У меня есть скрипт Python 3.6, который вызывает сторонний инструмент с помощью подпроцесса.

main_script.py:

#!/usr/bin/env python
import subprocess
result = subprocess.run(['third-party-tool', '-arg1'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

Проблема в том, что main_script.py должен быть запущен из виртуальной среды, а third-party-tool должен быть запущен из любой виртуальной среды.

Я не знаю много о third-party-tool, за исключением того, что он на моем пути. Вызов его, когда у меня активна виртуальная среда, вызывает его заклинивание и последующее исключение. Я не знаю, использует ли он двоичный файл Python по умолчанию, или он раскручивает свой собственный виртуальный env и делает что-то там. Это не скрипт Python, но, очевидно, как-то его вызывает.

Как я могу сказать подпроцессу выйти из моей виртуальной среды и запустить команду в среде оболочки по умолчанию?

Я изучил пару похожих вопросов:

Ответы [ 2 ]

1 голос
/ 18 апреля 2019

Из документации подпроцесса:

https://docs.python.org/3/library/subprocess.html

Допустимые аргументы:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None,
    capture_output=False, shell=False, cwd=None, timeout=None, check=False,
    encoding=None, errors=None, text=None, env=None, universal_newlines=None)

В частности,

Еслиenv - это не None, это должно быть отображение, определяющее переменные среды для нового процесса;они используются вместо поведения по умолчанию наследования среды текущего процесса.Он передается непосредственно Попену.

Таким образом, передача пустого словаря env={} (начать с пустой среды) и использование bash --login (запуск в качестве оболочки входа в систему, которая читает значения по умолчанию для env) должен выполнитьтрюк.

subprocess.run(['bash', '--login', '-c', '/full/path/to/third-party-tool', '-arg1'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env={})
0 голосов
/ 19 апреля 2019

Спасибо за вашу помощь, nullUser; Ваше решение является кратким и правильным ответом на мой вопрос.

Однако, когда я опробовал его, мой сторонний инструмент теперь выходит из строя по какой-то другой (неизвестной) причине. Вероятно, была другая переменная окружения, о которой я не знаю, которая теряется в новой оболочке. К счастью, я нашел альтернативное решение, которым я поделюсь для всех, кто борется.

Мое решение

Насколько я могу судить, единственное отличие, которое делает вход в виртуальную среду для моей среды, заключается в добавлении нового пути к моей переменной PATH и добавлении переменной VIRTUAL_ENV.

Я могу реплицировать поведение внешней виртуальной среды, создав копию своей среды, в которой я:

  • удалить эту переменную среды VIRTUAL_ENV и
  • удалить префикс python из PATH.

Пример

my_script.py

my_script.py Реализует мое решение:

#!/usr/bin/env python
import subprocess, os, sys

env = os.environ.copy()
if hasattr(sys,'real_prefix'):
    # If in virtual environment, gotta forge a copy of the environment, where we:
    # Delete the VIRTUAL_ENV variable.
    del(env['VIRTUAL_ENV'])

    # Delete the "/home/me/.python_venv/main/bin:" from the front of my PATH variable.
    orig_path = env['PATH']
    virtual_env_prefix = sys.prefix + '/bin:'
    env['PATH'] = orig_path.replace(virtual_env_prefix, '')

# Pass the environment into the third party tool, modified if and when required.
subprocess.run(['./third-party-tool'], shell=False, env=env)

третья сторона-инструмент

third-party-tool смоделирован как скрипт, который сообщает вам, находится ли он в виртуальной среде, и распечатывает переменные среды. В этом примере third-party-tool является скриптом Python, но в общем случае это может быть не так.

#!/usr/bin/env python
# third-party-tool
import sys, os
in_venv = hasattr(sys, 'real_prefix')
print('This is third-party Tool and you {} in a virtual environment.'.format("ARE" if in_venv else "ARE NOT"))
os.system('env')

Тестирование

Теперь я пытаюсь вызвать сторонний инструмент из-за пределов виртуальной среды, изнутри виртуальной среды и из скрипта Python в виртуальной среде, захватив выходные данные.

[me@host ~]$ ./third-party-tool > without_venv.txt
# Now I activate virtual environment
(main) [me@host ~]$ ./third-party-tool > within_venv.txt
(main) [me@host ~]$ ./my_script.py > within_venv_from_python.txt

Примечание: выходные данные выглядят так: Это сторонний инструмент, и вы НЕ находитесь в виртуальной среде. (Приступает к выводу списка переменных среды KEY = VALUE)

Я использую мой любимый инструмент сравнения и сравниваю результаты. within_venv_from_python.txt идентичен without_venv.txt, что является хорошим признаком (в обоих случаях third-party-tool работает с одинаковыми переменными среды и указывает, что он не живет в матрице). После реализации этого решения мой настоящий сторонний инструмент работает.

...