fix(theme): make template lookup stateless with theme-prefixed names#116
Merged
Conversation
Route theme selection through theme-prefixed template names
(get_template("<theme>/<name>")) instead of mutable loader.current_theme.
The loader resolves the custom / theme / default fallback chain from the
prefix, and a ThemedEnvironment.join_path keeps extends/includes within
the parent's theme. Removes the shared per-request state that let
concurrent renders with different theme overrides cross-contaminate, and
the save/restore in render_partial.
Closes #110
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR addresses issue #110 by removing mutable, per-request theme state from the shared Jinja loader to prevent concurrent requests with different theme overrides from contaminating each other’s template resolution. It does so by encoding the theme into template names (<theme>/<template>) and adding an environment hook to keep {% extends %} / {% include %} resolution within the parent template’s theme.
Changes:
- Introduces theme-prefixed template names and a stateless loader lookup path (custom cache → requested theme → default fallback).
- Adds
ThemedEnvironment.join_pathso bare extends/includes inherit the parent’s theme. - Adds focused tests covering fallback behavior,
join_path, and concurrent mixed-theme rendering.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/squishmark/services/theme/loader.py |
Removes mutable theme state and resolves templates via theme-prefixed names with fallback chain; adds ThemedEnvironment.join_path. |
src/squishmark/services/theme/engine.py |
Switches template loading to use theme-prefixed names and removes current_theme save/restore logic in render_partial. |
tests/test_theme_loader.py |
Adds regression tests for split/prefix logic, loader fallback chain, join_path behavior, and concurrent interleaving. |
tests/test_admin_notes.py |
Updates partial-render tests to assert theme-prefixed lookups instead of current_theme restoration. |
Guard AsyncHybridLoader.get_source against theme or template names that are absolute, contain backslashes, or have ".." segments; such names now raise TemplateNotFound before any filesystem access. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #110
The loader's mutable
current_themeallowed concurrent requests with different theme overrides to cross-contaminate template resolution, since Jinja resolves extends/includes through the loader at render time.<theme>/<template>); the loader resolves the same custom cache, theme dir, default dir fallback chain per lookup with no shared stateThemedEnvironment.join_pathkeeps extends/includes within the parent template's themeloader.current_themeand the save/restore logic inrender_partialtests/test_theme_loader.py: fallback chain, join_path, and a concurrent-render test interleaving all three themesVerification: checks green (340 tests). Browser-verified all three bundled themes (default, blue-tech, terminal) on index and post pages, a per-post
theme: blue-techoverride rendering alongside a default-theme index, and 30 concurrent mixed-theme requests with zero CSS cross-contamination.🤖 Generated with Claude Code