Virtualenv: Comprimento de Shebang excedido no executável pip

Criado em 25 abr. 2014  ·  16Comentários  ·  Fonte: pypa/virtualenv

Quando um novo virtualenv é criado, há várias coisas instaladas nele. Uma dessas coisas é o instalador do pacote python, pip.

No Linux, o executável pip é um script de shell. No topo deste script de shell pip está uma linha shebang (#!) Que especifica o interpretador python no virtualenv. Esta linha contém o caminho absoluto para o interpretador python.

Se o caminho absoluto para o interpretador python no virtualenv for muito longo (nomes de caminhos profundamente aninhados e / ou grandes), ele pode exceder o comprimento máximo permitido para uma linha shebang.

O comprimento máximo para uma linha shebang é limitado no kernel por BINPRM_BUF_SIZE, definido em /usr/include/linux/binfmts.h. Nas máquinas Linux que examinei, esse limite é definido como 128.

Portanto, quando o caminho para onde um virtualenv python é criado se torna muito longo, usar o pip do virtualenv não funcionará. Ele falhará com o erro: "mau intérprete: arquivo ou diretório inexistente"

Uma solução alternativa para esse problema é não executar o pip diretamente, mas executar o interpretador python do virtualenv e passar o script pip para o python como a fonte a ser executada.

Comentários muito úteis

Se alguém achar isso confuso:

Uma solução alternativa para esse problema é não executar o pip diretamente, mas executar o interpretador python do virtualenv e passar o script pip para o python como a fonte a ser executada.

Isso significa que em vez de pip install -r requirements.txt faça python -m pip install -r requirements.txt

Todos 16 comentários

Também estou enfrentando esse problema.

Eu também.

Obrigado pela solução alternativa!

Observe que os scripts de wrapper são, na verdade, gerados por setuptools (se você instalar a partir do sdist) ou distlib (se você instalar a partir do wheel). Portanto, qualquer correção para esse problema deve ser solicitada a esses projetos.

Mas se for uma limitação do sistema operacional, talvez simplesmente _não_ haja uma solução viável? Parece que me lembro que uma vez, Perl usou um encantamento mágico para executar scripts (googles um pouco ...) Sim, algo assim (traduzido para Python)

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

Você precisaria de algumas coisas extras para que o Python não tentasse executar a linha eval-exec, mas isso pode funcionar.

Se alguém quisesse propor algo assim como uma solicitação de recurso para ferramentas de configuração e distlib, isso seria ótimo.

Portanto, quando o caminho para onde um virtualenv python é criado se torna muito longo, usar o pip do virtualenv não funcionará.

Seria _realmente_ bom se executando virtualenv em um sistema no qual este problema ocorre, o comando geraria algum aviso (ou até mesmo um erro) de que estar em um diretório com um nome de caminho tão longo essencialmente não é suportado por os padrões no momento.

Eu estou acertando isso também. É especificamente um problema para mim, pois estou executando pip de dentro das compilações do Jenkins, que têm caminhos _muito_ longos para o pwd. Curiosamente, eu tenho vários escravos de construção construídos de forma idêntica (todos têm BINPRM_BUF_SIZE definido como 128 e o mesmo pip e python e versões de virtualenv) e estou experimentando isso em alguns deles, mas não em outros, mesmo com comprimentos de caminho variáveis.

Eu gosto da sugestão de @b-long; se virtualenv vai criar um invólucro que não funciona no sistema atual, deve pelo menos dar ao usuário um aviso, se não for uma falha total.

Não está claro como o virtualenv poderia detectar essa situação. Não podemos usar exatamente um valor de um cabeçalho C e não sei como detectaríamos que estamos em um sistema com essa limitação (o Windows não tem, tem OSX?)

Estou inclinado a encerrar esse problema como uma limitação do sistema operacional, não um problema do virtualenv.

Para valer a pena, algumas reflexões ...

  1. pode ctypes fazer isso?
  2. Que tal algo tão simples como:
# 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. Não faço ideia, desculpe.
  2. Sou usuário do Windows, então não tenho opinião. Se você acha que isso é razoável, sugiro levantar um PR e ver o que o pessoal do Linux pensa ...

Tenho certeza de que outros usuários também gostariam da mudança que sugeri. Podemos deixar isso aberto para comentários e para inspirar um PR? Obrigado @jantman e @pfmoore : smile:

BINPRM_BUF_SIZE é definido em um cabeçalho do kernel e parece ser usado apenas por um pequeno punhado de funções do kernel. Não acredito que haja alguma maneira de detectar isso programaticamente (além da leitura nos cabeçalhos, o que não é nem de perto viável).

Dito isso, acho que é razoável supor que isso não mudará tão cedo (há uma rápida visão geral do comprimento máximo do shebang aqui ). O comprimento atual também é claramente fornecido na seção "Notas" da página do manual execve (2) , onde afirma: "Um comprimento máximo de linha de 127 caracteres é permitido para a primeira linha em um script de shell #! Executável."

Eu presumiria que todos os sistemas operacionais compatíveis com POSIX têm algum tipo de limite, embora pareça que alguns deles, especificamente as variantes do BSD, podem ter limites acima de 8.000 caracteres.

Embora pareça uma solução razoável simplesmente codificar algo tão ingênuo quanto minha sugestão acima (se a plataforma for Linux e a linha tiver mais de 127 caracteres), parece excessivamente rude, específico e inflexível para mim.

Ainda estou pensando em como eu testaria isso programaticamente de uma forma que não adicionasse muita sobrecarga a virtualenv (concedido, só precisaríamos testar isso no momento da criação de venv, então eu ' d assumir que alguma sobrecarga pode ser aceitável).

Eu tenho um código simples de prova de conceito para testar se um determinado caminho é ou não um comprimento aceitável, mas é bastante feio, pois grava um arquivo no disco e, em seguida, executa o arquivo para capturar a saída. O exemplo e a saída estão aqui: https://gist.github.com/jantman/ba39f98936643bc948bd

Vou ter que encerrar a noite, mas vou tentar voltar a isso. Eu certamente apreciaria a contribuição de qualquer outro usuário Linux, ou usuários de outros sistemas operacionais, que possam confirmar se eles têm ou não um limite semelhante.

Em vez de tentar fazer algo complicado como fazer suposições sobre o limite, por que não apenas fazer um script bash de teste funcional? Se o python for invocado corretamente, então tudo está bem, caso contrário, não é.

Reiterar:

  1. Envie PRs para setuptools e distlib se quiser que isso seja corrigido - o código não está no virtualenv ou pip.
  2. Para ser aceitável, o código precisaria funcionar em todas as plataformas suportadas, incluindo OSX, BSD, ... e não apenas Linux (condicionais específicas da plataforma são aceitáveis, é claro, se não houver outra maneira)

Fechando este problema, já que não é um problema de virtualenv (você pode obter o mesmo efeito instalando um interpretador Python completo em um nome de diretório longo) ..

Acabamos de encontrar esse problema.

Por que não usar o python do PATH? virtualenv já adiciona o diretório bin.

#!/usr/bin/env python

virtualenv já adiciona o diretório bin

Somente se você ativar o virtualenv. Virtualenv suporta ser usado sem ativação.

Se alguém achar isso confuso:

Uma solução alternativa para esse problema é não executar o pip diretamente, mas executar o interpretador python do virtualenv e passar o script pip para o python como a fonte a ser executada.

Isso significa que em vez de pip install -r requirements.txt faça python -m pip install -r requirements.txt

Esta página foi útil?
0 / 5 - 0 avaliações