Skip to main content

Opinionated Python web framework with an EF Core-inspired ORM

Project description

Spry

Spry é um framework Python opinado para quem quer sair do boilerplate rápido sem cair em muita magia.

Ele pega algumas ideias do ASP.NET Core e adapta para um fluxo mais pythonic:

  • AppBuilder para bootstrap, configuração e DI
  • Descoberta automática de controllers no pacote da aplicação
  • ControllerBase para API e Controller para MVC
  • DbContext e DbSet inspirados no EF Core
  • Middleware por pipeline
  • Validação de payload com resposta 422
  • Suporte WSGI e ASGI no mesmo app
  • Scaffold de projeto com templates api e mvc
  • CLI para new, run, watch, migrate e seed

Requirements

  • Python 3.11+
  • pip

Quick start

Instale o framework localmente:

pip install -e .

Crie uma API:

spry new taskboard
cd taskboard
spry run --app taskboard.app:create_app

Crie um projeto MVC:

spry new backoffice --template mvc
cd backoffice
spry run --app backoffice.app:create_app

Hot reload

spry watch --app taskboard.app:create_app

First manual app

O menor exemplo útil com Spry hoje:

from dataclasses import dataclass

from spry import AppBuilder, ControllerBase, DbContext, controller, dbset, get, key, post


@dataclass(slots=True)
class Todo:
    id: int | None = key()
    title: str = ""
    done: bool = False


class AppDbContext(DbContext):
    todos = dbset(Todo)


@controller("/todos")
class TodosController(ControllerBase):
    def __init__(self, db: AppDbContext) -> None:
        self.db = db

    @get("/")
    def list(self):
        return self.db.todos.all()

    @post("/")
    def create(self, todo: Todo):
        self.db.todos.add(todo)
        self.db.save_changes()
        return self.created(f"/todos/{todo.id}", todo)


builder = AppBuilder()
builder.add_db_context(AppDbContext)
app = builder.build()
app.run()

Você não precisa registrar controllers manualmente. O AppBuilder descobre automaticamente classes decoradas com @controller no pacote da aplicação.

API vs MVC

Use ControllerBase quando:

  • O retorno principal é JSON
  • O app é uma API
  • Você quer helpers como self.created(), self.not_found() e self.no_content()

Use Controller quando:

  • O app serve HTML
  • Você quer self.view(...), self.partial_view(...) e self.redirect(...)
  • O projeto segue MVC server-side

Creating a project

Templates

spry new taskboard               # template api (padrão)
spry new backoffice --template mvc
spry new inventory --output ./projetos

Template api:

  • main.py — entrypoint para desenvolvimento
  • appsettings.json — host, porta e configuração de banco
  • src/<app>/app.py — composição do AppBuilder
  • src/<app>/controllers.py — controllers HTTP
  • src/<app>/data.py — entidades e DbContext
  • src/<app>/seed.py — carga inicial de dados

Template mvc:

  • Tudo do template api
  • views/ — layouts, páginas e partials
  • static/site.css — estilos da interface

Conventions the framework assumes

  • Controllers são classes decoradas com @controller
  • A descoberta automática olha para o pacote da aplicação
  • DbContext é tipicamente registrado com builder.add_db_context(...)
  • Para MVC, views ficam em arquivos dentro de views/
  • Middlewares devem ser pequenos e focados em preocupações transversais

CLI reference

spry new <nome> [--template api|mvc] [--output <pasta>]
spry run --app modulo:factory [--host 127.0.0.1] [--port 8000]
spry watch --app modulo:factory [--path extra]
spry migrate add <nome> --context modulo:DbContext [--output migrations]
spry migrate apply --database app.db [--input migrations]
spry seed --entry modulo:funcao [--context modulo:DbContext] [--database app.db]

Database, migrations and seed

Gerar SQL inicial a partir do DbContext:

spry migrate add initial --context taskboard.data:AppDbContext

Aplicar migrações:

spry migrate apply --database taskboard.db

Executar seed:

spry seed --entry taskboard.seed:seed --context taskboard.data:AppDbContext --database taskboard.db

Fluxo completo local:

spry migrate add initial --context taskboard.data:AppDbContext
spry migrate apply --database taskboard.db
spry seed --entry taskboard.seed:seed --context taskboard.data:AppDbContext --database taskboard.db
spry run --app taskboard.app:create_app

Production

WSGI server (recommended)

A Application do Spry é um callable WSGI compatível com qualquer servidor WSGI.

# Gunicorn
pip install gunicorn
gunicorn taskboard.app:create_app -w 4 -b 0.0.0.0:8000

# Waitress (Windows-friendly)
pip install waitress
waitress-serve taskboard.app:create_app

ASGI server

Para ambientes que requerem async, Spry também é um callable ASGI válido.

# Uvicorn
pip install uvicorn
uvicorn taskboard.app:create_app --host 0.0.0.0 --port 8000 --workers 4

# Hypercorn
pip install hypercorn
hypercorn taskboard.app:create_app --bind 0.0.0.0:8000 --workers 4

Health check

Toda aplicação Spry expõe automaticamente GET /health:

