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.1.tar.gz (83.3 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.1-py3-none-any.whl (87.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: spry_core-0.1.1.tar.gz
  • Upload date:
  • Size: 83.3 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.1.tar.gz
Algorithm Hash digest
SHA256 811bad64427934548ec415fbc2d40c17a605d725a13196a3ac0f4444602cceca
MD5 d3e76cb59de1a6864455c6c2b6b6dc7f
BLAKE2b-256 3c5162c76b25850ac8fc92303078986e36ad0f9ed557f13a507d0cc024e22e13

See more details on using hashes here.

Provenance

The following attestation bundles were made for spry_core-0.1.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: spry_core-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 87.6 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2fcae5e7feaaf212d0fb5edb9881e7fc8ced5adcd2fa96ae4235e5c4d974aa5b
MD5 567695bef37eed6f6b46707964af1e58
BLAKE2b-256 c32fd7b41acc6de62dbcfb7691621aa38b49566080fd4681a8eba3bd8fad9d87

See more details on using hashes here.

Provenance

The following attestation bundles were made for spry_core-0.1.1-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