thiagocosta.py

Programming, Management etc


  • python , pip , pypi

Gerenciando melhor os requirements em projetos Python

É bastante comum em projetos escritos em python encontrarmos um arquivo requirements.pip contendo todos os pacotes python necessários para rodar o projeto. Esse arquivo normalmente é gerado com o PIP, uma ferramenta para instalação e gerenciamento de pacotes python.

Uma abordagem muito comum para criação desse arquivo é:

  • Instalar a última versão dos pacotes necessários. Ex:

    pip install django
    pip install psycopg2
    pip install celery
    pip install python-memcached
    pip install flake8
    pip install django-debug-toolbar
    pip install ipdb
    pip install ipython
    pip install fabric
    pip install supervisor
    pip install gunicorn
    
  • Gerar automaticamente o arquivo requirements.pip:

    pip freeze > requirements.pip
    

Essa abordagem é muito prática, mas um tanto desorganizada. Basta olhar para o conteúdo do arquivo requirements.pip:

Django==1.7
Fabric==1.10.0
amqp==1.4.6
anyjson==0.3.3
billiard==3.3.0.18
celery==3.1.16
django-debug-toolbar==1.2.1
ecdsa==0.11
flake8==2.2.3
gunicorn==19.1.1
ipdb==0.8
ipython==2.3.0
kombu==3.0.23
mccabe==0.2.1
meld3==1.0.0
paramiko==1.15.1
pep8==1.5.7
psycopg2==2.5.4
pycrypto==2.6.1
pyflakes==0.8.1
python-memcached==1.53
pytz==2014.7
sqlparse==0.1.12
supervisor==3.1.2
wsgiref==0.1.2

Você reconhece todos esses pacotes? amqp, anyjson, billiard? Não, né? Isso porque o comando pip freeze exibe não apenas os pacotes que você instalou, mas as suas dependências também. Dependendo do projeto, esse arquivo pode ficar gigante.

Na minha opinião, uma abordagem mais "elegante" é:

  • Criar manualmente o arquivo requirements.pip adicionando os pacotes necessários;

    # requirements.pip
    Django==1.7
    psycopg2==2.5.4
    celery==3.1.16
    python-memcached==1.53
    flake8==2.2.3
    django-debug-toolbar==1.2.1
    ipdb==0.8
    ipython==2.3.0
    fabric==1.10.0
    supervisor==3.1.2
    gunicorn==19.1.1
    
  • Instalar os pacotes:

    pip install -r requirements.pip
    

A diferença aqui é que toda vez que você precisar instalar um pacote, você deverá incluí-lo no requirements.pip antes de fazer a instalação.

O benefício é que seu requirements.pip ficará bem enxuto, limpo e organizando, contendo apenas os pacotes necessários, afinal, você não precisa conhecer todas as dependências.

Um ponto "negativo" é ter que saber qual a última versão do pacote a ser instalado, mas isso não é tão ruim assim; basta acessar http://pypi.python.org e buscar o pacote ou se preferir, usar o comando pip search "package"

Requirements diferentes em cada ambiente

Um ponto negativo comum entre as duas abordagens é que pacotes como django-debug-toolbar, ipdb, ipython e flake8, por exemplo, são necessários apenas no ambiente de desenvolvimento; porém, ao executar o comando pip install -r requirements.pip no deploy para produção, esses pacotes também serão instalados lá, o que não é uma boa idéia, principalmente quando você possui muitos pacotes de desenvolvimento.

O que tenho feito é criar um arquivo de requirements para cada ambiente e organizá-los em uma pasta chamada "requirements":

requirements/
├── common.pip (pacotes comuns a todos os ambientes)
├── dev.pip
└── prod.pip

Vejamos abaixo como ficaria o conteúdo desses arquivos:

# common.pip
Django==1.7
psycopg2==2.5.4
celery==3.1.16
python-memcached==1.53

# dev.pip
flake8==2.2.3
django-debug-toolbar==1.2.1
ipdb==0.8
ipython==2.3.0
Fabric==1.10.0

# prod.pip
supervisor==3.1.2
gunicorn==19.1.1

Para instalar os requirements em Dev você faria o seguinte:

pip install -r requirements/common.pip
pip install -r requirements/dev.pip

E em produção:

pip install -r requirements/common.pip
pip install -r requirements/prod.pip

Essa abordagem tem funcionado comigo. E você? O que acha?

Update 1

Como recomendado pelo Rafael Lopes, no seu requirements de prod ou dev, você pode incluir na primeira linha a chamada ao requirements de common. Ex:

# prod.pip
-r common.pip

supervisor==3.1.2
gunicorn==19.1.1

Dessa forma, você não precisa chamar duas vezes o comando pip install -r ...

Obrigado Rafael!

Update 2

O único ponto negativo dessa abordagem sugerida pelo Rafael é que se você executar pip uninstall -r requirements/prod.pip, por exemplo, você irá desinstalar não somente os pacotes de prod, mas os pacotes de common também. Então, leve isso em consideração ao decidir a abordagem que irá seguir.

Thiago Costa

Desenvolvedor apaixonado orientado à melhoria contínua (kaizen), agente de mudanças e praticante de métodos ágeis, morando no Rio de Janeiro.

comments powered by Disqus