curl http://localhost:8000/health
# {"status":"ok","version":"0.1.0","uptime_seconds":42}

CORS

Para consumir a API de um browser SPA, configure CORS:

builder.add_cors(origins=["https://meuapp.com"])
# ou para desenvolvimento:
builder.add_cors(origins=["*"], credentials=False)

Security

Secret key: A configuração auth.secret_key é obrigatória em produção. Não use o valor padrão:

{
  "auth": {
    "secret_key": "substitua-por-uma-chave-forte-aqui",
    "cookie_name": "meuapp_auth"
  }
}

Request body limit: O padrão é 10 MB. Ajuste conforme necessário:

builder.set_max_body_size(50 * 1024 * 1024)  # 50 MB

Debug mode: Em produção, desative o debug para não vazar stack traces:

{ "server": { "debug": false } }

Ou programaticamente:

builder.set_debug(False)

Environment config

O Spry carrega appsettings.json e sobrescreve com variáveis de ambiente prefixadas com APP__:

APP__database__url=postgresql://usuario:senha@host/db spry run --app app:create_app

Troubleshooting

ModuleNotFoundError ao rodar um projeto gerado

Normalmente acontece por um destes motivos:

  • Você está rodando fora da pasta do projeto e o PYTHONPATH não inclui o src correto
  • O --app não bate com o nome do pacote gerado

Exemplo correto:

spry run --app taskboard.app:create_app

Se estiver trabalhando com o framework e o app lado a lado:

$env:PYTHONPATH="$PSScriptRoot\..\src;$PSScriptRoot\taskboard\src"
python -m spry.cli run --app taskboard.app:create_app

Controller não responde rota

Checklist:

  • A classe tem @controller("/prefixo")
  • O método tem @get, @post, @put, @patch ou @delete
  • O controller está dentro do pacote da aplicação
  • A rota chamada bate com o prefixo + método

Payload retorna 422

Isso significa que o binding do payload para a dataclass falhou.

Cheque:

  • Campos obrigatórios ausentes
  • Tipos inválidos
  • Nomes de propriedades divergentes do DTO esperado

MVC não encontra view

Cheque:

  • Se builder.add_views(...) foi chamado
  • Se os arquivos existem dentro da pasta views/
  • Se o nome passado em self.view("home/index") bate com views/home/index.html

Contributing and branch strategy

Contribuições são bem-vindas! Leia o CONTRIBUTING.md para setup, estilo de código e processo de PR.

Branch naming

Branch Base Merge para Descrição
feat/* main main via PR Nova funcionalidade
fix/* main main via PR Correção de bug
docs/* main main via PR Documentação
chore/* main main via PR Manutenção (CI, dependências)

Release flow

  1. Crie uma branch release/vX.Y.Z a partir de main
  2. Ajuste versão e changelog
  3. Merge para main e crie uma tag vX.Y.Z
  4. O GitHub Release é criado a partir da tag

CI

O workflow de CI roda em todos os PRs para main com Python 3.11, 3.12 e 3.13 em Linux, Windows e macOS.

Repository structure

  • src/spry — núcleo do framework
  • src/spry/templates/api — template de API
  • src/spry/templates/mvc — template MVC server-side
  • examples/taskboard — exemplo de API usando o framework
  • docs — site de documentação do framework
  • tests — suite de testes

Developing locally

Instale em modo editável:

pip install -e .
pip install -e ".[all]"   # dependências opcionais

Rodando os exemplos

pip install -e .
cd examples/taskboard
spy run --app taskboard.app:create_app

Rodando os testes

python -m unittest discover -s tests

Documentação local

cd docs
spry run --app spry_docs.app:create_app --host 127.0.0.1 --port 8010

Documentation site

O site de documentação fica em docs/ e cobre guias mais visuais e organizados por assunto.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spry_core-0.1.2.tar.gz (85.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spry_core-0.1.2-py3-none-any.whl (91.8 kB view details)

Uploaded Python 3

File details

Details for the file spry_core-0.1.2.tar.gz.

File metadata

  • Download URL: spry_core-0.1.2.tar.gz
  • Upload date:
  • Size: 85.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for spry_core-0.1.2.tar.gz
Algorithm Hash digest
SHA256 6ae9b60f632a8078a44dc159062645adaf787810987766275f85d8f66627f93a
MD5 514d7fbe33400f393057bf4d0ce2b9a4
BLAKE2b-256 0e03e7edd593e85e51fa5f9dd2a9bc58c35be61e4933b0253dc34da08d52adc4

See more details on using hashes here.

Provenance

The following attestation bundles were made for spry_core-0.1.2.tar.gz:

Publisher: publish.yml on renidantass/spry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spry_core-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: spry_core-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 91.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for spry_core-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 68ac97e9b61156768a386bbe81e0d3a5d98302856438c557881a720430598c16
MD5 8f83ef8df7c41bce62dfbbee6d8f7904
BLAKE2b-256 c3746b376704f89352253c14069bcb940a5c3cd6874f0564b1c43ad46a162e6c

See more details on using hashes here.

Provenance

The following attestation bundles were made for spry_core-0.1.2-py3-none-any.whl:

Publisher: publish.yml on renidantass/spry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page