Skip to content

Commit 0d8e8ae

Browse files
committed
feat: Refactor extra context system
- Add ABC hierarchy: ExtraContext, ParsingPhaseExtraContext, ParsedPhaseExtraContext, ResolvingPhaseExtraContext, GlobalExtraContext - Add @extra_context decorator for registering custom extra context - Template now has extra field to declare required context - Templates use load('name') to access extra context - Registry integration via REGISTRY.source - Update documentation and examples BREAKING CHANGE: Extra context access changed from {{ _name }} to {% set _name = load('name') %}; context names no longer prefixed with '_'
1 parent 8079d26 commit 0d8e8ae

8 files changed

Lines changed: 306 additions & 199 deletions

File tree

docs/api.rst

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,27 @@ See :doc:`tmpl` for the higher-level guide.
7575
.. autoclass:: sphinxnotes.render.Phase
7676
:members:
7777

78-
Extra Context
79-
-------------
78+
Sources
79+
-------
80+
81+
See :doc:`tmpl` for built-in extra-context names such as ``doc`` and
82+
``sphinx``, plus usage examples.
83+
84+
.. autofunction:: sphinxnotes.render.extra_context
85+
86+
.. autoclass:: sphinxnotes.render.ExtraContext
8087

81-
See :doc:`tmpl` for built-in extra-context names such as ``_doc`` and
82-
``_sphinx``, plus usage examples.
88+
.. autoclass:: sphinxnotes.render.ParsingPhaseExtraContext
89+
:members: generate
8390

84-
.. autoclass:: sphinxnotes.render.GlobalExtraContxt
91+
.. autoclass:: sphinxnotes.render.ParsedPhaseExtraContext
92+
:members: generate
8593

86-
.. autoclass:: sphinxnotes.render.ParsePhaseExtraContext
94+
.. autoclass:: sphinxnotes.render.ResolvingPhaseExtraContext
95+
:members: generate
8796

88-
.. autoclass:: sphinxnotes.render.ResolvePhaseExtraContext
97+
.. autoclass:: sphinxnotes.render.GlobalExtraContext
98+
:members: generate
8999

90100
.. autoclass:: sphinxnotes.render.ExtraContextRegistry
91101
:members:
@@ -153,12 +163,12 @@ Registry
153163
========
154164

155165
Developers can extend this extension (for example, to support more data types
156-
or add new extra context) by adding new items to
166+
or add new sources) by adding new items to
157167
:py:class:`sphinxnotes.render.REGISTRY`.
158168

159169
.. autodata:: sphinxnotes.render.REGISTRY
160170

161171
.. autoclass:: sphinxnotes.render.Registry
162172

163173
.. autoproperty:: data
164-
.. autoproperty:: extra_context
174+
.. autoproperty:: source

docs/tmpl.rst

Lines changed: 88 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,9 @@ the :rst:dir:`data.schema` directive.
153153
Extra Context
154154
-------------
155155

156-
Templates may also receive extra context entries in addition to the main data
157-
context. These entries are stored under names prefixed with ``_``.
156+
Templates can access additional context through **extra context**. Extra context
157+
must be explicitly declared using the ``:extra:`` option and loaded in the
158+
template using the ``load()`` function.
158159

159160
Built-in extra context
160161
......................
@@ -163,23 +164,23 @@ Built-in extra context
163164
:header-rows: 1
164165

165166
* - Name
166-
- Available in
167+
- Available in Pahses
167168
- Description
168-
* - ``_sphinx``
169-
- all phases
169+
* - ``sphinx``
170+
- all
170171
- A proxy to the Sphinx application object.
171-
* - ``_docutils``
172-
- all phases
172+
* - ``docutils``
173+
- all
173174
- A mapping that exposes registered docutils directives and roles.
174-
* - ``_markup``
175-
- parsing and later
175+
* - ``markup``
176+
- :term:`parsing` and later
176177
- Information about the current directive or role invocation, such as its
177178
type, name, source text, and line number.
178-
* - ``_section``
179-
- parsing and later
179+
* - ``section``
180+
- :term:`parsing` and later
180181
- A proxy to the current section node, when one exists.
181-
* - ``_doc``
182-
- parsing and later
182+
* - ``doc``
183+
- :term:`parsing` and later
183184
- A proxy to the current document node.
184185

185186
These values are wrapped for safer template access. In practice this means
@@ -190,17 +191,25 @@ arbitrary Python object behavior.
190191
:style: grid
191192

192193
.. data.render::
194+
:extra: doc
193195
194196
Current document title is
195-
"{{ _doc.title }}".
197+
"{{ load('doc').title }}".
196198
197199
Extending extra context
198200
.......................
199201

200-
Extension authors can register more context generators through
201-
:py:data:`sphinxnotes.render.REGISTRY`.
202+
Extension authors can register custom extra context using the
203+
:py:func:`~sphinxnotes.render.extra_context` decorator.
202204

203-
TODO.
205+
.. code-block:: python
206+
207+
from sphinxnotes.render import extra_context, ParsingPhaseExtraContext
208+
209+
@extra_context('custom')
210+
class CustomExtraContext(ParsingPhaseExtraContext):
211+
def generate(self, directive):
212+
return {'info': 'custom data'}
204213
205214
Template
206215
========
@@ -213,64 +222,81 @@ Render Phases
213222
Each :py:class:`~sphinxnotes.render.Template` has a render phase controlled by
214223
:py:class:`~sphinxnotes.render.Phase`.
215224

216-
``parsing`` (:py:data:`sphinxnotes.render.Phase.Parsing`)
217-
Render immediately while the directive or role is running.
225+
.. glossary::
218226

