Virtualenv: Skripte mit falschem Shebang unter Unterprozess installiert

Erstellt am 20. Jan. 2016  ·  27Kommentare  ·  Quelle: pypa/virtualenv

Auf Python 3.5.1, aber nicht auf 2.7.10, wenn ich pip durch einen Unterprozess in einer virtualenv aufrufe, werden die Skripte mit dem falschen Shebang erstellt und können daher nicht ausgeführt werden:

$ 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

Man würde erwarten, dass das Skript py.test einen Shebang mit 'env' enthält.

Die Verwendung von pyvenv stattdessen ist nicht Gegenstand des Problems. Das Entfernen der Umgebungsvariablen __PYVENV_LAUNCHER__ vor dem Starten des Unterprozesses umgeht das Problem, wie hier gemeldet . Das Problem wurde mit 13.1.2 und 14.0.0 beobachtet.

Ist dieses Verhalten zu erwarten? Wenn ja, ist das Entfernen der Umgebungsvariablen für einen übergeordneten Prozess angemessen, um das Problem zu umgehen?

Hilfreichster Kommentar

Ich wurde gerade von genau diesem Fehler gebissen. Es ist meiner Meinung nach ein ziemlich schwerwiegender Fehler, vor allem, weil er so extrem verwirrend und schwer zu erkennen ist, wenn er trifft.

Alle 27 Kommentare

tut

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

Gleiche oder unterschiedliche Ergebnisse liefern?

Und gleiche Frage mit

$ env/bin/python -m pip install pytest

?

Möglicherweise eine Regression irgendwie auf https://github.com/pypa/virtualenv/issues/322 / https://github.com/pypa/virtualenv/pull/541

Können Sie in diesem Fall testen, ob

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

hilft oder nicht?

Hmm, es gab Code in pip / distlib, um vielleicht damit umzugehen, aber er wurde vor einem Jahr auskommentiert-

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

Gleiche oder unterschiedliche Ergebnisse liefern?

In beiden Fällen führt das Aufrufen von pip direkt zu einem richtigen Shebang:

$ 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

Auch das Aufrufen mit einer leeren env funktioniert:

$ 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

Laut Commit wurde diese Problemumgehung mit der Aufnahme von distlib 0.2.0 in pip 6.0 kommentiert.

Dieser Commit verweist auf pip 2031 .

Außerdem habe ich Python über das python.org Mac-Installationsprogramm installiert, nicht über Homebrew oder andere Methoden.

Der Code wurde in diesem Commit aus distlib entfernt , was wenig

Ich denke, es ist "zu erwarten", da Ihr anfängliches $ python __VENV_LAUNCHER__ festlegt und danach andere Skripte / ausführbare Dateien täuscht. Leider habe ich kein OS X, um zu debuggen, wie genau dieser Prozess des "Täuschens" abläuft.

Könnte auch ein ähnliches / gleiches Problem sein, wie in #620 gemeldet wurde

@jaraco es könnte sich lohnen, ein pip in einem virtualenv zu modifizieren, um die erwähnten Distlib-Zeilen zu entkommentieren und zu sehen, ob dies das Verhalten von pip zu beheben scheint, das falsche Python zum Schreiben aufzunehmen

Ich habe diesen venv-Erkennungscode bis zu diesem Commit zurückverfolgt, was leider die Ursprünge der Idee nicht aufklärt.

Meine Neigung war ähnlich der, die Ronald hier vorgeschlagen hat .

@vsajip könntest du einen Rat geben?

