[codex] Improve UndefinedError diagnostics for framework views#132
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a structured, surface-neutral diagnostic payload for UndefinedError so framework debug views can render rich error pages without parsing terminal-formatted strings, alongside escaped HTML/Markdown renderers and improved attribution for imported components/slots and coalesced output.
Changes:
- Introduces
UndefinedError.to_diagnostic()+ newTemplateDiagnosticdatatypes with HTML fragment/page and Markdown renderers. - Improves error attribution by carrying template/component stack context and preserving source line markers under f-string coalescing.
- Enhances streaming render paths to wrap generic runtime exceptions consistently with non-streaming render.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_diagnostics_contract.py | Adds contract tests for structured diagnostics, escaping, stack attribution, and streaming error enhancement. |
| src/kida/template/render_helpers.py | Tracks imported macro call-site separately to preserve component stack caller attribution. |
| src/kida/template/helpers.py | Enriches UndefinedError for attribute/key misses with stacks, declared definitions, and fuzzy suggestions. |
| src/kida/template/core.py | Enables/enhances error wrapping for render_stream and async block streaming to match render() behavior. |
| src/kida/render_context.py | Extends RenderContext with component_call_* to support imported macro call-site overrides. |
| src/kida/exceptions.py | Adds structured diagnostic dataclasses and renderers; refactors UndefinedError to expose structured fields and hints. |
| src/kida/compiler/statements/functions.py | Updates component stack push logic to use call-site overrides; adjusts call-block wrapper attribution behavior. |
| src/kida/compiler/coalescing.py | Preserves first output line marker when emitting coalesced f-string output for correct diagnostics. |
| site/content/docs/usage/framework-integration.md | Documents how frameworks should render structured diagnostics instead of parsing terminal output. |
| site/content/docs/usage/error-handling.md | Updates guidance to prefer to_diagnostic() for framework debug pages; clarifies source/stack interpretation. |
| site/content/docs/troubleshooting/undefined-variable.md | Documents new structured fields and imported-slot attribution behavior; clarifies hint ordering. |
Comment on lines
+522
to
+530
| if self.source_snippet: | ||
| parts.extend(["", "```text"]) | ||
| for lineno, content in self.source_snippet.lines: | ||
| marker = ">" if lineno == self.source_snippet.error_line else " " | ||
| parts.append(f"{marker}{lineno:4} | {content}") | ||
| if self.source_snippet.column is not None: | ||
| caret = " " * self.source_snippet.column + "^" | ||
| parts.append(f" | {caret}") | ||
| parts.append("```") |
Comment on lines
+693
to
+761
| wrapper_body: list[ast.stmt] = [ | ||
| ast.Assign( | ||
| targets=[ast.Name(id="_rc", ctx=ast.Store())], | ||
| value=ast.BoolOp( | ||
| op=ast.Or(), | ||
| values=[ | ||
| ast.Call( | ||
| func=ast.Name(id="_get_render_ctx", ctx=ast.Load()), | ||
| args=[], | ||
| keywords=[], | ||
| ), | ||
| ast.Name(id="_null_rc", ctx=ast.Load()), | ||
| ], | ||
| ), | ||
| ), | ||
| ast.Assign( | ||
| targets=[ast.Name(id="_prev_template_name", ctx=ast.Store())], | ||
| value=ast.Attribute( | ||
| value=ast.Name(id="_rc", ctx=ast.Load()), | ||
| attr="template_name", | ||
| ctx=ast.Load(), | ||
| ), | ||
| ), | ||
| ast.Assign( | ||
| targets=[ast.Name(id="_prev_source", ctx=ast.Store())], | ||
| value=ast.Attribute( | ||
| value=ast.Name(id="_rc", ctx=ast.Load()), | ||
| attr="source", | ||
| ctx=ast.Load(), | ||
| ), | ||
| ), | ||
| ast.Assign( | ||
| targets=[ast.Name(id="_prev_line", ctx=ast.Store())], | ||
| value=ast.Attribute( | ||
| value=ast.Name(id="_rc", ctx=ast.Load()), | ||
| attr="line", | ||
| ctx=ast.Load(), | ||
| ), | ||
| ), | ||
| ast.Assign( | ||
| targets=[ | ||
| ast.Attribute( | ||
| value=ast.Name(id="_rc", ctx=ast.Load()), | ||
| attr="template_name", | ||
| ctx=ast.Store(), | ||
| ) | ||
| ], | ||
| value=ast.Name(id="_caller_template_name", ctx=ast.Load()), | ||
| ), | ||
| ast.Assign( | ||
| targets=[ | ||
| ast.Attribute( | ||
| value=ast.Name(id="_rc", ctx=ast.Load()), | ||
| attr="source", | ||
| ctx=ast.Store(), | ||
| ) | ||
| ], | ||
| value=ast.Name(id="_caller_source", ctx=ast.Load()), | ||
| ), | ||
| ast.Assign( | ||
| targets=[ | ||
| ast.Attribute( | ||
| value=ast.Name(id="_rc", ctx=ast.Load()), | ||
| attr="line", | ||
| ctx=ast.Store(), | ||
| ) | ||
| ], | ||
| value=ast.Name(id="_caller_line", ctx=ast.Load()), | ||
| ), |
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.
Summary
Adds a structured
UndefinedErrordiagnostic payload that framework debug views can consume without parsing terminal strings, plus escaped HTML/Markdown renderers for the same diagnostic data.Changes
UndefinedError.to_diagnostic()with code, kind, location, source snippet, ordered hints, docs URL, metadata, template stack, and component stack.Steward Notes
Consulted runtime, template runtime, render-surface, tests, and docs stewards. Accepted findings centered on diagnostic truth before UI polish, surface-neutral data, escaped final renderers, render-mode parity, and docs/test collateral. Deferred public frame API, column-accurate carets, Python traceback remapping, and exposing context values.
Verification
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run pytest tests/test_diagnostics_contract.py tests/test_error_stack_traces.py tests/test_undefined_nullsafe_hint.py tests/test_kida_error_handling.py::TestFormatCompactmake docsmake lintmake ty