virtualenv: ambientes virtuais para desenvolvimento

O post de hoje não será tão estreitamente relacionado à dicas sobre código Python como foram os anteriores. Ele irá tratar sobre o ambiente usado para o desenvolvimento em sua máquina.

Para quem está envolvido no desenvolvimento de vários projetos em paralelo, é bastante comum que um projeto tenha dependências de bibliotecas diferentes das usadas pelos outros projetos.
Em um ambiente Ubuntu Linux, por exemplo, os módulos Python instalados no sistema são armazenados em /usr/lib/python2.7/dist-packages/ (para Python 2.7). Dessa forma, se tivermos desenvolvendo dois projetos diferentes, eles estarão compartilhando algumas bibliotecas. E se for necessário que o projeto A utilize a versão x de determinado módulo, enquanto que o projeto B deve utilizar a versão y do mesmo módulo? Como os dois projetos, A e B, utilizam os módulos instalados no mesmo local do disco, fica difícil satisfazer esse requisito.

Outra situação muito comum de acontecer é estarmos desenvolvendo ou testando uma aplicação em um ambiente sobre o qual não temos permissões para a instalação de pacotes no sistema. Sabendo que muita gente passa por situações parecidas, foi criado o virtualenv. Se tivermos o virtualenv à disposição, podemos criar um ambiente virtual em nossa pasta pessoal e instalar os pacotes necessários dentro desse ambiente, sem a necessidade de ter privilégios de super-usuário. Quando for necessário lidar com vários projetos ao mesmo tempo, podemos criar um ambiente virtual para cada projeto, ambos na mesma máquina.

Assim, o virtualenv é uma ferramenta que permite que criemos, com o perdão da redundância, ambientes virtuais isolados para projetos Python. Por exemplo, se tivermos dois projetos, A e B, podemos criar dois ambientes virtuais, um para cada um dos projetos. Poderíamos chamá-los de venvA e venvB, por exemplo. Quando criamos esses dois ambientes, é criado um diretório com o nome de cada ambiente, com o seguinte conteúdo cada um:

bin  include  lib  local

Dentro do diretório bin, são criados arquivos binários (executáveis) necessários em um ambiente de desenvolvimento Python:

$ ls bin/
activate          activate.fish     easy_install    get_env_details
pip-2.7           postdeactivate    predeactivate   activate.csh
activate_this.py  easy_install-2.7  pip             postactivate
preactivate       python

Perceba que temos, dentre os arquivos listados, o interpretador Python (python), além de outras ferramentas importantes como o pip, que pode ser usadoo como instalador de pacotes do virtualenv. Existem também arquivos que são relacionados ao próprio ambiente virtual. Assim, cada ambiente virtual terá seus próprios executáveis para interpretar seus programas e gerenciar seus pacotes. Além disso, é criado também um diretório lib/python2.7/site-packages/, onde serão armazenados os pacotes que você instalar para aquele ambiente. Ou seja, ambos os ambientes venvA e venvB possuirão seu próprio interpretador Python, bem como suas próprias bibliotecas de código. Assim, cada projeto poderá ter versões específicas de determinados pacotes, sem a ocorrência de conflitos entre versões.

Como usar o virtualenv?

O virtualenv pode ser instalado de várias formas. A forma mais comum é através do gerenciador de pacotes pip. Tendo o pip instalado, você pode instalar o virtualenv com o seguinte comando:

user@host:~/$ sudo pip install virtualenv

Tendo feito isso, agora podemos começar a criar os ambientes virtuais para projetos Python. Primeiramente, vamos criar um ambiente:

user@host:~/$ virtualenv NomeDoAmbiente

Após executado o comando acima, será criado, no diretório atual, um subdiretório chamado NomeDoAmbiente, contendo aquela mesma estrutura já comentada anteriormente. Após o ambiente ter sido criado, precisamos ativá-lo:

user@host:~/$ source ./NomeDoAmbiente/bin/activate
(NomeDoAmbiente)user@host:~/$

Você irá perceber que o prompt do seu shell é alterado após a execução do comando acima, sendo a partir daí, precedido pelo nome do ambiente virtual ativo entre parênteses (veja acima). Isso faz também com que sua variável de ambiente $PATH passe a apontar, em primeiro lugar, para a pasta bin de dentro do ambiente virtual, de forma que quando você chamar o interpretador Python pela linha de comando, o executável que será aberto será o interpretador que está instalado dentro do ambiente virtual atual, pois será o primeiro encontrado no $PATH.

Instalando pacotes dentro do ambiente virtual

Uma vez que ativamos o ambiente virtual que desejamos usar, podemos então instalar os pacotes que forem necessários para nosso projeto. Por exemplo, considere que estamos trabalhando em nosso ambiente (ativado anteriormente), chamado de NomeDoAmbiente, e desejamos instalar o pacote Django. Podemos utilizar o gerenciador de pacotes pip que está instalado dentro de nosso ambiente virtual NomeDoAmbiente:

(NomeDoAmbiente)user@host:~/$ pip install Django
Downloading/unpacking Django
    Downloading Django-1.4.1.tar.gz (7.7Mb): 7.7Mb downloaded
    Running setup.py egg_info for package Django
Installing collected packages: Django
    Running setup.py install for Django
Successfully installed Django
Cleaning up...

Agora, podemos abrir um shell Python dentro do ambiente NomeDoAmbiente recém criado, e testar se o Django está mesmo instalado:

(NomeDoAmbiente)user@host:~/$ python
Python 2.7.2+ (default, Jul 20 2012, 22:15:08) 
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> django.__file__
'/home/user/NomeDoAmbiente/local/lib/python2.7/site-packages/django/__init__.pyc'

Tudo certo, o Django está instalado corretamente dentro do ambiente NomeDoAmbiente.

Para sair do ambiente virtual ativo, utilize o comando deactivate.

Gerando lista de dependências do projeto

Lembra quando você envia um projeto pronto para o chefe e ele manda um email dizendo que o projeto não funciona? Muitas vezes, o problema é que o computador do chefe não possui instaladas as bibliotecas que o projeto necessita. Nessa situação, a dupla virtualenv + pip nos ajuda novamente.

Uma vez que estejamos utilizando ambientes virtuais para nossos projetos, e que estejamos instalando todos os pacotes necessários via pip, temos facilmente em mãos a lista de pacotes dos quais nosso projeto depende. Para obter essa lista, basta utilizar o comando freeze do pip:

(NomeDoAmbiente)user@host:~/$ pip freeze
Django==1.4.1
Werkzeug==0.8.3
argparse==1.2.1
distribute==0.6.24
django-bootstrap-toolkit==2.5.8
django-extensions==0.9
django-registration==0.8
wsgiref==0.1.2

Tal comando escreve na saída-padrão a lista de pacotes (bem como suas versões), de cada uma das dependências instaladas via pip no projeto ativo. De posse dessa lista, podemos agora facilmente enviar a lista de dependências para o nosso chefe, utilizando as informações fornecidas pelo pip freeze para garantir que a máquina do chefe irá satisfazer todas as dependências do nosso projeto. Primeiro, devemos armazenar em um arquivo as informações geradas pelo pip freeze:

(NomeDoAmbiente)user@host:~/$ pip freeze > requirements.txt

Após isso, podemos enviar o arquivo requirements.txt para o chefão e, usando o pip, ele poderá executar:

(NomeDoAmbiente)anotheruser@anotherhost:~/$ pip install -r requirements.txt

O comando acima irá instalar as versões especificadas dos pacotes listados no arquivo fornecido como entrada. Tendo instalado corretamente os pacotes listados, nosso projeto estará com todas as dependências satisfeitas no computador do chefe, e poderá ser executado sem problemas.

virtualenvwrapper

Existe outro projeto, chamado virtualenvwrapper, que é um wrapper sobre o virtualenv, e que provê uma série de facilidades para a manipulação de ambientes virtuais. Vale muito a pena dar uma conferida nele!

Utilizando o virtualenvwrapper, a ativação de um ambiente fica muito mais simples:

user@host:~/$ workon NomeDoAmbiente
(NomeDoAmbiente)user@host:~/$

Além disso, ele provê vários atalhos para facilitar a nossa vida, como o cdvirtualenv, que troca o diretório atual para o diretório do virtualenv ativo. Alguns outros aliases úteis:

  • cdsitepackages: troca o diretório atual para o diretório onde os pacotes Python do ambiente virtual ativo estão instalados.
  • lssitepackages: comando muito útil para listarmos os arquivos/diretórios presentes no diretório de instalação dos módulos do ambiente virtual ativo.
  • mkvirtualenv NOME: cria um ambiente virtual chamado NOME.
  • dentre outros 😉

virtualenv embutido no Python 3.3

A versão 3.3 do Python traz consigo a possibilidade de criarmos ambientes virtuais sem a necessidade de instalação do pacote virtualenv separadamente, ou seja, o virtualenv fará parte da distribuição oficial do Python. Mais informações podem ser encontradas na documentação oficial: http://docs.python.org/dev/library/venv.html.

Enfim…

O virtualenv é extremamente útil quando você está trabalhando com vários projetos ao mesmo tempo, ou em um ambiente sobre o qual você não tenha permissões de super-usuário. Mas fique atento, pois o virtualenv irá instalar uma versão de cada biblioteca e dos executáveis para cada um dos seus ambientes virtuais, o que irá consumir mais espaço em disco.