Virtualenv: Skrip diinstal dengan shebang yang salah di bawah subproses

Dibuat pada 20 Jan 2016  ·  27Komentar  ·  Sumber: pypa/virtualenv

Pada Python 3.5.1 tetapi tidak pada 2.7.10, ketika saya memanggil pip melalui subproses di virtualenv, skrip dibuat dengan shebang yang salah dan dengan demikian gagal dijalankan:

$ 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

Orang akan mengharapkan skrip py.test memiliki Shebang dengan 'env' di dalamnya.

Menggunakan pyvenv sebagai gantinya tidak tunduk pada masalah. Menghapus variabel lingkungan __PYVENV_LAUNCHER__ sebelum meluncurkan subproses akan mengatasi masalah tersebut, seperti yang dilaporkan di sini . Masalah ini diamati dengan 13.1.2 dan 14.0.0.

Apakah perilaku ini diharapkan? Jika demikian, apakah menghapus variabel lingkungan merupakan hal yang tepat untuk dilakukan proses induk untuk mengatasi masalah tersebut?

Komentar yang paling membantu

Saya baru saja digigit oleh bug yang tepat ini. Ini adalah bug yang cukup parah menurut saya, terutama karena sangat membingungkan dan sulit untuk diketahui kapan itu terjadi.

Semua 27 komentar

melakukan

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

Memberikan hasil yang sama atau berbeda?

Dan pertanyaan yang sama dengan

$ env/bin/python -m pip install pytest

?

Mungkin regresi entah bagaimana di https://github.com/pypa/virtualenv/issues/322 / https://github.com/pypa/virtualenv/pull/541

Dalam hal ini, dapatkah Anda menguji apakah

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

membantu atau tidak?

Hmm, ada kode di pip / distlib untuk menangani ini, tetapi dikomentari setahun yang lalu-

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

Memberikan hasil yang sama atau berbeda?

Dalam kedua kasus, memanggil pip secara langsung menghasilkan shebang yang tepat:

$ 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

Juga, memanggil dengan env kosong berfungsi:

$ 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

Menurut komit , solusi itu dikomentari dengan dimasukkannya distlib 0.2.0 yang dirilis di pip 6.0.

Komit itu merujuk pip 2031 .

Juga, saya telah menginstal Python dari penginstal Mac python.org, bukan melalui homebrew atau metode lain.

Kode telah dihapus dari distlib di commit ini , yang memberikan sedikit alasan untuk perubahan tersebut.

Saya kira itu "diharapkan" mengingat $ python awal Anda mengatur __VENV_LAUNCHER__ dan setelah itu membodohi skrip/executable lain. Sayangnya saya tidak memiliki OS X untuk men-debug bagaimana tepatnya proses "membodohi" itu berlangsung.

Juga bisa serupa / masalah yang sama seperti yang dilaporkan di #620

@jaraco mungkin ada baiknya memodifikasi pip di virtualenv untuk menghapus komentar pada baris distlib yang disebutkan dan melihat apakah itu tampaknya memperbaiki perilaku pip dalam mengambil python yang salah untuk ditulis

Saya melacak kode deteksi venv itu kembali ke commit ini , yang sayangnya tidak menjelaskan asal usul ide tersebut.

Saya telah menemukan penjelasan ini .

Kecenderungan saya mirip dengan apa yang disarankan Ronald di sini .

@vsajip bisa kasih saran?

Beberapa pemikiran:

  • __PYVENV_LAUNCHER__ ditambahkan karena untuk versi Python sebelumnya (< 3.3, menurut Ronald) tetapi tidak untuk versi yang lebih baru, site.py Python pada OS X perlu membedakan lokasi peluncur rintisan dari kerangka kerja yang dapat dieksekusi. Menurut komentar ini oleh Ned Deily, sys.executable sekarang menunjuk ke peluncur rintisan, dan inilah mengapa distlib berhenti menggunakan __PYVENV_LAUNCHER__ . Satu-satunya penggunaannya sekarang adalah di site.py - jika tersedia, di OS X, ini digunakan untuk mencari file pyvenv.cfg .
  • Mungkin perlu diperiksa untuk melihat apa yang terjadi di misalnya Python 3.4, untuk melihat apakah semacam regresi, atau apakah semua Python >= 3.3 memiliki perilaku yang sama.
  • Dugaan saya adalah bahwa sesuatu, di suatu tempat, melakukan panggilan os.path.realpath() padahal seharusnya tidak. Sepertinya distlib melakukan itu. Jika (sesuai komentar Ned) sys.executable dan env var selalu sama, maka itu tidak masalah; tetapi jika sesuatu melakukan realpath pada sys.executable dan mengeksekusi Python melalui hasilnya, maka itu akan menghasilkan shebang yang tidak terduga (karena sys.executable kemudian akan menjadi jalur dereferensi).

Demonstrasi sederhana (lain) dari masalah, yang ditemukan kembali oleh Homebrew di 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

Saya baru saja digigit oleh bug yang tepat ini. Ini adalah bug yang cukup parah menurut saya, terutama karena sangat membingungkan dan sulit untuk diketahui kapan itu terjadi.

Saya telah terkena apa yang saya pikir merupakan manifestasi yang lebih parah dari masalah ini.

Saya sudah mulai menggunakan xonsh sebagai shell harian saya.

Tetapi ketika saya mencoba menggunakan virtualenv di bawah xonsh, itu tidak dapat digunakan:

~ $ 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

Semua skrip yang diinstal tampaknya mendapatkan awalan sistem dan bukan awalan virtualenv.

Ini mungkin berasal dari fakta bahwa xonsh berjalan di bawah Python 3.7 (awalan sistem) dan juga ini di env:

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

Jika saya malah meluncurkan zsh dan menjalankan perintah yang sama atau jika saya pertama kali memanggil del $__PYVENV_LAUNCHER__ , paver berjalan seperti yang diharapkan dan garis Shebang menunjuk ke virtualenv.

Haruskah xonsh menghapus variabel lingkungan itu ketika dimulai?

Ada kemungkinan perbaikan bug di https://github.com/python/cpython/pull/9516

Masalah ini secara otomatis ditandai sebagai basi karena tidak ada aktivitas terbaru. Ini akan ditutup jika tidak ada aktivitas lebih lanjut yang terjadi. Cukup tambahkan komentar jika Anda ingin tetap membukanya. Terima kasih atas kontribusi Anda.

Saya masih melihat perilaku yang sama di Mojave dengan Python 3.7.6 (diinstal melalui Homebrew).

Bisakah Anda memeriksa dengan cabang penulisan ulang?

@gaborbernat Mencoba membangun cabang rewrite (fbdd782257d8eace7f5440a2b665f2ddb72e9db6) memberi saya kesalahan build dari python3 setup.py build .

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

yang tampaknya tidak terkait dengan masalah ini.

Mencoba membangun cabang penulisan ulang (fbdd782) memberi saya kesalahan build dari python3 setup.py build.

Anda harus menggunakan pip untuk melakukan pembangunan - pip wheel . - karena cabang penulisan ulang menggunakan pyproject.toml untuk mendefinisikan proses pembangunan.

Kesalahan yang Anda dapatkan adalah cara setuptools untuk mengatakan saya tidak mendukung cara standar baru membangun perpustakaan python (PEP-517/518). Ini adalah bug setuptools yang terbaik, tetapi seperti yang ditunjukkan @pfmoore, Anda harus menggunakan pip untuk membuat roda, atau bahkan lebih baik mengarahkannya ke folder virtualenv untuk menginstalnya (itu akan secara otomatis membuat roda dan menginstalnya sekaligus).

Kasus cobaan:

#!/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

Ini gagal di bawah python3+virtualenv 16.7.9, dan lewat di bawah python3+virtualenv-16.7.10.dev11+gfbdd782 (yaitu, cabang rewrite ).

Tetap dalam penulisan ulang seperti di atas.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat