На 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.
Ожидается ли такое поведение? Если да, то подходит ли удаление переменной среды для родительского процесса, чтобы обойти проблему?
делает
$ 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 был код для решения этой проблемы, но он был закомментирован год назад -
Давать одинаковые или разные результаты?
В обоих случаях вызов 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 до этого коммита , который, к сожалению, не проясняет происхождение идеи.
Кажется, никто не знает значения этого env var .
Я нашел это объяснение .
Моя склонность была похожа на то, что здесь предложил Рональд .
@vsajip не могли бы вы дать совет?
Некоторые мысли:
__PYVENV_LAUNCHER__
был добавлен, потому что для более ранних версий Python (<3.3, по словам Рональда), но не для более поздних версий, site.py
Python в OS X требовалось отличать расположение программ запуска заглушек от исполняемых файлов фреймворка. Согласно этому комментарию Неда Дейли, sys.executable
теперь указывает на средство запуска заглушки, и именно поэтому distlib
перестал использовать __PYVENV_LAUNCHER__
. Единственное использование его сейчас - в site.py
- если доступно, в OS X, он используется для поиска файла pyvenv.cfg
.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
).
Исправлено при переписывании, как описано выше.
Самый полезный комментарий
Меня только что укусила именно эта ошибка. На мой взгляд, это довольно серьезная ошибка, в основном потому, что она очень сбивает с толку и трудно понять, когда она возникает.