1313 Unpicklable ,
1414 Report ,
1515 Reporter ,
16- find_current_document ,
1716 find_nearest_block_element ,
1817)
1918from ..config import Config
@@ -35,6 +34,8 @@ class pending_node(Base, Unpicklable):
3534 template : Template
3635 #: Whether rendering to inline nodes.
3736 inline : bool
37+ #: Whether the rendering pipeline is finished (failed is also finished).
38+ rendered : bool
3839
3940 def __init__ (
4041 self ,
@@ -50,31 +51,26 @@ def __init__(
5051 self .extra = {}
5152 self .template = tmpl
5253 self .inline = inline
54+ self .rendered = False
5355
5456 # Init hook lists.
5557 self ._raw_data_hooks = []
5658 self ._parsed_data_hooks = []
5759 self ._markup_text_hooks = []
58- self ._rendered_node_hooks = []
60+ self ._rendered_nodes_hooks = []
5961
60- def render (self , host : Host ) -> rendered_node :
62+ def render (self , host : Host ) -> None :
6163 """
6264 The core function for rendering data to docutils nodes.
6365
6466 1. Schema.parse(RawData) -> ParsedData
6567 2. TemplateRenderer.render(ParsedData) -> Markup Text (``str``)
6668 3. MarkupRenderer.render(Markup Text) -> doctree Nodes (list[nodes.Node])
6769 """
68- # 0. Create container for rendered nodes.
69- rendered = rendered_node ()
70- # Copy attributes from pending_node.
71- rendered .update_all_atts (self )
72- # Copy source and line (which are not included in update_all_atts).
73- rendered .source , rendered .line = self .source , self .line
74- # Copy the pending's children to the rendered.
75- rendered [:0 ] = [x .deepcopy () for x in self .children ]
76- # Clear all empty reports.
77- Reporter (rendered ).clear_empty ()
70+
71+ # Make sure the function is called once.
72+ assert not self .rendered
73+ self .rendered = True
7874
7975 report = Report (
8076 'Render Debug Report' , 'DEBUG' , source = self .source , line = self .line
@@ -91,35 +87,33 @@ def render(self, host: Host) -> rendered_node:
9187 hook (self , self .data .raw )
9288
9389 try :
94- data = self .data .parse ()
90+ data = self .data = self . data .parse ()
9591 except ValueError :
9692 report .text ('Failed to parse raw data:' )
9793 report .excption ()
98- rendered += report
99- return rendered
94+ self += report
95+ return
10096 else :
10197 data = self .data
10298
10399 for hook in self ._parsed_data_hooks :
104100 hook (self , data )
105101
106- rendered .data = data
107-
108- report .text ('Parsed data:' )
102+ report .text (f'Parsed data (type: { type (data )} ):' )
109103 report .code (pformat (data ), lang = 'python' )
110- report .text ('Extra context (just key ):' )
104+ report .text ('Extra context (only keys ):' )
111105 report .code (pformat (list (self .extra .keys ())), lang = 'python' )
112- report .text ('Template:' )
106+ report .text (f 'Template (phase: { self . template . phase } ) :' )
113107 report .code (self .template .text , lang = 'jinja' )
114108
115109 # 2. Render the template and data to markup text.
116110 try :
117111 markup = TemplateRenderer (self .template .text ).render (data , extra = self .extra )
118- except Exception : # TODO: what excetpion?
112+ except Exception :
119113 report .text ('Failed to render Jinja template:' )
120114 report .excption ()
121- rendered += report
122- return rendered
115+ self += report
116+ return
123117
124118 for hook in self ._markup_text_hooks :
125119 markup = hook (self , markup )
@@ -136,8 +130,8 @@ def render(self, host: Host) -> rendered_node:
136130 f'to { "inline " if self .inline else "" } nodes:'
137131 )
138132 report .excption ()
139- rendered += report
140- return rendered
133+ self += report
134+ return
141135
142136 report .text (f'Rendered nodes (inline: { self .inline } ):' )
143137 report .code ('\n \n ' .join ([n .pformat () for n in ns ]), lang = 'xml' )
@@ -146,21 +140,45 @@ def render(self, host: Host) -> rendered_node:
146140 [report .node (msg ) for msg in msgs ]
147141
148142 # 4. Add rendered nodes to container.
149- rendered += ns
143+ for hook in self ._rendered_nodes_hooks :
144+ hook (self , ns )
145+ # TODO: set_source_info?
146+ self += ns
150147
151148 if self .template .debug or Config .render_debug :
152- rendered += report
149+ self += report
153150
154- for hook in self ._rendered_node_hooks :
155- hook (self , rendered )
151+ Reporter (self ).clear_empty ()
156152
157- return rendered
153+ return
158154
159- def replace_self_inline (
160- self , rendered : rendered_node , inliner : Report .Inliner
161- ) -> None :
162- # Split inline nodes and system_message noeds from rendered_node node.
163- ns , msgs = rendered .inline (inliner )
155+ def unwrap (self ) -> list [nodes .Node ]:
156+ children = self .children
157+ self .clear ()
158+ return children
159+
160+ def unwrap_inline (
161+ self , inliner : Report .Inliner
162+ ) -> tuple [list [nodes .Node ], list [nodes .system_message ]]:
163+ # Report (nodes.system_message subclass) is not inline node,
164+ # should be removed before inserting to doctree.
165+ reports = Reporter (self ).clear ()
166+ for report in reports :
167+ self .append (report .problematic (inliner ))
168+
169+ children = self .children
170+ self .clear ()
171+
172+ return children , [x for x in reports ]
173+
174+ def unwrap_and_replace_self (self ) -> None :
175+ children = self .unwrap ()
176+ # Replace self with children.
177+ self .replace_self (children )
178+
179+ def unwrap_and_replace_self_inline (self , inliner : Report .Inliner ) -> None :
180+ # Unwrap inline nodes and system_message noeds from node.
181+ ns , msgs = self .unwrap_inline (inliner )
164182
165183 # Insert reports to nearst block elements (usually nodes.paragraph).
166184 doctree = inliner .document if isinstance (inliner , Inliner ) else inliner [1 ]
@@ -175,12 +193,12 @@ def replace_self_inline(
175193 type RawDataHook = Callable [[pending_node , RawData ], None ]
176194 type ParsedDataHook = Callable [[pending_node , ParsedData | dict [str , Any ]], None ]
177195 type MarkupTextHook = Callable [[pending_node , str ], str ]
178- type RenderedNodeHook = Callable [[pending_node , rendered_node ], None ]
196+ type RenderedNodesHook = Callable [[pending_node , list [ nodes . Node ] ], None ]
179197
180198 _raw_data_hooks : list [RawDataHook ]
181199 _parsed_data_hooks : list [ParsedDataHook ]
182200 _markup_text_hooks : list [MarkupTextHook ]
183- _rendered_node_hooks : list [RenderedNodeHook ]
201+ _rendered_nodes_hooks : list [RenderedNodesHook ]
184202
185203 def hook_raw_data (self , hook : RawDataHook ) -> None :
186204 self ._raw_data_hooks .append (hook )
@@ -191,25 +209,5 @@ def hook_parsed_data(self, hook: ParsedDataHook) -> None:
191209 def hook_markup_text (self , hook : MarkupTextHook ) -> None :
192210 self ._markup_text_hooks .append (hook )
193211
194- def hook_rendered_node (self , hook : RenderedNodeHook ) -> None :
195- self ._rendered_node_hooks .append (hook )
196-
197-
198- class rendered_node (Base , nodes .container ):
199- # The data used when rendering this node.
200- data : ParsedData | dict [str , Any ] | None
201-
202- def inline (
203- self ,
204- inliner : Inliner | tuple [nodes .document , nodes .Element ],
205- ) -> tuple [list [nodes .Node ], list [nodes .system_message ]]:
206- # Report (nodes.system_message subclass) is not inline node,
207- # should be removed before inserting to doctree.
208- reports = Reporter (self ).clear ()
209- for report in reports :
210- self .append (report .problematic (inliner ))
211-
212- children = self .children
213- self .clear ()
214-
215- return children , [x for x in reports ]
212+ def hook_rendered_nodes (self , hook : RenderedNodesHook ) -> None :
213+ self ._rendered_nodes_hooks .append (hook )
0 commit comments