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

@@ -235,7 +235,7 @@ def register(url_prefix, title):
from shared.sx.page import get_template_context
from sx.sx_components import render_new_post_page, render_editor_panel
tctx = await get_template_context()
tctx["editor_html"] = render_editor_panel(save_error="Invalid JSON in editor content.")
tctx["editor_html"] = await render_editor_panel(save_error="Invalid JSON in editor content.")
html = await render_new_post_page(tctx)
return await make_response(html, 400)
@@ -244,7 +244,7 @@ def register(url_prefix, title):
from shared.sx.page import get_template_context
from sx.sx_components import render_new_post_page, render_editor_panel
tctx = await get_template_context()
tctx["editor_html"] = render_editor_panel(save_error=reason)
tctx["editor_html"] = await render_editor_panel(save_error=reason)
html = await render_new_post_page(tctx)
return await make_response(html, 400)
@@ -291,7 +291,7 @@ def register(url_prefix, title):
from shared.sx.page import get_template_context
from sx.sx_components import render_new_post_page, render_editor_panel
tctx = await get_template_context()
tctx["editor_html"] = render_editor_panel(save_error="Invalid JSON in editor content.", is_page=True)
tctx["editor_html"] = await render_editor_panel(save_error="Invalid JSON in editor content.", is_page=True)
tctx["is_page"] = True
html = await render_new_post_page(tctx)
return await make_response(html, 400)
@@ -301,7 +301,7 @@ def register(url_prefix, title):
from shared.sx.page import get_template_context
from sx.sx_components import render_new_post_page, render_editor_panel
tctx = await get_template_context()
tctx["editor_html"] = render_editor_panel(save_error=reason, is_page=True)
tctx["editor_html"] = await render_editor_panel(save_error=reason, is_page=True)
tctx["is_page"] = True
html = await render_new_post_page(tctx)
return await make_response(html, 400)

View File

@@ -17,10 +17,10 @@ from shared.sx.helpers import sx_response
def register():
bp = Blueprint("menu_items", __name__, url_prefix='/settings/menu_items')
def get_menu_items_nav_oob_sync(menu_items):
async def get_menu_items_nav_oob_async(menu_items):
"""Helper to generate OOB update for root nav menu items"""
from sx.sx_components import render_menu_items_nav_oob
return render_menu_items_nav_oob(menu_items)
return await render_menu_items_nav_oob(menu_items)
@bp.get("/new/")
@require_admin
@@ -51,8 +51,8 @@ def register():
# Get updated list and nav OOB
menu_items = await get_all_menu_items(g.s)
from sx.sx_components import render_menu_items_list
html = render_menu_items_list(menu_items)
nav_oob = get_menu_items_nav_oob_sync(menu_items)
html = await render_menu_items_list(menu_items)
nav_oob = await get_menu_items_nav_oob_async(menu_items)
return sx_response(html + nav_oob)
except MenuItemError as e:
@@ -91,8 +91,8 @@ def register():
# Get updated list and nav OOB
menu_items = await get_all_menu_items(g.s)
from sx.sx_components import render_menu_items_list
html = render_menu_items_list(menu_items)
nav_oob = get_menu_items_nav_oob_sync(menu_items)
html = await render_menu_items_list(menu_items)
nav_oob = await get_menu_items_nav_oob_async(menu_items)
return sx_response(html + nav_oob)
except MenuItemError as e:
@@ -112,8 +112,8 @@ def register():
# Get updated list and nav OOB
menu_items = await get_all_menu_items(g.s)
from sx.sx_components import render_menu_items_list
html = render_menu_items_list(menu_items)
nav_oob = get_menu_items_nav_oob_sync(menu_items)
html = await render_menu_items_list(menu_items)
nav_oob = await get_menu_items_nav_oob_async(menu_items)
return sx_response(html + nav_oob)
@bp.get("/pages/search/")
@@ -128,7 +128,7 @@ def register():
has_more = (page * per_page) < total
from sx.sx_components import render_page_search_results
return sx_response(render_page_search_results(pages, query, page, has_more))
return sx_response(await render_page_search_results(pages, query, page, has_more))
@bp.post("/reorder/")
@require_admin
@@ -153,8 +153,8 @@ def register():
# Get updated list and nav OOB
menu_items = await get_all_menu_items(g.s)
from sx.sx_components import render_menu_items_list
html = render_menu_items_list(menu_items)
nav_oob = get_menu_items_nav_oob_sync(menu_items)
html = await render_menu_items_list(menu_items)
nav_oob = await get_menu_items_nav_oob_async(menu_items)
return sx_response(html + nav_oob)
return bp

