Types¶
Type definitions for Aksara.
Overview¶
Aksara is fully typed and provides type stubs for IDE support.
Core Types¶
Model Types¶
from aksara import Model
from typing import TypeVar, Generic
# Model type variable
ModelT = TypeVar("ModelT", bound=Model)
# Generic model type
class ModelViewSet(Generic[ModelT]):
model: type[ModelT]
ID Types¶
from uuid import UUID
from typing import Union
# Primary key type
PK = Union[str, UUID]
# Model ID
class Model:
id: UUID
pk: UUID # Alias for id
QuerySet Types¶
from typing import TypeVar, Generic, AsyncIterator, List, Optional
ModelT = TypeVar("ModelT", bound=Model)
class QuerySet(Generic[ModelT]):
async def all(self) -> List[ModelT]: ...
async def first(self) -> Optional[ModelT]: ...
async def get(self, **kwargs) -> ModelT: ...
async def filter(self, **kwargs) -> "QuerySet[ModelT]": ...
async def count(self) -> int: ...
async def exists(self) -> bool: ...
def __aiter__(self) -> AsyncIterator[ModelT]: ...
Field Types¶
Basic Field Types¶
from aksara import fields
# Fields use the pattern: fields.FieldType
class User(Model):
name = fields.String(max_length=100)
age = fields.Integer()
score = fields.Float()
is_active = fields.Boolean(default=True)
email = fields.Email()
metadata = fields.JSON(default=dict)
Optional Fields¶
from datetime import datetime
class Post(Model):
title = fields.String(max_length=200)
published_at = fields.DateTime(null=True) # null=True makes it optional
Relationship Types¶
from aksara import fields
class Post(Model):
author = fields.ForeignKey("User", on_delete=fields.CASCADE)
tags = fields.ManyToMany("Tag", related_name="posts")
API Types¶
Request Types¶
from typing import Any, Dict, Optional
from aksara.api.request import Request
class Request:
user: "User"
data: Dict[str, Any]
query_params: Dict[str, str]
headers: Dict[str, str]
method: str
path: str
Response Types¶
from typing import Any, Dict, Optional, Union, Tuple
# Response can be:
ResponseType = Union[
Dict[str, Any], # JSON dict
Tuple[Dict[str, Any], int], # Dict with status code
"Response", # Response object
]
Serializer Types¶
from typing import TypeVar, Generic, Type, Dict, Any, List
ModelT = TypeVar("ModelT", bound=Model)
class ModelSerializer(Generic[ModelT]):
class Meta:
model: Type[ModelT]
fields: Union[List[str], str]
async def is_valid(self, raise_exception: bool = False) -> bool: ...
async def save(self, **kwargs) -> ModelT: ...
@property
def data(self) -> Dict[str, Any]: ...
@property
def errors(self) -> Dict[str, List[str]]: ...
ViewSet Types¶
from typing import TypeVar, Generic, Type, List, Optional
ModelT = TypeVar("ModelT", bound=Model)
class ModelViewSet(Generic[ModelT]):
model: Type[ModelT]
serializer_class: Type[ModelSerializer[ModelT]]
permission_classes: List[Type["BasePermission"]]
def get_queryset(self) -> QuerySet[ModelT]: ...
async def get_object(self) -> ModelT: ...
Permission Types¶
from typing import Protocol
class BasePermission(Protocol):
async def has_permission(
self,
request: "Request",
view: "ViewSet"
) -> bool: ...
async def has_object_permission(
self,
request: "Request",
view: "ViewSet",
obj: Model
) -> bool: ...
Pagination Types¶
from typing import TypedDict, List, Any, Optional
class PagedResponse(TypedDict):
count: int
next: Optional[str]
previous: Optional[str]
results: List[Any]
Filter Types¶
Cache Types¶
from typing import TypeVar, Optional, Any, Callable, Awaitable
T = TypeVar("T")
CacheKey = str
CacheTTL = int
class Cache:
async def get(self, key: CacheKey, default: T = None) -> Optional[T]: ...
async def set(self, key: CacheKey, value: Any, ttl: CacheTTL = None) -> None: ...
async def delete(self, key: CacheKey) -> None: ...
Signal Types¶
from typing import Callable, Awaitable, Any, TypeVar
ModelT = TypeVar("ModelT", bound=Model)
SignalHandler = Callable[..., Awaitable[None]]
class Signal:
def connect(
self,
handler: SignalHandler,
sender: type[ModelT] = None
) -> None: ...
async def send(
self,
sender: type[ModelT],
**kwargs: Any
) -> None: ...
AI Types¶
from typing import TypedDict, List, Optional, Any
class QueryResult(TypedDict):
data: List[Any]
count: int
sql: str
class SchemaIssue(TypedDict):
severity: str # "critical", "high", "medium", "low"
message: str
fix_hint: Optional[str]
model: str
field: Optional[str]
class AgentResult(TypedDict):
output: str
session_id: str
steps: List[str]
Utility Types¶
Settings Type¶
from typing import TypedDict, List, Dict, Any, Optional
class AksaraSettings(TypedDict, total=False):
DEBUG: bool
SECRET_KEY: str
DATABASE_URL: str
INSTALLED_APPS: List[str]
MIDDLEWARE: List[str]
CACHE: Dict[str, Any]
AI_MODE: bool
AI_API_KEY: Optional[str]
Callable Types¶
from typing import Callable, Awaitable, TypeVar
T = TypeVar("T")
# Async function
AsyncFunc = Callable[..., Awaitable[T]]
# Validator
Validator = Callable[[Any], Any]
# Async validator
AsyncValidator = Callable[[Any], Awaitable[Any]]
Type Checking¶
Using mypy¶
# Install
pip install mypy
# Run
mypy myapp/
# Configuration in pyproject.toml
[tool.mypy]
plugins = ["aksara.mypy"]
strict = true
Using pyright¶
# Install
pip install pyright
# Run
pyright myapp/
# Configuration in pyrightconfig.json
{
"typeCheckingMode": "strict"
}
Type Stubs¶
Aksara includes inline type annotations and a py.typed marker. Type stubs are available for all public APIs.
# Example stub (fields.pyi)
from typing import TypeVar, Generic, Optional, Any
T = TypeVar("T")
class Field(Generic[T]):
def __init__(
self,
null: bool = False,
default: Optional[T] = None,
unique: bool = False,
db_index: bool = False,
validators: list = ...,
**kwargs: Any
) -> None: ...
def __get__(self, obj: Any, type: Any = None) -> T: ...
def __set__(self, obj: Any, value: T) -> None: ...
class String(Field[str]):
def __init__(
self,
max_length: int = ...,
min_length: int = ...,
**kwargs: Any
) -> None: ...
class Integer(Field[int]): ...
class Float(Field[float]): ...
class Boolean(Field[bool]): ...