Einige Gedanken:

  • __PYVENV_LAUNCHER__ wurde hinzugefügt, weil für frühere Versionen von Python (< 3.3, laut Ronald), aber nicht für spätere Versionen, Pythons site.py unter OS X benötigte, um die Position von Stub-Startprogrammen von ausführbaren Framework-Dateien zu unterscheiden. Laut diesem Kommentar von Ned Deily zeigt sys.executable jetzt auf den Stub-Launcher, und deshalb hat distlib aufgehört, __PYVENV_LAUNCHER__ . Die einzige Verwendung davon ist jetzt in site.py - falls verfügbar, wird es unter OS X verwendet, um die Datei pyvenv.cfg .
  • Es kann sich lohnen zu prüfen, was zB in Python 3.4 passiert, ob es sich um eine Art Regression handelt oder ob alle Python >= 3.3 das gleiche Verhalten haben.
  • Ich vermute, dass irgendwo etwas einen os.path.realpath() Anruf tätigt, obwohl dies nicht der Fall sein sollte. Es sieht nicht so aus, als ob es distlib tun würde. Wenn (gemäß Neds Kommentar) sys.executable und die env var immer gleich sind, dann sollte es keine Rolle spielen; aber wenn etwas realpath auf einem sys.executable ausführt und Python durch das Ergebnis ausführt, dann würde das zu einem unerwarteten Shebang führen (weil sys.executable dann ein dereferenzierter Pfad wäre).

Eine (weitere) einfache Demonstration des Problems, das Homebrew in https://github.com/Homebrew/homebrew-core/pull/8129 wiederentdeckt hat:

$ 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

Ich wurde gerade von genau diesem Fehler gebissen. Es ist meiner Meinung nach ein ziemlich schwerwiegender Fehler, vor allem, weil er so extrem verwirrend und schwer zu erkennen ist, wenn er trifft.

Ich wurde von einer meiner Meinung nach schwerwiegenderen Manifestation dieses Problems getroffen.

Ich habe angefangen, xonsh als meine tägliche Shell zu verwenden.

Aber wenn ich versuche, virtualenv unter xonsh zu verwenden, ist es unbrauchbar:

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

Alle installierten Skripte scheinen das Systempräfix und nicht das virtualenv-Präfix zu erhalten.

Dies liegt wahrscheinlich daran, dass xonsh unter Python 3.7 (Systempräfix) läuft und dies auch in der Umgebung hat:

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

Wenn ich stattdessen zsh starte und dieselben Befehle ausführe oder zuerst del $__PYVENV_LAUNCHER__ aufrufe, läuft paver wie erwartet und die Shebang-Linie zeigt auf die virtualenv.

Sollte xonsh diese Umgebungsvariable beim Start löschen?

Es gibt einen möglichen Bugfix unter https://github.com/python/cpython/pull/9516

Dieses Problem wurde automatisch als veraltet markiert, da es in letzter Zeit keine Aktivität hatte. Es wird geschlossen, wenn keine weitere Aktivität stattfindet. Fügen Sie einfach einen Kommentar hinzu, wenn Sie ihn geöffnet lassen möchten. Vielen Dank für Ihre Beiträge.

Ich sehe dieses Verhalten immer noch bei Mojave mit Python 3.7.6 (installiert über Homebrew).

Kannst du mit dem Rewrite-Zweig nachschauen?

@gaborbernat Der Versuch, den rewrite Zweig (fbdd782257d8eace7f5440a2b665f2ddb72e9db6) zu erstellen, gibt mir einen Build-Fehler von python3 setup.py build .

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

was anscheinend nichts mit diesem Problem zu tun hat.

Beim Versuch, den Rewrite-Zweig (fbdd782) zu erstellen, erhalte ich einen Build-Fehler von python3 setup.py build.

Sie sollten pip verwenden, um den Build durchzuführen - pip wheel . - da der Rewrite-Zweig pyproject.toml , um den Build-Prozess zu definieren.

Der Fehler, den Sie erhalten, ist, dass setuptools sagt, dass ich die neue Standardmethode zum Erstellen von Python-Bibliotheken (PEP-517/518) nicht unterstütze. Es ist bestenfalls ein Setuptools-Fehler, aber wie @pfmoore darauf hingewiesen hat, sollten Sie pip verwenden, um ein Rad zu bauen, oder noch besser, es auf den virtualenv-Ordner zu verweisen, um es zu installieren (es wird automatisch ein Rad erstellen und in einem Schritt installieren).

Testfall:

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

Dies schlägt unter python3+virtualenv 16.7.9 fehl und geht unter python3+virtualenv-16.7.10.dev11+gfbdd782 (dh dem rewrite Zweig) weiter.

Behoben im Rewrite wie oben beschrieben.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen