Virtualenv: Longueur Shebang dépassée dans l'exécutable pip

Créé le 25 avr. 2014  ·  16Commentaires  ·  Source: pypa/virtualenv

Lorsqu'un nouveau virtualenv est créé, un certain nombre de choses sont installées dans ce virtualenv. L'une de ces choses est le programme d'installation du package python, pip.

Sous Linux, l'exécutable pip est un script shell. En haut de ce script shell pip se trouve une ligne shebang (#!) qui spécifie l'interpréteur python dans virtualenv. Cette ligne contient le chemin absolu vers l'interpréteur python.

Si le chemin absolu vers l'interpréteur python dans virtualenv est très long (noms de chemin profondément imbriqués et/ou grands), il peut dépasser la longueur maximale autorisée pour une ligne shebang.

La longueur maximale d'une ligne shebang est limitée dans le noyau par BINPRM_BUF_SIZE, défini dans /usr/include/linux/binfmts.h. Sur les machines Linux que j'ai examinées, cette limite est fixée à 128.

Ainsi, lorsque le chemin vers lequel un virtualenv python est créé, devient trop long, l'utilisation du pip de ce virtualenv ne fonctionnera pas. Il échouera avec l'erreur : "mauvais interprète : aucun fichier ou répertoire de ce type"

Une solution de contournement à ce problème consiste à ne pas exécuter pip directement, mais à exécuter l'interpréteur python de virtualenv et à transmettre le script pip à python comme source à exécuter.

Commentaire le plus utile

Si quelqu'un trouve cela confus :

Une solution de contournement à ce problème consiste à ne pas exécuter pip directement, mais à exécuter l'interpréteur python de virtualenv et à transmettre le script pip à python comme source à exécuter.

Cela signifie qu'au lieu de pip install -r requirements.txt faites python -m pip install -r requirements.txt

Tous les 16 commentaires

Je rencontre également ce problème.

Moi aussi.

Merci pour la solution de contournement !

Notez que les scripts wrapper sont en fait générés par setuptools (si vous installez à partir de sdist) ou distlib (si vous installez à partir de wheel). Donc, tout correctif pour ce problème devrait vraiment être demandé à ces projets.

Mais s'il s'agit d'une limitation du système d'exploitation, peut-être qu'il n'y a tout simplement pas de solution viable ? Il me semble qu'à une certaine époque, Perl utilisait une incantation magique pour exécuter des scripts (googles un peu...) Oui, quelque chose comme ça (traduit pour Python)

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

Vous auriez besoin de quelques éléments supplémentaires pour que Python n'essaie pas d'exécuter la ligne eval-exec, mais cela pourrait fonctionner.

Si quelqu'un voulait proposer quelque chose comme ça en tant que demande de fonctionnalité pour setuptools et distlib, ce serait formidable.

Ainsi, lorsque le chemin vers lequel un virtualenv python est créé, devient trop long, l'utilisation du pip de ce virtualenv ne fonctionnera pas.

Ce serait _vraiment_ bien si vous exécutiez virtualenv sur un système dans lequel ce problème se produit, la commande afficherait un avertissement (ou même une erreur) indiquant que le fait d'être dans un répertoire avec un nom de chemin si long n'est essentiellement pas pris en charge par les valeurs par défaut pour le moment.

Je frappe ça aussi. C'est particulièrement un problème pour moi car j'exécute pip partir des versions Jenkins, qui ont de très longs chemins vers le mot de passe. Fait intéressant, j'ai un certain nombre d'esclaves de construction de construction identique (tous ont BINPRM_BUF_SIZE défini sur 128, et les mêmes versions pip et python et virtualenv) et je rencontre cela sur certains d'entre eux mais pas sur d'autres, même avec des longueurs de chemin variables.

J'aime la suggestion de @b-long ; si virtualenv va créer un wrapper qui ne fonctionne pas sur le système actuel, il devrait au moins donner un avertissement à l'utilisateur, sinon échouer complètement.

On ne sait pas comment virtualenv pourrait détecter cette situation. Nous ne pouvons pas exactement utiliser une valeur d'un en-tête C, et je ne sais pas comment nous détecterions que nous sommes sur un système avec cette limitation (Windows ne l'a pas, n'est-ce pas OSX ?)

Je suis enclin à clore ce problème en tant que limitation du système d'exploitation, et non en tant que problème virtualenv.

Pour ce que ça vaut, quelques réflexions...

  1. ctypes peut-il faire cela ?
  2. Que diriez-vous de quelque chose d'aussi simple que :
