Skip to main content

Uma introdução (leve) ao gerenciamento de dependências em Python

Escrito por
Headshot of Lucian Irsigler

Lucian Irsigler

Python dependency management

14 de setembro de 2021

0 minutos de leitura

Python é considerada uma linguagem “simples” — fácil de usar e de desenvolver scripts para realizar diversas tarefas, da raspagem de dados da web à automação, passando pela criação de aplicações web de grande escala e até pela ciência de dados. No entanto, o gerenciamento de dependências em Python é bem diferente do que ocorre em outras linguagens, e as inúmeras opções para configurar um ambiente e usar gerenciadores de pacotes só aumentam a confusão. Neste post, vamos conhecer diferentes maneiras de gerenciar dependências em Python e explorar brevemente a segurança dessas dependências.

Python como linguagem interpretada

Uma linguagem interpretada não tem seu script convertido em código de máquina nem em um executável. Em vez disso, o script passa por outro programa — neste caso, o interpretador Python — que executa o código.

Se eu escrever um script simples em Python como este:

print("Hello world") #main.py

E depois executá-lo com:

python pathToScript/main.py

Obtemos o seguinte resultado:

Hello world

Você percebeu que não há arquivos executáveis, como .exe, na pasta em que esse código foi executado? Isso acontece porque o executável do Python compila e executa o arquivo durante a execução, e não antecipadamente.

O detalhe é que há um arquivo .exe executando o código Python. Main.py passa por esse .exe e, em seguida, é executado. Esse arquivo .exe é o interpretador Python compilado, disponível no caminho do seu ambiente.

Fluxograma que mostra o main.py, um executável que lê código Python e o executa

O que é uma dependência em Python

Uma dependência em Python é como em qualquer outra linguagem: uma biblioteca de código necessária para executar o código-fonte do script que a importou.

Por exemplo, se você quiser interagir com um banco de dados PostgreSQL, há duas opções: escrever todas as funções por conta própria ou instalar o pacote postgres, que já oferece consultas e os outros recursos de que você precisa.

Então, como instalar o pacote PostgreSQL adequado?

pip install postgres

Um aspecto importante do gerenciamento de dependências, em qualquer linguagem, é fazer a devida verificação para garantir que o pacote seja bem mantido e não tenha problemas de segurança. Uma maneira de avaliar a integridade geral do pacote é usar o Snyk Advisor.

Página do Snyk Open Source Advisor que mostra a busca por pacotes e a pontuação de integridade 90/100 do pacote nodemon.

Com o Snyk Advisor, você pode pesquisar a integridade de pacotes de bibliotecas em diferentes ecossistemas, como PyPI e npm. Também pode analisar imagens base do Docker e consultar estatísticas gerais, popularidade, tags disponíveis e outras informações úteis.

Voltando ao nosso projeto relacionado ao PostgreSQL, vamos conferir se a avaliação de integridade do pacote postgres está dentro de um limite razoável:

Página do Snyk Advisor para o pacote postgres do Python, exibindo uma pontuação de integridade de 56/100 e gráficos de popularidade e manutenção.

Parece que o pacote postgres não tem uma pontuação muito boa: 56 de 100. Ele não é muito popular, com cerca de 10 mil downloads por semana, e seu último lançamento foi há dois anos — um possível sinal de que sua manutenção está deixando a desejar.

Ao rolar a página até as seções de segurança e comunidade, um ponto que chama a atenção é o risco relacionado à licença da versão mais recente do pacote — a versão 3.0.0, de 19 de outubro de 2019 —, que merece uma análise mais cuidadosa:

Painel de segurança de pacotes que mostra a versão 3.0.0 do PostgreSQL, licença MIT, ausência de política de segurança e pontuação de integridade do pacote de 56/100

Se você optar por usar esse pacote, depois de executar a etapa anterior pip install, seu sistema terá acesso ao pacote postgres.

Para importá-lo nos seus projetos:

import postgres

