Remove render_to_sx from public API: enforce sx_call for all service code
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m44s

Replace ~250 render_to_sx calls across all services with sync sx_call,
converting many async functions to sync where no other awaits remained.
Make render_to_sx/render_to_sx_with_env private (_render_to_sx).
Add (post-header-ctx) IO primitive and shared post/post-admin defmacros.
Convert built-in post/post-admin layouts from Python to register_sx_layout
with .sx defcomps. Remove dead post_admin_mobile_nav_sx.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 19:30:45 +00:00
parent 57e0d0c341
commit 959e63d440
61 changed files with 1352 additions and 1208 deletions

View File

@@ -46,6 +46,7 @@ IO_PRIMITIVES: frozenset[str] = frozenset({
"url-for",
"route-prefix",
"root-header-ctx",
"post-header-ctx",
"select-colours",
"account-nav-ctx",
"app-rights",
@@ -482,6 +483,80 @@ async def _io_app_rights(
return getattr(g, "rights", None) or {}
async def _io_post_header_ctx(
args: list[Any], kwargs: dict[str, Any], ctx: RequestContext
) -> dict[str, Any]:
"""``(post-header-ctx)`` → dict with post-level header values.
Reads post data from ``g._defpage_ctx`` (set by per-service page
helpers), fetches container-nav and page cart count. Result is
cached on ``g`` per request.
Returns dict with keys: slug, title, feature-image, link-href,
container-nav, page-cart-count, cart-href, admin-href, is-admin,
is-admin-page, select-colours.
"""
from quart import g, request
cached = getattr(g, "_post_header_ctx", None)
if cached is not None:
return cached
from shared.infrastructure.urls import app_url
from .types import NIL
from .parser import SxExpr
dctx = getattr(g, "_defpage_ctx", None) or {}
post = dctx.get("post") or {}
slug = post.get("slug", "")
if not slug:
result: dict[str, Any] = {"slug": ""}
g._post_header_ctx = result
return result
title = (post.get("title") or "")[:160]
feature_image = post.get("feature_image") or NIL
# Container nav (pre-fetched by page helper into defpage ctx)
raw_nav = dctx.get("container_nav") or ""
container_nav: Any = NIL
nav_str = str(raw_nav).strip()
if nav_str and nav_str.replace("(<>", "").replace(")", "").strip():
if isinstance(raw_nav, SxExpr):
container_nav = raw_nav
else:
container_nav = SxExpr(nav_str)
page_cart_count = dctx.get("page_cart_count", 0) or 0
rights = getattr(g, "rights", None) or {}
is_admin = (
rights.get("admin", False)
if isinstance(rights, dict)
else getattr(rights, "admin", False)
)
is_admin_page = dctx.get("is_admin_section") or "/admin" in request.path
from quart import current_app
select_colours = current_app.jinja_env.globals.get("select_colours", "")
result = {
"slug": slug,
"title": title,
"feature-image": feature_image,
"link-href": app_url("blog", f"/{slug}/"),
"container-nav": container_nav,
"page-cart-count": page_cart_count,
"cart-href": app_url("cart", f"/{slug}/") if page_cart_count else "",
"admin-href": app_url("blog", f"/{slug}/admin/"),
"is-admin": is_admin,
"is-admin-page": is_admin_page or NIL,
"select-colours": select_colours,
}
g._post_header_ctx = result
return result
_IO_HANDLERS: dict[str, Any] = {
"frag": _io_frag,
"query": _io_query,
@@ -499,6 +574,7 @@ _IO_HANDLERS: dict[str, Any] = {
"url-for": _io_url_for,
"route-prefix": _io_route_prefix,
"root-header-ctx": _io_root_header_ctx,
"post-header-ctx": _io_post_header_ctx,
"select-colours": _io_select_colours,
"account-nav-ctx": _io_account_nav_ctx,
"app-rights": _io_app_rights,