##// END OF EJS Templates
Renamed preprocessors to transformers to maintain consistency
Jonathan Frederic -
Show More
@@ -1,316 +1,315 b''
1 """This module defines Exporter, a highly configurable converter
1 """This module defines Exporter, a highly configurable converter
2 that uses Jinja2 to export notebook files into different formats.
2 that uses Jinja2 to export notebook files into different formats.
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 inspect
22 import inspect
23
23
24 # IPython imports
24 # IPython imports
25 from IPython.config.configurable import Configurable
25 from IPython.config.configurable import Configurable
26 from IPython.nbformat import current as nbformat
26 from IPython.nbformat import current as nbformat
27 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
27 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
28 from IPython.utils.text import indent
28 from IPython.utils.text import indent
29
29
30 # other libs/dependencies
30 # other libs/dependencies
31 from jinja2 import Environment, FileSystemLoader
31 from jinja2 import Environment, FileSystemLoader
32 from markdown import markdown
32 from markdown import markdown
33
33
34 # local import
34 # local import
35 import nbconvert.filters.strings
35 import nbconvert.filters.strings
36 import nbconvert.filters.markdown
36 import nbconvert.filters.markdown
37 import nbconvert.filters.latex
37 import nbconvert.filters.latex
38 import nbconvert.filters.datatypefilter
38 import nbconvert.filters.datatypefilter
39 import nbconvert.filters.highlight
39 import nbconvert.filters.highlight
40 import nbconvert.filters.ansi
40 import nbconvert.filters.ansi
41
41
42 import nbconvert.transformers.extractfigure
42 import nbconvert.transformers.extractfigure
43 import nbconvert.transformers.coalescestreams
43 import nbconvert.transformers.coalescestreams
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Globals and constants
46 # Globals and constants
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 #Jinja2 extensions to load.
49 #Jinja2 extensions to load.
50 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
50 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # Class
53 # Class
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56 class Exporter(Configurable):
56 class Exporter(Configurable):
57 """
57 """
58 Exports notebooks into other file formats. Uses Jinja 2 templating engine
58 Exports notebooks into other file formats. Uses Jinja 2 templating engine
59 to output new formats. Inherit from this class if you are creating a new
59 to output new formats. Inherit from this class if you are creating a new
60 template type along with new filters/transformers. If the filters/
60 template type along with new filters/transformers. If the filters/
61 transformers provided by default suffice, there is no need to inherit from
61 transformers provided by default suffice, there is no need to inherit from
62 this class. Instead, override the template_file and file_extension
62 this class. Instead, override the template_file and file_extension
63 traits via a config file.
63 traits via a config file.
64 """
64 """
65
65
66 template_file = Unicode(
66 template_file = Unicode(
67 '', config=True,
67 '', config=True,
68 help="Name of the template file to use")
68 help="Name of the template file to use")
69
69
70 file_extension = Unicode(
70 file_extension = Unicode(
71 'txt', config=True,
71 'txt', config=True,
72 help="Extension of the file that should be written to disk"
72 help="Extension of the file that should be written to disk"
73 )
73 )
74
74
75 template_path = Unicode(
75 template_path = Unicode(
76 "/../templates/", config=True,
76 "/../templates/", config=True,
77 help="Path where the template files are located.")
77 help="Path where the template files are located.")
78
78
79 template_skeleton_path = Unicode(
79 template_skeleton_path = Unicode(
80 "/../templates/skeleton/", config=True,
80 "/../templates/skeleton/", config=True,
81 help="Path where the template skeleton files are located.")
81 help="Path where the template skeleton files are located.")
82
82
83 #Jinja block definitions
83 #Jinja block definitions
84 jinja_comment_block_start = Unicode("", config=True)
84 jinja_comment_block_start = Unicode("", config=True)
85 jinja_comment_block_end = Unicode("", config=True)
85 jinja_comment_block_end = Unicode("", config=True)
86 jinja_variable_block_start = Unicode("", config=True)
86 jinja_variable_block_start = Unicode("", config=True)
87 jinja_variable_block_end = Unicode("", config=True)
87 jinja_variable_block_end = Unicode("", config=True)
88 jinja_logic_block_start = Unicode("", config=True)
88 jinja_logic_block_start = Unicode("", config=True)
89 jinja_logic_block_end = Unicode("", config=True)
89 jinja_logic_block_end = Unicode("", config=True)
90
90
91 #Extension that the template files use.
91 #Extension that the template files use.
92 template_extension = Unicode(".tpl", config=True)
92 template_extension = Unicode(".tpl", config=True)
93
93
94 #Processors that process the input data prior to the export, set in the
94 #Processors that process the input data prior to the export, set in the
95 #constructor for this class.
95 #constructor for this class.
96 preprocessors = []
96 transformers = []
97
97
98
98
99 def __init__(self, transformers=None, filters=None, config=None, **kw):
99 def __init__(self, transformers=None, filters=None, config=None, **kw):
100 """
100 """
101 Public constructor
101 Public constructor
102
102
103 Parameters
103 Parameters
104 ----------
104 ----------
105 transformers : list[of transformer]
105 transformers : list[of transformer]
106 Custom transformers to apply to the notebook prior to engaging
106 Custom transformers to apply to the notebook prior to engaging
107 the Jinja template engine. Any transformers specified here
107 the Jinja template engine. Any transformers specified here
108 will override existing transformers if a naming conflict
108 will override existing transformers if a naming conflict
109 occurs.
109 occurs.
110 filters : list[of filter]
110 filters : list[of filter]
111 Custom filters to make accessible to the Jinja templates. Any
111 Custom filters to make accessible to the Jinja templates. Any
112 filters specified here will override existing filters if a
112 filters specified here will override existing filters if a
113 naming conflict occurs.
113 naming conflict occurs.
114 config : config
114 config : config
115 User configuration instance.
115 User configuration instance.
116 """
116 """
117
117
118 #Call the base class constructor
118 #Call the base class constructor
119 super(Exporter, self).__init__(config=config, **kw)
119 super(Exporter, self).__init__(config=config, **kw)
120
120
121 #Standard environment
121 #Standard environment
122 self._init_environment()
122 self._init_environment()
123
123
124 #Add transformers
124 #Add transformers
125 self._register_transformers()
125 self._register_transformers()
126
126
127 #Add filters to the Jinja2 environment
127 #Add filters to the Jinja2 environment
128 self._register_filters()
128 self._register_filters()
129
129
130 #Load user transformers. Overwrite existing transformers if need be.
130 #Load user transformers. Overwrite existing transformers if need be.
131 if not transformers is None:
131 if not transformers is None:
132 for transformer in transformers:
132 for transformer in transformers:
133 self.register_transformer(transformer)
133 self.register_transformer(transformer)
134
134
135 #Load user filters. Overwrite existing filters if need be.
135 #Load user filters. Overwrite existing filters if need be.
136 if not filters is None:
136 if not filters is None:
137 for key, user_filter in filters.iteritems():
137 for key, user_filter in filters.iteritems():
138 if issubclass(user_filter, MetaHasTraits):
138 if issubclass(user_filter, MetaHasTraits):
139 self.environment.filters[key] = user_filter(config=config)
139 self.environment.filters[key] = user_filter(config=config)
140 else:
140 else:
141 self.environment.filters[key] = user_filter
141 self.environment.filters[key] = user_filter
142
142
143
143
144 def from_notebook_node(self, nb):
144 def from_notebook_node(self, nb):
145 """
145 """
146 Convert a notebook from a notebook node instance.
146 Convert a notebook from a notebook node instance.
147
147
148 Parameters
148 Parameters
149 ----------
149 ----------
150 nb : Notebook node
150 nb : Notebook node
151 """
151 """
152
152
153 nb, resources = self._preprocess(nb)
153 nb, resources = self._preprocess(nb)
154
154
155 #Load the template file.
155 #Load the template file.
156 self.template = self.environment.get_template(self.template_file+self.template_extension)
156 self.template = self.environment.get_template(self.template_file+self.template_extension)
157
157
158 return self.template.render(nb=nb, resources=resources), resources
158 return self.template.render(nb=nb, resources=resources), resources
159
159
160
160
161 def from_filename(self, filename):
161 def from_filename(self, filename):
162 """
162 """
163 Convert a notebook from a notebook file.
163 Convert a notebook from a notebook file.
164
164
165 Parameters
165 Parameters
166 ----------
166 ----------
167 filename : str
167 filename : str
168 Full filename of the notebook file to open and convert.
168 Full filename of the notebook file to open and convert.
169 """
169 """
170
170
171 with io.open(filename) as f:
171 with io.open(filename) as f:
172 return self.from_notebook_node(nbformat.read(f, 'json'))
172 return self.from_notebook_node(nbformat.read(f, 'json'))
173
173
174
174
175 def from_file(self, file_stream):
175 def from_file(self, file_stream):
176 """
176 """
177 Convert a notebook from a notebook file.
177 Convert a notebook from a notebook file.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181 file_stream : file-like object
181 file_stream : file-like object
182 Notebook file-like object to convert.
182 Notebook file-like object to convert.
183 """
183 """
184 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
184 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
185
185
186
186
187 def register_transformer(self, transformer):
187 def register_transformer(self, transformer):
188 """
188 """
189 Register a transformer.
189 Register a transformer.
190 Transformers are classes that act upon the notebook before it is
190 Transformers are classes that act upon the notebook before it is
191 passed into the Jinja templating engine. Transformers are also
191 passed into the Jinja templating engine. Transformers are also
192 capable of passing additional information to the Jinja
192 capable of passing additional information to the Jinja
193 templating engine.
193 templating engine.
194
194
195 Parameters
195 Parameters
196 ----------
196 ----------
197 transformer : transformer
197 transformer : transformer
198 """
198 """
199
199
200 if inspect.isfunction(transformer):
200 if inspect.isfunction(transformer):
201 self.preprocessors.append(transformer)
201 self.transformers.append(transformer)
202 return transformer
202 return transformer
203 elif isinstance(transformer, MetaHasTraits):
203 elif isinstance(transformer, MetaHasTraits):
204 transformer_instance = transformer(config=self.config)
204 transformer_instance = transformer(config=self.config)
205 self.preprocessors.append(transformer_instance)
205 self.transformers.append(transformer_instance)
206 return transformer_instance
206 return transformer_instance
207 else:
207 else:
208 transformer_instance = transformer()
208 transformer_instance = transformer()
209 self.preprocessors.append(transformer_instance)
209 self.transformers.append(transformer_instance)
210 return transformer_instance
210 return transformer_instance
211
211
212
212
213 def register_filter(self, name, filter):
213 def register_filter(self, name, filter):
214 """
214 """
215 Register a filter.
215 Register a filter.
216 A filter is a function that accepts and acts on one string.
216 A filter is a function that accepts and acts on one string.
217 The filters are accesible within the Jinja templating engine.
217 The filters are accesible within the Jinja templating engine.
218
218
219 Parameters
219 Parameters
220 ----------
220 ----------
221 name : str
221 name : str
222 name to give the filter in the Jinja engine
222 name to give the filter in the Jinja engine
223 filter : filter
223 filter : filter
224 """
224 """
225
226 if inspect.isfunction(filter):
225 if inspect.isfunction(filter):
227 self.environment.filters[name] = filter
226 self.environment.filters[name] = filter
228 elif isinstance(filter, MetaHasTraits):
227 elif isinstance(filter, MetaHasTraits):
229 self.environment.filters[name] = filter(config=self.config)
228 self.environment.filters[name] = filter(config=self.config)
230 else:
229 else:
231 self.environment.filters[name] = filter()
230 self.environment.filters[name] = filter()
232 return self.environment.filters[name]
231 return self.environment.filters[name]
233
232
234
233
235 def _register_transformers(self):
234 def _register_transformers(self):
236 """
235 """
237 Register all of the transformers needed for this exporter.
236 Register all of the transformers needed for this exporter.
238 """
237 """
239
238
240 self.register_transformer(nbconvert.transformers.coalescestreams.coalesce_streams)
239 self.register_transformer(nbconvert.transformers.coalescestreams.coalesce_streams)
241
240
242 #Remember the figure extraction transformer so it can be enabled and
241 #Remember the figure extraction transformer so it can be enabled and
243 #disabled easily later.
242 #disabled easily later.
244 self.extract_figure_transformer = self.register_transformer(nbconvert.transformers.extractfigure.ExtractFigureTransformer)
243 self.extract_figure_transformer = self.register_transformer(nbconvert.transformers.extractfigure.ExtractFigureTransformer)
245
244
246
245
247 def _register_filters(self):
246 def _register_filters(self):
248 """
247 """
249 Register all of the filters required for the exporter.
248 Register all of the filters required for the exporter.
250 """
249 """
251
250
252 self.register_filter('indent', indent)
251 self.register_filter('indent', indent)
253 self.register_filter('markdown', markdown)
252 self.register_filter('markdown', markdown)
254 self.register_filter('ansi2html', nbconvert.filters.ansi.ansi2html)
253 self.register_filter('ansi2html', nbconvert.filters.ansi.ansi2html)
255 self.register_filter('filter_data_type', nbconvert.filters.datatypefilter.DataTypeFilter)
254 self.register_filter('filter_data_type', nbconvert.filters.datatypefilter.DataTypeFilter)
256 self.register_filter('get_lines', nbconvert.filters.strings.get_lines)
255 self.register_filter('get_lines', nbconvert.filters.strings.get_lines)
257 self.register_filter('highlight', nbconvert.filters.highlight.highlight)
256 self.register_filter('highlight', nbconvert.filters.highlight.highlight)
258 self.register_filter('highlight2html', nbconvert.filters.highlight.highlight)
257 self.register_filter('highlight2html', nbconvert.filters.highlight.highlight)
259 self.register_filter('highlight2latex', nbconvert.filters.highlight.highlight2latex)
258 self.register_filter('highlight2latex', nbconvert.filters.highlight.highlight2latex)
260 self.register_filter('markdown2latex', nbconvert.filters.markdown.markdown2latex)
259 self.register_filter('markdown2latex', nbconvert.filters.markdown.markdown2latex)
261 self.register_filter('markdown2rst', nbconvert.filters.markdown.markdown2rst)
260 self.register_filter('markdown2rst', nbconvert.filters.markdown.markdown2rst)
262 self.register_filter('pycomment', nbconvert.filters.strings.python_comment)
261 self.register_filter('pycomment', nbconvert.filters.strings.python_comment)
263 self.register_filter('rm_ansi', nbconvert.filters.ansi.remove_ansi)
262 self.register_filter('rm_ansi', nbconvert.filters.ansi.remove_ansi)
264 self.register_filter('rm_dollars', nbconvert.filters.strings.strip_dollars)
263 self.register_filter('rm_dollars', nbconvert.filters.strings.strip_dollars)
265 self.register_filter('rm_fake', nbconvert.filters.strings.rm_fake)
264 self.register_filter('rm_fake', nbconvert.filters.strings.rm_fake)
266 self.register_filter('rm_math_space', nbconvert.filters.latex.rm_math_space)
265 self.register_filter('rm_math_space', nbconvert.filters.latex.rm_math_space)
267 self.register_filter('wrap', nbconvert.filters.strings.wrap)
266 self.register_filter('wrap', nbconvert.filters.strings.wrap)
268
267
269
268
270 def _init_environment(self):
269 def _init_environment(self):
271 """
270 """
272 Create the Jinja templating environment.
271 Create the Jinja templating environment.
273 """
272 """
274
273
275 self.environment = Environment(
274 self.environment = Environment(
276 loader=FileSystemLoader([
275 loader=FileSystemLoader([
277 os.path.dirname(os.path.realpath(__file__)) + self.template_path,
276 os.path.dirname(os.path.realpath(__file__)) + self.template_path,
278 os.path.dirname(os.path.realpath(__file__)) + self.template_skeleton_path,
277 os.path.dirname(os.path.realpath(__file__)) + self.template_skeleton_path,
279 ]),
278 ]),
280 extensions=JINJA_EXTENSIONS
279 extensions=JINJA_EXTENSIONS
281 )
280 )
282
281
283 #Set special Jinja2 syntax that will not conflict with latex.
282 #Set special Jinja2 syntax that will not conflict with latex.
284 if self.jinja_logic_block_start:
283 if self.jinja_logic_block_start:
285 self.environment.block_start_string = self.jinja_logic_block_start
284 self.environment.block_start_string = self.jinja_logic_block_start
286 if self.jinja_logic_block_end:
285 if self.jinja_logic_block_end:
287 self.environment.block_end_string = self.jinja_logic_block_end
286 self.environment.block_end_string = self.jinja_logic_block_end
288 if self.jinja_variable_block_start:
287 if self.jinja_variable_block_start:
289 self.environment.variable_start_string = self.jinja_variable_block_start
288 self.environment.variable_start_string = self.jinja_variable_block_start
290 if self.jinja_variable_block_end:
289 if self.jinja_variable_block_end:
291 self.environment.variable_end_string = self.jinja_variable_block_end
290 self.environment.variable_end_string = self.jinja_variable_block_end
292 if self.jinja_comment_block_start:
291 if self.jinja_comment_block_start:
293 self.environment.comment_start_string = self.jinja_comment_block_start
292 self.environment.comment_start_string = self.jinja_comment_block_start
294 if self.jinja_comment_block_end:
293 if self.jinja_comment_block_end:
295 self.environment.comment_end_string = self.jinja_comment_block_end
294 self.environment.comment_end_string = self.jinja_comment_block_end
296
295
297
296
298 def _preprocess(self, nb):
297 def _preprocess(self, nb):
299 """
298 """
300 Preprocess the notebook before passing it into the Jinja engine.
299 Preprocess the notebook before passing it into the Jinja engine.
301 To preprocess the notebook is to apply all of the
300 To preprocess the notebook is to apply all of the
302
301
303 Parameters
302 Parameters
304 ----------
303 ----------
305 nb : notebook node
304 nb : notebook node
306 notebook that is being exported.
305 notebook that is being exported.
307 """
306 """
308
307
309 #Dict of 'resources' that can be filled by the preprocessors.
308 #Dict of 'resources' that can be filled by the transformers.
310 resources = {}
309 resources = {}
311
310
312 #Run each transformer on the notebook. Carry the output along
311 #Run each transformer on the notebook. Carry the output along
313 #to each transformer
312 #to each transformer
314 for transformer in self.preprocessors:
313 for transformer in self.transformers:
315 nb, resources = transformer(nb, resources)
314 nb, resources = transformer(nb, resources)
316 return nb, resources
315 return nb, resources
General Comments 0
You need to be logged in to leave comments. Login now