##// END OF EJS Templates
allow to pass a resource dict with notebook...
Matthias BUSSONNIER -
Show More
@@ -1,317 +1,322 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 transformers = None
96 transformers = None
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 transformers :
131 if transformers :
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, resources=None):
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 resources : a dict of additional resources that
152 can be accessed read/write by transformers
153 and filters.
151 """
154 """
152
155 if resources is None:
153 nb, resources = self._preprocess(nb)
156 resources = {}
157 nb, resources = self._preprocess(nb, resources)
154
158
155 #Load the template file.
159 #Load the template file.
156 self.template = self.environment.get_template(self.template_file+self.template_extension)
160 self.template = self.environment.get_template(self.template_file+self.template_extension)
157
161
158 return self.template.render(nb=nb, resources=resources), resources
162 return self.template.render(nb=nb, resources=resources), resources
159
163
160
164
161 def from_filename(self, filename):
165 def from_filename(self, filename):
162 """
166 """
163 Convert a notebook from a notebook file.
167 Convert a notebook from a notebook file.
164
168
165 Parameters
169 Parameters
166 ----------
170 ----------
167 filename : str
171 filename : str
168 Full filename of the notebook file to open and convert.
172 Full filename of the notebook file to open and convert.
169 """
173 """
170
174
171 with io.open(filename) as f:
175 with io.open(filename) as f:
172 return self.from_notebook_node(nbformat.read(f, 'json'))
176 return self.from_notebook_node(nbformat.read(f, 'json'))
173
177
174
178
175 def from_file(self, file_stream):
179 def from_file(self, file_stream):
176 """
180 """
177 Convert a notebook from a notebook file.
181 Convert a notebook from a notebook file.
178
182
179 Parameters
183 Parameters
180 ----------
184 ----------
181 file_stream : file-like object
185 file_stream : file-like object
182 Notebook file-like object to convert.
186 Notebook file-like object to convert.
183 """
187 """
184 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
188 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
185
189
186
190
187 def register_transformer(self, transformer):
191 def register_transformer(self, transformer):
188 """
192 """
189 Register a transformer.
193 Register a transformer.
190 Transformers are classes that act upon the notebook before it is
194 Transformers are classes that act upon the notebook before it is
191 passed into the Jinja templating engine. Transformers are also
195 passed into the Jinja templating engine. Transformers are also
192 capable of passing additional information to the Jinja
196 capable of passing additional information to the Jinja
193 templating engine.
197 templating engine.
194
198
195 Parameters
199 Parameters
196 ----------
200 ----------
197 transformer : transformer
201 transformer : transformer
198 """
202 """
199 if self.transformers is None:
203 if self.transformers is None:
200 self.transformers = []
204 self.transformers = []
201
205
202 if inspect.isfunction(transformer):
206 if inspect.isfunction(transformer):
203 self.transformers.append(transformer)
207 self.transformers.append(transformer)
204 return transformer
208 return transformer
205 elif isinstance(transformer, MetaHasTraits):
209 elif isinstance(transformer, MetaHasTraits):
206 transformer_instance = transformer(config=self.config)
210 transformer_instance = transformer(config=self.config)
207 self.transformers.append(transformer_instance)
211 self.transformers.append(transformer_instance)
208 return transformer_instance
212 return transformer_instance
209 else:
213 else:
210 transformer_instance = transformer()
214 transformer_instance = transformer()
211 self.transformers.append(transformer_instance)
215 self.transformers.append(transformer_instance)
212 return transformer_instance
216 return transformer_instance
213
217
214
218
215 def register_filter(self, name, filter):
219 def register_filter(self, name, filter):
216 """
220 """
217 Register a filter.
221 Register a filter.
218 A filter is a function that accepts and acts on one string.
222 A filter is a function that accepts and acts on one string.
219 The filters are accesible within the Jinja templating engine.
223 The filters are accesible within the Jinja templating engine.
220
224
221 Parameters
225 Parameters
222 ----------
226 ----------
223 name : str
227 name : str
224 name to give the filter in the Jinja engine
228 name to give the filter in the Jinja engine
225 filter : filter
229 filter : filter
226 """
230 """
227 if inspect.isfunction(filter):
231 if inspect.isfunction(filter):
228 self.environment.filters[name] = filter
232 self.environment.filters[name] = filter
229 elif isinstance(filter, MetaHasTraits):
233 elif isinstance(filter, MetaHasTraits):
230 self.environment.filters[name] = filter(config=self.config)
234 self.environment.filters[name] = filter(config=self.config)
231 else:
235 else:
232 self.environment.filters[name] = filter()
236 self.environment.filters[name] = filter()
233 return self.environment.filters[name]
237 return self.environment.filters[name]
234
238
235
239
236 def _register_transformers(self):
240 def _register_transformers(self):
237 """
241 """
238 Register all of the transformers needed for this exporter.
242 Register all of the transformers needed for this exporter.
239 """
243 """
240
244
241 self.register_transformer(nbconvert.transformers.coalescestreams.coalesce_streams)
245 self.register_transformer(nbconvert.transformers.coalescestreams.coalesce_streams)
242
246
243 #Remember the figure extraction transformer so it can be enabled and
247 #Remember the figure extraction transformer so it can be enabled and
244 #disabled easily later.
248 #disabled easily later.
245 self.extract_figure_transformer = self.register_transformer(nbconvert.transformers.extractfigure.ExtractFigureTransformer)
249 self.extract_figure_transformer = self.register_transformer(nbconvert.transformers.extractfigure.ExtractFigureTransformer)
246
250
247
251
248 def _register_filters(self):
252 def _register_filters(self):
249 """
253 """
250 Register all of the filters required for the exporter.
254 Register all of the filters required for the exporter.
251 """
255 """
252
256
253 self.register_filter('indent', indent)
257 self.register_filter('indent', indent)
254 self.register_filter('markdown', markdown)
258 self.register_filter('markdown', markdown)
255 self.register_filter('ansi2html', nbconvert.filters.ansi.ansi2html)
259 self.register_filter('ansi2html', nbconvert.filters.ansi.ansi2html)
256 self.register_filter('filter_data_type', nbconvert.filters.datatypefilter.DataTypeFilter)
260 self.register_filter('filter_data_type', nbconvert.filters.datatypefilter.DataTypeFilter)
257 self.register_filter('get_lines', nbconvert.filters.strings.get_lines)
261 self.register_filter('get_lines', nbconvert.filters.strings.get_lines)
258 self.register_filter('highlight', nbconvert.filters.highlight.highlight)
262 self.register_filter('highlight', nbconvert.filters.highlight.highlight)
259 self.register_filter('highlight2html', nbconvert.filters.highlight.highlight)
263 self.register_filter('highlight2html', nbconvert.filters.highlight.highlight)
260 self.register_filter('highlight2latex', nbconvert.filters.highlight.highlight2latex)
264 self.register_filter('highlight2latex', nbconvert.filters.highlight.highlight2latex)
261 self.register_filter('markdown2latex', nbconvert.filters.markdown.markdown2latex)
265 self.register_filter('markdown2latex', nbconvert.filters.markdown.markdown2latex)
262 self.register_filter('markdown2rst', nbconvert.filters.markdown.markdown2rst)
266 self.register_filter('markdown2rst', nbconvert.filters.markdown.markdown2rst)
263 self.register_filter('pycomment', nbconvert.filters.strings.python_comment)
267 self.register_filter('pycomment', nbconvert.filters.strings.python_comment)
264 self.register_filter('rm_ansi', nbconvert.filters.ansi.remove_ansi)
268 self.register_filter('rm_ansi', nbconvert.filters.ansi.remove_ansi)
265 self.register_filter('rm_dollars', nbconvert.filters.strings.strip_dollars)
269 self.register_filter('rm_dollars', nbconvert.filters.strings.strip_dollars)
266 self.register_filter('rm_fake', nbconvert.filters.strings.rm_fake)
270 self.register_filter('rm_fake', nbconvert.filters.strings.rm_fake)
267 self.register_filter('rm_math_space', nbconvert.filters.latex.rm_math_space)
271 self.register_filter('rm_math_space', nbconvert.filters.latex.rm_math_space)
268 self.register_filter('wrap', nbconvert.filters.strings.wrap)
272 self.register_filter('wrap', nbconvert.filters.strings.wrap)
269
273
270
274
271 def _init_environment(self):
275 def _init_environment(self):
272 """
276 """
273 Create the Jinja templating environment.
277 Create the Jinja templating environment.
274 """
278 """
275
279
276 self.environment = Environment(
280 self.environment = Environment(
277 loader=FileSystemLoader([
281 loader=FileSystemLoader([
278 os.path.dirname(os.path.realpath(__file__)) + self.template_path,
282 os.path.dirname(os.path.realpath(__file__)) + self.template_path,
279 os.path.dirname(os.path.realpath(__file__)) + self.template_skeleton_path,
283 os.path.dirname(os.path.realpath(__file__)) + self.template_skeleton_path,
280 ]),
284 ]),
281 extensions=JINJA_EXTENSIONS
285 extensions=JINJA_EXTENSIONS
282 )
286 )
283
287
284 #Set special Jinja2 syntax that will not conflict with latex.
288 #Set special Jinja2 syntax that will not conflict with latex.
285 if self.jinja_logic_block_start:
289 if self.jinja_logic_block_start:
286 self.environment.block_start_string = self.jinja_logic_block_start
290 self.environment.block_start_string = self.jinja_logic_block_start
287 if self.jinja_logic_block_end:
291 if self.jinja_logic_block_end:
288 self.environment.block_end_string = self.jinja_logic_block_end
292 self.environment.block_end_string = self.jinja_logic_block_end
289 if self.jinja_variable_block_start:
293 if self.jinja_variable_block_start:
290 self.environment.variable_start_string = self.jinja_variable_block_start
294 self.environment.variable_start_string = self.jinja_variable_block_start
291 if self.jinja_variable_block_end:
295 if self.jinja_variable_block_end:
292 self.environment.variable_end_string = self.jinja_variable_block_end
296 self.environment.variable_end_string = self.jinja_variable_block_end
293 if self.jinja_comment_block_start:
297 if self.jinja_comment_block_start:
294 self.environment.comment_start_string = self.jinja_comment_block_start
298 self.environment.comment_start_string = self.jinja_comment_block_start
295 if self.jinja_comment_block_end:
299 if self.jinja_comment_block_end:
296 self.environment.comment_end_string = self.jinja_comment_block_end
300 self.environment.comment_end_string = self.jinja_comment_block_end
297
301
298
302
299 def _preprocess(self, nb):
303 def _preprocess(self, nb, resources):
300 """
304 """
301 Preprocess the notebook before passing it into the Jinja engine.
305 Preprocess the notebook before passing it into the Jinja engine.
302 To preprocess the notebook is to apply all of the
306 To preprocess the notebook is to apply all of the
303
307
304 Parameters
308 Parameters
305 ----------
309 ----------
306 nb : notebook node
310 nb : notebook node
307 notebook that is being exported.
311 notebook that is being exported.
312 resources : a dict of additional resources that
313 can be accessed read/write by transformers
314 and filters.
308 """
315 """
309
316
310 #Dict of 'resources' that can be filled by the transformers.
311 resources = {}
312
317
313 #Run each transformer on the notebook. Carry the output along
318 #Run each transformer on the notebook. Carry the output along
314 #to each transformer
319 #to each transformer
315 for transformer in self.transformers:
320 for transformer in self.transformers:
316 nb, resources = transformer(nb, resources)
321 nb, resources = transformer(nb, resources)
317 return nb, resources
322 return nb, resources
General Comments 0
You need to be logged in to leave comments. Login now