Skip to main content

The Spring Boot of Python for Flutter

Project description

๐Ÿ Sagnos

The Spring Boot of Python for Flutter.

Write Python. Get a Flutter app. Zero manual API code.


What is Sagnos?

Building a Flutter app with a Python backend normally means:

  • Manually writing HTTP calls in Dart
  • Manually parsing JSON
  • Manually keeping Python and Dart models in sync
  • Silent runtime crashes when you rename a field

Sagnos eliminates all of that.

You write Python functions with type hints. Sagnos automatically generates the entire Dart client โ€” models, HTTP calls, error handling, everything.


The 30-Second Demo

You write this Python:

from sagnos import expose, model, SagnosApp

@model
class User:
    id:    int
    name:  str
    email: str

@expose
async def get_user(id: int) -> User:
    return User(id=id, name="Ada Lovelace", email="ada@dev.com")

@expose
async def list_users() -> list[User]:
    return [User(id=1, name="Ada", email="ada@dev.com")]

app = SagnosApp()
app.run()

Sagnos generates this Dart automatically:

// You never write this โ€” Sagnos generates it
class User {
  final int id;
  final String name;
  final String email;
  // fromJson, toJson, copyWith all included
}

class SagnosClient {
  Future<User> getUser(int id) async { ... }
  Future<List<User>> listUsers() async { ... }
}

You use it in Flutter like this:

final client = SagnosClient();

// That's it. No HTTP. No JSON. Full type safety.
final user = await client.getUser(1);
Text(user.name)

Why Sagnos?

Plain FastAPI + Flutter Firebase gRPC Sagnos
Write Python backend โœ… โŒ โœ… โœ…
Keep real Flutter UI โœ… โœ… โœ… โœ…
Auto-generate Dart client โŒ โŒ โœ… (via .proto) โœ…
Python-native (just decorators) โŒ โŒ โŒ โœ…
Works with Python ML/AI โœ… โŒ โœ… โœ…
Zero boilerplate both sides โŒ โŒ โŒ โœ…

Installation

pip install sagnos

Flutter side โ€” add to pubspec.yaml:

dependencies:
  http: ^1.2.0

Quick Start

1. Write your Python backend

# backend.py
from datetime import datetime
from typing import Optional
from sagnos import expose, model, SagnosApp, NotFoundError

@model
class Product:
    id:       int
    title:    str
    price:    float
    in_stock: bool

PRODUCTS = {
    1: Product(id=1, title="Keyboard", price=49.99, in_stock=True),
    2: Product(id=2, title="Monitor",  price=299.99, in_stock=False),
}

@expose(method="GET")
async def list_products() -> list[Product]:
    """Get all products"""
    return list(PRODUCTS.values())

@expose(method="GET")
async def get_product(id: int) -> Product:
    """Get product by ID"""
    product = PRODUCTS.get(id)
    if not product:
        raise NotFoundError(f"Product {id} not found")
    return product

@expose
async def create_product(title: str, price: float) -> Product:
    """Create a new product"""
    new_id = max(PRODUCTS.keys()) + 1
    product = Product(id=new_id, title=title, price=price, in_stock=True)
    PRODUCTS[new_id] = product
    return product

if __name__ == "__main__":
    app = SagnosApp(title="My Shop")
    app.run()

2. Run the backend

python backend.py
โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘            ๐Ÿ  Sagnos v0.1.0                 โ•‘
โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
โ•‘  Server  โ†’  http://127.0.0.1:8000            โ•‘
โ•‘  Docs    โ†’  http://127.0.0.1:8000/docs       โ•‘
โ•‘  Schema  โ†’  http://127.0.0.1:8000/sagnos/schema
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

3. Generate Dart bindings

python -c "
from sagnos.codegen import generate
generate(
  'http://127.0.0.1:8000/sagnos/schema',
  './my_flutter_app/lib/sagnos'
)
"

This generates 4 files into your Flutter project:

my_flutter_app/lib/sagnos/
โ”œโ”€โ”€ models.dart            โ† Product class, fromJson, toJson
โ”œโ”€โ”€ sagnos_client.dart     โ† listProducts(), getProduct(), createProduct()
โ”œโ”€โ”€ sagnos_exception.dart  โ† typed error handling
โ””โ”€โ”€ sagnos_stream.dart     โ† WebSocket streaming support

4. Use in Flutter

import 'sagnos/sagnos_client.dart';
import 'sagnos/models.dart';
import 'sagnos/sagnos_exception.dart';

final client = SagnosClient(baseUrl: 'http://127.0.0.1:8000');

// List products
final products = await client.listProducts();

// Get one product
final product = await client.getProduct(1);
print(product.title); // Keyboard

// Create a product
final newProduct = await client.createProduct('USB Hub', 29.99);

// Typed error handling
try {
  await client.getProduct(999);
} on SagnosException catch (e) {
  if (e.isNotFound) print('Product not found');
}

Decorators

@model

Registers a Python class as a Sagnos data model. Auto-generates the Dart class with fromJson, toJson, copyWith.

@model
class User:
    id:         int
    name:       str
    created_at: datetime       # โ†’ DateTime in Dart
    bio:        Optional[str]  # โ†’ String? in Dart (null safe)

