From 67b469d56da8b96757d3b187aab780c6cfe0b1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Thu, 22 Oct 2026 17:33:05 +0800 Subject: [PATCH] feat: per-theme Jinja env enables theme-level macro override Co-Authored-By: Claude Code --- app/theme_pro.py | 18 ++++++++++++++++-- tests/test_theme_registry.py | 17 +++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/theme_pro.py b/app/theme_pro.py index af711f1..2e2e9ce 100644 --- a/app/theme_pro.py +++ b/app/theme_pro.py @@ -16,7 +16,21 @@ from markupsafe import Markup from .core import sanitize, route_path, THEMES ROOT=Path(__file__).resolve().parent.parent -LOADER=Environment(loader=FileSystemLoader(str(ROOT/'themes')),autoescape=select_autoescape(['html','xml'])) +_ENVS={} + +def env_for(theme): + """Per-theme Jinja env: theme dir first, shared themes/ root as fallback. + + Lets a theme override shared macros (_professional_components.html) while + inheriting everything else. Cached: one env per theme across large builds. + """ + env=_ENVS.get(theme) + if env is None: + theme_dir=ROOT/'themes'/theme + search=[str(theme_dir),str(ROOT/'themes')] if theme_dir.is_dir() else [str(ROOT/'themes')] + env=Environment(loader=FileSystemLoader(search),autoescape=select_autoescape(['html','xml'])) + _ENVS[theme]=env + return env TITLES={'product':'产品中心','vehicle':'车型中心','post':'新闻资讯','case':'项目案例','brand':'品牌中心','service':'服务与解决方案'} @@ -186,4 +200,4 @@ def render(theme,site,page,records,mode='detail',listing_items=None,blocks_html= if theme not in THEMES:raise ValueError('不是内置专业主题') ctx=make_context(site,page,records,mode,listing_items,prepared=prepared) ctx.update(custom_blocks=Markup(blocks_html or ''),has_custom=bool(blocks_html),noindex=(ctx['kind']=='notfound'),designer_replace=meta(page).get('layout_mode')=='replace') - return LOADER.get_template(theme+'/pro.html').render(**ctx) + return env_for(theme).get_template('pro.html').render(**ctx) diff --git a/tests/test_theme_registry.py b/tests/test_theme_registry.py index cc079ac..d6b5dc4 100644 --- a/tests/test_theme_registry.py +++ b/tests/test_theme_registry.py @@ -37,3 +37,20 @@ def test_discover_fails_fast_when_themes_dir_missing(tmp_path, monkeypatch): import pytest with pytest.raises(RuntimeError, match='themes directory missing'): core.discover_themes() + +def test_env_for_theme_prefers_theme_dir_then_shared_root(): + from app import theme_pro + env = theme_pro.env_for('industrial') + paths = [str(p).replace('\\', '/') for p in env.loader.searchpath] + assert paths[0].endswith('themes/industrial') + assert paths[1].endswith('themes') + # 共享宏库必须仍可解析(回落路径) + assert env.get_template('_professional_components.html') is not None + +def test_env_for_is_cached_per_theme(): + from app import theme_pro + assert theme_pro.env_for('industrial') is theme_pro.env_for('industrial') + +def test_env_for_pro_template_loads_unprefixed(): + from app import theme_pro + assert theme_pro.env_for('industrial').get_template('pro.html') is not None