Skip to main content

O guia definitivo para criar um pacote Python seguro

Escrito por
Headshot of Gourav Singh Bais

Gourav Singh Bais

feature assert in python

8 de maio de 2024

0 minutos de leitura

Criar um pacote Python envolve várias etapas, como definir uma estrutura de diretórios adequada, criar os arquivos do pacote e configurar os metadados antes de publicá-lo. Também é preciso seguir algumas outras etapas, como criar um subdiretório para testes e preparar uma documentação clara. Quando o pacote estiver pronto, você poderá distribuí-lo em diferentes repositórios. Assim, outras pessoas poderão instalar e usar seu pacote Python.

Este guia apresenta todas as etapas para criar um pacote Python moderno. Você encontra o código necessário para acompanhar este tutorial neste repositório do GitHub. Depois de seguir o tutorial, você verá que criar um pacote Python pode ser tão simples quanto usar um já existente. Mas, primeiro, vamos aprender a usar pacotes em Python.

Como criar um pacote Python

Antes de começar a criar um pacote Python, você precisa conhecer os diferentes métodos de instalação e importação, além da estrutura geral dos pacotes. 

Como instalar pacotes em Python

Para usar pacotes Python, você pode recorrer a pacotes públicos do PyPI ou a índices privados que contêm código proprietário de uma organização. 

Veja duas maneiras diferentes de instalar um pacote Python:

Usando o PyPI

O PyPI é o repositório oficial de pacotes Python públicos.

$ pip install package_name

Usando um índice privado

Em algumas situações, você pode precisar usar pacotes públicos disponíveis no PyPI e pacotes privados disponíveis em um índice privado. Grandes organizações costumam usar índices privados em projetos proprietários cujo código-fonte não será compartilhado publicamente. Esses índices permitem armazenar e distribuir pacotes Python internamente na organização. 

Para instalar pacotes de um índice privado, use o comando pip install com a opção -- index-url, seguida da URL do índice privado e do nome do pacote. Veja um exemplo do comando necessário para instalar um pacote:

$ pip install -- index-url <private-index-url> package_name

Por segurança, recomendamos usar Transport Layer Security (TLS) em qualquer índice privado de pacotes. Se o seu índice privado não tiver um certificado TLS válido, será necessário especificar a opção  -- trusted-host no comando pip install para instalar pacotes dele. Isso porque o pip considera o índice não confiável sem um certificado TLS válido.

Como importar um pacote Python

Você pode importar um pacote em Python usando a instrução import. Em seguida, o interpretador Python procura o pacote no cache, nas bibliotecas integradas e nos caminhos de instalação. Se não encontrar o pacote, ele gera um ImportError.

Você também pode importar módulos específicos de um pacote usando a palavra-chave from, como mostrado aqui:

from datetime import date

Outra opção é importar vários módulos ou todos os módulos de um pacote usando os comandos a seguir:

from datetime import date, datetime
from datetime import *

Também é possível criar um alias para um pacote usando a palavra-chave as. Por exemplo, você pode usar o pacote `pandas` como pd, assim:

import pandas as pd

O que compõe os pacotes Python

Os pacotes Python precisam seguir uma estrutura de diretórios que contenha os seguintes arquivos e subdiretórios:

  • Um diretório src com um subdiretório para o nome do pacote, incluindo um arquivo de inicialização __init__.py. O diretório src também conterá um ou mais arquivos module.py com o código-fonte do pacote

  • Um diretório tests com scripts para testar diferentes funções do pacote. Você decide se quer incluir esse diretório no pacote.

  • Um arquivo pyproject.toml com os detalhes de configuração e as dependências do pacote.

  • Um arquivo LICENSE que especifica os termos de uso do pacote. Há várias licenças disponíveis para você escolher, ou você pode criar a sua.

  • Um arquivo README.md com documentação clara, instruções de uso e outras informações úteis e relevantes para quem usa o pacote.