@expose

Registers a function as a REST endpoint. Auto-generates a typed Dart method in SagnosClient.

@expose(method="GET")               # GET or POST
async def get_user(id: int) -> User:
    ...

@expose(auth_required=True)         # Protected endpoint
async def delete_user(id: int) -> bool:
    ...

@expose(deprecated=True)            # Marks as deprecated in Dart
async def old_endpoint() -> str:
    ...

@stream

Registers an async generator as a WebSocket stream. Auto-generates SagnosStream<T> usage in Flutter.

@stream
async def live_updates() -> AsyncGenerator[User, None]:
    while True:
        yield get_latest_user()
        await asyncio.sleep(1)
// Flutter side
final stream = SagnosStream<User>(
  url: 'ws://127.0.0.1:8000/ws/live-updates',
  fromJson: User.fromJson,
);
stream.stream.listen((user) => setState(() => _user = user));

Type Mapping

Sagnos automatically converts Python types to Dart:

Python Dart
int int
float double
str String
bool bool
datetime DateTime
UUID String
Decimal double
Optional[X] X?
list[X] List<X>
dict[K, V] Map<K, V>
@model class Dart class

Error Handling

Define typed errors in Python:

from sagnos import NotFoundError, ValidationError_, AuthError

@expose
async def get_user(id: int) -> User:
    user = db.get(id)
    if not user:
        raise NotFoundError(f"User {id} not found")
    return user

Catch them by type in Flutter:

try {
  final user = await client.getUser(999);
} on SagnosException catch (e) {
  if (e.isNotFound)     print('User not found');
  if (e.isUnauthorized) print('Please login');
  if (e.isValidation)   print('Bad input: ${e.message}');
}

Real World Use Cases

AI Mobile App

import torch
from sagnos import expose, model, SagnosApp

@model
class Prediction:
    label:      str
    confidence: float

@expose
async def predict(text: str) -> Prediction:
    result = my_ml_model(text)
    return Prediction(label=result.label, confidence=result.score)

Flutter sends text, Python ML model processes it, result shows in UI. Zero HTTP code written.

IoT Dashboard

@stream
async def sensor_data() -> AsyncGenerator[Reading, None]:
    while True:
        yield read_sensor()
        await asyncio.sleep(0.5)

Real-time sensor readings streamed to Flutter UI via WebSocket.


Project Structure

my_app/
โ”œโ”€โ”€ backend.py              โ† your Python code (@expose, @model)
โ”œโ”€โ”€ requirements.txt
โ””โ”€โ”€ flutter_app/
    โ”œโ”€โ”€ lib/
    โ”‚   โ”œโ”€โ”€ main.dart       โ† your Flutter UI
    โ”‚   โ””โ”€โ”€ sagnos/         โ† AUTO-GENERATED, never edit
    โ”‚       โ”œโ”€โ”€ models.dart
    โ”‚       โ”œโ”€โ”€ sagnos_client.dart
    โ”‚       โ”œโ”€โ”€ sagnos_exception.dart
    โ”‚       โ””โ”€โ”€ sagnos_stream.dart
    โ””โ”€โ”€ pubspec.yaml

Rule: Edit backend.py for logic. Edit main.dart for UI. Never touch the sagnos/ folder โ€” it gets regenerated.


API Docs

When your backend is running, visit:

  • http://localhost:8000/docs โ€” Interactive Swagger UI
  • http://localhost:8000/sagnos/schema โ€” Raw schema JSON
  • http://localhost:8000/sagnos/health โ€” Health check

Contributing

Pull requests welcome. For major changes please open an issue first.

git clone https://github.com/siddhardh-codemonk/sagnos
cd sagnos
python -m venv .venv
.venv\Scripts\activate
pip install -e .
pytest tests/ -v

License

MIT


Author

Built by Siddhardh โ€” an 18-year-old CS student who wanted Python to work seamlessly with Flutter.

"Write Python. Get Flutter. That's it."

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

sagnos-0.2.0.tar.gz (22.9 kB view details)

Uploaded Source

Built Distribution

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

sagnos-0.2.0-py3-none-any.whl (21.9 kB view details)

Uploaded Python 3

File details

Details for the file sagnos-0.2.0.tar.gz.

File metadata

  • Download URL: sagnos-0.2.0.tar.gz
  • Upload date:
  • Size: 22.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for sagnos-0.2.0.tar.gz
Algorithm Hash digest
SHA256 561297cd1eb64511bc4d8e996a5b45c29db40bc2aad6a416e70dc93d33ad5865
MD5 7c1c4bf86e2e23c863ceef14a292c788
BLAKE2b-256 a4ae113ac9d47330f48e3f226a3d3ca903d6a7d964383df4c837ed2279882444

See more details on using hashes here.

File details

Details for the file sagnos-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: sagnos-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 21.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for sagnos-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2118142e04b63cc014c2f68b13fa07122c7601a5c51b6a380691709cf16bd96d
MD5 d169e97cd54c9ac0917aa57ecc0de809
BLAKE2b-256 67eaa5c729b3afa74dc15d9e0b012f9796fa4a36230fc2993e65e35aa4846360

See more details on using hashes here.

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