Skip to content

Commit ebbe2f9

Browse files
SilverRainZDeepSeek
andauthored
feat: Add caption parameter to Report.code and simplify callers (#20)
Add an optional caption parameter to Report.code(), exception(), and traceback() methods. When provided, the code block is wrapped in a container node with literal-block-wrapper class and a caption child, similar to .. code-block::'s :caption: option. Refactor all report.text() + report.code() and report.text() + report.exception() pairs in ctxnodes.py and jinja.py to use the new caption parameter directly. Co-authored-by: DeepSeek <service@deepseek.com>
1 parent 452b856 commit ebbe2f9

3 files changed

Lines changed: 26 additions & 30 deletions

File tree

src/sphinxnotes/render/ctxnodes.py

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,19 +95,17 @@ def err_report() -> Report:
9595

9696
if self._ctx_pickle_error is not None:
9797
report = err_report()
98-
report.text(
98+
report.exception(self._ctx_pickle_error, caption=(
9999
f'UnresolvedContext used by {self.template.phase} phase templates '
100100
'must be picklable:'
101-
)
102-
report.exception(self._ctx_pickle_error)
101+
))
103102
self += report
104103
return None
105104

106105
# 1. Prepare context for Jinja template.
107106
if isinstance(self.ctx, UnresolvedContext):
108107
pdata = self.ctx
109-
report.text('Unresolved context:')
110-
report.code(pformat(pdata), lang='python')
108+
report.code(pformat(pdata), lang='python', caption='Unresolved context:')
111109

112110
for hook in self._unresolved_context_hooks:
113111
hook(self, pdata)
@@ -116,8 +114,7 @@ def err_report() -> Report:
116114
ctx = self.ctx = pdata.resolve(host.env)
117115
except Exception as e:
118116
report = err_report()
119-
report.text('Failed to resolve unresolved context:')
120-
report.exception(e)
117+
report.exception(e, caption='Failed to resolve unresolved context:')
121118
self += report
122119
return None
123120
else:
@@ -126,14 +123,11 @@ def err_report() -> Report:
126123
for hook in self._resolved_context_hooks:
127124
hook(self, ctx)
128125

129-
report.text(f'Resolved context (type: {type(ctx)}):')
130-
report.code(pformat(ctx), lang='python')
131-
report.text(f'Template (phase: {self.template.phase}):')
132-
report.code(self.template.text, lang='jinja')
126+
report.code(pformat(ctx), lang='python', caption=f'Resolved context (type: {type(ctx)}):')
127+
report.code(self.template.text, lang='jinja', caption=f'Template (phase: {self.template.phase}):')
133128

134129
extractx_req = ExtraContextRequest(self.template.phase, self, host.env, host)
135-
report.text('Available extra context names:')
136-
report.code(pformat(sorted(extra_context_names())), lang='python')
130+
report.code(pformat(sorted(extra_context_names())), lang='python', caption='Available extra context names:')
137131

138132
# 2. Render the template and context to markup text.
139133
try:
@@ -144,32 +138,28 @@ def err_report() -> Report:
144138
)
145139
except Exception as e:
146140
report = err_report()
147-
report.text('Failed to render Jinja template:')
148-
report.exception(e)
141+
report.exception(e, caption='Failed to render Jinja template:')
149142
self += report
150143
return
151144

152145
for hook in self._markup_text_hooks:
153146
markup = hook(self, markup)
154147

155-
report.text('Rendered markup text:')
156-
report.code(markup, lang='rst')
148+
report.code(markup, lang='rst', caption='Rendered markup text:')
157149

158150
# 3. Render the markup text to doctree nodes.
159151
try:
160152
ns, msgs = MarkupRenderer(host).render(markup, inline=self.inline)
161153
except Exception as e:
162154
report = err_report()
163-
report.text(
155+
report.exception(e, caption=(
164156
'Failed to render markup text '
165157
f'to {"inline " if self.inline else ""}nodes:'
166-
)
167-
report.exception(e)
158+
))
168159
self += report
169160
return
170161

171-
report.text(f'Rendered nodes (inline: {self.inline}):')
172-
report.code('\n\n'.join([n.pformat() for n in ns]), lang='xml')
162+
report.code('\n\n'.join([n.pformat() for n in ns]), lang='xml', caption=f'Rendered nodes (inline: {self.inline}):')
173163
if msgs:
174164
report.text('Systemd messages:')
175165
[report.node(msg) for msg in msgs]

src/sphinxnotes/render/jinja.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ def _render(self, ctx: dict[str, Any], debug: bool = False) -> str:
6464
return env.from_string(self.text).render(ctx)
6565

6666
def _report_self(self, reporter: Report) -> None:
67-
reporter.text('Template:')
68-
reporter.code(self.text, lang='jinja')
67+
reporter.code(self.text, lang='jinja', caption='Template:')
6968

7069

7170
class _JinjaEnv(SandboxedEnvironment):

src/sphinxnotes/render/utils/__init__.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,18 @@ def log(self, msg: str) -> None:
123123
def text(self, text: str) -> None:
124124
self.node(nodes.paragraph(text, text))
125125

126-
def code(self, code: str, lang: str | None = None) -> None:
126+
def code(self, code: str, lang: str | None = None, caption: str | None = None) -> None:
127127
blk = nodes.literal_block(code, code)
128128
if lang:
129129
blk['language'] = lang
130-
self.node(blk)
130+
if caption:
131+
# See also: :meth:`sphinx.directives.code.container_wrapper`.
132+
container = nodes.container('', literal_block=True, classes=['literal-block-wrapper'])
133+
container += nodes.caption(caption, '', nodes.Text(caption))
134+
container += blk
135+
self.node(container)
136+
else:
137+
self.node(blk)
131138

132139
def list(self, lines: Iterable[str]) -> None:
133140
bullet_list = nodes.bullet_list(bullet='*')
@@ -141,13 +148,13 @@ def list(self, lines: Iterable[str]) -> None:
141148

142149
self.node(bullet_list)
143150

144-
def traceback(self) -> None:
151+
def traceback(self, caption: str | None = None) -> None:
145152
# https://pygments.org/docs/lexers/#pygments.lexers.python.PythonTracebackLexer
146-
self.code(traceback.format_exc(), lang='pytb')
153+
self.code(traceback.format_exc(), lang='pytb', caption=caption)
147154

148-
def exception(self, e: Exception) -> None:
155+
def exception(self, e: Exception, caption: str | None = None) -> None:
149156
# https://pygments.org/docs/lexers/#pygments.lexers.python.PythonTracebackLexer
150-
self.code(str(e), lang='pytb')
157+
self.code(str(e), lang='pytb', caption=caption)
151158

152159
def is_error(self) -> bool:
153160
return self['type'] == 'ERROR'

0 commit comments

Comments
 (0)