Virtualenv: サブプロセスで間違ったシバンでインストールされたスクリプト

作成日 2016年01月20日  ·  27コメント  ·  ソース: pypa/virtualenv

Python 3.5.1では、2.7.10ではなく、virtualenvのサブプロセスを介してpipを呼び出すと、スクリプトが間違ったシバンで作成されるため、実行に失敗します。

$ 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スクリプトには、「env」が含まれるシバンが含まれていると予想されます。

代わりにpyvenvを使用しても、問題は発生しません。 ここで報告されているように、サブプロセスを起動する前に__PYVENV_LAUNCHER__環境変数を削除すると、問題が回避されます。 この問題は13.1.2および14.0.0で観察されました。

この動作は予想されますか? もしそうなら、環境変数を削除することは、問題を回避するために親プロセスが行うのに適切なことですか?

最も参考になるコメント

私はこの正確なバグに噛まれたばかりです。 私の意見では、これは非常に深刻なバグです。これは主に、非常に混乱し、いつヒットするかを理解するのが難しいためです。

全てのコメント27件

NS

$ 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にありましたが、1年前にコメントアウトされました-

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

コミットによると、その回避策は、pip6.0でリリースされたdistlib0.2.0を含めることでコメントされました。

そのコミットはpip2031を参照します。

また、自作やその他の方法ではなく、python.orgMacインストーラーからPythonをインストールしました。

このコミットでコードが

最初の$ python__VENV_LAUNCHER__を設定し、その後他のスクリプト/実行可能ファイルをだましていることを考えると、「予想される」と思います。 残念ながら、「だまし」のプロセスがどのように正確に進行するかをデバッグするためのOSXがありません。

また、#620で報告されたものと同様/同じ問題である可能性があります

@jaraco virtualenvのpipを変更して、前述のdistlib行のコメントを解除し、それが間違ったpythonを取得して書き込むpipの動作を修正するように見えるかどうかを確認する価値があります。

私はそのvenv検出コードをこのコミットまでさかのぼりましたが、残念ながらアイデアの起源は解明されていません。

私はこの説明を見つけました。

私の傾向は、ロナルドがここで提案したものと似てい

@vsajip何かアドバイスはありますか?

いくつかの考え:

  • __PYVENV_LAUNCHER__が追加されたのは、以前のバージョンのPython(<3.3、Ronaldによると)ではなく、OS X上のPythonのsite.pyが、スタブランチャーの場所とフレームワーク実行可能ファイルを区別する必要があったためです。 Ned Deilyによるこのコメントによると、 sys.executableはスタブランチャーを指しているため、 distlib__PYVENV_LAUNCHER__使用を停止しました。 現在の唯一の使用法はsite.py -利用可能な場合、OS Xでは、 pyvenv.cfgファイルを見つけるために使用されます。
  • たとえばPython3.4で何が起こっているか、ある種のリグレッションがあるかどうか、またはすべてのPython> = 3.3が同じ動作をするかどうかを確認することは価値があるかもしれません。
  • 私の推測では、どこかで、あるべきではないときにos.path.realpath()呼び出しを行っていると思います。 distlibそうしているようには見えません。 (Nedのコメントによると) sys.executableとenv varが常に同じである場合、それは問題ではありません。 何かがない場合はrealpathsys.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を使い始めました。

しかし、xonshでvirtualenvを使おうとすると、使用できなくなります。

~ $ 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__呼び出した場合、ペーバーは期待どおりに実行され、シバンラインはvirtualenvを指します。

xonshは、起動時にその環境変数をクリアする必要がありますか?

https://github.com/python/cpython/pull/9516にバグ修正の可能性があり

この問題は、最近のアクティビティがないため、自動的に古いものとしてマークされています。 それ以上のアクティビティが発生しない場合は閉じられます。 開いたままにしておきたい場合は、コメントを追加してください。 貢献していただきありがとうございます。

Python 3.7.6(Homebrew経由でインストール)を使用したMojaveでも、これと同じ動作が見られます。

リライトブランチで確認できますか?

構築しようとすると@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)をビルドしようとすると、python3setup.pyビルドからビルドエラーが発生します。

rewriteブランチはpyproject.tomlを使用してビルドプロセスを定義するため、pipを使用してビルド( pip wheel .を実行する必要があります。

あなたが得ているエラーは、Pythonライブラリを構築する新しい標準的な方法(PEP-517 / 518)をサポートしていないというsetuptoolsの言い方です。 これはせいぜい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 評価