def _render_nb_cell_code_source(self: SelfType, token: SyntaxTreeNode) -> None: """Render a notebook code cell's source.""" cell_index = token.meta["index"] line = token_line(token, 0) or None node = self.create_highlighted_code_block( token.content, self._get_nb_source_code_lexer(cell_index, line=line), number_lines=self.get_cell_level_config( "number_source_lines", token.meta["metadata"], line=line, ), source=self.document["source"], line=token_line(token), ) self.add_line_and_source_path(node, token) self.current_node.append(node)
def render_nb_cell_raw(self: SelfType, token: SyntaxTreeNode) -> None: """Render a notebook raw cell.""" line = token_line(token, 0) _nodes = self.nb_renderer.render_raw_cell( token.content, token.meta["metadata"], token.meta["index"], line ) self.add_line_and_source_path_r(_nodes, token) self.current_node.extend(_nodes)
def _get_nb_code_cell_outputs( self, token: SyntaxTreeNode ) -> tuple[int | None, list[NotebookNode]]: """Get the outputs for a code cell and its execution count.""" cell_index = token.meta["index"] line = token_line(token, 0) or None exec_count, outputs = self.nb_client.code_cell_outputs(cell_index) if self.get_cell_level_config("merge_streams", token.meta["metadata"], line): # TODO should this be saved on the output notebook outputs = coalesce_streams(outputs) return exec_count, outputs
def render_nb_cell_code(self: SelfType, token: SyntaxTreeNode) -> None: """Render a notebook code cell.""" cell_index = token.meta["index"] tags = token.meta["metadata"].get("tags", []) exec_count, outputs = self._get_nb_code_cell_outputs(token) # TODO do we need this -/_ duplication of tag names, or can we deprecate one? remove_input = ( self.get_cell_level_config( "remove_code_source", token.meta["metadata"], line=token_line(token, 0) or None, ) or ("remove_input" in tags) or ("remove-input" in tags) ) remove_output = ( self.get_cell_level_config( "remove_code_outputs", token.meta["metadata"], line=token_line(token, 0) or None, ) or ("remove_output" in tags) or ("remove-output" in tags) ) # if we are remove both the input and output, we can skip the cell if remove_input and remove_output: return # create a container for all the input/output classes = ["cell"] for tag in tags: classes.append(f"tag_{tag.replace(' ', '_')}") cell_container = nodes.container( nb_element="cell_code", cell_index=cell_index, # TODO some way to use this to allow repr of count in outputs like HTML? exec_count=exec_count, cell_metadata=token.meta["metadata"], classes=classes, ) self.add_line_and_source_path(cell_container, token) with self.current_node_context(cell_container, append=True): # render the code source code if not remove_input: cell_input = nodes.container( nb_element="cell_code_source", classes=["cell_input"] ) self.add_line_and_source_path(cell_input, token) with self.current_node_context(cell_input, append=True): self._render_nb_cell_code_source(token) # render the execution output, if any if outputs and (not remove_output): cell_output = nodes.container( nb_element="cell_code_output", classes=["cell_output"] ) self.add_line_and_source_path(cell_output, token) with self.current_node_context(cell_output, append=True): self._render_nb_cell_code_outputs(token, outputs)
def _render_nb_cell_code_outputs( self, token: SyntaxTreeNode, outputs: list[nbformat.NotebookNode]) -> None: """Render a notebook code cell's outputs.""" line = token_line(token, 0) cell_index = token.meta["index"] metadata = token.meta["metadata"] # render the outputs for output_index, output in enumerate(outputs): if output.output_type == "stream": if output.name == "stdout": _nodes = self.nb_renderer.render_stdout( output, metadata, cell_index, line) self.add_line_and_source_path_r(_nodes, token) self.current_node.extend(_nodes) elif output.name == "stderr": _nodes = self.nb_renderer.render_stderr( output, metadata, cell_index, line) self.add_line_and_source_path_r(_nodes, token) self.current_node.extend(_nodes) else: pass # TODO warning elif output.output_type == "error": _nodes = self.nb_renderer.render_error(output, metadata, cell_index, line) self.add_line_and_source_path_r(_nodes, token) self.current_node.extend(_nodes) elif output.output_type in ("display_data", "execute_result"): # Note, this is different to the docutils implementation, # where we directly select a single output, based on the mime_priority. # Here, we do not know the mime priority until we know the output format # so we output all the outputs during this parsing phase # (this is what sphinx caches as "output format agnostic" AST), # and replace the mime_bundle with the format specific output # in a post-transform (run per output format on the cached AST) figure_options = (self.get_cell_level_config( "render_figure_options", metadata, line=line) or None) with create_figure_context(self, figure_options, line): mime_bundle = nodes.container(nb_element="mime_bundle") with self.current_node_context(mime_bundle): for mime_type, data in output["data"].items(): mime_container = nodes.container( mime_type=mime_type) with self.current_node_context(mime_container): _nodes = self.nb_renderer.render_mime_type( MimeData( mime_type, data, cell_metadata=metadata, output_metadata=output.get( "metadata", {}), cell_index=cell_index, output_index=output_index, line=line, )) self.current_node.extend(_nodes) if mime_container.children: self.current_node.append(mime_container) if mime_bundle.children: self.add_line_and_source_path_r([mime_bundle], token) self.current_node.append(mime_bundle) else: self.create_warning( f"Unsupported output type: {output.output_type}", line=line, append_to=self.current_node, wtype=DEFAULT_LOG_TYPE, subtype="output_type", )