Ambiente
Descrição
Posso instalar um pacote de um repo git em um diretório local como:
pip install git+file:///"k/my/path with/lots of/spaces/repo/.git/"
No entanto, quando coloco git+file:///"k/my/path with/lots of/spaces/repo/.git/"
em meu requirements.txt
e tento instalar com pip install -r requirements.txt
ele falha com ValueError: No closing quotation
.
Comportamento esperado
Esperava-se que o pacote fosse instalado do diretório local, exatamente como quando executo o comando diretamente.
Como reproduzir
requirements.txt
pip install -r requirements.txt
Saída
pip install -r .\requirements.txt
ERROR: Exception:
Traceback (most recent call last):
File "C:\Users\username\AppData\Local\Continuum\anaconda3\lib\site-packages\pip\_internal\cli\base_command.py", line 178, in main
status = self.run(options, args)
File "C:\Users\username\AppData\Local\Continuum\anaconda3\lib\site-packages\pip\_internal\commands\install.py", line 326, in run
self.name, wheel_cache
File "C:\Users\username\AppData\Local\Continuum\anaconda3\lib\site-packages\pip\_internal\cli\base_command.py", line 288, in populate_requirement_set
use_pep517=options.use_pep517):
File "C:\Users\username\AppData\Local\Continuum\anaconda3\lib\site-packages\pip\_internal\req\req_file.py", line 112, in parse_requirements
for req in req_iter:
File "C:\Users\username\AppData\Local\Continuum\anaconda3\lib\site-packages\pip\_internal\req\req_file.py", line 173, in process_line
shlex.split(options_str), defaults) # type: ignore
File "C:\Users\username\AppData\Local\Continuum\anaconda3\lib\shlex.py", line 305, in split
return list(lex)
File "C:\Users\username\AppData\Local\Continuum\anaconda3\lib\shlex.py", line 295, in __next__
token = self.get_token()
File "C:\Users\username\AppData\Local\Continuum\anaconda3\lib\shlex.py", line 105, in get_token
raw = self.read_token()
File "C:\Users\username\AppData\Local\Continuum\anaconda3\lib\shlex.py", line 187, in read_token
raise ValueError("No closing quotation")
ValueError: No closing quotation
requirements.txt
:
git+file:///"k/my/path with/lots of/spaces/repo/.git/"
pandas
requests
retrying
xlsxwriter
Veja também a questão SO relacionada.
O tratamento de cotações quando o pip é executado diretamente é controlado pelo seu shell. No Bash, por exemplo, pares não aninhados de aspas são removidos e seus conteúdos concatenados com o que vem antes / depois para criar cada argumento.
Os arquivos de requisitos, por outro lado, são lidos no estado em que se encontram pelo optparse e não ocorre nenhum tratamento especial de cotação ou eliminação.
Dito isso, neste caso, ao tentar fornecer um URL, os caracteres inválidos do URL (como espaço) devem ser codificados por porcentagem (o espaço é% 20). Veja este script para um exemplo que instala com sucesso um repo git que tinha espaços no caminho:
repro.sh
#!/bin/sh
cd "$(mktemp -d)"
dir="$PWD/a b c/d e f"
mkdir -p "$dir"
cd "$dir"
cat <<EOF > setup.py
from setuptools import setup
setup(name='example')
EOF
git init
git add .
git commit -m init
cd -
python -V
python -m venv venv
venv/bin/python -m pip install --upgrade pip
cat <<EOF | tee requirements.txt
git+file://$PWD/a%20b%20c/d%20e%20f
EOF
python -m pip install -r requirements.txt
Saída
Initialized empty Git repository in /tmp/user/1000/tmp.kITsbsZCPO/a b c/d e f/.git/
[master (root-commit) d347157] init
1 file changed, 3 insertions(+)
create mode 100644 setup.py
/tmp/user/1000/tmp.kITsbsZCPO
Python 3.7.2
Collecting pip
Using cached https://files.pythonhosted.org/packages/00/b6/9cfa56b4081ad13874b0c6f96af8ce16cfbc1cb06bedf8e9164ce5551ec1/pip-19.3.1-py2.py3-none-any.whl
Installing collected packages: pip
Found existing installation: pip 18.1
Uninstalling pip-18.1:
Successfully uninstalled pip-18.1
Successfully installed pip-19.3.1
git+file:///tmp/user/1000/tmp.kITsbsZCPO/a%20b%20c/d%20e%20f
Collecting git+file:///tmp/user/1000/tmp.kITsbsZCPO/a%20b%20c/d%20e%20f (from -r requirements.txt (line 1))
Cloning file:///tmp/user/1000/tmp.kITsbsZCPO/a b c/d e f to /tmp/user/1000/pip-req-build-ts2s099_
Requirement already satisfied (use --upgrade to upgrade): example==0.0.0 from git+file:///tmp/user/1000/tmp.kITsbsZCPO/a%20b%20c/d%20e%20f in /home/chris/.pyenv/versions/3.7.2/lib/python3.7/site-packages (from -r requirements.txt (line 1))
Isso funcionou muito obrigado !!
Você quer responder a pergunta do SO? Caso contrário, citarei sua explicação como resposta, se você não se importar.
Vou encerrar este problema, por curiosidade, este é um problema apenas do Windows? Porque de acordo com o usuário 00 no SO, funciona para ele sem% 20 no Mac.
Estou feliz que ajudou. :)
Por favor, vá em frente!
Eu ficaria um pouco surpreso se o comportamento fosse específico da plataforma. O código aqui deve ser o que divide a URL e não vejo nada que mudaria entre as plataformas. Em qualquer caso, a codificação por cento deve funcionar em qualquer lugar fora da caixa, então é definitivamente o caminho a seguir, mesmo para pessoas que podem fazer com que funcione de outra maneira em outras plataformas.