# 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. Aucune idée, désolé.
  2. Je suis un utilisateur de Windows donc je n'ai pas d'opinion. Si vous pensez que c'est raisonnable, je suggère d'élever un PR et de voir ce que les gens de Linux pensent...

Je suis sûr que d'autres utilisateurs apprécieraient également le changement que j'ai suggéré. Pouvons-nous laisser cela ouvert aux commentaires et inspirer un PR ? Merci @jantman et @pfmoore :sourire:

BINPRM_BUF_SIZE est défini dans un en-tête du noyau et semble n'être utilisé que par une petite poignée de fonctions du noyau. Je ne crois pas qu'il existe un moyen de détecter cela par programme (à court de lecture dans les en-têtes, ce qui n'est pas du tout faisable).

Cela étant dit, je pense qu'il est raisonnable de supposer que cela ne changera pas de sitôt (il y a un aperçu rapide de la longueur maximale de shebang ici ). La longueur actuelle est également clairement indiquée dans la section "Notes" de la page de manuel execve(2) , où il est indiqué "Une longueur de ligne maximale de 127 caractères est autorisée pour la première ligne d'un script shell exécutable #!."

Je suppose que tous les systèmes d'exploitation compatibles POSIX ont une certaine limite, bien qu'il semble que certains d'entre eux, en particulier les variantes BSD, puissent avoir des limites supérieures à 8 000 caractères.

Bien qu'il semble que ce serait une solution raisonnable de simplement coder en dur quelque chose d'aussi naïf que ma suggestion ci-dessus (si la plate-forme est Linux et que la ligne fait plus de 127 caractères), cela me semble trop grossier, spécifique et inflexible.

Je réfléchis toujours à la façon dont je testerais cela par programme d'une manière qui n'ajouterait pas trop de frais généraux à virtualenv (accordé, nous n'aurions besoin de tester cela qu'au moment de la création de venv, d supposer qu'une certaine surcharge pourrait être acceptable).

J'ai un code de preuve de concept simple pour tester si un chemin donné est une longueur de she-bang acceptable, mais c'est plutôt moche car il écrit un fichier sur le disque, puis exécute le fichier pour capturer la sortie. L'exemple et la sortie sont ici : https://gist.github.com/jantman/ba39f98936643bc948bd

Je vais devoir l'arrêter une nuit, mais je vais essayer d'y revenir. J'apprécierais certainement la contribution de tout autre utilisateur de Linux ou d'utilisateurs d'autres systèmes d'exploitation pouvant confirmer s'ils ont ou non une limite similaire.

Au lieu d'essayer de faire quelque chose de délicat comme faire des hypothèses sur la limite, pourquoi ne pas simplement créer un script bash de test fonctionnel ? Si python est correctement invoqué, alors tout est peachy, sinon ce n'est pas le cas.

Recommencer:

  1. Veuillez soumettre des PR à setuptools et distlib si vous voulez que cela soit corrigé - le code n'est pas dans virtualenv ou pip.
  2. Pour être acceptable, le code devrait fonctionner sur toutes les plates-formes prises en charge, y compris OSX, BSD, ... et pas seulement Linux (les conditions spécifiques à la plate-forme sont acceptables, bien sûr, s'il n'y a pas d'autre moyen)

Fermeture de ce problème, car il ne s'agit pas d'un problème virtualenv (vous pouvez obtenir le même effet en installant un interpréteur Python complet sur un nom de répertoire long).

Nous venons d'aborder ce problème.

Pourquoi ne pas utiliser le python du PATH ? virtualenv l'ajoute déjà avec le répertoire bin.

#!/usr/bin/env python

virtualenv le préfixe déjà avec le répertoire bin

Seulement si vous activez le virtualenv. Virtualenv prend en charge l'utilisation sans activation.

Si quelqu'un trouve cela confus :

Une solution de contournement à ce problème consiste à ne pas exécuter pip directement, mais à exécuter l'interpréteur python de virtualenv et à transmettre le script pip à python comme source à exécuter.

Cela signifie qu'au lieu de pip install -r requirements.txt faites python -m pip install -r requirements.txt

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

erbatyr picture erbatyr  ·  5Commentaires

jdandrea picture jdandrea  ·  3Commentaires

Tset-Noitamotua picture Tset-Noitamotua  ·  4Commentaires

oconnor663 picture oconnor663  ·  3Commentaires

neildhar picture neildhar  ·  4Commentaires