219-
This is the default render phase.
220-
Choose this when the template only needs local information and does not rely
221-
on the final doctree or cross-document state.
227+
``parsing``
228+
Corresponding to :py:data:`sphinxnotes.render.Phase.Parsing`.
229+
Render immediately while the directive or role is running.
222230

223-
.. example::
224-
:style: grid
231+
This is the default render phase.
232+
Choose this when the template only needs local information and does not rely
233+
on the final doctree or cross-document state.
225234

226-
.. data.render::
227-
:on: parsing
235+
.. example::
236+
:style: grid
228237

229-
- The current document has
230-
{{ _doc.sections | length }}
231-
section(s).
232-
- The current project has
233-
{{ _sphinx.env.all_docs | length }}
234-
document(s).
238+
.. data.render::
239+
:on: parsing
240+
:extra: doc sphinx
235241
236-
``parsed`` (:py:data:`sphinxnotes.render.Phase.Parsed`)
237-
Render after the current document has been parsed.
242+
{% set doc = load('doc') %}
243+
{% set sphinx = load('sphinx') %}
238244
239-
Choose this when the template needs the complete doctree of the current
240-
document.
245+
- The current document has
246+
{{ doc.sections | length }}
247+
section(s).
248+
- The current project has
249+
{{ sphinx.env.all_docs | length }}
250+
document(s).
241251
242-
.. example::
243-
:style: grid
252+
``parsed``
253+
Corresponding to :py:data:`sphinxnotes.render.Phase.Parsed`.
254+
Render after the current document has been parsed.
244255

245-
.. data.render::
246-
:on: parsed
256+
Choose this when the template needs the complete doctree of the current
257+
document.
247258

248-
- The current document has
249-
{{ _doc.sections | length }}
250-
section(s).
251-
- The current project has
252-
{{ _sphinx.env.all_docs | length }}
253-
document(s).
259+
.. example::
260+
:style: grid
254261

255-
``resolving`` (:py:data:`sphinxnotes.render.Phase.Resolving`)
256-
Render late in the build, after references and other transforms are being
257-
resolved.
262+
.. data.render::
263+
:on: parsed
264+
:extra: doc sphinx
258265
259-
Choose this when the template depends on project-wide state or on document
260-
structure that is only stable near the end of the pipeline.
266+
{% set doc = load('doc') %}
267+
{% set sphinx = load('sphinx') %}
261268
262-
.. example::
263-
:style: grid
269+
- The current document has
270+
{{ doc.sections | length }}
271+
section(s).
272+
- The current project has
273+
{{ sphinx.env.all_docs | length }}
274+
document(s).
264275
265-
.. data.render::
266-
:on: resolving
267-
268-
- The current document has
269-
{{ _doc.sections | length }}
270-
section(s).
271-
- The current project has
272-
{{ _sphinx.env.all_docs | length }}
273-
document(s).
276+
``resolving``
277+
Corresponding to :py:data:`sphinxnotes.render.Phase.Resolving`.
278+
Render late in the build, after references and other transforms are being
279+
resolved.
280+
281+
Choose this when the template depends on project-wide state or on document
282+
structure that is only stable near the end of the pipeline.
283+
284+
.. example::
285+
:style: grid
286+
287+
.. data.render::
288+
:on: resolving
289+
:extra: doc sphinx
290+
291+
{% set doc = load('doc') %}
292+
{% set sphinx = load('sphinx') %}
293+
294+
- The current document has
295+
{{ doc.sections | length }}
296+
section(s).
297+
- The current project has
298+
{{ sphinx.env.all_docs | length }}
299+
document(s).
274300
275301
Debugging
276302
---------

src/sphinxnotes/render/__init__.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@
3232
from .extractx import (
3333
ExtraContextRegistry,
3434
ExtraContextGenerator,
35-
GlobalExtraContxt,
36-
ParsePhaseExtraContext,
37-
ResolvePhaseExtraContext,
35+
ExtraContext,
36+
ParsingPhaseExtraContext,
37+
ParsedPhaseExtraContext,
38+
ResolvingPhaseExtraContext,
39+
GlobalExtraContext,
40+
extra_context,
3841
)
3942
from .pipeline import BaseContextRole, BaseContextDirective
4043
from .sources import (
@@ -63,9 +66,14 @@
6366
'Host',
6467
'PendingContext',
6568
'ResolvedContext',
66-
'GlobalExtraContxt',
67-
'ParsePhaseExtraContext',
68-
'ResolvePhaseExtraContext',
69+
'ExtraContext',
70+
'ParsingPhaseExtraContext',
71+
'ParsedPhaseExtraContext',
72+
'ResolvingPhaseExtraContext',
73+
'GlobalExtraContext',
74+
'extra_context',
75+
'ExtraContextRegistry',
76+
'ExtraContextGenerator',
6977
'pending_node',
7078
'BaseContextRole',
7179
'BaseContextDirective',
@@ -84,12 +92,15 @@ def data(self) -> DataRegistry:
8492
return DATA_REGISTRY
8593

8694
@property
87-
def extra_context(cls) -> ExtraContextRegistry:
88-
return ExtraContextGenerator.registry
95+
def source(self) -> ExtraContextRegistry:
96+
from .extractx import REGISTRY as SOURCE_REGISTRY
97+
98+
return SOURCE_REGISTRY
8999

90100

91101
REGISTRY = Registry()
92102

103+
93104
def setup(app: Sphinx):
94105
meta.pre_setup(app)
95106

0 commit comments

Comments
 (0)