Virtualenv: Shebang-Länge in ausführbarer Pip-Datei überschritten

Erstellt am 25. Apr. 2014  ·  16Kommentare  ·  Quelle: pypa/virtualenv

Wenn eine neue virtuelle Umgebung erstellt wird, werden eine Reihe von Dingen in dieser virtuellen Umgebung installiert. Eines dieser Dinge ist das Installationsprogramm für Python-Pakete, pip.

Unter Linux ist die ausführbare pip-Datei ein Shell-Skript. Am Anfang dieses Pip-Shell-Skripts befindet sich eine Shebang-Zeile (#!), die den Python-Interpreter in der virtualenv angibt. Diese Zeile enthält den absoluten Pfad zum Python-Interpreter.

Wenn der absolute Pfad zum Python-Interpreter in der virtualenv sehr lang ist (tief verschachtelte und/oder große Pfadnamen), kann er die maximal zulässige Länge für eine Shebang-Zeile überschreiten.

Die maximale Länge für eine Shebang-Zeile wird im Kernel durch BINPRM_BUF_SIZE begrenzt, eingestellt in /usr/include/linux/binfmts.h. Auf den Linux-Rechnern, die ich mir angesehen habe, ist diese Grenze auf 128 festgelegt.

Wenn also der Pfad, zu dem eine Python-Virtualenv erstellt wird, zu lang wird, funktioniert die Verwendung des Pips dieser Virtualenv nicht. Es wird mit dem Fehler fehlschlagen: "schlechter Interpreter: No such file or directory"

Eine Problemumgehung für dieses Problem besteht darin, pip nicht direkt auszuführen, sondern den Python-Interpreter von virtualenv auszuführen und das pip-Skript als auszuführende Quelle an Python zu übergeben.

Hilfreichster Kommentar

Falls das jemand verwirrend findet:

Eine Problemumgehung für dieses Problem besteht darin, pip nicht direkt auszuführen, sondern den Python-Interpreter von virtualenv auszuführen und das pip-Skript als auszuführende Quelle an Python zu übergeben.

Das bedeutet statt pip install -r requirements.txt python -m pip install -r requirements.txt

Alle 16 Kommentare

Ich habe auch dieses Problem.

Ich auch.

Danke für die Problemumgehung!

Beachten Sie, dass die Wrapper-Skripte tatsächlich von setuptools (wenn Sie von sdist installieren) oder von distlib (wenn Sie von Wheel installieren) generiert werden. Daher sollte jede Lösung für dieses Problem wirklich von diesen Projekten angefordert werden.

Aber wenn es eine Einschränkung des Betriebssystems ist, gibt es vielleicht einfach _keine_ praktikable Lösung? Ich glaube mich zu erinnern, dass Perl einmal eine magische Beschwörung verwendet hat, um Skripte auszuführen (googelt ein bisschen ...) Ja, so etwas (übersetzt für Python)

#!/bin/sh
eval 'exec /the/long/interpreter/path/to/python $0 ${1+"$@"}'

Sie würden einige zusätzliche Dinge benötigen, damit Python nicht versucht, die eval-exec-Zeile auszuführen, aber das könnte funktionieren.

Wenn jemand so etwas als Feature-Request für setuptools und distlib vorschlagen möchte, wäre das großartig.

Wenn also der Pfad, zu dem eine Python-Virtualenv erstellt wird, zu lang wird, funktioniert die Verwendung des Pips dieser Virtualenv nicht.

Es wäre _wirklich_ schön, wenn virtualenv auf einem System ausgeführt würde, in dem dieses Problem auftritt, der Befehl eine Warnung (oder sogar einen Fehler) ausgeben würde, dass ein Verzeichnis mit einem so langen Pfadnamen im Wesentlichen nicht unterstützt wird von die Voreinstellungen im Moment.

Ich schlage das auch. Es ist insbesondere ein Problem für mich, da ich pip innerhalb von Jenkins-Builds ausführe, die _sehr_ lange Pfade zum pwd haben. Interessanterweise habe ich eine Reihe von identisch gebauten Build-Slaves (alle haben BINPRM_BUF_SIZE auf 128 gesetzt und die gleichen Pip- und Python- und Virtualenv-Versionen) und ich erlebe dies bei einigen von ihnen, aber nicht bei anderen, selbst mit unterschiedlichen Pfadlängen.

Ich mag den Vorschlag von @b-long; Wenn virtualenv einen Wrapper erstellen will, der auf dem aktuellen System nicht funktioniert, sollte es den Benutzer zumindest warnen, wenn nicht komplett fehlschlagen.

Es ist nicht klar, wie virtualenv diese Situation erkennen könnte. Wir können nicht genau einen Wert aus einem C-Header verwenden, und ich weiß nicht, wie wir feststellen würden, dass wir uns auf einem System mit dieser Einschränkung befinden (Windows hat es nicht, oder OSX?)

Ich neige dazu, dieses Problem als Einschränkung des Betriebssystems zu schließen, nicht als Virtualenv-Problem.

Für was es wert ist, einige Gedanken...

  1. kann ctypes tun?
  2. Wie wäre es mit etwas so Einfachem wie:
# on Linux, BINPRM_BUF_SIZE == 128, giving us a maximum shebang length of 127
# 2 bytes for #!, 11 bytes for '/bin/python' leaves us with 114
if sys.platform() == 'Linux' and len(home_dir) > 114:
    log.warn("bin/activate may not work your system, as the length of the shebang line will exceed 128 characters")
  1. Keine Ahnung, tut mir leid.
  2. Ich bin ein Windows-Benutzer, also habe ich keine Meinung. Wenn Sie das für vernünftig halten, schlage ich vor, eine PR zu machen und zu sehen, was die Linux-Leute denken ...

Ich bin sicher, dass auch andere Benutzer die von mir vorgeschlagene Änderung begrüßen würden. Können wir dies offen lassen für einen Kommentar und um eine PR zu inspirieren? Danke @jantman und @pfmoore :smile:

BINPRM_BUF_SIZE ist in einem Kernel-Header definiert und scheint nur von einer kleinen Handvoll Kernel-Funktionen verwendet zu werden. Ich glaube nicht, dass es eine Möglichkeit gibt, dies programmgesteuert zu erkennen (außer in den Headern zu lesen, was nicht annähernd machbar ist).

That being said, ich denke , es ist vernünftig anzunehmen , dass dies nicht in absehbarer Zeit werden zu ändern (es gibt einen schnellen Überblick über die Länge shebang maximal hier ). Die aktuelle Länge ist auch im Abschnitt "Notes" der execve(2)-Manpage klar angegeben, wo es heißt: "Eine maximale Zeilenlänge von 127 Zeichen ist für die erste Zeile in einem ausführbaren #!-Shell-Skript zulässig."

Ich würde davon ausgehen, dass alle POSIX-kompatiblen Betriebssysteme eine Beschränkung haben, obwohl es scheint, dass einige von ihnen, insbesondere die BSD-Varianten, Beschränkungen von mehr als 8.000 Zeichen haben können.

Obwohl es eine vernünftige Lösung zu sein scheint, etwas so Naives wie mein obiger Vorschlag einfach hart zu codieren (wenn die Plattform Linux ist und die Zeile länger als 127 Zeichen ist), fühlt es sich für mich zu grob und spezifisch und unflexibel an.

Ich denke immer noch darüber nach, wie ich dies programmatisch so testen würde, dass virtualenv nicht zu viel Overhead verursacht (zugegeben, wir müssten dies nur zum Zeitpunkt der venv-Erstellung testen, also ' d gehen davon aus, dass ein gewisser Overhead akzeptabel ist).

Ich habe einen einfachen Proof-of-Concept-Code, um zu testen, ob ein bestimmter Pfad eine akzeptable Länge hat oder nicht, aber es ist ziemlich hässlich, da es eine Datei auf die Festplatte schreibt und dann die Datei ausführt, um die Ausgabe zu erfassen. Das Beispiel und die Ausgabe finden Sie hier: https://gist.github.com/jantman/ba39f98936643bc948bd

Ich muss es für eine Nacht beenden, aber ich werde versuchen, darauf zurückzukommen. Ich würde mich sicherlich über den Beitrag anderer Linux-Benutzer oder Benutzer anderer Betriebssysteme freuen, die bestätigen können, ob sie ein ähnliches Limit haben oder nicht.

Anstatt zu versuchen, etwas Schwieriges zu tun, wie Annahmen über das Limit zu machen, warum nicht einfach ein Funktionstest-Bash-Skript erstellen? Wenn Python korrekt aufgerufen wird, ist alles pfirsichfarben, andernfalls nicht.

Wiederholen:

  1. Bitte senden Sie PRs an setuptools und distlib wenn dies behoben werden soll - der Code ist nicht in virtualenv oder pip.
  2. Um akzeptabel zu sein, müsste Code auf allen unterstützten Plattformen funktionieren, einschließlich OSX, BSD, ... und nicht nur Linux (plattformspezifische Bedingungen sind natürlich akzeptabel, wenn es nicht anders geht)

Schließen dieses Problems, da es sich nicht um ein Virtualenv-Problem handelt (Sie können den gleichen Effekt erzielen, indem Sie einen vollständigen Python-Interpreter in einem langen Verzeichnisnamen installieren).

Wir haben gerade dieses Thema angesprochen.

Warum nicht die Python aus dem PATH verwenden? virtualenv stellt ihm bereits das bin dir voran.

#!/usr/bin/env python

virtualenv stellt ihm bereits das bin dir voran

Nur wenn Sie die virtualenv aktivieren. Virtualenv unterstützt die Verwendung ohne Aktivierung.

Falls das jemand verwirrend findet:

Eine Problemumgehung für dieses Problem besteht darin, pip nicht direkt auszuführen, sondern den Python-Interpreter von virtualenv auszuführen und das pip-Skript als auszuführende Quelle an Python zu übergeben.

Das bedeutet statt pip install -r requirements.txt python -m pip install -r requirements.txt

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen