Virtualenv: Скрипты установлены с неправильным шебангом в подпроцессе

Созданный на 20 янв. 2016  ·  27Комментарии  ·  Источник: pypa/virtualenv

На Python 3.5.1, но не на 2.7.10, когда я вызываю pip через подпроцесс в virtualenv, скрипты создаются с неправильным shebang и, таким образом, не запускаются:

$ cat > invoke.py
import sys
import subprocess

subprocess.Popen(sys.argv[1:]).wait()
$ rm -Rf env
$ python -m virtualenv --version
14.0.0
$ python --version
Python 3.5.1
$ python -m virtualenv env
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.5'
New python executable in /Users/jaraco/Dropbox/code/public/aspen/env/bin/python3
Also creating executable in /Users/jaraco/Dropbox/code/public/aspen/env/bin/python
Installing setuptools, pip, wheel...done.
$ python invoke.py env/bin/pip install pytest
Collecting pytest
  Using cached pytest-2.8.5-py2.py3-none-any.whl
Collecting py>=1.4.29 (from pytest)
  Using cached py-1.4.31-py2.py3-none-any.whl
Installing collected packages: py, pytest
Successfully installed py-1.4.31 pytest-2.8.5
$ head -n 1 env/bin/py.test
#!/Library/Frameworks/Python.framework/Versions/3.5/bin/python3

Можно было бы ожидать, что скрипт py.test будет иметь в себе shebang с env.

Использование pyvenv вместо этого не вызывает проблемы. Удаление переменной среды __PYVENV_LAUNCHER__ перед запуском подпроцесса позволяет решить проблему, как описано здесь . Проблема наблюдалась с 13.1.2 и 14.0.0.

Ожидается ли такое поведение? Если да, то подходит ли удаление переменной среды для родительского процесса, чтобы обойти проблему?

Самый полезный комментарий

Меня только что укусила именно эта ошибка. На мой взгляд, это довольно серьезная ошибка, в основном потому, что она очень сбивает с толку и трудно понять, когда она возникает.

Все 27 Комментарий

делает

$ env/bin/pip uninstall pytest
$ env/bin/pip install pytest
$ head -n 1 env/bin/py.test

Давать одинаковые или разные результаты?

И тот же вопрос с

$ env/bin/python -m pip install pytest

?

Возможно, регресс каким-то образом на https://github.com/pypa/virtualenv/issues/322 / https://github.com/pypa/virtualenv/pull/541

В таком случае не могли бы вы проверить,

subprocess.Popen(sys.argv[1:], env={}).wait()

помогает или нет?

Хм, в pip / distlib был код для решения этой проблемы, но он был закомментирован год назад -

https://github.com/pypa/pip/blob/7cea748d0fb2e8980c2676304607426585550b41/pip/_vendor/distlib/util.py#L157 -L165

Давать одинаковые или разные результаты?

В обоих случаях вызов pip напрямую приводит к правильному шебангу:

$ env/bin/pip install pytest
Collecting pytest
  Using cached pytest-2.8.5-py2.py3-none-any.whl
Requirement already satisfied (use --upgrade to upgrade): py>=1.4.29 in ./env/lib/python3.5/site-packages (from pytest)
Installing collected packages: pytest
Successfully installed pytest-2.8.5
$ head -n 1 env/bin/py.test
#!/Users/jaraco/Dropbox/code/public/aspen/env/bin/python3
$ env/bin/pip uninstall -y pytest
Uninstalling pytest-2.8.5:
  Successfully uninstalled pytest-2.8.5
$ env/bin/python -m pip install pytest
Collecting pytest
  Using cached pytest-2.8.5-py2.py3-none-any.whl
Requirement already satisfied (use --upgrade to upgrade): py>=1.4.29 in ./env/lib/python3.5/site-packages (from pytest)
Installing collected packages: pytest
Successfully installed pytest-2.8.5
$ head -n 1 env/bin/py.test
#!/Users/jaraco/Dropbox/code/public/aspen/env/bin/python

Также работает вызов с пустым env:

$ cat invoke.py 
import sys
import os
import subprocess

env = dict(os.environ)
env.pop('__PYVENV_LAUNCHER__')
env = {}

subprocess.Popen(sys.argv[1:], env=env).wait()
$ python -m virtualenv env
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.5'
New python executable in /Users/jaraco/Dropbox/code/public/aspen/env/bin/python3
Also creating executable in /Users/jaraco/Dropbox/code/public/aspen/env/bin/python
Installing setuptools, pip, wheel...done.
$ python invoke.py env/bin/pip install pytest
Collecting pytest
  Using cached pytest-2.8.5-py2.py3-none-any.whl
Collecting py>=1.4.29 (from pytest)
  Using cached py-1.4.31-py2.py3-none-any.whl
Installing collected packages: py, pytest
Successfully installed py-1.4.31 pytest-2.8.5
$ head -n 1 env/bin/py.test
#!/Users/jaraco/Dropbox/code/public/aspen/env/bin/python3

В соответствии с фиксацией , что обходной путь был прокомментирован с включением distlib 0.2.0 выпущен в пипе 6.0.

Этот коммит ссылается на pip 2031 .

Кроме того, я установил Python из установщика python.org для Mac, а не с помощью homebrew или других методов.

В этом коммите код был

Я предполагаю, что этого следовало ожидать, учитывая, что ваш начальный $ python устанавливает __VENV_LAUNCHER__ а затем обманывает другие скрипты / исполняемые файлы. К сожалению, у меня нет OS X, чтобы отлаживать, как именно происходит этот процесс "обмана".

Также может быть аналогичная / та же проблема, о которой сообщалось в №620.

@jaraco, возможно, стоит изменить pip в virtualenv, чтобы раскомментировать упомянутые строки distlib и посмотреть, исправляет ли это поведение pip при подборе неправильного питона для записи

Я проследил этот код обнаружения venv до этого коммита , который, к сожалению, не проясняет происхождение идеи.

Я нашел это объяснение .

Моя склонность была похожа на то, что здесь предложил Рональд .

@vsajip не могли бы вы дать совет?

Некоторые мысли:

  • __PYVENV_LAUNCHER__ был добавлен, потому что для более ранних версий Python (<3.3, по словам Рональда), но не для более поздних версий, site.py Python в OS X требовалось отличать расположение программ запуска заглушек от исполняемых файлов фреймворка. Согласно этому комментарию Неда Дейли, sys.executable теперь указывает на средство запуска заглушки, и именно поэтому distlib перестал использовать __PYVENV_LAUNCHER__ . Единственное использование его сейчас - в site.py - если доступно, в OS X, он используется для поиска файла pyvenv.cfg .
  • Возможно, стоит проверить, что происходит, например, в Python 3.4, чтобы увидеть, есть ли какая-то регрессия или все Python> = 3.3 ведут себя одинаково.
  • Я предполагаю, что что-то где-то выполняет вызов os.path.realpath() хотя этого быть не должно. Не похоже, что это делает distlib . Если (согласно комментарию Неда) sys.executable и env var всегда одинаковы, это не имеет значения; но если что-то выполняет realpath на sys.executable и запускает Python через результат, тогда это приведет к неожиданному шебангу (потому что sys.executable тогда будет разыменованным путем).

(Другая) простая демонстрация проблемы, которую Homebrew повторно обнаружил в https://github.com/Homebrew/homebrew-core/pull/8129 :

$ virtualenv -p python3 test
$ test/bin/python3 -c 'import sys; print(sys.executable)'
/Users/tim/test/bin/python3

$ /usr/local/bin/python3 -c 'import subprocess; subprocess.call(["/Users/tim/test/bin/python3", "-c", "import sys; print(sys.executable)"])'
/usr/local/bin/python3

$ /usr/local/bin/python3 -c 'import subprocess, os; del os.environ["__PYVENV_LAUNCHER__"]; subprocess.call(["/Users/tim/test/bin/python3", "-c", "import sys; print(sys.executable)"])'
/Users/tim/test/bin/python3

Меня только что укусила именно эта ошибка. На мой взгляд, это довольно серьезная ошибка, в основном потому, что она очень сбивает с толку и трудно понять, когда она возникает.

Меня поразило то, что я считаю более серьезным проявлением этой проблемы.

