Guia definitivo para organizar meu ambiente Python

Sabe quando você está no meio de uma tarefa, e precisa executar um comando rápido para seguir em frente, mas ele não funciona porque o ambiente de trabalho ficou zoneado?

O efeito prático é que você perde o fluxo do raciocínio e precisa parar pra resolver o problema que vai te ajudar a resolver o problema.

(╯°□°)╯︵ ┻━┻

Por isso eu sempre busco aprimorar os meus processos pra programar como um chef de cozinha, tendo as ferramentas certas disponíveis na hora certa. Sempre com um comando.

Quando se está começando, organizar o ambiente de desenvolvimento Python no Unix é fácil. Mas com o tempo pode virar uma bola de neve devido a multiplicidade de versões, interpretadores, utilitários e projetos.

O que é importante no meu ambiente?

Eu tenho algumas necessidades e restrições:

  1. Eu preciso das versões do CPython 2.7 e 3.6, mas quero poder incluir outros interpretadores como PyPy e Anaconda;
  2. Python3 deve ser meu padrão pra TUDO, mas quero poder dar um estratégico passo pra trás quando precisar do Python2.
  3. Quero ter apenas um Jupyter Notebook que funcione com Python2 e Python3 simultaneamente, e que ambos detectem se tem um virtualenv ativado quando eu executar o comando jupyter notebook.
  4. Quero ter apenas um iPython Console para Python3 e um iPython Console para Python2, ou seja, nada de ficar instalando iPython no virtualenv dos meus projetos;
  5. Quero ter utilitários genéricos escritos em Python (ex: youtube-dl) disponíveis no meu sistema sem poluir as instalações globais do Python, evitando assim qualquer possibilidade de aporrinhação com versões de bibliotecas globais.
  6. Quero usar virtualenvwrapper para os projetos que desenvolvo permitindo que eu mude de contexto/projeto rapidamente com apenas um comando.
  7. Quero que este ambiente tenha fácil manutenção sem ficar customizando demais o PATH do sistema.

Qual a melhor forma de instalar o Python no Unix?

Pra mim o pyenv é a melhor forma de instalar o Python no Mac e no Linux. Ele instala tudo localmente apenas para o seu usuário, sem complicar o ambiente do sistema como um todo. Além disso ele disponibiliza várias implementações do Python como PyPy, Anaconda, CPython, e outros. Tudo com um comando.

Primeiro é preciso instalar o pyenv com suas 2 extensões pyenv-virtualenv e pyenv-virtualenvwrapper. Eu uso cada uma das extensões com propósitos diferentes:

  1. Uso o pyenv para instalar interpretadores Python;
  2. Uso o pyenv-virtualenv para configurar meu ambiente global;
  3. Uso o pyenv-virtualenvwrapper para os projetos em que trabalho;

Para instalar o pyenv no Mac eu uso o Homebrew. Se você usa outro SO, veja as instruções na documentação do pyenv.

brew install pyenv
brew install pyenv-virtualenv
brew install pyenv-virtualenvwrapper

O virtualenvwrapper concentra seus virtualenvs em um mesmo diretório e o código dos seus projetos em outro. No meu ambiente organizo assim:

# Todos meus virtualenvs ficam em...
mkdir ~/.ve
# Todos meus projetos ficam em...
mkdir ~/workspace

É preciso configurar o shell para ativar o pyenv quando você iniciar uma sessão do terminal. Coloque as linhas abaixo no final do arquivo ~/.bashrc:

export WORKON_HOME=~/.ve
export PROJECT_HOME=~/workspace
eval "$(pyenv init -)"
#pyenv virtualenvwrapper_lazy
  1. Veja que tem um # na última linha do ~/.bashrc para manter o pyenv-virtualenvwrapper desativado neste primeiro momento. Voltaremos nisso mais tarde.
  2. Observe que eu não inclui o comando pyenv virtualenv init no ~/.bashrc contrariando o que sugere a documentação. Isso é proposital. Ativas as 2 extensões simultaneamente causa conflitos.

Agora é preciso reiniciar a sessão do terminal fechando a janela e abrindo uma nova.

Próximo passo é instalar o CPython 3.6.0, CPython 2.7.13.

pyenv install 3.6.0
pyenv install 2.7.13

Evite a tentação de poluir sua instalação global do Python

Tem alguns utilitários feitos em Python que eu uso com frequência. Gosto que eles estejam disponíveis em todas as sessões do shell, sem precisar ativar virtualenvs.

Entretanto eu não gosto de “sujar” a instalação global do Python na minha máquina pra evitar à todo custo confusões com bibliotecas.

Outra chatice que eu evito é ficar instalando o Jupiter/iPython em tudo quanto é virtualenv dos meus projetos.

Eu gosto de ter apenas uma instalação global do Jupyter Notebook, do iPython Console para Python3, do iPython Console para Python2, e de outros utilitários como youtube-dl, rename, gnucash-to-beancount, rows, s3cmd, fabric, mercurial, etc.

É para fazer estas instalações globais que uso o pyenv-virtualenv. Começo criando 4 virtualenvs especiais com o pyenv-virtualenv:

pyenv virtualenv 3.6.0 jupyter3
pyenv virtualenv 3.6.0 tools3
pyenv virtualenv 2.7.13 ipython2
pyenv virtualenv 2.7.13 tools2

O Jupyter suporta vários kernels. Dessa forma uma mesma instalação do Jupyter pode permitir a criação de notebooks para Python2, Python3, R, Bash e muitas outras linguagens. Hoje eu quero configurar apenas o suporte para Python2 e Python3.

Primeiro começo pelo Python3:

pyenv activate jupyter3
pip install jupyter
python -m ipykernel install --user
pyenv deactivate

