Description
Nestipy is a Python framework built on top of FastAPI that follows the modular architecture of NestJS
Under the hood, Nestipy makes use of FastAPI, but also provides compatibility with a wide range of other libraries, like Blacksheep, allowing for easy use of the myriad of third-party plugins which are available.
Getting started
Scaffold a full project (backend + a generated React/Vue/Svelte frontend) with the Nestipy CLI:
nestipy new myapp --fullstack --react # or --vue / --svelte
cd myapp && uv sync && nestipy start --dev
cd inertia && npm install && npm run dev
Or add it to an existing project:
pip install nestipy-inertia
Full manual: https://nestipy.github.io/nestipy/technique/inertia.html
Features
Full latest Inertia.js protocol parity:
- Partial reloads —
only(X-Inertia-Partial-Data),except(X-Inertia-Partial-Except, takes precedence) andX-Inertia-Reset. - Prop helpers —
optional(fn),defer(fn, group=..., merge=...),merge(fn),deep_merge(fn, match_on=[...])(pluslazyalias). - Deferred props (
deferredProps) and merge props (mergeProps/deepMergeProps/matchPropsOn). - History encryption —
res.inertia.encrypt_history()/clear_history()(+InertiaConfig(encrypt_history=True)). - Asset versioning with
409(GET only) +X-Inertia-Location, and automatic302 → 303forPUT/PATCH/DELETE. - Shared props, session flash messages, and Pydantic validation-error handling with error bags.
- SSR via an external Inertia SSR server, with template fallback.
Full example
main.py
import os
import uvicorn
from nestipy.core import NestipyFactory
from nestipy.common import session
from app_module import AppModule, inertia_config
from nestipy_inertia import inertia_head, inertia_body, vite_react_refresh
app = NestipyFactory.create(AppModule)
# set view engine mini jinja and
app.set_base_view_dir(os.path.join(os.path.dirname(__file__), "views"))
# enable session
app.use(session())
if __name__ == '__main__':
uvicorn.run('main:app', host="0.0.0.0", port=8000, reload=True)
app_module.py
import os.path
from nestipy.common import Module
from app_controller import AppController
from app_service import AppService
from nestipy_inertia import InertiaModule, InertiaConfig
@Module(
imports=[
InertiaModule.register(
InertiaConfig(
root_dir=os.path.join(os.getcwd(), "inertia")
)
)
],
controllers=[AppController],
providers=[
AppService,
]
)
class AppModule:
...
vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import nestipyVite from "./nestipy.inertia";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
nestipyVite({
entry: './src/main.tsx',
ssr: './src/ssr.tsx'
}),
],
})
nestipy.inertia.ts
import { PluginOption } from "vite";
type Input = {
entry: string,
ssr?: string,
manifest?: string
}
type NestipyPlugin = (options: Input) => PluginOption
const nestipyVite: NestipyPlugin = ({entry, ssr, manifest = "manifest.json"}) => {
return {
name: "nestipy-vite-plugin",
config: (config, env) => {
return {
...config,
build: {
manifest: env.isSsrBuild ? false: manifest,
outDir: env.isSsrBuild ? "dist/ssr" : "dist",
rollupOptions: {
input: env.isSsrBuild && ssr ? ssr : entry,
},
},
ssr: {
noExternal: ['@inertiajs/server']
}
}
}
}
}
export default nestipyVite
views/index.html
<!Doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<link rel="icon" type="image/svg+xml" href="/vite.svg"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Nestipy + Vite + React + TS + Inertia + Mini jinja</title>
{{ inertiaHead() }}
</head>
<body>
{{ viteReactRefresh() }}
{{ inertiaBody() }}
</body>
</html>
app_controller.py
from typing import Annotated
from nestipy.common import Controller, Get, Response, Post
from nestipy.ioc import Inject, Res, Body
from pydantic import BaseModel, EmailStr
from app_service import AppService
from nestipy_inertia import InertiaResponse, optional, defer
class UserLogin(BaseModel):
email: EmailStr
password: str
@Controller()
class AppController:
service: Annotated[AppService, Inject()]
@Get()
async def get(self, res: Annotated[InertiaResponse, Res()]) -> Response:
props = {
"message": "hello from index",
"details": optional(lambda: "loaded only on partial reload"),
"stats": defer(lambda: {"users": 42, "online": 7}),
}
return await res.inertia.render("Index", props)
@Get('/about')
async def about(self, res: Annotated[InertiaResponse, Res()]) -> Response:
return await res.inertia.render("About", {"framework": "Nestipy + Inertia.js"})
@Post("/login")
async def some_form(self, user: Annotated[UserLogin, Body()], res: Annotated[InertiaResponse, Res()]) -> Response:
res.inertia.flash("form submitted", category="success")
return await res.inertia.back()
Viw full example code here.
Support
Nestipy is an MIT-licensed open source project. It can grow thanks to the sponsors and support from the amazing backers. If you'd like to join them, please [read more here].
Stay in touch
- Author - Tsiresy Mila
License
Nestipy is MIT licensed.
Metadata
Release files for nestipy-inertia 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nestipy_inertia-0.2.0.tar.gz | 12.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nestipy_inertia-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.2 kB
Release files / nestipy_inertia-0.2.0.tar.gz
| Download URL | nestipy_inertia-0.2.0.tar.gz |
|---|---|
| Size | 12.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
90629c16f474ba75af59828396af60f98faea272f90e26a0195dbf762082ddbc
|
|
BLAKE2b-256 checksum How to use checksums |
bea32e1059c6ed429658c92031d798780c9d1a9331629d583239f8ffb3223a29
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.21
|
Release files / nestipy_inertia-0.2.0-py3-none-any.whl
| Download URL | nestipy_inertia-0.2.0-py3-none-any.whl |
|---|---|
| Size | 16.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
30e779dc4f149d20d8e5efabd9c0a661e32f0af309b6ad1e2c884b4cae95be7d
|
|
BLAKE2b-256 checksum How to use checksums |
fc73085fbc399c9b3bac0224c0549b75a98c9698747371107026be0b6ec98f82
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.21
|