-
Notifications
You must be signed in to change notification settings - Fork 567
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #640 from mpacer/tag_preprocessor
Tag remove preprocessor
- Loading branch information
Showing
5 changed files
with
190 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
""" | ||
Module containing a preprocessor that removes cells if they match | ||
one or more regular expression. | ||
""" | ||
|
||
# Copyright (c) IPython Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||
|
||
from traitlets import Set, Unicode | ||
from . import ClearOutputPreprocessor | ||
|
||
|
||
class TagRemovePreprocessor(ClearOutputPreprocessor): | ||
""" | ||
Removes cells from a notebook that have tags that designate they are to be | ||
removed prior to exporting the notebook. | ||
Traitlets: | ||
---------- | ||
remove_cell_tags: removes cells tagged with these values | ||
remove_all_output_tags: removes entire output areas on cells | ||
tagged with these values | ||
remove_single_output_tags: removes individual output objects on | ||
outputs tagged with these values | ||
""" | ||
|
||
remove_cell_tags = Set(Unicode, default_value=[], | ||
help=("Tags indicating which cells are to be removed," | ||
"matches tags in `cell.metadata.tags`.")).tag(config=True) | ||
remove_all_outputs_tags = Set(Unicode, default_value=[], | ||
help=("Tags indicating cells for which the outputs are to be removed," | ||
"matches tags in `cell.metadata.tags`.")).tag(config=True) | ||
remove_single_output_tags = Set(Unicode, default_value=[], | ||
help=("Tags indicating which individual outputs are to be removed," | ||
"matches output *i* tags in `cell.outputs[i].metadata.tags`.") | ||
).tag(config=True) | ||
|
||
def check_cell_conditions(self, cell, resources, index): | ||
""" | ||
Checks that a cell has a tag that is to be removed | ||
Returns: Boolean. | ||
True means cell should *not* be removed. | ||
""" | ||
|
||
# Return true if any of the tags in the cell are removable. | ||
return not self.remove_cell_tags.intersection( | ||
cell.get('metadata', {}).get('tags', [])) | ||
|
||
def preprocess(self, nb, resources): | ||
""" | ||
Preprocessing to apply to each notebook. See base.py for details. | ||
""" | ||
# Skip preprocessing if the list of patterns is empty | ||
if not any([self.remove_cell_tags, | ||
self.remove_all_outputs_tags, | ||
self.remove_single_output_tags]): | ||
return nb, resources | ||
|
||
# Filter out cells that meet the conditions | ||
nb.cells = [self.preprocess_cell(cell, resources, index)[0] | ||
for index, cell in enumerate(nb.cells) | ||
if self.check_cell_conditions(cell, resources, index)] | ||
|
||
return nb, resources | ||
|
||
def preprocess_cell(self, cell, resources, cell_index): | ||
""" | ||
Apply a transformation on each cell. See base.py for details. | ||
""" | ||
|
||
if (self.remove_all_outputs_tags.intersection( | ||
cell.get('metadata', {}).get('tags', [])) | ||
and cell.cell_type == 'code'): | ||
cell.outputs = [] | ||
cell.execution_count = None | ||
# Remove metadata associated with output | ||
if 'metadata' in cell: | ||
for field in self.remove_metadata_fields: | ||
cell.metadata.pop(field, None) | ||
if cell.get('outputs', []): | ||
cell.outputs = [output | ||
for output_index, output in enumerate(cell.outputs) | ||
if self.check_output_conditions(output, | ||
resources, | ||
cell_index, | ||
output_index) | ||
] | ||
return cell, resources | ||
|
||
def check_output_conditions(self, output, resources, | ||
cell_index, output_index): | ||
""" | ||
Checks that an output has a tag that indicates removal. | ||
Returns: Boolean. | ||
True means output should *not* be removed. | ||
""" | ||
return not self.remove_single_output_tags.intersection( | ||
output.get('metadata', {}).get('tags', [])) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
""" | ||
Module with tests for the TagRemovePreprocessor. | ||
""" | ||
|
||
# Copyright (c) IPython Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||
|
||
from nbformat import v4 as nbformat | ||
|
||
from .base import PreprocessorTestsBase | ||
from ..tagremove import TagRemovePreprocessor | ||
|
||
|
||
class TestTagRemove(PreprocessorTestsBase): | ||
"""Contains test functions for tagremove.py""" | ||
|
||
def build_notebook(self): | ||
""" | ||
Build a notebook to have metadata tags for cells, output_areas, and | ||
individual outputs. | ||
""" | ||
notebook = super(TestTagRemove, self).build_notebook() | ||
# Add a few empty cells | ||
notebook.cells[0].outputs.extend( | ||
[nbformat.new_output("display_data", | ||
data={'text/plain': 'i'}, | ||
metadata={'tags': ["hide_one_output"]} | ||
), | ||
]) | ||
outputs_to_be_removed = [ | ||
nbformat.new_output("display_data", | ||
data={'text/plain': "remove_my_output"}), | ||
] | ||
outputs_to_be_kept = [ | ||
nbformat.new_output("stream", | ||
name="stdout", | ||
text="remove_my_output", | ||
), | ||
] | ||
notebook.cells.extend( | ||
[nbformat.new_code_cell(source="display('remove_my_output')", | ||
execution_count=2, | ||
outputs=outputs_to_be_removed, | ||
metadata={"tags": ["hide_all_outputs"]}), | ||
|
||
nbformat.new_code_cell(source="print('remove this cell')", | ||
execution_count=3, | ||
outputs=outputs_to_be_kept, | ||
metadata={"tags": ["hide_this_cell"]}), | ||
] | ||
) | ||
|
||
return notebook | ||
|
||
def build_preprocessor(self): | ||
"""Make an instance of a preprocessor""" | ||
preprocessor = TagRemovePreprocessor() | ||
preprocessor.enabled = True | ||
return preprocessor | ||
|
||
def test_constructor(self): | ||
"""Can a TagRemovePreprocessor be constructed?""" | ||
self.build_preprocessor() | ||
|
||
def test_output(self): | ||
"""Test the output of the TagRemovePreprocessor""" | ||
nb = self.build_notebook() | ||
res = self.build_resources() | ||
preprocessor = self.build_preprocessor() | ||
preprocessor.remove_cell_tags.add("hide_this_cell") | ||
preprocessor.remove_all_outputs_tags.add('hide_all_outputs') | ||
preprocessor.remove_single_output_tags.add('hide_one_output') | ||
|
||
nb, res = preprocessor(nb, res) | ||
|
||
# checks that we can remove entire cells | ||
self.assertEqual(len(nb.cells), 3) | ||
|
||
# checks that we can remove output areas | ||
self.assertEqual(len(nb.cells[-1].outputs), 0) | ||
|
||
# checks that we can remove individual outputs | ||
self.assertEqual(len(nb.cells[0].outputs), 8) |