Então faço para Python2:

pyenv activate ipython2
pip install ipykernel
python -m ipykernel install --user
pyenv deactivate

Veja que no Python3 eu instalo o Jupyter que por padrão já instala o iPython com o Kernel também. Já no Python2 eu instalo apenas o iPython com Kernel. Explico melhor isso lá embaixo.

Agora vamos instalar as ferramentas globais que suportam Python3:

pyenv activate tools3
pip install youtube-dl gnucash-to-beancount rows
pyenv deactivate

Agora vamos instalar as ferramentas globais que não suportam Python3… ou seja… que continuam no Python2. ¯\_(ツ)_/¯

pyenv activate tools2
pip install rename s3cmd fabric mercurial
pyenv deactivate

Finalmente, este é o momento de fazer todas essas versões do Python e virtualenvs especiais funcionarem cooperativamente:

pyenv global 3.6.0 2.7.13 jupyter3 ipython2 tools3 tools2

O comando acima estabelece a prioridade do PATH para que os scripts sejam acessados na ordem certa, e sem precisar ficar ativando virtualenv nenhum.

ヾ(⌐■_■)ノ♪

Pra entender o resultado final disso, veja como o shell encontra cada comando:

~$ pyenv which python
/Users/henrique/.pyenv/versions/3.6.0/bin/python

~$ pyenv which python2
/Users/henrique/.pyenv/versions/2.7.13/bin/python2

~$ pyenv which jupyter
/Users/henrique/.pyenv/versions/jupyter3/bin/jupyter

~$ pyenv which ipython
/Users/henrique/.pyenv/versions/jupyter3/bin/ipython

~$ pyenv which ipython2
/Users/henrique/.pyenv/versions/ipython2/bin/ipython2

~$ pyenv which youtube-dl
/Users/henrique/.pyenv/versions/tools3/bin/youtube-dl

~$ pyenv which rename
/Users/henrique/.pyenv/versions/tools2/bin/rename

Como ficam os virtualenvs dos meus projetos?

Eu uso o pyenv-virtualenvwrapper para criar os virtualenvs dos meus projetos. Esta extensão faz muito pouco. Ela apenas ajusta o virtualenvwrapper para trabalhar direito com os interpretadores instalados com o pyenv.

Este é o momento de descomentar a linha #pyenv virtualenvwrapper_lazy no seu ~/.bashrc e reiniciar o terminal fechando e abrindo a janela novamente.

Quando você abrir a nova sessão, o pyenv-virtualenvwrapper vai instalar as dependências do virtualenvwrapper se não estiverem presentes.

Agora basta usar os comandos normais do virtualenvwrapper e cada virtualenv será criado usando como base o Python adequado que eu instalei no pyenv.

Vamos à alguns exemplos:

  1. Digamos que eu queira iniciar um projeto novo com Python3 chamado proj3. Basta executar mkproject proj3 para criar o virtualenv com Python3 (que é o padrão) em ~/.ve/proj3 e o diretório de projeto vazio em ~/workspace/proj3 .
  2. Agora pense que eu acabei de abrir uma janela do terminal e quero trabalhar no projeto proj3 criado anteriormente. Basta executar workon proj3 para ativar o virtualenv ~/.ve/proj3 e entrar no diretório do projeto ~/workspace/proj3 para trabalhar.
  3. Vamos dizer agora que eu fiz um clone de um projeto chamado proj2 que funciona com Python2 em ~/workspace/proj2 e preciso de um virtualenv pra trabalhar nele. Basta executar: mkvirtualenv -a ~/workspace/proj2 -p python2 proj2 para criar o virtualenv com Python2 em ~/.ve/proj2 associando à ele o diretório do projeto ~/workspace/proj2. Assim um workon proj2 vai funcionar normalmente.

Como usar o Jupyter e o iPython com meus projetos?

Essa foi a maior motivação para eu escrever esse artigo.

Tanto o Notebook quanto o Console eram partes do projeto iPython, que como o nome diz era focado apenas na linguagem Python. Com a evolução do Notebook, começaram a adicionar suporte para outras linguagens e para manter a casa em ordem, os desenvolvedores decidiram quebrar o projeto em 2: Jupyter e iPython

O Jupyter ficou com o Notebook, enquanto o iPython ficou com o Console e com o kernel de Python para que o Jupyter possa executar código Python.

Eu usava o iPython antigo e numa atualização desastrada me enrolei com o Jupyter, que parou de detectar o virtualenv ativo para permitir que eu importe as bibliotecas instaladas nele.

Na verdade, quem detecta o virtualenv não é o Jupyter, mas o iPython que o Jupyter inicializa.

O problema é que o código detector de virtualenv do iPython só é executado no modo console interativo, mas não no modo kernel. Dá uma olhada no culpado.

Além disso o detector do iPython só funciona quando a versão do Python que está rodando o iPython é igual à do Virtualenv ativo. (>ლ)

A solução é aproveitar que o iPython permite customizar sua inicialização e executar a detecção de virtualenv neste momento.

Para isso precisamos criar um profile padrão do iPython e instalar um arquivo de inicialização que criei para fazer essa mágica:

ipython profile create
curl -L http://hbn.link/hb-ipython-startup-script > ~/.ipython/profile_default/startup/00-venv-sitepackages.py

Com isso, sempre que o iPython for inicializado tanto no modo interativo quanto no modo kernel, o caminho para o site-packages do virtualenv estará disponível no PYTHONPATH.

Então voltando ao nosso proj3, entrando no virtualenv com o comando workon proj3, basta executar ipython para iniciar o modo interativo, ou jupyter notebook.

Pronto. Agora que está tudo está organizado, bora codar! ^‿^

[]’s, HB!