Os arquivos e diretórios mencionados são os requisitos básicos para criar seu pacote. Você também pode encontrar estruturas mais complexas, com arquivos adicionais, submódulos ou testes.

Empacotando seu código

Para disponibilizar publicamente um pacote Python, primeiro você precisa criá-lo. Neste tutorial, vamos mostrar como criar um programa Python simples que converte quilômetros (km) em milhas (mi).

Como escolher o nome do pacote Python

Para dar um nome ao seu pacote Python, verifique no PyPI se o nome escolhido já está em uso. Em geral, os desenvolvedores usam o mesmo nome no PyPI e no pacote, mas você pode escolher nomes diferentes, se preferir. 

Para instalar um pacote, você precisa usar o nome dele no PyPI. Para importar um pacote, use o nome do pacote.

Como configurar seu pacote Python

A estrutura do pacote deve seguir a estrutura de diretórios exigida, apresentada anteriormente. Coloque este código no arquivo km2miles.py. Você pode criar um arquivo __init__.py com este código.

O arquivo km2miles.py contém uma função que converte quilômetros em milhas usando a biblioteca NumPy. O arquivo __init__.py importa o módulo principal e especifica a versão do pacote. 

Antes de publicar o pacote, configure o arquivo pyproject.toml, no qual você também especificará o sistema de build, como veremos a seguir. 

Como configurar o sistema de build

Você precisa de um sistema de build para gerar os arquivos que serão publicados no pacote Python. Você pode usar uma ferramenta de interface de build, como pip, ou um backend de build, como setuptools, Flit, Hatchling ou PDM.

Aqui, você usará setuptools, uma ferramenta de build que resolve automaticamente as dependências de pacotes Python existentes. Isso será útil na criação de um pacote Python para um caso de uso real. 

O sistema de build usa o arquivo pyproject.toml, que contém as instruções para as ferramentas de backend criarem pacotes de distribuição do projeto. As especificações do sistema de build são definidas neste arquivo:

# pyproject.toml
[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

Você pode encontrar tutoriais on-line que não usam o arquivo pyproject.toml e, em vez disso, usam um arquivo setup.py para configurar os pacotes Python. Isso acontece porque, antigamente, o setuptools usava o arquivo setup.py para executar o processo de instalação de pacotes complexos. No entanto, em projetos modernos, o arquivo pyproject.toml costuma ser a forma recomendada de configurar projetos Python, em vez dos arquivos setup.py ou setup.cfg.

Como configurar o pacote Python

Depois de configurar o sistema de build, você precisa configurar as informações específicas do pacote. Esses detalhes de configuração ficam abaixo das informações do sistema de build no arquivo .toml:

[project]
name = "milesConverter"
version = "1.0.0"
description = "Convert KMs to Miles"
readme = "README.md"
authors = [{ name = "name", email = "name@gmail.com" }]
license = { file = "LICENSE" }
classifiers = [
 "License :: OSI Approved :: MIT License",
 "Programming Language :: Python",
 "Programming Language :: Python :: 3",
 "Operating System :: MacOS :: MacOS X",
 "Operating System :: Microsoft :: Windows",
 "Intended Audience :: Education"
]
keywords = ["converter", "miles", "kms"]

Os detalhes a seguir costumam fazer parte da configuração do projeto e, em geral, recomendamos incluí-los em todos os pacotes. No entanto, nem todos são obrigatórios:

  • Nome: (obrigatório) nome do pacote que será usado no PyPI

  • Versão: (obrigatório) versão atual do pacote, também exibida na página principal do pacote no PyPI.

  • Descrição: (obrigatório) informações adicionais sobre o pacote, exibidas na página dele no PyPI.

  • Autores: (obrigatório) informações sobre os desenvolvedores do pacote.

  • Readme: (opcional) descrição do pacote em formato Markdown, incluindo informações sobre como usá-lo. Ela será exibida na página principal do pacote no PyPI.

  • Licença: (opcional, mas altamente recomendável) informações sobre como outras pessoas podem usar o pacote.

  • Classificadores: (opcional) categorias que descrevem o público-alvo, a compatibilidade com plataformas e o nível de maturidade do pacote, facilitando a busca no PyPI. Veja aqui a lista completa de classificadores aceitos.

  • Palavras-chave: (opcional) lista de termos que ajuda as pessoas a encontrar o pacote no PyPI ao buscar assuntos relacionados. Por exemplo, quem procura um pacote para converter milhas em quilômetros pode buscar palavras-chave como "converter", "milhas" e "kms".

Como especificar dependências

Para especificar dependências no arquivo `pyproject.toml`) de um projeto, adicione um campo de dependências após a descrição do projeto:

dependencies = ["numpy >= 1.20.3"]

Isso especifica que o projeto depende da biblioteca NumPy. Quando o projeto é instalado, o pip resolve essas dependências. Ao especificar dependências, lembre-se do seguinte:

  • Não especifique dependências que já são fornecidas por pacotes de terceiros.

  • Use >= para definir uma versão mínima das dependências necessárias para funcionalidades adicionadas em uma versão específica.

  • Use < para definir uma versão máxima das dependências que podem causar problemas de compatibilidade durante uma atualização de versão principal.

Você pode adicionar dependências opcionais usando o campo project.optional-dependencies:

[project.optional-dependencies]
dev = ["pip-tools", "pytest"]

Essas dependências não são instaladas automaticamente, mas podem ser especificadas durante a instalação do projeto usando a sintaxe pip install package_name[optional_dependency_name].

Como definir a versão do pacote

Como explicado anteriormente no tutorial, você pode definir a versão do pacote Python usando um número de versão e incluí-lo na documentação do pacote. Esse número deve seguir o formato de versionamento semântico mais usado: MAJOR.MINOR.PATCH. Nele, MAJOR representa mudanças significativas no projeto, MINOR representa novos recursos e PATCH representa correções de bugs ou melhorias de desempenho. 

Veja como adicionar uma versão ao arquivo de configuração:

version = "1.0.0"

Isso definirá a versão do projeto como 1.0.0. Você poderá atualizar o número da versão ao lançar novas versões do projeto.

Como testar seu pacote

Há várias maneiras de testar seu pacote Python. Em projetos menores, testes manuais podem ser suficientes, mas é sempre bom contar com outros tipos de testes automatizados para garantir que o código atenda a determinados padrões sem intervenção manual. A disponibilidade de testes automatizados aumenta a confiança na confiabilidade do pacote.

  • Testes unitários: ajudam a testar trechos específicos de código de forma isolada, usando uma estrutura de testes como `robot`, `pytest`, `testify` ou `nose`.

  • Testes de integração: testam como diferentes partes do pacote funcionam em conjunto, configurando ambientes de teste e executando o código. Para implementar testes de integração, você pode usar um pacote como `tox`.

  • Testes manuais: execute o código e confira se os resultados são os esperados. Você pode usar qualquer cliente Python para fazer testes manuais.

Você pode colocar todos esses testes na pasta tests descrita anteriormente no tutorial. Projetos complexos geralmente exigem relatórios de análise e visibilidade, além de relatórios de cobertura de testes. Para isso, você pode usar pacotes como coverage.py e `pytest-cov`.

Como adicionar arquivos de recursos ao pacote

Para incluir no pacote Python arquivos que não contêm código-fonte, como arquivos de dados, binários, manuais e arquivos de configuração, você pode criar um arquivo de recursos chamado MANIFEST.in. Use regras nesse arquivo para especificar quais arquivos devem ser incluídos ou excluídos durante a criação do pacote. 

Por exemplo, o código a seguir incluirá todos os arquivos .toml localizados no diretório src/mileConverter:

