Theme
Version
GitHub PyPI Discord
On this page

Contrib integrations

Adapters mounting citry into web frameworks, and cache adapters for shared stores (the citry.contrib.<name> modules).

View source

mount function

mount(app: Any, citry_instance: Citry, prefix: str = '/citry') -> None

Mount citry_instance's routes into a FastAPI/Starlette app at prefix, and record the prefix on the instance.

View source

mount function

mount(app: Any, citry_instance: Citry, prefix: str = '/citry') -> None

Mount citry_instance's routes into a Flask app at prefix, and record the prefix on the instance.

View source

urlpatterns function

urlpatterns(citry_instance: Citry, prefix: str | None = None) -> list[Any]

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.

View source

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).

View source

secret function

secret() -> str

Django'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.
View source

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, ...).

View source

set function

set(key: str, value: str, ttl: float | None = None) -> None
View source

asgi_app function

asgi_app(citry_instance: Citry) -> Callable[[Scope, Receive, Send], Awaitable[None]]

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).

View source

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.

View source

wsgi_app function

wsgi_app(citry_instance: Citry) -> WSGIApp

Build 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.

View source

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:.)

View source

set function

set(key: str, value: str, ttl: float | None = None) -> None
View source

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.

View source

set function

set(key: str, value: str, ttl: float | None = None) -> None
Citry version: 0.3.0