Nesta aula, você aprenderá a organizar um projeto Python de forma profissional, seguindo padrões amplamente adotados pela comunidade. Uma boa estrutura de projeto é essencial para a manutenibilidade, escalabilidade e colaboração em equipe. Vamos explorar desde o layout básico de pastas até a configuração moderna com pyproject.toml, incluindo o src layout e boas práticas que facilitam o desenvolvimento, teste e distribuição do seu código.

Muitos projetos Python começam com scripts soltos, mas conforme o código cresce, a falta de organização gera problemas como dificuldade de importação, testes frágeis e dificuldade de empacotamento. Ao final desta aula, você terá um modelo claro para iniciar novos projetos ou reorganizar os existentes, alinhado às ferramentas atuais como pip, build e poetry.

Layout

O layout de um projeto Python define a estrutura de diretórios e arquivos que compõem o projeto. Um layout bem planejado separa claramente o código-fonte, os testes, a documentação e os arquivos de configuração. Isso torna o projeto mais fácil de navegar, entender e manter.

Um layout comum para projetos pequenos e médios é o flat layout, onde o pacote principal fica na raiz, ao lado de outros arquivos. No entanto, para projetos maiores ou que serão publicados como bibliotecas, o src layout (que veremos adiante) é mais recomendado. Vamos começar com um exemplo simples e evoluir para o src layout.

Exemplo de layout flat:

meu_projeto/
├── meu_pacote/
│   ├── __init__.py
│   ├── modulo1.py
│   └── modulo2.py
├── tests/
│   ├── test_modulo1.py
│   └── test_modulo2.py
├── README.md
├── pyproject.toml
└── .gitignore

Nesse layout, o pacote meu_pacote está na raiz, o que facilita importações simples, mas pode causar conflitos de nomes em projetos grandes ou ao instalar o pacote em modo desenvolvimento. Por isso, muitos projetos adotam o src layout.

pyproject.toml (visão geral)

O arquivo pyproject.toml é o formato padrão para configuração de projetos Python, definido na PEP 518 e estendido pela PEP 621. Ele substitui arquivos como setup.py e setup.cfg em muitos projetos, centralizando metadados, dependências e configurações de ferramentas em um único arquivo.

Um pyproject.toml típico contém seções para o sistema de build, metadados do projeto e configurações de ferramentas (como pytest, black, isort). Exemplo:

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "meu-projeto"
version = "0.1.0"
description = "Um projeto exemplo"
requires-python = ">=3.9"
dependencies = [
    "requests>=2.25",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0",
    "black",
]

[tool.pytest.ini_options]
testpaths = ["tests"]

Nesse exemplo, a seção [build-system] define o backend de build (setuptools). A seção [project] contém metadados como nome, versão e dependências. A seção [project.optional-dependencies] define dependências opcionais para desenvolvimento. Configurações de ferramentas são colocadas em seções como [tool.pytest.ini_options].

O pyproject.toml é usado por ferramentas como pip (para instalar o pacote), build (para gerar distribuições) e editores de código para configuração de linting e formatação. É importante conhecer sua estrutura para configurar corretamente seu projeto.

src layout

O src layout é uma estrutura de diretórios onde o código-fonte do pacote fica dentro de uma pasta src/. Por exemplo:

meu_projeto/
├── src/
│   └── meu_pacote/
│       ├── __init__.py
│       ├── modulo1.py
│       └── modulo2.py
├── tests/
│   ├── test_modulo1.py
│   └── test_modulo2.py
├── README.md
├── pyproject.toml
└── .gitignore

Esse layout oferece várias vantagens: evita conflitos de importação acidentais, garante que os testes testem a versão instalada do pacote (e não uma cópia local), e facilita o empacotamento. Com o src layout, o código é instalado em modo desenvolvimento (pip install -e .) e os testes importam o pacote instalado, não o código da árvore de origem.

Para configurar o src layout no pyproject.toml, é necessário indicar onde está o pacote. Com setuptools, você pode usar a opção package-dir ou simplesmente a configuração automática:

[tool.setuptools.packages.find]
where = ["src"]

Isso faz com que o setuptools descubra pacotes dentro de src/. Ao instalar o pacote com pip install -e ., o Python poderá importar o pacote de qualquer lugar, pois ele é instalado no ambiente.

O src layout é recomendado para projetos que serão distribuídos, pois reduz erros de importação e garante consistência entre o desenvolvimento e o uso real do pacote.

Boas práticas

Além da estrutura de pastas, boas práticas de organização incluem: usar nomes descritivos para módulos e pacotes, manter a separação entre código, testes e documentação, e configurar ferramentas de qualidade de código (linters, formatters).

Algumas boas práticas essenciais:

  • Use um ambiente virtual para isolar dependências do projeto.
  • Mantenha os testes separados em uma pasta tests/, com nomes começando com test_.
  • Documente o projeto com um README claro e, se possível, docstrings nos módulos.
  • Configure ferramentas como black, isort e flake8 no pyproject.toml ou em arquivos de configuração.
  • Use controle de versão (git) e inclua um .gitignore adequado.
  • Defina uma licença e um arquivo CHANGELOG.md para registrar mudanças.

Exemplo de configuração para black no pyproject.toml:

[tool.black]
line-length = 88
target-version = ["py39"]

Seguir essas práticas torna o projeto mais profissional e fácil de manter, tanto para você quanto para outros colaboradores.

Referências

Exercícios

  1. Crie a estrutura de diretórios para um projeto chamado meu_app usando o src layout, com um pacote meu_pacote e uma pasta de testes.
  2. ✓ Resposta:
    meu_app/
    ├── src/
    │   └── meu_pacote/
    │       ├── __init__.py
    │       └── modulo.py
    ├── tests/
    │   └── test_modulo.py
    ├── README.md
    ├── pyproject.toml
    └── .gitignore
    
  3. Escreva um pyproject.toml mínimo para um pacote chamado meu_pacote, versão 0.1.0, com dependência em requests e usando setuptools como backend.
  4. ✓ Resposta:
    [build-system]
    requires = ["setuptools>=61.0"]
    build-backend = "setuptools.build_meta"
    
    [project]
    name = "meu_pacote"
    version = "0.1.0"
    dependencies = [
        "requests>=2.25",
    ]
    
  5. Explique por que o src layout é preferível ao flat layout em projetos que serão publicados como bibliotecas.
  6. ✓ Resposta: O src layout evita que o Python importe o código diretamente do diretório de origem, forçando que o pacote seja instalado. Isso previne conflitos de importação, garante que os testes testem a versão instalada e facilita o empacotamento e distribuição.
  7. Adicione uma configuração no pyproject.toml para que o pytest considere a pasta tests como diretório de testes.
  8. ✓ Resposta:
    [tool.pytest.ini_options]
    testpaths = ["tests"]
    
  9. Liste três boas práticas para manter um projeto Python organizado e explique brevemente cada uma.
  10. ✓ Resposta:
    • Usar um ambiente virtual: isola as dependências do projeto, evitando conflitos com outros projetos.
    • Manter testes separados: facilita a execução e manutenção dos testes.
    • Configurar ferramentas de qualidade: como black e flake8, para manter o código consistente e legível.

Observações finais

Estruturar um projeto Python corretamente é um investimento que economiza tempo e dores de cabeça no futuro. Comece com uma estrutura simples e evolua conforme a complexidade aumentar. Lembre-se de que a consistência é mais importante do que seguir cegamente um padrão; adapte o layout às necessidades do seu projeto.

Explore ferramentas como poetry e hatch, que gerenciam ambientes e empacotamento de forma integrada. O conhecimento de pyproject.toml é essencial para interagir com essas ferramentas modernas.