Tina4 Python – Quick Reference
Installation
pip install tina4-python
tina4 init my-project
cd my-project
tina4 startStatic Websites
Put .twig files in ./src/templates • assets in ./src/public
<!-- src/templates/index.twig -->
<h1>Hello Static World</h1>Basic Routing
from tina4_python import get, post
@get("/")
async def get_home(request, response):
return response("<h1>Hello Tina4 Python</h1>")
# post requires a formToken in body or Bearer auth
@post("/api")
async def post_api(request, response):
return response({"data": request.params})
# redirect after post
@post("/register")
async def post_register(request, response):
return response.redirect("/welcome")Middleware
class RunSomething:
@staticmethod
def before_something(request, response):
response.content += "Before"
return request, response
@staticmethod
def after_something(request, response):
response.content += "After"
return request, response
@staticmethod
def before_and_after_something(request, response):
response.content += "[Before / After Something]"
return request, response
@middleware(RunSomething)
@get("/middleware")
async def get_middleware(request, response):
return response("Route") # Before[Before / After Something]Route[Before / After Something]AfterTemplate Rendering
Put .twig files in ./src/templates • assets in ./src/public
<!-- src/templates/index.twig -->
<h1>Hello {{name}}</h1>from tina4_python import get, post
@get("/")
async def get_home(request, response):
return response.render("index.twig", {"name": "World!"})Sessions
The default session handling is SessionFileHandler, override TINA4_SESSION_HANDLER in .env
@get("/session/set")
async def get_session_set(request, response):
request.session.set("name", "Joe")
request.session.set("info", {"info": ["one", "two", "three"]})
return response("Session Set!")
@get("/session/get")
async def get_session_set(request, response):
name = request.session.get("name")
info = request.session.get("info")
return response({"name": name, "info": info})SCSS Stylesheets
Drop in ./src/scss → auto-compiled to ./src/public/css
// src/scss/main.scss
$primary: #2c3e50;
body {
background: $primary;
color: white;
}Environments
Default development environment can be found in .env
PROJECT_NAME="My Project"
VERSION=1.0.0
TINA4_LANGUAGE=en
TINA4_DEBUG_LEVEL=ALL
API_KEY=ABC1234
TINA4_TOKEN_LIMIT=1
DATABASE_NAME=sqlite3:test.dbimport os
api_key = os.getenv("API_KEY", "ABC1234")Authentication
Pass Authorization: Bearer API_KEY to secured routes in requests. See .env for default API_KEY.
from tina4_python import get, post, noauth, secured
@post("/login")
@noauth()
async def login(request, response):
return response("Logged in", cookies={"session": "abc123"})
@get("/protected")
@secured()
async def secret(request, response):
return f"Hi {request.cookies.get('username', 'guest')}!"HTML Forms and Tokens
<form method="POST" action="/register">
{{ ("Register" ~ RANDOM()) | form_token }}
<input name="email">
<button>Save</button>
</form>AJAX and tina4helper.js
Tina4 ships with a small javascript library, in the bin folder, to assist with the heavy lifting of ajax calls.
More details on available features.
OpenAPI and Swagger UI
Visit http://localhost:7145/swagger
@get("/users", "Get all users")
async def users(request, response):
"""Returns all users"""
return response(User().select("*"))Databases
from tina4_python.Database import Database
# dba = Database("<driver>:<hostname>/<port>:database_name", username, password)
dba = Database("sqlite3:data.db")Database Results
result = dba.fetch("select * from test_record order by id", limit=3, skip=1)
alist = result.to_list()
array = result.to_array()
dictionary = result.to_dict()
paginated = result.to_paginate()
csv = result.to_csv()
json = result.to_json()Migrations
tina4 migrate:create create_users_table-- migrations/00001_create_users_table.sql
CREATE TABLE users
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT
);tina4 migrateORM
from tina4_python import ORM
class User(ORM):
table_name = "users"
User({"name": "Alice"}).save()
User().load("id = ?", 1)CRUD
@get("/users/dashboard")
async def dashboard(request, response):
users = User().select("id, name, email")
return response.render("users/dashboard.twig", {"crud": users.to_crud(request)}){{ crud }}Consuming REST APIs
from tina4_python import Api
api = Api("https://api.example.com", auth_header="Bearer xyz")
result = api.get("/users/42")
print(result["body"])Inline Testing
from tina4python import tests
@tests(
assert_equal((7, 7), 1),
assert_equal((-1, 1), -1),
assert_raises(ZeroDivisionError, (5, 0)),
)
def divide(a: int, b: int) -> float:
if b == 0:
raise ZeroDivisionError("division by zero")
return a / bRun: tina4 test
Services
Due to the nature of python, services are not necessary.
Threads
Due to the nature of python, threads are not necessary.
Queues
Documentation pending . . .
Full details of queues are available though
WSDL
from tina4_python.WSDL import WSDL, wsdl_operation
from typing import List
class Calculator(WSDL):
SERVICE_URL = "http://localhost:7145/calculator"
def Add(self, a: int, b: int):
return {"Result": a + b}
def SumList(self, Numbers: List[int]):
return {
"Numbers": Numbers,
"Total": sum(Numbers),
"Error": None
}
@wsdl("/calculator")
async def wsdl_cis(request, response):
return response.wsdl(Calculator(request))