Agora você já deve perceber como as dependências em Python podem se tornar complicadas. Se eu entregar esse script a um amigo que não tem Python instalado e ele tentar executá-lo, vai encontrar um erro.

Por que ocorre um erro?

Primeiro, seu amigo precisa ter o Python instalado. Além disso, precisa dos pacotes necessários dos quais o projeto depende — neste caso, postgres.

Além disso, o ambiente Python também precisa de todos os módulos necessários para executar o script, assim como acontece em outras linguagens quando falta uma biblioteca específica ou um código-fonte.

Portanto, há dois requisitos para compartilhar meu projeto Python com um amigo:

  • Todos os arquivos necessários para executar o Python

  • O pacote postgres

Gerenciamento de dependências em Python

Ao compartilhar seus projetos Python com alguém, você precisa incluir um arquivo chamado requirements.txt. Use o comando pip para instalar especificamente as dependências exigidas pelo projeto:

pip3 install -r requirements.txt

Usamos pip3 em vez de apenas pip para garantir que você não instale a versão errada. pip aponta para a versão do Python que você instalou primeiro. Portanto, se você instalou primeiro uma versão do Python 2, o comando pip apontará para pip2, usado para instalar pacotes do Python 2.

Assim, o termo pip3 indica explicitamente ao pip que ele deve instalar o pacote do Python 3.

Se você não tiver nenhuma versão do Python 2 instalada no computador, não precisa se preocupar com isso.

Para conferir qual pip (pip2 ou pip3) seu comando pip está usando, execute isto no console:

pip --version

Esse comando lê o arquivo de texto requirements.txt, que declara todas as dependências necessárias para o projeto, e depois instala os pacotes listados nele.

Então, para que os pacotes sejam instalados quando alguém executar este comando:

  • Você precisa criar este arquivo de manifesto de pacotes

  • O formato das entradas de pacotes nesse arquivo deve seguir este padrão: <Package name> <Higher/equal to> <some version>

Por exemplo:

requirements.txt

cloudscraper==1.2.58        # Version Matching. Must be version 1.2.58
Newspaper3k >= 0.1          # Minimum version 0.1
requests != 3.4             # Version Exclusion. Anything except version 3.4
beautifulsoup4 ~= 1.1       # Compatible release. Same as >= 1.1, == 1.*
discord.py                  # Installs latest release 

Os operadores de comparação são usados para verificar as versões. Eles garantem que o gerenciador de pacotes pip instale as versões corretas para o seu projeto. Se nenhuma versão for especificada, a versão mais recente será instalada.

Agora, se você compartilhar o código-fonte do projeto com seus amigos, basta pedir que executem o comando pip3 com o arquivo requirements.txt incluído no projeto para que tenham as dependências de código aberto necessárias para executá-lo.

E os gerenciadores de dependências para Python?

Além do arquivo de manifesto de pacotes que conhecemos (requirements.txt), há alguns gerenciadores de pacotes que você pode usar para facilitar a manutenção e o gerenciamento das dependências de projetos em Python. Veja algumas opções que você pode instalar e usar:

  1. Poetry

  2. pyenv

  3. Setuptools

Poetry

O Poetry permite criar arquivos de lock com as dependências do projeto. O arquivo de lock é instalado automaticamente quando você instala o pacote. A vantagem é que o Poetry facilita a atualização das dependências necessárias para o projeto.

O Poetry funciona com ferramentas de linha de comando. Assim, comandos como:

poetry add <module>

poetry build <module>

poetry <publish>

Esses comandos facilitam o acompanhamento e a inclusão de dependências nesse arquivo de lock, que depois podem ser adicionadas ao seu pacote PyPI.

Você também pode usar a flag --tree para exibir um diagrama em árvore das dependências do seu projeto:

my-package
├── pyproject.toml
├── README.rst
├── my_package
│   └── __init__.py
└── tests
    ├── __init__.py
    └── test_my_package.py

O Poetry facilita o gerenciamento e a inclusão de dependências.

pyenv

