No Python 3.5.1, mas não no 2.7.10, quando eu invoco o pip por meio de um subprocesso em um virtualenv, os scripts são criados com o shebang errado e, portanto, falham ao executar:
$ 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
Seria de se esperar que o script py.test tivesse um shebang com 'env' nele.
Usar pyvenv em vez disso não está sujeito ao problema. Remover a variável de ambiente __PYVENV_LAUNCHER__
antes de iniciar o subprocesso resolve o problema, conforme relatado aqui . O problema foi observado com 13.1.2 e 14.0.0.
Este comportamento é esperado? Em caso afirmativo, remover a variável de ambiente é a coisa apropriada para um processo pai fazer para contornar o problema?
faz
$ env/bin/pip uninstall pytest
$ env/bin/pip install pytest
$ head -n 1 env/bin/py.test
Apresenta resultados iguais ou diferentes?
E a mesma pergunta com
$ env/bin/python -m pip install pytest
?
Possivelmente uma regressão de alguma forma em https://github.com/pypa/virtualenv/issues/322 / https://github.com/pypa/virtualenv/pull/541
Nesse caso, você poderia testar se
subprocess.Popen(sys.argv[1:], env={}).wait()
ajuda ou não?
Hmm, havia código em pip / distlib para talvez lidar com isso, mas foi comentado há um ano-
Apresenta resultados iguais ou diferentes?
Em ambos os casos, invocar pip resulta diretamente em um shebang adequado:
$ 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
Além disso, invocar com um env vazio funciona:
$ 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
De acordo com o commit , essa solução alternativa foi comentada com a inclusão do distlib 0.2.0 lançado no pip 6.0.
Esse commit faz referência ao pip 2031 .
Além disso, instalei o Python a partir do instalador python.org Mac, não por meio de homebrew ou outros métodos.
O código foi removido da distlib neste commit , o que fornece pouca justificativa para a mudança.
Eu acho que é "esperado", dado que seu $ python
está configurando __VENV_LAUNCHER__
e, a partir daí, enganando outros scripts / executáveis. Infelizmente não tenho o OS X para depurar exatamente como esse processo de "enganar" continua.
Também pode ser semelhante / mesmo problema que foi relatado em # 620
@jaraco pode valer a pena modificar um pip
em um virtualenv para descomentar as linhas distlib mencionadas e ver se isso parece consertar o comportamento do pip de pegar o python errado para escrever
Rastreei esse código de detecção de venv de volta a este commit , o que infelizmente não elucida as origens da ideia.
Parece que ninguém sabe o significado deste env var .
Eu encontrei essa explicação .
Minha inclinação era semelhante à que Ronald sugeriu aqui .
@vsajip você poderia dar algum conselho?
Alguns pensamentos:
__PYVENV_LAUNCHER__
foi adicionado porque para versões anteriores do Python (<3.3, de acordo com Ronald), mas não para versões posteriores, site.py
do Python no OS X precisava distinguir a localização dos stub launchers dos executáveis do framework. De acordo com este comentário de Ned Deily, sys.executable
agora aponta para o iniciador de stub, e é por isso que distlib
parou de usar __PYVENV_LAUNCHER__
. O único uso dele agora é em site.py
- se disponível, no OS X, é usado para localizar o arquivo pyvenv.cfg
.os.path.realpath()
quando não deveria. Não parece que distlib
fazendo isso. Se (de acordo com o comentário de Ned) sys.executable
e o env var forem sempre os mesmos, então não deve importar; mas se algo faz um realpath
em um sys.executable
e executa Python por meio do resultado, isso resultaria em um golpe inesperado (porque sys.executable
seria um caminho não referenciado).Uma (outra) demonstração simples do problema, que o Homebrew redescobriu em 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
Eu fui mordido por este inseto exato. É um bug bastante grave na minha opinião, principalmente porque é extremamente confuso e difícil de descobrir quando ele atinge.
Fui atingido pelo que considero uma manifestação mais grave desse problema.
Comecei a usar o xonsh como meu shell diário.
Mas quando tento usar o virtualenv no xonsh, ele é inutilizável:
~ $ 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
Todos os scripts instalados parecem estar recebendo o prefixo do sistema e não o prefixo virtualenv.
Isso provavelmente se origina do fato de que o xonsh está sendo executado no Python 3.7 (prefixo do sistema) e, portanto, está no env:
draft $ env | grep LAUNCHER
__PYVENV_LAUNCHER__=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3
Se eu, em vez disso, iniciar o zsh e executar os mesmos comandos ou se primeiro invocar del $__PYVENV_LAUNCHER__
, a pavimentadora será executada conforme o esperado e a linha shebang apontará para o virtualenv.
O xonsh deve limpar essa variável de ambiente quando é inicializado?
Existe uma possível correção de bug em https://github.com/python/cpython/pull/9516
Este problema foi marcado automaticamente como obsoleto porque não teve atividades recentes. Ele será fechado se nenhuma outra atividade ocorrer. Basta adicionar um comentário se quiser mantê-lo aberto. Obrigado por suas contribuições.
Ainda vejo esse mesmo comportamento no Mojave com Python 3.7.6 (instalado via Homebrew).
Você pode verificar com o branch de reescrita?
@gaborbernat Tentar construir o branch rewrite
(fbdd782257d8eace7f5440a2b665f2ddb72e9db6) me dá um erro de construção de python3 setup.py build
.
...src/virtualenv/__init__.py", line 3, in <module>
from .version import __version__
ModuleNotFoundError: No module named 'virtualenv.version'
que parece não ter relação com este problema.
Tentar construir o branch de reescrita (fbdd782) me dá um erro de compilação de python3 setup.py build.
Você deve usar pip para fazer a construção - pip wheel .
- já que o branch de reescrita usa pyproject.toml
para definir o processo de construção.
O erro que você está recebendo é a maneira de setuptools de dizer que não suporte a nova forma padrão de construção de bibliotecas Python (PEP-517/518). É um bug de setuptools na melhor das hipóteses, mas como @pfmoore apontou você deve usar pip para construir um wheel, ou melhor ainda, apontar para a pasta virtualenv para instalá-lo (ele irá automaticamente construir um wheel e instalá-lo de uma só vez).
Caso de teste:
#!/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
Isso falha em python3 + virtualenv 16.7.9 e passa em python3 + virtualenv-16.7.10.dev11 + gfbdd782 (ou seja, o ramo rewrite
).
Corrigido na reescrita conforme acima.
Comentários muito úteis
Eu fui mordido por este inseto exato. É um bug bastante grave na minha opinião, principalmente porque é extremamente confuso e difícil de descobrir quando ele atinge.