View File

@@ -90,7 +90,7 @@ def register():
features = result.get("features", {})
from sx.sx_components import render_features_panel
html = render_features_panel(
html = await render_features_panel(
features, post,
sumup_configured=result.get("sumup_configured", False),
sumup_merchant_code=result.get("sumup_merchant_code") or "",
@@ -129,7 +129,7 @@ def register():
features = result.get("features", {})
from sx.sx_components import render_features_panel
html = render_features_panel(
html = await render_features_panel(
features, post,
sumup_configured=result.get("sumup_configured", False),
sumup_merchant_code=result.get("sumup_merchant_code") or "",
@@ -259,8 +259,8 @@ def register():
from sx.sx_components import render_associated_entries, render_nav_entries_oob
post = g.post_data["post"]
admin_list = render_associated_entries(all_calendars, associated_entry_ids, post["slug"])
nav_entries_html = render_nav_entries_oob(associated_entries, calendars, post)
admin_list = await render_associated_entries(all_calendars, associated_entry_ids, post["slug"])
nav_entries_html = await render_nav_entries_oob(associated_entries, calendars, post)
return sx_response(admin_list + nav_entries_html)
@@ -436,7 +436,7 @@ def register():
page_markets = await _fetch_page_markets(post_id)
from sx.sx_components import render_markets_panel
return sx_response(render_markets_panel(page_markets, post))
return sx_response(await render_markets_panel(page_markets, post))
@bp.post("/markets/new/")
@require_admin
@@ -462,7 +462,7 @@ def register():
page_markets = await _fetch_page_markets(post_id)
from sx.sx_components import render_markets_panel
return sx_response(render_markets_panel(page_markets, post))
return sx_response(await render_markets_panel(page_markets, post))
@bp.delete("/markets/<market_slug>/")
@require_admin
@@ -482,6 +482,6 @@ def register():
page_markets = await _fetch_page_markets(post_id)
from sx.sx_components import render_markets_panel
return sx_response(render_markets_panel(page_markets, post))
return sx_response(await render_markets_panel(page_markets, post))
return bp

View File

@@ -125,7 +125,7 @@ def register():
# Get post_id from g.post_data
if not g.user:
return sx_response(render_like_toggle_button(slug, False, like_url), status=403)
return sx_response(await render_like_toggle_button(slug, False, like_url), status=403)
post_id = g.post_data["post"]["id"]
user_id = g.user.id
@@ -135,7 +135,7 @@ def register():
})
liked = result["liked"]
return sx_response(render_like_toggle_button(slug, liked, like_url))
return sx_response(await render_like_toggle_button(slug, liked, like_url))
@bp.get("/w/<widget_domain>/")
async def widget_paginate(slug: str, widget_domain: str):

View File

@@ -47,7 +47,7 @@ def register():
snippets = await _visible_snippets(g.s)
from sx.sx_components import render_snippets_list
return sx_response(render_snippets_list(snippets, is_admin))
return sx_response(await render_snippets_list(snippets, is_admin))
@bp.patch("/<int:snippet_id>/visibility/")
@require_login
@@ -71,6 +71,6 @@ def register():
snippets = await _visible_snippets(g.s)
from sx.sx_components import render_snippets_list
return sx_response(render_snippets_list(snippets, True))
return sx_response(await render_snippets_list(snippets, True))
return bp