# MANIFEST.in
include src/mileConverter/*.toml

Você também pode especificar um arquivo .toml separado para esse fim.

Como licenciar seu pacote

Para incluir uma licença no pacote Python e permitir que outras pessoas o usem, crie um arquivo chamado LICENSE no diretório do pacote e escolha uma licença existente entre as opções disponíveis, como as oferecidas em choosealicense.com. 

No arquivo pyproject.toml, você precisa especificar o nome do arquivo LICENSE na variável de licença para que a licença fique visível na página do PyPI. Foi isso que você fez ao começar a configurar o arquivo pyproject.toml do pacote.

Algumas das licenças de código aberto mais populares são a MIT License, a Apache License e a GNU General Public License (GPL), mas há muitas outras opções.

Instale seu pacote localmente

Agora que você criou todos os arquivos necessários e fez as configurações exigidas para o pacote, experimente instalá-lo localmente antes de publicá-lo no PyPI para verificar se há erros. Você pode fazer isso com o pip. Basta especificar a opção -e ou - editable, que indica que você está tentando instalar o pacote localmente, como no comando a seguir:

$ pip install -e .

Agora que você instalou o pacote localmente, ele está pronto para ser publicado no PyPI.

Publique seu pacote no PyPI

Para publicar seu pacote, primeiro você precisa compilá-lo.

Compile seu pacote

Use o pacote build para gerar um arquivo wheel para seu pacote Python. Para instalar o frontend de build, execute o seguinte comando:

$ pip install build

Em seguida, acesse o diretório que contém o arquivo pyproject.toml e execute o seguinte comando:

$ python -m build

Isso criará uma pasta dist/ no mesmo local do arquivo .toml, com dois arquivos:

dist/
├── milesConverter-1.0.0-py3-none-any.whl
└── milesConverter-1.0.0.tar.gz

O arquivo `.whl` é uma distribuição binária, e o arquivo tar.gz é uma distribuição de código-fonte. Esses arquivos podem ser enviados ao PyPI, mas você precisa testá-los primeiro.

Teste seu pacote

Para testar seu pacote, instale `twine`, uma biblioteca que também ajuda a enviar o pacote para o PyPI. Você pode instalá-la com o seguinte comando:

$ pip install twine

Depois de instalar o twine, você pode verificar se a descrição do pacote será exibida corretamente no PyPI com este comando:

$ twine check dist/*

A saída do comando anterior será parecida com esta:

(base) gouravbais@Gouravs-Air Python_Package % twine check dist/*
Checking dist/milesConverter-1.0.0-py3-none-any.whl: PASSED
Checking dist/milesConverter-1.1.0-py3-none-any.whl: PASSED
Checking dist/milesConverter-1.0.0.tar.gz: PASSED
Checking dist/milesConverter-1.1.0.tar.gz: PASSED

Se todos os testes forem aprovados, seu pacote estará pronto.

Envie seu pacote para o serviço TestPyPI

Antes de disponibilizar seu pacote publicamente, teste-o e valide-o usando o serviço TestPyPI. Para isso, envie o pacote para o TestPyPI. Primeiro, crie uma conta no site do PyPI. Em seguida, use o twine para enviar o pacote executando o comando a seguir. Você precisará do seu nome de usuário e da sua senha do PyPI:

$ twine upload -r testpypi dist/*

Quando o comando for executado com sucesso, você receberá um URL para acessar os resultados. Também poderá buscar seu pacote no site do TestPyPI. Para baixar seu pacote do serviço TestPyPI, use o seguinte comando:

$ pip install -i https://test.pypi.org/simple/ milesConverter==1.0.0

Depois de baixá-lo, você poderá testar o pacote e confirmar se está funcionando corretamente.

Envie seu pacote para o PyPI oficial

O envio para o PyPI oficial é semelhante ao envio para o TestPyPI. Depois de validar seu pacote na etapa anterior, você pode enviá-lo para o PyPI oficial. Mais uma vez, use a ferramenta twine para enviar os arquivos do pacote ao PyPI.

No terminal, execute o seguinte comando, substituindo dist/* pelo caminho dos arquivos do pacote:

twine upload dist/*

Depois de enviar o pacote, acesse o site e faça uma busca por ele.

Instale seu pacote

Agora, teste seu pacote. Você pode baixá-lo com o seguinte comando:

$ pip install milesConverter

Depois de instalar o pacote, abra qualquer editor ou ambiente de execução Python e teste se ele está funcionando:

from milesConverter import km2miles
a = km2miles.km2miles(16)
print(a)

A saída deve ser semelhante a esta:

9.941936

Seu pacote já foi enviado ao PyPI e pode ser instalado com pip em qualquer ambiente Python.

Publique seu pacote em um índice privado de pacotes Python

Você já viu por que algumas organizações podem querer distribuir seus pacotes usando um índice privado de pacotes Python. Além disso, publicar seu pacote Python em um índice privado é simples. Basta seguir estas etapas:

  • Configure a estrutura de diretórios do pacote com arquivos .whl ou .tar.gz para distribuição.

  • Configure seu servidor web para disponibilizar o diretório raiz do pacote com a indexação automática ativada.

  • Use o twine para enviar seu pacote ao índice privado, usando o URL do seu servidor web privado $ twine upload - repository-url your_web_server milesConverter/*.

  • Para instalar o pacote do índice privado, use o comando pip com o URL do seu servidor web ($ pip install - extra-index-url your_web_server milesConverter).

Depois de concluir essas etapas, seu pacote estará disponível no seu servidor web privado para você e sua equipe usarem.

Práticas recomendadas de segurança para criar pacotes Python

Agora que você sabe como publicar seu pacote, considere algumas práticas recomendadas antes de publicá-lo para garantir que ele seja seguro e funcione corretamente.

Fique de olho nas dependências

Antes de usar uma dependência de terceiros no seu projeto, consulte a documentação para saber se ela inclui verificações de segurança ou vulnerabilidades. Muitas bibliotecas têm uma seção inteira na documentação dedicada a problemas de segurança conhecidos e à forma de lidar com eles. Essa documentação ajuda você a escolher uma biblioteca de terceiros com mais confiança.

Se não houver documentação, uma ferramenta como o Snyk pode ajudar você a identificar vulnerabilidades nas bibliotecas de terceiros que está considerando usar.

Tenha cuidado com strings e SQL puro

É recomendável ter bastante cuidado ao trabalhar com strings em Python, especialmente ao usar SQL puro no código. Um uso incorreto pode expor você a ataques de injeção de string ou de SQL. Um invasor pode inserir código malicioso em uma string ou, mais provavelmente, em uma consulta SQL, fazendo com que comandos SQL inesperados e arbitrários sejam executados no seu banco de dados.

Você pode evitar esses ataques avaliando com cuidado como formata strings, principalmente quando recebe dados do usuário. O ideal é usar bibliotecas padrão para formatar strings, aproveitando o recurso f-string.

Ao trabalhar com SQL puro, use consultas parametrizadas em vez de concatenar diretamente a entrada do usuário à string SQL. Isso ajuda a evitar ataques de injeção de SQL, garantindo que a entrada do usuário seja escapada, colocada entre aspas e validada corretamente.

Faça a desserialização com cautela e segurança

O módulo pickle do Python não é muito seguro e pode estar vulnerável a ataques como o pickle bomb. Para garantir que seu pacote seja seguro, considere usar uma biblioteca alternativa de desserialização, como `dill`, que funciona essencialmente como uma camada segura sobre o pickle.

Uma das vulnerabilidades do pickle é permitir a execução de código arbitrário durante a desserialização. Nesse caso, um invasor pode inserir um arquivo pickle malicioso com código que será executado quando o arquivo for desserializado. O dill resolve esse problema permitindo que você especifique quais módulos ou funções podem ser desserializados, impedindo a execução de código arbitrário durante a desserialização e tornando o dill mais seguro que o pickle.

Não se esqueça de remover os segredos

Armazenar segredos com segurança é essencial ao trabalhar com dados confidenciais. Se eles não forem armazenados com segurança, um invasor poderá acessá-los e usá-los para obter acesso não autorizado ao seu sistema e aos seus dados. Para evitar isso, armazene os segredos com segurança usando uma biblioteca de gerenciamento de segredos, como keyring, passlib, pycryptodome ou pycrypto, que os armazenam em formato criptografado.

Além disso, altere seus segredos periodicamente. Isso reduz o risco de comprometimento. Algumas das ferramentas mencionadas oferecem esse recurso, assim como outras ferramentas, como o HashiCorp Vault.

Use uma ferramenta para verificar seu código regularmente em busca de vulnerabilidades

Como você viu, é importante conhecer as diversas ameaças que podem afetar seu projeto Python, especialmente no gerenciamento de dependências, na formatação de strings, nas consultas SQL puras e na desserialização. Talvez seja possível resolver tudo isso por conta própria, mas não é recomendável. É melhor usar uma ferramenta capaz de detectar e corrigir vulnerabilidades no seu projeto.

Uma ferramenta como o Snyk pode facilitar seu trabalho ao verificar regularmente se há vulnerabilidades no seu código. Com o Snyk, você pode identificar e corrigir possíveis problemas no seu projeto Python. Isso ajuda a proteger seu projeto e também a reduzir bugs e problemas de funcionamento na sua aplicação.

Conclusão

Neste tutorial, você aprendeu a criar um pacote Python. Também viu por que essa é uma forma útil de organizar seu código e como isso o torna reutilizável e sustentável.

Este tutorial também mostrou por que é tão importante conhecer as diversas ameaças e vulnerabilidades que podem comprometer seu projeto. Você aprendeu a lidar com algumas delas por conta própria, escrevendo mais código. No entanto, nem todas as organizações ou equipes têm capacidade para fazer isso — e, mesmo quando têm, não deveriam precisar. É melhor usar um produto completo e consolidado, que cuide continuamente das vulnerabilidades e ameaças e facilite seu trabalho.

Um produto como o Snyk pode ajudar você a mitigar essas ameaças, analisando seu código a fundo para identificar vulnerabilidades e corrigindo alguns desses problemas automaticamente.

Comece a proteger seus aplicativos Python

Encontre e corrija vulnerabilidades em Python gratuitamente com o Snyk.

Não é necessário informar cartão de crédito.

Ou cadastre-se com Azure AD Docker ID Bitbucket

Ao usar o Snyk, você concorda em cumprir nossas políticas, incluindo os Termos de Serviço e a Política de Privacidade.

Leia mais

illustration hero ai
Blog

PHP corrige duas vulnerabilidades críticas de RCE sem autenticação (CVE-2026-109618, CVE-2026-109619): atualize agora

Duas falhas críticas no ciclo de requisições do PHP podem permitir execução remota de código sem autenticação. Atualize para uma versão corrigida ou instale um backport do fornecedor para versões mais antigas.

blog feature ai lilac
Blog

Transforme seu backlog de vulnerabilidades em pull requests com remediação agentiva

O Evo Remediation Agent está em Open Preview e traz a resolução automatizada de dependências para o Evo Agentic AppSec. Agora, as equipes de AppSec podem executar campanhas contínuas de remediação

AI Background min crop
Blog

A IA está acionando todos os riscos que você aceitou: sete insights do painel de segurança de IA sem filtros

A IA está tornando os ataques mais baratos e rápidos, expondo riscos que as organizações já carregam. Quatro líderes de segurança explicam por que a defesa na velocidade das máquinas e a correção mais rápida são essenciais.