Я начал использовать xonsh в качестве своей повседневной оболочки.

Но когда я пытаюсь использовать virtualenv под xonsh, его невозможно использовать:

~ $ cd ~/draft
draft $ virtualenv --version
16.0.0
draft $ virtualenv .env
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.7'
New python executable in /Users/jaraco/draft/.env/bin/python3
Also creating executable in /Users/jaraco/draft/.env/bin/python
Installing setuptools, pip, wheel...done.
draft $ .env/bin/pip install paver
Collecting paver
  Using cached https://files.pythonhosted.org/packages/98/1e/37ba8a75bd77ea56a75ef5ae66fe657b79205bbc36556c9456cd641782a4/Paver-1.3.4-py2.py3-none-any.whl
Collecting six (from paver)
  Using cached https://files.pythonhosted.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl
Installing collected packages: six, paver
Successfully installed paver-1.3.4 six-1.11.0
  The script paver is installed in '/Users/jaraco/draft/.env/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
draft $ .env/bin/paver --help
Traceback (most recent call last):
  File ".env/bin/paver", line 7, in <module>
    from paver.tasks import main
ModuleNotFoundError: No module named 'paver'
draft $ head -n 1 .env/bin/paver
#!/Library/Frameworks/Python.framework/Versions/3.7/bin/python3

Кажется, что все установленные скрипты получают системный префикс, а не префикс virtualenv.

Вероятно, это связано с тем, что xonsh работает под управлением Python 3.7 (системный префикс) и поэтому имеет это в env:

draft $ env | grep LAUNCHER
__PYVENV_LAUNCHER__=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3

Если вместо этого я запускаю zsh и выполняю те же команды или сначала вызываю del $__PYVENV_LAUNCHER__ , асфальтоукладчик работает, как ожидалось, и строка shebang указывает на virtualenv.

Должен ли xonsh очищать эту переменную среды при запуске?

Возможное исправление ошибки на https://github.com/python/cpython/pull/9516

Эта проблема была автоматически помечена как устаревшая, поскольку в последнее время не было активности. Он будет закрыт, если больше не будет активности. Просто добавьте комментарий, если хотите, чтобы он оставался открытым. Спасибо за ваш вклад.

Я все еще наблюдаю такое же поведение в Mojave с Python 3.7.6 (установлен через Homebrew).

Можете проверить с веткой перезаписи?

@gaborbernat Попытка построить rewrite (fbdd782257d8eace7f5440a2b665f2ddb72e9db6) выдает ошибку сборки из python3 setup.py build .

...src/virtualenv/__init__.py", line 3, in <module>
    from .version import __version__
ModuleNotFoundError: No module named 'virtualenv.version'

который выглядит не связанным с этой проблемой.

Попытка создать ветку перезаписи (fbdd782) дает мне ошибку сборки из сборки python3 setup.py.

Вы должны использовать pip для сборки - pip wheel . - поскольку ветвь перезаписи использует pyproject.toml для определения процесса сборки.

Ошибка, которую вы получаете, - это способ setuptools сказать, что я не поддерживаю новый стандартный способ создания библиотек Python (PEP-517/518). В лучшем случае это ошибка setuptools, но, как указал @pfmoore, вы должны использовать pip для создания колеса или, еще лучше, указать его в папке virtualenv для его установки (он автоматически построит колесо и установит его за один раз).

Прецедент:

#!/bin/bash
rm -rf venv-test
virtualenv --python python3 venv-test
python3 -c 'import subprocess; subprocess.check_call(["./venv-test/bin/pip3", "install", "markdown"])'
shebang=$(head -1 venv-test/bin/markdown_py)
expected_shebang="#!$(pwd)/venv-test/bin/python"
if [ "$shebang" == "$expected_shebang" ]; then
    echo "PASSED"
else
    echo "FAILED: \"$shebang\" != \"$expected_shebang\""
    exit 1
fi

Это не работает под python3 + virtualenv 16.7.9 и проходит под python3 + virtualenv-16.7.10.dev11 + gfbdd782 (т. Е. Ветка rewrite ).

Исправлено при переписывании, как описано выше.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги