##// END OF EJS Templates
Add preprocessor that clears cell outputs
Julia Evans -
Show More
@@ -0,0 +1,32 b''
1 """Module containing a preprocessor that removes the outputs from code cells"""
2
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
5 #
6 # Distributed under the terms of the Modified BSD License.
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14
15 from .base import Preprocessor
16
17
18 #-----------------------------------------------------------------------------
19 # Classes
20 #-----------------------------------------------------------------------------
21 class ClearOutputPreprocessor(Preprocessor):
22 """
23 Removes the output from all code cells in a notebook.
24 """
25
26 def preprocess_cell(self, cell, resources, cell_index):
27 """
28 Apply a transformation on each cell. See base.py for details.
29 """
30 if cell.cell_type == 'code':
31 cell.outputs = []
32 return cell, resources
@@ -0,0 +1,46 b''
1 """
2 Module with tests for the clearoutput preprocessor.
3 """
4
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16 from IPython.nbformat import current as nbformat
17
18 from .base import PreprocessorTestsBase
19 from ..clearoutput import ClearOutputPreprocessor
20
21
22 #-----------------------------------------------------------------------------
23 # Class
24 #-----------------------------------------------------------------------------
25
26 class TestClearOutput(PreprocessorTestsBase):
27 """Contains test functions for clearoutput.py"""
28
29
30 def build_preprocessor(self):
31 """Make an instance of a preprocessor"""
32 preprocessor = ClearOutputPreprocessor()
33 preprocessor.enabled = True
34 return preprocessor
35
36 def test_constructor(self):
37 """Can a ClearOutputPreprocessor be constructed?"""
38 self.build_preprocessor()
39
40 def test_output(self):
41 """Test the output of the ClearOutputPreprocessor"""
42 nb = self.build_notebook()
43 res = self.build_resources()
44 preprocessor = self.build_preprocessor()
45 nb, res = preprocessor(nb, res)
46 assert nb.worksheets[0].cells[0].outputs == []
@@ -1,275 +1,276 b''
1 """This module defines a base Exporter class. For Jinja template-based export,
1 """This module defines a base Exporter class. For Jinja template-based export,
2 see templateexporter.py.
2 see templateexporter.py.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import print_function, absolute_import
17 from __future__ import print_function, absolute_import
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import io
20 import io
21 import os
21 import os
22 import copy
22 import copy
23 import collections
23 import collections
24 import datetime
24 import datetime
25
25
26
26
27 # IPython imports
27 # IPython imports
28 from IPython.config.configurable import LoggingConfigurable
28 from IPython.config.configurable import LoggingConfigurable
29 from IPython.config import Config
29 from IPython.config import Config
30 from IPython.nbformat import current as nbformat
30 from IPython.nbformat import current as nbformat
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List
32 from IPython.utils.importstring import import_item
32 from IPython.utils.importstring import import_item
33 from IPython.utils import text, py3compat
33 from IPython.utils import text, py3compat
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Class
36 # Class
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 class ResourcesDict(collections.defaultdict):
39 class ResourcesDict(collections.defaultdict):
40 def __missing__(self, key):
40 def __missing__(self, key):
41 return ''
41 return ''
42
42
43
43
44 class Exporter(LoggingConfigurable):
44 class Exporter(LoggingConfigurable):
45 """
45 """
46 Class containing methods that sequentially run a list of preprocessors on a
46 Class containing methods that sequentially run a list of preprocessors on a
47 NotebookNode object and then return the modified NotebookNode object and
47 NotebookNode object and then return the modified NotebookNode object and
48 accompanying resources dict.
48 accompanying resources dict.
49 """
49 """
50
50
51 file_extension = Unicode(
51 file_extension = Unicode(
52 'txt', config=True,
52 'txt', config=True,
53 help="Extension of the file that should be written to disk"
53 help="Extension of the file that should be written to disk"
54 )
54 )
55
55
56 # MIME type of the result file, for HTTP response headers.
56 # MIME type of the result file, for HTTP response headers.
57 # This is *not* a traitlet, because we want to be able to access it from
57 # This is *not* a traitlet, because we want to be able to access it from
58 # the class, not just on instances.
58 # the class, not just on instances.
59 output_mimetype = ''
59 output_mimetype = ''
60
60
61 #Configurability, allows the user to easily add filters and preprocessors.
61 #Configurability, allows the user to easily add filters and preprocessors.
62 preprocessors = List(config=True,
62 preprocessors = List(config=True,
63 help="""List of preprocessors, by name or namespace, to enable.""")
63 help="""List of preprocessors, by name or namespace, to enable.""")
64
64
65 _preprocessors = List()
65 _preprocessors = List()
66
66
67 default_preprocessors = List(['IPython.nbconvert.preprocessors.coalesce_streams',
67 default_preprocessors = List(['IPython.nbconvert.preprocessors.coalesce_streams',
68 'IPython.nbconvert.preprocessors.SVG2PDFPreprocessor',
68 'IPython.nbconvert.preprocessors.SVG2PDFPreprocessor',
69 'IPython.nbconvert.preprocessors.ExtractOutputPreprocessor',
69 'IPython.nbconvert.preprocessors.ExtractOutputPreprocessor',
70 'IPython.nbconvert.preprocessors.CSSHTMLHeaderPreprocessor',
70 'IPython.nbconvert.preprocessors.CSSHTMLHeaderPreprocessor',
71 'IPython.nbconvert.preprocessors.RevealHelpPreprocessor',
71 'IPython.nbconvert.preprocessors.RevealHelpPreprocessor',
72 'IPython.nbconvert.preprocessors.LatexPreprocessor',
72 'IPython.nbconvert.preprocessors.LatexPreprocessor',
73 'IPython.nbconvert.preprocessors.ClearOutputPreprocessor',
73 'IPython.nbconvert.preprocessors.HighlightMagicsPreprocessor'],
74 'IPython.nbconvert.preprocessors.HighlightMagicsPreprocessor'],
74 config=True,
75 config=True,
75 help="""List of preprocessors available by default, by name, namespace,
76 help="""List of preprocessors available by default, by name, namespace,
76 instance, or type.""")
77 instance, or type.""")
77
78
78
79
79 def __init__(self, config=None, **kw):
80 def __init__(self, config=None, **kw):
80 """
81 """
81 Public constructor
82 Public constructor
82
83
83 Parameters
84 Parameters
84 ----------
85 ----------
85 config : config
86 config : config
86 User configuration instance.
87 User configuration instance.
87 """
88 """
88 with_default_config = self.default_config
89 with_default_config = self.default_config
89 if config:
90 if config:
90 with_default_config.merge(config)
91 with_default_config.merge(config)
91
92
92 super(Exporter, self).__init__(config=with_default_config, **kw)
93 super(Exporter, self).__init__(config=with_default_config, **kw)
93
94
94 self._init_preprocessors()
95 self._init_preprocessors()
95
96
96
97
97 @property
98 @property
98 def default_config(self):
99 def default_config(self):
99 return Config()
100 return Config()
100
101
101 @nbformat.docstring_nbformat_mod
102 @nbformat.docstring_nbformat_mod
102 def from_notebook_node(self, nb, resources=None, **kw):
103 def from_notebook_node(self, nb, resources=None, **kw):
103 """
104 """
104 Convert a notebook from a notebook node instance.
105 Convert a notebook from a notebook node instance.
105
106
106 Parameters
107 Parameters
107 ----------
108 ----------
108 nb : :class:`~{nbformat_mod}.nbbase.NotebookNode`
109 nb : :class:`~{nbformat_mod}.nbbase.NotebookNode`
109 Notebook node
110 Notebook node
110 resources : dict
111 resources : dict
111 Additional resources that can be accessed read/write by
112 Additional resources that can be accessed read/write by
112 preprocessors and filters.
113 preprocessors and filters.
113 **kw
114 **kw
114 Ignored (?)
115 Ignored (?)
115 """
116 """
116 nb_copy = copy.deepcopy(nb)
117 nb_copy = copy.deepcopy(nb)
117 resources = self._init_resources(resources)
118 resources = self._init_resources(resources)
118
119
119 if 'language' in nb['metadata']:
120 if 'language' in nb['metadata']:
120 resources['language'] = nb['metadata']['language'].lower()
121 resources['language'] = nb['metadata']['language'].lower()
121
122
122 # Preprocess
123 # Preprocess
123 nb_copy, resources = self._preprocess(nb_copy, resources)
124 nb_copy, resources = self._preprocess(nb_copy, resources)
124
125
125 return nb_copy, resources
126 return nb_copy, resources
126
127
127
128
128 def from_filename(self, filename, resources=None, **kw):
129 def from_filename(self, filename, resources=None, **kw):
129 """
130 """
130 Convert a notebook from a notebook file.
131 Convert a notebook from a notebook file.
131
132
132 Parameters
133 Parameters
133 ----------
134 ----------
134 filename : str
135 filename : str
135 Full filename of the notebook file to open and convert.
136 Full filename of the notebook file to open and convert.
136 """
137 """
137
138
138 # Pull the metadata from the filesystem.
139 # Pull the metadata from the filesystem.
139 if resources is None:
140 if resources is None:
140 resources = ResourcesDict()
141 resources = ResourcesDict()
141 if not 'metadata' in resources or resources['metadata'] == '':
142 if not 'metadata' in resources or resources['metadata'] == '':
142 resources['metadata'] = ResourcesDict()
143 resources['metadata'] = ResourcesDict()
143 basename = os.path.basename(filename)
144 basename = os.path.basename(filename)
144 notebook_name = basename[:basename.rfind('.')]
145 notebook_name = basename[:basename.rfind('.')]
145 resources['metadata']['name'] = notebook_name
146 resources['metadata']['name'] = notebook_name
146
147
147 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
148 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
148 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
149 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
149
150
150 with io.open(filename, encoding='utf-8') as f:
151 with io.open(filename, encoding='utf-8') as f:
151 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
152 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
152
153
153
154
154 def from_file(self, file_stream, resources=None, **kw):
155 def from_file(self, file_stream, resources=None, **kw):
155 """
156 """
156 Convert a notebook from a notebook file.
157 Convert a notebook from a notebook file.
157
158
158 Parameters
159 Parameters
159 ----------
160 ----------
160 file_stream : file-like object
161 file_stream : file-like object
161 Notebook file-like object to convert.
162 Notebook file-like object to convert.
162 """
163 """
163 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
164 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
164
165
165
166
166 def register_preprocessor(self, preprocessor, enabled=False):
167 def register_preprocessor(self, preprocessor, enabled=False):
167 """
168 """
168 Register a preprocessor.
169 Register a preprocessor.
169 Preprocessors are classes that act upon the notebook before it is
170 Preprocessors are classes that act upon the notebook before it is
170 passed into the Jinja templating engine. preprocessors are also
171 passed into the Jinja templating engine. preprocessors are also
171 capable of passing additional information to the Jinja
172 capable of passing additional information to the Jinja
172 templating engine.
173 templating engine.
173
174
174 Parameters
175 Parameters
175 ----------
176 ----------
176 preprocessor : preprocessor
177 preprocessor : preprocessor
177 """
178 """
178 if preprocessor is None:
179 if preprocessor is None:
179 raise TypeError('preprocessor')
180 raise TypeError('preprocessor')
180 isclass = isinstance(preprocessor, type)
181 isclass = isinstance(preprocessor, type)
181 constructed = not isclass
182 constructed = not isclass
182
183
183 # Handle preprocessor's registration based on it's type
184 # Handle preprocessor's registration based on it's type
184 if constructed and isinstance(preprocessor, py3compat.string_types):
185 if constructed and isinstance(preprocessor, py3compat.string_types):
185 # Preprocessor is a string, import the namespace and recursively call
186 # Preprocessor is a string, import the namespace and recursively call
186 # this register_preprocessor method
187 # this register_preprocessor method
187 preprocessor_cls = import_item(preprocessor)
188 preprocessor_cls = import_item(preprocessor)
188 return self.register_preprocessor(preprocessor_cls, enabled)
189 return self.register_preprocessor(preprocessor_cls, enabled)
189
190
190 if constructed and hasattr(preprocessor, '__call__'):
191 if constructed and hasattr(preprocessor, '__call__'):
191 # Preprocessor is a function, no need to construct it.
192 # Preprocessor is a function, no need to construct it.
192 # Register and return the preprocessor.
193 # Register and return the preprocessor.
193 if enabled:
194 if enabled:
194 preprocessor.enabled = True
195 preprocessor.enabled = True
195 self._preprocessors.append(preprocessor)
196 self._preprocessors.append(preprocessor)
196 return preprocessor
197 return preprocessor
197
198
198 elif isclass and isinstance(preprocessor, MetaHasTraits):
199 elif isclass and isinstance(preprocessor, MetaHasTraits):
199 # Preprocessor is configurable. Make sure to pass in new default for
200 # Preprocessor is configurable. Make sure to pass in new default for
200 # the enabled flag if one was specified.
201 # the enabled flag if one was specified.
201 self.register_preprocessor(preprocessor(parent=self), enabled)
202 self.register_preprocessor(preprocessor(parent=self), enabled)
202
203
203 elif isclass:
204 elif isclass:
204 # Preprocessor is not configurable, construct it
205 # Preprocessor is not configurable, construct it
205 self.register_preprocessor(preprocessor(), enabled)
206 self.register_preprocessor(preprocessor(), enabled)
206
207
207 else:
208 else:
208 # Preprocessor is an instance of something without a __call__
209 # Preprocessor is an instance of something without a __call__
209 # attribute.
210 # attribute.
210 raise TypeError('preprocessor')
211 raise TypeError('preprocessor')
211
212
212
213
213 def _init_preprocessors(self):
214 def _init_preprocessors(self):
214 """
215 """
215 Register all of the preprocessors needed for this exporter, disabled
216 Register all of the preprocessors needed for this exporter, disabled
216 unless specified explicitly.
217 unless specified explicitly.
217 """
218 """
218 self._preprocessors = []
219 self._preprocessors = []
219
220
220 # Load default preprocessors (not necessarly enabled by default).
221 # Load default preprocessors (not necessarly enabled by default).
221 for preprocessor in self.default_preprocessors:
222 for preprocessor in self.default_preprocessors:
222 self.register_preprocessor(preprocessor)
223 self.register_preprocessor(preprocessor)
223
224
224 # Load user-specified preprocessors. Enable by default.
225 # Load user-specified preprocessors. Enable by default.
225 for preprocessor in self.preprocessors:
226 for preprocessor in self.preprocessors:
226 self.register_preprocessor(preprocessor, enabled=True)
227 self.register_preprocessor(preprocessor, enabled=True)
227
228
228
229
229 def _init_resources(self, resources):
230 def _init_resources(self, resources):
230
231
231 #Make sure the resources dict is of ResourcesDict type.
232 #Make sure the resources dict is of ResourcesDict type.
232 if resources is None:
233 if resources is None:
233 resources = ResourcesDict()
234 resources = ResourcesDict()
234 if not isinstance(resources, ResourcesDict):
235 if not isinstance(resources, ResourcesDict):
235 new_resources = ResourcesDict()
236 new_resources = ResourcesDict()
236 new_resources.update(resources)
237 new_resources.update(resources)
237 resources = new_resources
238 resources = new_resources
238
239
239 #Make sure the metadata extension exists in resources
240 #Make sure the metadata extension exists in resources
240 if 'metadata' in resources:
241 if 'metadata' in resources:
241 if not isinstance(resources['metadata'], ResourcesDict):
242 if not isinstance(resources['metadata'], ResourcesDict):
242 resources['metadata'] = ResourcesDict(resources['metadata'])
243 resources['metadata'] = ResourcesDict(resources['metadata'])
243 else:
244 else:
244 resources['metadata'] = ResourcesDict()
245 resources['metadata'] = ResourcesDict()
245 if not resources['metadata']['name']:
246 if not resources['metadata']['name']:
246 resources['metadata']['name'] = 'Notebook'
247 resources['metadata']['name'] = 'Notebook'
247
248
248 #Set the output extension
249 #Set the output extension
249 resources['output_extension'] = self.file_extension
250 resources['output_extension'] = self.file_extension
250 return resources
251 return resources
251
252
252
253
253 def _preprocess(self, nb, resources):
254 def _preprocess(self, nb, resources):
254 """
255 """
255 Preprocess the notebook before passing it into the Jinja engine.
256 Preprocess the notebook before passing it into the Jinja engine.
256 To preprocess the notebook is to apply all of the
257 To preprocess the notebook is to apply all of the
257
258
258 Parameters
259 Parameters
259 ----------
260 ----------
260 nb : notebook node
261 nb : notebook node
261 notebook that is being exported.
262 notebook that is being exported.
262 resources : a dict of additional resources that
263 resources : a dict of additional resources that
263 can be accessed read/write by preprocessors
264 can be accessed read/write by preprocessors
264 """
265 """
265
266
266 # Do a copy.deepcopy first,
267 # Do a copy.deepcopy first,
267 # we are never safe enough with what the preprocessors could do.
268 # we are never safe enough with what the preprocessors could do.
268 nbc = copy.deepcopy(nb)
269 nbc = copy.deepcopy(nb)
269 resc = copy.deepcopy(resources)
270 resc = copy.deepcopy(resources)
270
271
271 #Run each preprocessor on the notebook. Carry the output along
272 #Run each preprocessor on the notebook. Carry the output along
272 #to each preprocessor
273 #to each preprocessor
273 for preprocessor in self._preprocessors:
274 for preprocessor in self._preprocessors:
274 nbc, resc = preprocessor(nbc, resc)
275 nbc, resc = preprocessor(nbc, resc)
275 return nbc, resc
276 return nbc, resc
@@ -1,12 +1,13 b''
1 # Class base Preprocessors
1 # Class base Preprocessors
2 from .base import Preprocessor
2 from .base import Preprocessor
3 from .convertfigures import ConvertFiguresPreprocessor
3 from .convertfigures import ConvertFiguresPreprocessor
4 from .svg2pdf import SVG2PDFPreprocessor
4 from .svg2pdf import SVG2PDFPreprocessor
5 from .extractoutput import ExtractOutputPreprocessor
5 from .extractoutput import ExtractOutputPreprocessor
6 from .revealhelp import RevealHelpPreprocessor
6 from .revealhelp import RevealHelpPreprocessor
7 from .latex import LatexPreprocessor
7 from .latex import LatexPreprocessor
8 from .csshtmlheader import CSSHTMLHeaderPreprocessor
8 from .csshtmlheader import CSSHTMLHeaderPreprocessor
9 from .highlightmagics import HighlightMagicsPreprocessor
9 from .highlightmagics import HighlightMagicsPreprocessor
10 from .clearoutput import ClearOutputPreprocessor
10
11
11 # decorated function Preprocessors
12 # decorated function Preprocessors
12 from .coalescestreams import coalesce_streams
13 from .coalescestreams import coalesce_streams
General Comments 0
You need to be logged in to leave comments. Login now