Replace sx_call() with render_to_sx() across all services
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m6s

Python no longer generates s-expression strings. All SX rendering now
goes through render_to_sx() which builds AST from native Python values
and evaluates via async_eval_to_sx() — no SX string literals in Python.

- Add render_to_sx()/render_to_html() infrastructure in shared/sx/helpers.py
- Add (abort status msg) IO primitive in shared/sx/primitives_io.py
- Convert all 9 services: ~650 sx_call() invocations replaced
- Convert shared helpers (root_header_sx, full_page_sx, etc.) to async
- Fix likes service import bug (likes.models → models)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 00:08:33 +00:00
parent 0554f8a113
commit e085fe43b4
51 changed files with 1824 additions and 1742 deletions

View File

@@ -34,30 +34,30 @@ def _register_sx_layouts() -> None:
register_custom_layout("sx-section", _sx_section_full_headers, _sx_section_oob_headers, _sx_section_mobile)
def _sx_full_headers(ctx: dict, **kw: Any) -> str:
async def _sx_full_headers(ctx: dict, **kw: Any) -> str:
"""Full headers for sx home page: root + sx menu row."""
from shared.sx.helpers import root_header_sx
from sxc.sx_components import _sx_header_sx, _main_nav_sx
main_nav = _main_nav_sx(kw.get("section"))
root_hdr = root_header_sx(ctx)
sx_row = _sx_header_sx(main_nav)
main_nav = await _main_nav_sx(kw.get("section"))
root_hdr = await root_header_sx(ctx)
sx_row = await _sx_header_sx(main_nav)
return "(<> " + root_hdr + " " + sx_row + ")"
def _sx_oob_headers(ctx: dict, **kw: Any) -> str:
async def _sx_oob_headers(ctx: dict, **kw: Any) -> str:
"""OOB headers for sx home page."""
from shared.sx.helpers import root_header_sx, oob_header_sx
from sxc.sx_components import _sx_header_sx, _main_nav_sx
root_hdr = root_header_sx(ctx)
main_nav = _main_nav_sx(kw.get("section"))
sx_row = _sx_header_sx(main_nav)
root_hdr = await root_header_sx(ctx)
main_nav = await _main_nav_sx(kw.get("section"))
sx_row = await _sx_header_sx(main_nav)
rows = "(<> " + root_hdr + " " + sx_row + ")"
return oob_header_sx("root-header-child", "sx-header-child", rows)
return await oob_header_sx("root-header-child", "sx-header-child", rows)
def _sx_section_full_headers(ctx: dict, **kw: Any) -> str:
async def _sx_section_full_headers(ctx: dict, **kw: Any) -> str:
"""Full headers for sx section pages: root + sx row + sub row."""
from shared.sx.helpers import root_header_sx
from sxc.sx_components import (
@@ -70,14 +70,14 @@ def _sx_section_full_headers(ctx: dict, **kw: Any) -> str:
sub_nav = kw.get("sub_nav", "")
selected = kw.get("selected", "")
root_hdr = root_header_sx(ctx)
main_nav = _main_nav_sx(section)
sub_row = _sub_row_sx(sub_label, sub_href, sub_nav, selected)
sx_row = _sx_header_sx(main_nav, child=sub_row)
root_hdr = await root_header_sx(ctx)
main_nav = await _main_nav_sx(section)
sub_row = await _sub_row_sx(sub_label, sub_href, sub_nav, selected)
sx_row = await _sx_header_sx(main_nav, child=sub_row)
return "(<> " + root_hdr + " " + sx_row + ")"
def _sx_section_oob_headers(ctx: dict, **kw: Any) -> str:
async def _sx_section_oob_headers(ctx: dict, **kw: Any) -> str:
"""OOB headers for sx section pages."""
from shared.sx.helpers import root_header_sx, oob_header_sx
from sxc.sx_components import (
@@ -90,34 +90,34 @@ def _sx_section_oob_headers(ctx: dict, **kw: Any) -> str:
sub_nav = kw.get("sub_nav", "")
selected = kw.get("selected", "")
root_hdr = root_header_sx(ctx)
main_nav = _main_nav_sx(section)
sub_row = _sub_row_sx(sub_label, sub_href, sub_nav, selected)
sx_row = _sx_header_sx(main_nav, child=sub_row)
root_hdr = await root_header_sx(ctx)
main_nav = await _main_nav_sx(section)
sub_row = await _sub_row_sx(sub_label, sub_href, sub_nav, selected)
sx_row = await _sx_header_sx(main_nav, child=sub_row)
rows = "(<> " + root_hdr + " " + sx_row + ")"
return oob_header_sx("root-header-child", "sx-header-child", rows)
return await oob_header_sx("root-header-child", "sx-header-child", rows)
def _sx_mobile(ctx: dict, **kw: Any) -> str:
async def _sx_mobile(ctx: dict, **kw: Any) -> str:
"""Mobile menu for sx home page: main nav + root."""
from shared.sx.helpers import (
mobile_menu_sx, mobile_root_nav_sx, sx_call, SxExpr,
mobile_menu_sx, mobile_root_nav_sx, render_to_sx, SxExpr,
)
from sxc.sx_components import _main_nav_sx
main_nav = _main_nav_sx(kw.get("section"))
main_nav = await _main_nav_sx(kw.get("section"))
return mobile_menu_sx(
sx_call("mobile-menu-section",
await render_to_sx("mobile-menu-section",
label="sx", href="/", level=1, colour="violet",
items=SxExpr(main_nav)),
mobile_root_nav_sx(ctx),
await mobile_root_nav_sx(ctx),
)
def _sx_section_mobile(ctx: dict, **kw: Any) -> str:
async def _sx_section_mobile(ctx: dict, **kw: Any) -> str:
"""Mobile menu for sx section pages: sub nav + main nav + root."""
from shared.sx.helpers import (
mobile_menu_sx, mobile_root_nav_sx, sx_call, SxExpr,
mobile_menu_sx, mobile_root_nav_sx, render_to_sx, SxExpr,
)
from sxc.sx_components import _main_nav_sx
@@ -125,17 +125,17 @@ def _sx_section_mobile(ctx: dict, **kw: Any) -> str:
sub_label = kw.get("sub_label", section)
sub_href = kw.get("sub_href", "/")
sub_nav = kw.get("sub_nav", "")
main_nav = _main_nav_sx(section)
main_nav = await _main_nav_sx(section)
parts = []
if sub_nav:
parts.append(sx_call("mobile-menu-section",
parts.append(await render_to_sx("mobile-menu-section",
label=sub_label, href=sub_href, level=2, colour="violet",
items=SxExpr(sub_nav)))
parts.append(sx_call("mobile-menu-section",
parts.append(await render_to_sx("mobile-menu-section",
label="sx", href="/", level=1, colour="violet",
items=SxExpr(main_nav)))
parts.append(mobile_root_nav_sx(ctx))
parts.append(await mobile_root_nav_sx(ctx))
return mobile_menu_sx(*parts)