Contrib integrations
Adapters mounting citry into web frameworks, and cache adapters for shared stores (the citry.contrib.<name> modules).
mount function
Mount citry_instance's routes into a FastAPI/Starlette app at prefix, and record the prefix on the instance.
mount function
Mount citry_instance's routes into a Flask app at prefix, and record the prefix on the instance.
urlpatterns function
Citry.urls as Django URL patterns, for include()-ing.
Pass prefix (where you include the patterns, e.g. "/citry") to also record it on the instance, so URL building (fragment manifests, the runtime src) points at the right place; leaving it None means you call set_mounted_prefix yourself.
The generated views are synchronous, so every route handler must be a plain function; an async def handler raises TypeError here, pointing at the ASGI adapter as the fix.
enable_hot_reload function
enable_hot_reload(citry_instance: Citry, mode: Literal['hot', 'restart'] = 'hot') -> Callable[..., bool | None]Reload changed component files in development, using Django's autoreloader.
Connects a receiver to Django's file_changed autoreload signal. When a watched file changes, the receiver clears the caches of the components that loaded it (Citry.invalidate_file). With mode="hot" (the default) the change is handled in place and the server keeps running; with mode="restart" the process restart is left to Django (the same thing Django does for a Python edit). Files that back no loaded component fall through to Django's normal handling either way.
Call once at startup, e.g. from your AppConfig.ready(). Django watches its template and static directories, so this needs no watcher of its own. Returns the connected receiver (disconnect it via file_changed.disconnect if you ever need to).
secret function
secret() -> strDjango's SECRET_KEY, for passing as Citry(secret=...).
Citry signs values with the engine-level secret setting. In a Django project the natural signing key is the one the project already manages, so pass it through::
from citry import Citry
from citry.contrib.django import secret
app = Citry(secret=secret())
The key is read when this is called, so Django settings must be configured by then (in a normal Django startup they already are).
Returns
str: The ``SECRET_KEY`` of the active Django settings.
Raises
RuntimeError- When Django settings are not configured; the message names the fix.django.core.exceptions.ImproperlyConfigured- When settings are configured but the ``SECRET_KEY`` itself is unusable (for example empty); Django's own message explains the problem.
DjangoCache class
Adapt a Django cache (django.core.cache.caches[...]) to citry's CitryCache protocol, so citry's stored scripts live in whatever cache backend the Django project already runs (Redis, Memcached, database, ...).
asgi_app function
Build the ASGI application serving citry_instance.urls.
The returned app handles lifespan events (so it also works served standalone), routes each http request to the matched citry handler (preferring a route's handler_async twin when it carries one), translates the scope into a RouteRequest (_build_request), dispatches it (call_maybe_sync: async handlers are awaited, sync ones run in a worker thread), and translates the returned RouteResponse into ASGI messages (_send_response).
reload_lifespan function
reload_lifespan(engine: Citry, roots: Iterable[str | Path] | None = None, watcher: FileWatcher | None = None, on_reload: Callable[[set[Path], list[type[Component]]], None] | None = None) -> Callable[[Any], AbstractAsyncContextManager[None]]A Starlette/FastAPI lifespan that hot-reloads component files while the app runs.
Compose it into the app's root lifespan::
from contextlib import asynccontextmanager
from citry.contrib.asgi import reload_lifespan
watch_lifespan = reload_lifespan(citry_instance)
@asynccontextmanager
async def lifespan(app):
citry_instance.initialize()
async with watch_lifespan(app):
yield
app = FastAPI(lifespan=lifespan) # or Starlette(...)
It starts the :mod:citry.reload watcher on startup and stops it on shutdown, so editing a component's template/JS/CSS shows up on the next render without restarting. It manages only the watcher and does not call Citry.initialize(); the root lifespan owns initialization. For development; in production simply do not add it. If you already have a lifespan, nest this one inside yours. The keyword arguments mirror :func:citry.reload.watch.
wsgi_app function
wsgi_app(citry_instance: Citry) -> WSGIAppBuild the WSGI application serving citry_instance.urls.
The returned app routes each request to the matched citry handler, translates the environ into a RouteRequest (_build_request), calls the handler, and translates the returned RouteResponse back into the WSGI shape (respond). Async handlers are rejected with a pointed error up front: WSGI is synchronous.
RedisCache class
Adapt a Redis client (redis.Redis or compatible) to citry's CitryCache protocol. Values are stored as UTF-8 strings; ttl becomes the key's expiry (ex).
prefix is prepended to every key, for sharing a Redis database with other uses. (Citry's own keys already start with citry:.)
DiskCache class
Adapt a diskcache.Cache (or compatible) to citry's CitryCache protocol. The store is a directory on disk, shared by every worker process on the host.