O pyenv é uma ferramenta simples que permite alternar entre diferentes versões do Python. Assim, você pode verificar se suas dependências seriam incompatíveis com uma versão anterior do Python. Como esse é seu principal uso, o pyenv não tem os recursos de outros gerenciadores de dependências, como o Poetry.

No entanto, se você precisa de uma ferramenta para verificar se seu pacote funcionaria em uma versão anterior do Python, o pyenv é útil.

Setuptools

Este também é um pacote que ajuda no gerenciamento de pacotes. É um pouco mais trabalhoso do que algo como o Poetry, mas dá conta do recado.

Como o nome indica, o Setuptools ajuda a preparar os usuários para usar seu pacote — ou seja, garante que eles tenham os pacotes corretos para executar o script.

Com o setuptools, você cria dois arquivos: um arquivo pyproject.toml e um arquivo setup.py/setup.cfg.

No arquivo .toml, você insere o seguinte código para informar ao Python que usará o Setuptools para especificar as informações do pacote:

[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

Agora, no arquivo setup.py/setup.cfg, você teria algo assim:

[metadata]
name = mypackage
version = 0.0.1

[options]
packages = mypackage
install_requires =
    requests
    importlib; python_version == "2.6"

Agora você vai precisar de uma ferramenta de build, como o PyPA build. Seu projeto será compilado em um arquivo .gz, pronto para distribuição.

O Setuptools exige mais trabalho manual da sua parte, mas é eficiente no gerenciamento de pacotes e garante que seus usuários tenham todos os pacotes necessários para executar o script.

Esses três gerenciadores de dependências estão entre as opções mais populares. Cada um tem pontos fortes e fracos. Seja qual for sua escolha, todos funcionam bem e ajudam a simplificar o pesadelo do gerenciamento de dependências em Python.

Terminal mostrando a análise de dependências de um projeto Flask em Python, que detecta um caminho vulnerável no Jinja2 e recomenda uma atualização.

Melhor ainda: a Snyk CLI mostra o caminho da dependência que leva à vulnerabilidade e também como corrigir o problema — atualizando para uma versão mais recente que inclui uma correção de segurança.

Para concluir

Há outras questões de segurança além das vulnerabilidades em bibliotecas de código aberto. Por exemplo, código inseguro nas suas aplicações Python ou o uso de contêineres inseguros que empacotam suas aplicações Python, entre outros. Daniel Berman escreveu um artigo abrangente sobre como começar a usar a Snyk para desenvolver aplicações Python com segurança, que recomendo muito como complemento a este post.

Espero que você tenha gostado de aprender sobre o gerenciamento de dependências e a segurança em Python. Se quiser ler mais sobre segurança em Python, confira:

  1. Ferramentas de gerenciamento de dependências para Python

  2. O que é package-lock.json? Arquivos de lock para pacotes yarn e npm

  3. Como manter as dependências npm no seu projeto

  4. Gerenciador de pacotes Python Poetry e integração de segurança com ferramenta de análise de composição de software

Comece a jogar Capture the Flag

Aprenda a resolver desafios de Capture the Flag assistindo à gravação sob demanda do nosso workshop virtual introdutório.


Lucian Irsigler é um programador apaixonado que adora as complexidades da vida.

Leia mais

feature insights context
Blog

Os ataques autônomos já chegaram. A defesa precisa acompanhar o ritmo.

Os atacantes autônomos estão reduzindo o tempo disponível para a defesa. Saiba como a descoberta, a correção, a validação e a prevenção contínuas ajudam as equipes de segurança a acompanhar esse ritmo.

feature insights context
Blog

A prevenção é essencialmente um problema resolvido?

A prevenção em código gerado por agentes está resolvida do ponto de vista arquitetural — mas escolher controles que protejam a segurança sem desacelerar o desenvolvimento continua sendo um desafio.

Live Stream

Agentes de Remediação, Desmistificados: Por Que Corrigir é Melhor do que Encontrar

Veja como o Remediation Agent da Snyk usa inteligência de segurança, análise de explorabilidade e validação para transformar vulnerabilidades em pull requests prontos para merge.