Tina4Python - This is not another framework for Python
Project description
Tina4 Python — This is not a framework
Laravel joy. Python speed. 10x less code.
Quickstart
pip install tina4-python
tina4 init my_project
cd my_project
python app.py
You've just built your first Tina4 app — zero configuration, zero classes, zero boilerplate!
Prefer uv? Replace
pip install tina4-pythonwithuv add tina4-python, then useuv run tina4 startto launch the dev server.
Features
- ASGI compliant — works with any ASGI server (uvicorn, hypercorn, daphne)
- Full async — every route handler is
asyncby default - Routing — decorator-based with path parameters, type hints, and auto-discovery
- Twig/Jinja2 templates — with inheritance, partials, custom filters, and globals
- tina4-css — lightweight CSS framework (~24 KB) ships built-in, Bootstrap-compatible class names
- ORM — define models with typed fields, save/load/select/delete with one line
- Database — SQLite, PostgreSQL, MySQL, MariaDB, MSSQL, Firebird, MongoDB
- Migrations — versioned SQL files, CLI scaffolding
- Data seeder — zero-dependency fake data generation with ORM and table support
- Sessions — file, Redis, Valkey, or MongoDB backends
- JWT authentication — HS256 tokens signed with your
SECRETenv var, form tokens - Swagger/OpenAPI — auto-generated docs at
/swagger - CRUD scaffolding — instant searchable admin UI with one line of code
- GraphQL — zero-dependency engine with ORM auto-schema and GraphiQL IDE
- Middleware — before/after hooks per route or globally
- Queues — background processing with litequeue, RabbitMQ, Kafka, or MongoDB
- WebSockets — built-in support via
simple-websocket - WSDL/SOAP — auto-generated WSDL from Python classes
- REST client — built-in
Apiclass for external HTTP calls - SCSS compilation — auto-compiled to CSS on save
- Live reload — browser auto-refreshes during development
- Inline testing — decorator-based test cases with
@tests - Localization — i18n via gettext (English, French, Afrikaans, Chinese, Japanese, Spanish)
Install
pip install tina4-python
Or with uv (recommended):
uv add tina4-python
Optional extras
Install only the database driver you need:
pip install tina4-python[postgres] # PostgreSQL (psycopg2-binary)
pip install tina4-python[mysql] # MySQL / MariaDB (mysql-connector-python)
pip install tina4-python[mssql] # Microsoft SQL Server (pymssql)
pip install tina4-python[firebird] # Firebird (firebird-driver)
pip install tina4-python[mongo] # MongoDB (pymongo)
pip install tina4-python[all-db] # all of the above
pip install tina4-python[dev-reload] # hot-patching via jurigged
Routing
Routes live in src/routes/ and are auto-discovered on startup.
# src/routes/hello.py
from tina4_python import get
@get("/hello")
async def get_hello(request, response):
return response("Hello, Tina4 Python!")
@get("/hello/{name}")
async def get_hello_name(name, request, response):
return response(f"Hello, {name}!")
@get("/hello/json")
async def get_hello_json(request, response):
return response([{"brand": "BMW"}, {"brand": "Toyota"}])
@get("/hello/template")
async def get_hello_template(request, response):
return response.render("index.twig", {"data": request.params})
ORM
# src/orm/User.py
from tina4_python import ORM, IntegerField, StringField
class User(ORM):
id = IntegerField(primary_key=True, auto_increment=True)
name = StringField()
email = StringField()
User({"name": "Alice", "email": "alice@example.com"}).save()
Database
from tina4_python.Database import Database
db = Database("sqlite3:app.db")
db = Database("psycopg2:localhost/5432:mydb", "user", "password") # PostgreSQL
db = Database("mysql.connector:localhost/3306:mydb", "user", "password") # MySQL
db = Database("pymongo:localhost/27017:mydb") # MongoDB
result = db.fetch("SELECT * FROM users WHERE age > ?", [18])
Migrations
tina4 migrate:create "create users table"
# Edit the generated SQL file in migrations/
tina4 migrate
Data Seeder
Generate fake data for development and testing:
from tina4_python.Seeder import FakeData, seed_orm, seed_table
fake = FakeData()
fake.name() # "Alice Johnson"
fake.email() # "alice.johnson@example.com"
fake.phone() # "+27 82 123 4567"
# Seed an ORM model
seed_orm(User, count=50)
# Seed a raw table
seed_table(db, "products", columns, count=100)
CLI:
tina4 seed # run all files in src/seeds/
tina4 seed:create "initial users" # scaffold a new seed file
CRUD Scaffolding
Generate a searchable, paginated admin UI with one call:
from tina4_python.CRUD import CRUD
@get("/admin/users")
async def admin_users(request, response):
return response(CRUD.to_crud(request, {
"sql": "SELECT id, name, email FROM users",
"title": "User Management",
"primary_key": "id",
}))
Sessions
Built-in session management with pluggable backends:
| Handler | Backend | Package |
|---|---|---|
SessionFileHandler (default) |
File system | — |
SessionRedisHandler |
Redis | redis |
SessionValkeyHandler |
Valkey | valkey |
SessionMongoHandler |
MongoDB | pymongo |
request.session.set("user_id", 42)
user_id = request.session.get("user_id")
JWT Authentication
Tokens are signed with HS256 using your SECRET env var. Set it in .env:
SECRET=your-strong-random-secret-32-chars-min
from tina4_python import tina4_auth
token = tina4_auth.get_token({"user_id": 42})
is_valid = tina4_auth.valid(token)
payload = tina4_auth.get_payload(token)
hashed = tina4_auth.hash_password("mypassword")
ok = tina4_auth.check_password(hashed, "mypassword")
Queues
Background processing with litequeue (default), RabbitMQ, Kafka, or MongoDB.
from tina4_python.Queue import Queue, Producer, Consumer
# Enqueue from a route
Producer(Queue(topic="emails")).produce({"to": "alice@example.com"})
# Process in a worker
for msg in Consumer(Queue(topic="emails")).messages():
send_email(msg.data)
GraphQL
Zero-dependency GraphQL engine with ORM auto-schema:
from tina4_python.GraphQL import GraphQL
gql = GraphQL()
gql.schema.from_orm(User) # auto-generates type, queries, and mutations
gql.schema.from_orm(Product)
gql.register_route("/graphql") # GET = GraphiQL IDE, POST = queries
Middleware
from tina4_python.Router import get, middleware
class AuthCheck:
@staticmethod
def before_auth(request, response):
if "authorization" not in request.headers:
return request, response("Unauthorized", 401)
return request, response
@middleware(AuthCheck)
@get("/protected")
async def protected(request, response):
return response({"secret": True})
Swagger / OpenAPI
Auto-generated at /swagger. Add metadata with decorators:
from tina4_python import description, tags
@get("/users")
@description("Get all users")
@tags(["users"])
async def users(request, response):
return response(User().select("*"))
REST Client
from tina4_python import Api
api = Api("https://api.example.com", auth_header="Bearer xyz")
result = api.send_request("/users/42")
WSDL / SOAP
from tina4_python.WSDL import WSDL, wsdl_operation
from tina4_python import get, post
class Calculator(WSDL):
@wsdl_operation({"Result": int})
def Add(self, a: int, b: int):
return {"Result": a + b}
@get("/calculator")
@post("/calculator")
async def calculator(request, response):
return response(Calculator(request).handle())
Inline Testing
from tina4_python import tests, assert_equal, assert_raises
@tests(
assert_equal((7, 7), 1),
assert_raises(ZeroDivisionError, (5, 0)),
)
def divide(a: int, b: int) -> float:
if b == 0:
raise ZeroDivisionError("division by zero")
return a / b
Run with tina4 test or uv run pytest.
Environment
Key .env settings:
SECRET=your-jwt-secret-32-chars-min
API_KEY=your-api-key
DATABASE_NAME=sqlite3:app.db
TINA4_DEBUG_LEVEL=ALL
TINA4_LANGUAGE=en
TINA4_SESSION_HANDLER=SessionFileHandler
SWAGGER_TITLE=My API
Further Documentation
Community
License
MIT (c) 2007-2025 Tina4 Stack https://opensource.org/licenses/MIT
Tina4 — The framework that keeps out of the way of your coding.
Our Sponsors
Sponsored with 🩵 by Code Infinity
Supporting open source communities • Innovate • Code • Empower
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tina4_python-0.2.204.tar.gz.
File metadata
- Download URL: tina4_python-0.2.204.tar.gz
- Upload date:
- Size: 450.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
362a0b5e2a2f61560ca3647684162590cfb7bcce4503509bdf1ecaf53dd92206
|
|
| MD5 |
fc7530fcb5c336c8967a6b0f7f6217a8
|
|
| BLAKE2b-256 |
d7643dc22fbb39b863a8bac51b99a8d611dd222daf1cfd1d8dd027885d3698b1
|
File details
Details for the file tina4_python-0.2.204-py3-none-any.whl.
File metadata
- Download URL: tina4_python-0.2.204-py3-none-any.whl
- Upload date:
- Size: 501.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63962874cd6c03e464824007d1501f6ce7ce7b59918cfe231935204f835e44da
|
|
| MD5 |
f001fad60393374476cf0c068e10c2b3
|
|
| BLAKE2b-256 |
4a1f41b6bf98e0e680090ea945d1d5026a92633c03b428ef0fbdd00310e66903
|