Conversation
There was a problem hiding this comment.
Pull request overview
Adds a large set of runnable modern + legacy examples, while expanding the core engine’s compatibility-mode behavior to better support legacy .httkweb.html templates and legacy site initialization/config patterns.
Changes:
- Implement legacy
.httkweb.htmlrendering via a newHttkTemplateFormatterand integrate it intoHttkCompatTemplateEngine. - Add site-wide config loading (
config_name*) + startupfunctions/init.pysupport, and extend legacy list/frontmatter normalization. - Add multiple modern and legacy example sites (templates/content/functions/assets) plus expanded compatibility-mode tests.
Reviewed changes
Copilot reviewed 121 out of 128 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_api.py | Adds compatibility-mode tests for legacy repeat/pages calls, config loading, and init execution. |
| src/httk/web/templating/httk_compat.py | Extends compat engine to render legacy .httkweb.html via a formatter while keeping Jinja for modern templates. |
| src/httk/web/templating/_legacy_formatter.py | Introduces a legacy formatter supporting repeat/call/getitem/getattr/if + escaping behavior. |
| src/httk/web/renderers/_frontmatter.py | Extends *-list normalization to support comma-separated strings. |
| src/httk/web/model/config.py | Adds config_name and compatibility fallback to _functions for function discovery. |
| src/httk/web/engine/site_engine.py | Adds global config metadata + init bootstrap, publish/serve template overrides, and case-insensitive metadata lookups. |
| src/httk/web/api.py | Exposes config_name through create_asgi_app, serve, and publish. |
| examples/modern/search_app/src/templates/search_results.html.j2 | Adds modern search results fragment template. |
| examples/modern/search_app/src/templates/search_page.html.j2 | Adds modern search page template wiring query + fragments. |
| examples/modern/search_app/src/templates/material_details.html.j2 | Adds modern material-details fragment template. |
| examples/modern/search_app/src/templates/base_default.html.j2 | Adds modern base layout for the search example. |
| examples/modern/search_app/src/functions/search.py | Adds example search function over an in-memory dataset. |
| examples/modern/search_app/src/functions/init.py | Initializes example dataset in global_data. |
| examples/modern/search_app/src/functions/details.py | Adds example details lookup function. |
| examples/modern/search_app/src/content/index.md | Adds modern page metadata wiring function injections. |
| examples/modern/search_app/serve.py | Adds runnable serve script for the modern search example. |
| examples/modern/search_app/publish.py | Adds runnable publish script for the modern search example. |
| examples/modern/search_app/README.md | Documents the modern search example. |
| examples/modern/rst_site/src/templates/default.html.j2 | Adds default template for modern RST site. |
| examples/modern/rst_site/src/templates/base_default.html.j2 | Adds base layout for modern RST site. |
| examples/modern/rst_site/src/content/index.rst | Adds modern RST front page content. |
| examples/modern/rst_site/src/content/about.rst | Adds modern RST about page. |
| examples/modern/rst_site/serve.py | Adds runnable serve script for modern RST site. |
| examples/modern/rst_site/publish.py | Adds runnable publish script for modern RST site. |
| examples/modern/rst_site/README.md | Documents the modern RST site example. |
| examples/modern/minimal/src/templates/default.html.j2 | Adds minimal modern default template. |
| examples/modern/minimal/src/templates/base_default.html.j2 | Adds minimal modern base layout. |
| examples/modern/minimal/src/content/index.md | Adds minimal modern content example. |
| examples/modern/minimal/serve.py | Adds runnable serve script for minimal example. |
| examples/modern/minimal/publish.py | Adds runnable publish script for minimal example. |
| examples/modern/minimal/public/index.html | Adds a prebuilt published HTML artifact for the minimal example. |
| examples/modern/minimal/README.md | Documents the minimal modern example. |
| examples/modern/blog/src/templates/default.html.j2 | Adds modern blog default template. |
| examples/modern/blog/src/templates/blog_post.html.j2 | Adds modern blog post template. |
| examples/modern/blog/src/templates/blog_index.html.j2 | Adds modern blog index template using pages(). |
| examples/modern/blog/src/templates/blog_home.html.j2 | Adds modern blog home template with latest posts. |
| examples/modern/blog/src/templates/base_default.html.j2 | Adds modern blog base layout. |
| examples/modern/blog/src/functions/init.py | Builds blog post lists at startup via global_data["pages"]. |
| examples/modern/blog/src/content/index.md | Adds modern blog home content. |
| examples/modern/blog/src/content/contact.md | Adds modern blog contact content. |
| examples/modern/blog/src/content/blogposts/migration-notes.md | Adds modern blog sample post content. |
| examples/modern/blog/src/content/blogposts/hello-modern.md | Adds modern blog sample post content. |
| examples/modern/blog/src/content/blog.md | Adds modern blog listing page content. |
| examples/modern/blog/serve.py | Adds runnable serve script for modern blog. |
| examples/modern/blog/publish.py | Adds runnable publish script for modern blog. |
| examples/modern/blog/README.md | Documents the modern blog example. |
| examples/legacy/static_simple/src/templates/default.httkweb.html | Adds legacy static-simple default template. |
| examples/legacy/static_simple/src/templates/base_default.httkweb.html | Adds legacy static-simple base template demonstrating repeat/pages calls. |
| examples/legacy/static_simple/src/templates/bare.httkweb.html | Adds legacy static-simple bare base template. |
| examples/legacy/static_simple/src/templates/404.httkweb.html | Adds legacy static-simple 404 template using legacy conditional formatting. |
| examples/legacy/static_simple/src/static/resources/css/httkdemo.css | Adds legacy CSS asset. |
| examples/legacy/static_simple/src/static/img/Example.png | Adds legacy example image asset. |
| examples/legacy/static_simple/src/content/index.httkweb | Adds legacy .httkweb content sample. |
| examples/legacy/static_simple/src/content/contact.httkweb | Adds legacy .httkweb contact content. |
| examples/legacy/static_simple/src/content/bare.httkweb | Adds legacy .httkweb bare page. |
| examples/legacy/static_simple/src/content/404.httkweb | Adds legacy .httkweb 404 content. |
| examples/legacy/static_simple/src/config_dynamic.httkweb | Adds legacy dynamic config example. |
| examples/legacy/static_simple/src/config.httkweb | Adds legacy config example. |
| examples/legacy/static_simple/serve_legacy_static_simple.py | Adds serve script for legacy static-simple example. |
| examples/legacy/static_simple/publish_legacy_static_simple.py | Adds publish script for legacy static-simple example. |
| examples/legacy/search_app/src/templates/search_result.httkweb.html | Adds legacy search results template. |
| examples/legacy/search_app/src/templates/search_page.httkweb.html | Adds legacy search page template. |
| examples/legacy/search_app/src/templates/material_details.httkweb.html | Adds legacy material details template. |
| examples/legacy/search_app/src/templates/default.httkweb.html | Adds legacy search default template. |
| examples/legacy/search_app/src/templates/base_default.httkweb.html | Adds legacy search base template. |
| examples/legacy/search_app/src/templates/base_app.httkweb.html | Adds legacy search alternate base template. |
| examples/legacy/search_app/src/static/resources/css/httkdemo.css | Adds legacy search CSS asset. |
| examples/legacy/search_app/src/static/img/Example.png | Adds legacy search image asset. |
| examples/legacy/search_app/src/functions/search.py | Adds legacy search function (depends on external legacy httk DB). |
| examples/legacy/search_app/src/functions/init.py | Adds legacy search init function (legacy DB bootstrap). |
| examples/legacy/search_app/src/functions/details.py | Adds legacy details function (legacy DB). |
| examples/legacy/search_app/src/content/index.httkweb | Adds legacy search page metadata wiring function injections. |
| examples/legacy/search_app/src/content/404.httkweb | Adds legacy search 404 content. |
| examples/legacy/search_app/src/config.httkweb | Adds legacy search config. |
| examples/legacy/search_app/serve_legacy_search_app.py | Adds serve script for legacy search example. |
| examples/legacy/search_app/publish_legacy_search_app.py | Adds publish script for legacy search example. |
| examples/legacy/rst_templator/src/templates/default.templator.html | Adds legacy web.py templator template (legacy baseline). |
| examples/legacy/rst_templator/src/templates/default.httkweb.html | Adds legacy .httkweb.html default template. |
| examples/legacy/rst_templator/src/templates/base_default.templator.html | Adds legacy web.py templator base template. |
| examples/legacy/rst_templator/src/templates/base_default.httkweb.html | Adds legacy .httkweb.html base template. |
| examples/legacy/rst_templator/src/templates/bare.templator.html | Adds legacy web.py templator bare template. |
| examples/legacy/rst_templator/src/templates/bare.httkweb.html | Adds legacy .httkweb.html bare template. |
| examples/legacy/rst_templator/src/static/resources/css/httkdemo.css | Adds legacy rst_templator CSS asset. |
| examples/legacy/rst_templator/src/static/img/Example.png | Adds legacy rst_templator image asset. |
| examples/legacy/rst_templator/src/content/index.rst | Adds legacy RST content sample. |
| examples/legacy/rst_templator/src/content/contact.rst | Adds legacy contact content sample. |
| examples/legacy/rst_templator/src/content/bare.rst | Adds legacy bare content sample. |
| examples/legacy/rst_templator/src/content/404.rst | Adds legacy 404 content sample. |
| examples/legacy/rst_templator/src/config_dynamic.rst | Adds legacy dynamic config in RST field-list form. |
| examples/legacy/rst_templator/src/config.rst | Adds legacy config in RST field-list form. |
| examples/legacy/rst_templator/serve_legacy_rst_templator.py | Adds serve script for legacy rst_templator example. |
| examples/legacy/rst_templator/publish_legacy_rst_templator.py | Adds publish script for legacy rst_templator example. |
| examples/legacy/hello_world_app/src/templates/hello_world_result.httkweb.html | Adds legacy hello-world result fragment template. |
| examples/legacy/hello_world_app/src/templates/default.httkweb.html | Adds legacy hello-world default template including injected fragment. |
| examples/legacy/hello_world_app/src/templates/base_default.httkweb.html | Adds legacy hello-world base template. |
| examples/legacy/hello_world_app/src/static/resources/css/httkdemo.css | Adds legacy hello-world CSS asset. |
| examples/legacy/hello_world_app/src/static/img/Example.png | Adds legacy hello-world image asset. |
| examples/legacy/hello_world_app/src/functions/init.py | Adds legacy init function for hello-world app. |
| examples/legacy/hello_world_app/src/functions/hello_world.py | Adds legacy hello-world function. |
| examples/legacy/hello_world_app/src/content/index.httkweb | Adds legacy hello-world page metadata for function injection. |
| examples/legacy/hello_world_app/src/content/404.httkweb | Adds legacy hello-world 404 content. |
| examples/legacy/hello_world_app/src/config.httkweb | Adds legacy hello-world config. |
| examples/legacy/hello_world_app/serve_legacy_hello_world.py | Adds serve script for legacy hello-world example. |
| examples/legacy/hello_world_app/publish_legacy_hello_world.py | Adds publish script for legacy hello-world example. |
| examples/legacy/blog/src/templates/default.httkweb.html | Adds legacy blog default template. |
| examples/legacy/blog/src/templates/blogpost.httkweb.html | Adds legacy blog post template. |
| examples/legacy/blog/src/templates/blog.httkweb.html | Adds legacy blog index template. |
| examples/legacy/blog/src/templates/base_default.httkweb.html | Adds legacy blog base template. |
| examples/legacy/blog/src/templates/404.httkweb.html | Adds legacy blog 404 template. |
| examples/legacy/blog/src/static/resources/css/httk.css | Adds legacy blog CSS asset. |
| examples/legacy/blog/src/static/js/paginate.js | Adds legacy blog pagination JS. |
| examples/legacy/blog/src/static/img/.gitignore | Adds placeholder ignore file for blog images directory. |
| examples/legacy/blog/src/static/favicon.ico | Adds legacy blog favicon asset. |
| examples/legacy/blog/src/functions/init.py | Adds legacy blog init function building blog lists. |
| examples/legacy/blog/src/content/index.md | Adds legacy blog home content with legacy-style front matter delimiters. |
| examples/legacy/blog/src/content/contact.md | Adds legacy blog contact content. |
| examples/legacy/blog/src/content/blogposts/third_post.md | Adds legacy blog sample post content. |
| examples/legacy/blog/src/content/blogposts/hello-everyone.md | Adds legacy blog sample post content. |
| examples/legacy/blog/src/content/blogposts/another_post.md | Adds legacy blog sample post content. |
| examples/legacy/blog/src/content/blog.md | Adds legacy blog listing page content. |
| examples/legacy/blog/src/content/404.md | Adds legacy blog 404 content. |
| examples/legacy/blog/src/config_dynamic.httkweb | Adds legacy blog dynamic config example. |
| examples/legacy/blog/src/config.httkweb | Adds legacy blog config example. |
| examples/legacy/blog/serve_legacy_blog.py | Adds serve script for legacy blog example. |
| examples/legacy/blog/publish_legacy_blog.py | Adds publish script for legacy blog example. |
| examples/legacy/README.md | Adds top-level legacy examples index/notes. |
| examples/README.md | Adds top-level examples index explaining modern vs legacy. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| page_data = { | ||
| key: value | ||
| for key, value in metadata.items() | ||
| if isinstance(key, str) and key and not key.startswith("_") and not key.endswith("-function") | ||
| } |
There was a problem hiding this comment.
page_data filters out keys ending with "-function" in a case-sensitive way, but function injection now detects *-function keys case-insensitively. If metadata uses a different casing (e.g., Results-Function), it will incorrectly be exposed on page even though it’s treated as a function injection key elsewhere. Consider using a case-insensitive endswith here as well.
| <!doctype html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="utf-8" /> | ||
| <meta name="viewport" content="width=device-width,initial-scale=1" /> | ||
| <title>Minimal Modern Example</title> | ||
| </head> | ||
| <body> | ||
| <main> | ||
| <article> | ||
| <h1>Minimal Modern Example</h1> | ||
| <h1>Hello from httk-web</h1> | ||
| <p>This is the modern example using Jinja2 templates.</p> | ||
| </article> | ||
| </main> | ||
| </body> | ||
| </html> No newline at end of file |
There was a problem hiding this comment.
This looks like a generated publish artifact rather than source for the example. Committing built HTML output can get stale and creates noise in diffs; consider removing it from version control and adding a .gitignore entry (or clearly documenting why this output is tracked).
| @@ -0,0 +1,3 @@ | |||
| def execute(global_data, **kargs): | |||
| print("Debug: running website initalization function.") | |||
There was a problem hiding this comment.
Typo in the debug message: "initalization" should be "initialization".
| print("Debug: running website initalization function.") | |
| print("Debug: running website initialization function.") |
| <th>#</th> | ||
| <th>Compound id</th> | ||
| <th>Formula</th> | ||
| <th>Anonumous formula</th> |
There was a problem hiding this comment.
Typo in column header: "Anonumous" should be "Anonymous".
| if spec == "unquoted" or spec.startswith("unquoted:"): | ||
| return self._format_field(value, spec[len("unquoted::") :], quote=False) | ||
| if spec == "quote" or spec.startswith("quote:"): | ||
| return self._format_field(value, spec[len("quote::") :], quote=True) |
There was a problem hiding this comment.
unquoted: / quote: spec parsing slices using len("unquoted::") / len("quote::"), which drops one extra character for specs like unquoted:if:... (single colon) and breaks downstream spec handling (e.g., if: becomes f:). Use the correct prefix length (e.g., len("unquoted:")) or split on the first : to pass the remainder spec through unchanged.
| def vformat(self, format_string: str, args: Sequence[Any], kwargs: Mapping[str, Any]) -> str: | ||
| self._current_args = args | ||
| self._current_kwargs = kwargs | ||
| return super().vformat(format_string, args, kwargs) |
There was a problem hiding this comment.
vformat() mutates self._current_args / self._current_kwargs but never restores the previous values. Because repeat/if call self.format(...) recursively, nested formatting will overwrite the outer context and can leak loop variables (e.g., item, index) into subsequent fields after the loop. Save/restore the prior state in vformat() (e.g., with a try/finally) so nested calls don’t affect the parent formatting context.
No description provided.