##// END OF EJS Templates
s/templat_paths/templat_path
Jonathan Frederic -
Show More
@@ -1,445 +1,445 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 import copy
23 import copy
24 import collections
24 import collections
25 import datetime
25 import datetime
26
26
27 # other libs/dependencies
27 # other libs/dependencies
28 from jinja2 import Environment, FileSystemLoader, ChoiceLoader
28 from jinja2 import Environment, FileSystemLoader, ChoiceLoader
29
29
30 # IPython imports
30 # IPython imports
31 from IPython.config.configurable import Configurable
31 from IPython.config.configurable import Configurable
32 from IPython.config import Config
32 from IPython.config import Config
33 from IPython.nbformat import current as nbformat
33 from IPython.nbformat import current as nbformat
34 from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict
34 from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict
35 from IPython.utils.importstring import import_item
35 from IPython.utils.importstring import import_item
36 from IPython.utils.text import indent
36 from IPython.utils.text import indent
37 from IPython.utils import py3compat
37 from IPython.utils import py3compat
38
38
39 from IPython.nbconvert import transformers as nbtransformers
39 from IPython.nbconvert import transformers as nbtransformers
40 from IPython.nbconvert import filters
40 from IPython.nbconvert import filters
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Globals and constants
43 # Globals and constants
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 #Jinja2 extensions to load.
46 #Jinja2 extensions to load.
47 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
47 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
48
48
49 default_filters = {
49 default_filters = {
50 'indent': indent,
50 'indent': indent,
51 'markdown': filters.markdown2html,
51 'markdown': filters.markdown2html,
52 'ansi2html': filters.ansi2html,
52 'ansi2html': filters.ansi2html,
53 'filter_data_type': filters.DataTypeFilter,
53 'filter_data_type': filters.DataTypeFilter,
54 'get_lines': filters.get_lines,
54 'get_lines': filters.get_lines,
55 'highlight': filters.highlight,
55 'highlight': filters.highlight,
56 'highlight2html': filters.highlight,
56 'highlight2html': filters.highlight,
57 'highlight2latex': filters.highlight2latex,
57 'highlight2latex': filters.highlight2latex,
58 'markdown2latex': filters.markdown2latex,
58 'markdown2latex': filters.markdown2latex,
59 'markdown2rst': filters.markdown2rst,
59 'markdown2rst': filters.markdown2rst,
60 'pycomment': filters.python_comment,
60 'pycomment': filters.python_comment,
61 'rm_ansi': filters.remove_ansi,
61 'rm_ansi': filters.remove_ansi,
62 'rm_dollars': filters.strip_dollars,
62 'rm_dollars': filters.strip_dollars,
63 'rm_fake': filters.rm_fake,
63 'rm_fake': filters.rm_fake,
64 'html_text' : filters.html_text,
64 'html_text' : filters.html_text,
65 'add_anchor': filters.add_anchor,
65 'add_anchor': filters.add_anchor,
66 'ansi2latex': filters.ansi2latex,
66 'ansi2latex': filters.ansi2latex,
67 'rm_math_space': filters.rm_math_space,
67 'rm_math_space': filters.rm_math_space,
68 'wrap': filters.wrap
68 'wrap': filters.wrap
69 }
69 }
70
70
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72 # Class
72 # Class
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74
74
75 class ResourcesDict(collections.defaultdict):
75 class ResourcesDict(collections.defaultdict):
76 def __missing__(self, key):
76 def __missing__(self, key):
77 return ''
77 return ''
78
78
79
79
80 class Exporter(Configurable):
80 class Exporter(Configurable):
81 """
81 """
82 Exports notebooks into other file formats. Uses Jinja 2 templating engine
82 Exports notebooks into other file formats. Uses Jinja 2 templating engine
83 to output new formats. Inherit from this class if you are creating a new
83 to output new formats. Inherit from this class if you are creating a new
84 template type along with new filters/transformers. If the filters/
84 template type along with new filters/transformers. If the filters/
85 transformers provided by default suffice, there is no need to inherit from
85 transformers provided by default suffice, there is no need to inherit from
86 this class. Instead, override the template_file and file_extension
86 this class. Instead, override the template_file and file_extension
87 traits via a config file.
87 traits via a config file.
88
88
89 {filters}
89 {filters}
90 """
90 """
91
91
92 # finish the docstring
92 # finish the docstring
93 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
93 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
94
94
95
95
96 template_file = Unicode(
96 template_file = Unicode(
97 '', config=True,
97 '', config=True,
98 help="Name of the template file to use")
98 help="Name of the template file to use")
99
99
100 file_extension = Unicode(
100 file_extension = Unicode(
101 'txt', config=True,
101 'txt', config=True,
102 help="Extension of the file that should be written to disk"
102 help="Extension of the file that should be written to disk"
103 )
103 )
104
104
105 template_paths = List(['.'], config=True)
105 template_path = List(['.'], config=True)
106
106
107 default_template_path = Unicode(
107 default_template_path = Unicode(
108 os.path.join("..", "templates"),
108 os.path.join("..", "templates"),
109 help="Path where the template files are located.")
109 help="Path where the template files are located.")
110
110
111 template_skeleton_path = Unicode(
111 template_skeleton_path = Unicode(
112 os.path.join("..", "templates", "skeleton"),
112 os.path.join("..", "templates", "skeleton"),
113 help="Path where the template skeleton files are located.")
113 help="Path where the template skeleton files are located.")
114
114
115 #Jinja block definitions
115 #Jinja block definitions
116 jinja_comment_block_start = Unicode("", config=True)
116 jinja_comment_block_start = Unicode("", config=True)
117 jinja_comment_block_end = Unicode("", config=True)
117 jinja_comment_block_end = Unicode("", config=True)
118 jinja_variable_block_start = Unicode("", config=True)
118 jinja_variable_block_start = Unicode("", config=True)
119 jinja_variable_block_end = Unicode("", config=True)
119 jinja_variable_block_end = Unicode("", config=True)
120 jinja_logic_block_start = Unicode("", config=True)
120 jinja_logic_block_start = Unicode("", config=True)
121 jinja_logic_block_end = Unicode("", config=True)
121 jinja_logic_block_end = Unicode("", config=True)
122
122
123 #Extension that the template files use.
123 #Extension that the template files use.
124 template_extension = Unicode(".tpl", config=True)
124 template_extension = Unicode(".tpl", config=True)
125
125
126 #Configurability, allows the user to easily add filters and transformers.
126 #Configurability, allows the user to easily add filters and transformers.
127 transformers = List(config=True,
127 transformers = List(config=True,
128 help="""List of transformers, by name or namespace, to enable.""")
128 help="""List of transformers, by name or namespace, to enable.""")
129
129
130 filters = Dict(config=True,
130 filters = Dict(config=True,
131 help="""Dictionary of filters, by name and namespace, to add to the Jinja
131 help="""Dictionary of filters, by name and namespace, to add to the Jinja
132 environment.""")
132 environment.""")
133
133
134 default_transformers = List([nbtransformers.coalesce_streams,
134 default_transformers = List([nbtransformers.coalesce_streams,
135 nbtransformers.SVG2PDFTransformer,
135 nbtransformers.SVG2PDFTransformer,
136 nbtransformers.ExtractOutputTransformer,
136 nbtransformers.ExtractOutputTransformer,
137 nbtransformers.CSSHTMLHeaderTransformer,
137 nbtransformers.CSSHTMLHeaderTransformer,
138 nbtransformers.RevealHelpTransformer,
138 nbtransformers.RevealHelpTransformer,
139 nbtransformers.LatexTransformer,
139 nbtransformers.LatexTransformer,
140 nbtransformers.SphinxTransformer],
140 nbtransformers.SphinxTransformer],
141 config=True,
141 config=True,
142 help="""List of transformers available by default, by name, namespace,
142 help="""List of transformers available by default, by name, namespace,
143 instance, or type.""")
143 instance, or type.""")
144
144
145
145
146 def __init__(self, config=None, extra_loaders=None, **kw):
146 def __init__(self, config=None, extra_loaders=None, **kw):
147 """
147 """
148 Public constructor
148 Public constructor
149
149
150 Parameters
150 Parameters
151 ----------
151 ----------
152 config : config
152 config : config
153 User configuration instance.
153 User configuration instance.
154 extra_loaders : list[of Jinja Loaders]
154 extra_loaders : list[of Jinja Loaders]
155 ordered list of Jinja loder to find templates. Will be tried in order
155 ordered list of Jinja loder to find templates. Will be tried in order
156 before the default FileSysteme ones.
156 before the default FileSysteme ones.
157 """
157 """
158
158
159 #Call the base class constructor
159 #Call the base class constructor
160 c = self.default_config
160 c = self.default_config
161 if config:
161 if config:
162 c.merge(config)
162 c.merge(config)
163
163
164 super(Exporter, self).__init__(config=c, **kw)
164 super(Exporter, self).__init__(config=c, **kw)
165
165
166 #Init
166 #Init
167 self._init_environment(extra_loaders=extra_loaders)
167 self._init_environment(extra_loaders=extra_loaders)
168 self._init_transformers()
168 self._init_transformers()
169 self._init_filters()
169 self._init_filters()
170
170
171
171
172 @property
172 @property
173 def default_config(self):
173 def default_config(self):
174 return Config()
174 return Config()
175
175
176
176
177 def from_notebook_node(self, nb, resources=None, **kw):
177 def from_notebook_node(self, nb, resources=None, **kw):
178 """
178 """
179 Convert a notebook from a notebook node instance.
179 Convert a notebook from a notebook node instance.
180
180
181 Parameters
181 Parameters
182 ----------
182 ----------
183 nb : Notebook node
183 nb : Notebook node
184 resources : dict (**kw)
184 resources : dict (**kw)
185 of additional resources that can be accessed read/write by
185 of additional resources that can be accessed read/write by
186 transformers and filters.
186 transformers and filters.
187 """
187 """
188 nb_copy = copy.deepcopy(nb)
188 nb_copy = copy.deepcopy(nb)
189 resources = self._init_resources(resources)
189 resources = self._init_resources(resources)
190
190
191 #Preprocess
191 #Preprocess
192 nb_copy, resources = self._transform(nb_copy, resources)
192 nb_copy, resources = self._transform(nb_copy, resources)
193
193
194 #Convert
194 #Convert
195 self.template = self.environment.get_template(self.template_file + self.template_extension)
195 self.template = self.environment.get_template(self.template_file + self.template_extension)
196 output = self.template.render(nb=nb_copy, resources=resources)
196 output = self.template.render(nb=nb_copy, resources=resources)
197 return output, resources
197 return output, resources
198
198
199
199
200 def from_filename(self, filename, resources=None, **kw):
200 def from_filename(self, filename, resources=None, **kw):
201 """
201 """
202 Convert a notebook from a notebook file.
202 Convert a notebook from a notebook file.
203
203
204 Parameters
204 Parameters
205 ----------
205 ----------
206 filename : str
206 filename : str
207 Full filename of the notebook file to open and convert.
207 Full filename of the notebook file to open and convert.
208 """
208 """
209
209
210 #Pull the metadata from the filesystem.
210 #Pull the metadata from the filesystem.
211 if resources is None:
211 if resources is None:
212 resources = ResourcesDict()
212 resources = ResourcesDict()
213 if not 'metadata' in resources or resources['metadata'] == '':
213 if not 'metadata' in resources or resources['metadata'] == '':
214 resources['metadata'] = ResourcesDict()
214 resources['metadata'] = ResourcesDict()
215 basename = os.path.basename(filename)
215 basename = os.path.basename(filename)
216 notebook_name = basename[:basename.rfind('.')]
216 notebook_name = basename[:basename.rfind('.')]
217 resources['metadata']['name'] = notebook_name
217 resources['metadata']['name'] = notebook_name
218
218
219 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
219 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
220 resources['metadata']['modified_date'] = modified_date.strftime("%B %-d, %Y")
220 resources['metadata']['modified_date'] = modified_date.strftime("%B %-d, %Y")
221
221
222 with io.open(filename) as f:
222 with io.open(filename) as f:
223 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
223 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
224
224
225
225
226 def from_file(self, file_stream, resources=None, **kw):
226 def from_file(self, file_stream, resources=None, **kw):
227 """
227 """
228 Convert a notebook from a notebook file.
228 Convert a notebook from a notebook file.
229
229
230 Parameters
230 Parameters
231 ----------
231 ----------
232 file_stream : file-like object
232 file_stream : file-like object
233 Notebook file-like object to convert.
233 Notebook file-like object to convert.
234 """
234 """
235 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
235 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
236
236
237
237
238 def register_transformer(self, transformer, enabled=False):
238 def register_transformer(self, transformer, enabled=False):
239 """
239 """
240 Register a transformer.
240 Register a transformer.
241 Transformers are classes that act upon the notebook before it is
241 Transformers are classes that act upon the notebook before it is
242 passed into the Jinja templating engine. Transformers are also
242 passed into the Jinja templating engine. Transformers are also
243 capable of passing additional information to the Jinja
243 capable of passing additional information to the Jinja
244 templating engine.
244 templating engine.
245
245
246 Parameters
246 Parameters
247 ----------
247 ----------
248 transformer : transformer
248 transformer : transformer
249 """
249 """
250 if transformer is None:
250 if transformer is None:
251 raise TypeError('transformer')
251 raise TypeError('transformer')
252 isclass = isinstance(transformer, type)
252 isclass = isinstance(transformer, type)
253 constructed = not isclass
253 constructed = not isclass
254
254
255 #Handle transformer's registration based on it's type
255 #Handle transformer's registration based on it's type
256 if constructed and isinstance(transformer, py3compat.string_types):
256 if constructed and isinstance(transformer, py3compat.string_types):
257 #Transformer is a string, import the namespace and recursively call
257 #Transformer is a string, import the namespace and recursively call
258 #this register_transformer method
258 #this register_transformer method
259 transformer_cls = import_item(transformer)
259 transformer_cls = import_item(transformer)
260 return self.register_transformer(transformer_cls, enabled)
260 return self.register_transformer(transformer_cls, enabled)
261
261
262 if constructed and hasattr(transformer, '__call__'):
262 if constructed and hasattr(transformer, '__call__'):
263 #Transformer is a function, no need to construct it.
263 #Transformer is a function, no need to construct it.
264 #Register and return the transformer.
264 #Register and return the transformer.
265 if enabled:
265 if enabled:
266 transformer.enabled = True
266 transformer.enabled = True
267 self._transformers.append(transformer)
267 self._transformers.append(transformer)
268 return transformer
268 return transformer
269
269
270 elif isclass and isinstance(transformer, MetaHasTraits):
270 elif isclass and isinstance(transformer, MetaHasTraits):
271 #Transformer is configurable. Make sure to pass in new default for
271 #Transformer is configurable. Make sure to pass in new default for
272 #the enabled flag if one was specified.
272 #the enabled flag if one was specified.
273 self.register_transformer(transformer(parent=self), enabled)
273 self.register_transformer(transformer(parent=self), enabled)
274
274
275 elif isclass:
275 elif isclass:
276 #Transformer is not configurable, construct it
276 #Transformer is not configurable, construct it
277 self.register_transformer(transformer(), enabled)
277 self.register_transformer(transformer(), enabled)
278
278
279 else:
279 else:
280 #Transformer is an instance of something without a __call__
280 #Transformer is an instance of something without a __call__
281 #attribute.
281 #attribute.
282 raise TypeError('transformer')
282 raise TypeError('transformer')
283
283
284
284
285 def register_filter(self, name, jinja_filter):
285 def register_filter(self, name, jinja_filter):
286 """
286 """
287 Register a filter.
287 Register a filter.
288 A filter is a function that accepts and acts on one string.
288 A filter is a function that accepts and acts on one string.
289 The filters are accesible within the Jinja templating engine.
289 The filters are accesible within the Jinja templating engine.
290
290
291 Parameters
291 Parameters
292 ----------
292 ----------
293 name : str
293 name : str
294 name to give the filter in the Jinja engine
294 name to give the filter in the Jinja engine
295 filter : filter
295 filter : filter
296 """
296 """
297 if jinja_filter is None:
297 if jinja_filter is None:
298 raise TypeError('filter')
298 raise TypeError('filter')
299 isclass = isinstance(jinja_filter, type)
299 isclass = isinstance(jinja_filter, type)
300 constructed = not isclass
300 constructed = not isclass
301
301
302 #Handle filter's registration based on it's type
302 #Handle filter's registration based on it's type
303 if constructed and isinstance(jinja_filter, py3compat.string_types):
303 if constructed and isinstance(jinja_filter, py3compat.string_types):
304 #filter is a string, import the namespace and recursively call
304 #filter is a string, import the namespace and recursively call
305 #this register_filter method
305 #this register_filter method
306 filter_cls = import_item(jinja_filter)
306 filter_cls = import_item(jinja_filter)
307 return self.register_filter(name, filter_cls)
307 return self.register_filter(name, filter_cls)
308
308
309 if constructed and hasattr(jinja_filter, '__call__'):
309 if constructed and hasattr(jinja_filter, '__call__'):
310 #filter is a function, no need to construct it.
310 #filter is a function, no need to construct it.
311 self.environment.filters[name] = jinja_filter
311 self.environment.filters[name] = jinja_filter
312 return jinja_filter
312 return jinja_filter
313
313
314 elif isclass and isinstance(jinja_filter, MetaHasTraits):
314 elif isclass and isinstance(jinja_filter, MetaHasTraits):
315 #filter is configurable. Make sure to pass in new default for
315 #filter is configurable. Make sure to pass in new default for
316 #the enabled flag if one was specified.
316 #the enabled flag if one was specified.
317 filter_instance = jinja_filter(parent=self)
317 filter_instance = jinja_filter(parent=self)
318 self.register_filter(name, filter_instance )
318 self.register_filter(name, filter_instance )
319
319
320 elif isclass:
320 elif isclass:
321 #filter is not configurable, construct it
321 #filter is not configurable, construct it
322 filter_instance = jinja_filter()
322 filter_instance = jinja_filter()
323 self.register_filter(name, filter_instance)
323 self.register_filter(name, filter_instance)
324
324
325 else:
325 else:
326 #filter is an instance of something without a __call__
326 #filter is an instance of something without a __call__
327 #attribute.
327 #attribute.
328 raise TypeError('filter')
328 raise TypeError('filter')
329
329
330
330
331 def _init_environment(self, extra_loaders=None):
331 def _init_environment(self, extra_loaders=None):
332 """
332 """
333 Create the Jinja templating environment.
333 Create the Jinja templating environment.
334 """
334 """
335 here = os.path.dirname(os.path.realpath(__file__))
335 here = os.path.dirname(os.path.realpath(__file__))
336 loaders = []
336 loaders = []
337 if extra_loaders:
337 if extra_loaders:
338 loaders.extend(extra_loaders)
338 loaders.extend(extra_loaders)
339
339
340 paths = self.template_paths
340 paths = self.template_path
341 paths.extend([os.path.join(here, self.default_template_path),
341 paths.extend([os.path.join(here, self.default_template_path),
342 os.path.join(here, self.template_skeleton_path)])
342 os.path.join(here, self.template_skeleton_path)])
343 loaders.append(FileSystemLoader(paths))
343 loaders.append(FileSystemLoader(paths))
344
344
345 self.environment = Environment(
345 self.environment = Environment(
346 loader= ChoiceLoader(loaders),
346 loader= ChoiceLoader(loaders),
347 extensions=JINJA_EXTENSIONS
347 extensions=JINJA_EXTENSIONS
348 )
348 )
349
349
350 #Set special Jinja2 syntax that will not conflict with latex.
350 #Set special Jinja2 syntax that will not conflict with latex.
351 if self.jinja_logic_block_start:
351 if self.jinja_logic_block_start:
352 self.environment.block_start_string = self.jinja_logic_block_start
352 self.environment.block_start_string = self.jinja_logic_block_start
353 if self.jinja_logic_block_end:
353 if self.jinja_logic_block_end:
354 self.environment.block_end_string = self.jinja_logic_block_end
354 self.environment.block_end_string = self.jinja_logic_block_end
355 if self.jinja_variable_block_start:
355 if self.jinja_variable_block_start:
356 self.environment.variable_start_string = self.jinja_variable_block_start
356 self.environment.variable_start_string = self.jinja_variable_block_start
357 if self.jinja_variable_block_end:
357 if self.jinja_variable_block_end:
358 self.environment.variable_end_string = self.jinja_variable_block_end
358 self.environment.variable_end_string = self.jinja_variable_block_end
359 if self.jinja_comment_block_start:
359 if self.jinja_comment_block_start:
360 self.environment.comment_start_string = self.jinja_comment_block_start
360 self.environment.comment_start_string = self.jinja_comment_block_start
361 if self.jinja_comment_block_end:
361 if self.jinja_comment_block_end:
362 self.environment.comment_end_string = self.jinja_comment_block_end
362 self.environment.comment_end_string = self.jinja_comment_block_end
363
363
364
364
365 def _init_transformers(self):
365 def _init_transformers(self):
366 """
366 """
367 Register all of the transformers needed for this exporter, disabled
367 Register all of the transformers needed for this exporter, disabled
368 unless specified explicitly.
368 unless specified explicitly.
369 """
369 """
370 self._transformers = []
370 self._transformers = []
371
371
372 #Load default transformers (not necessarly enabled by default).
372 #Load default transformers (not necessarly enabled by default).
373 if self.default_transformers:
373 if self.default_transformers:
374 for transformer in self.default_transformers:
374 for transformer in self.default_transformers:
375 self.register_transformer(transformer)
375 self.register_transformer(transformer)
376
376
377 #Load user transformers. Enable by default.
377 #Load user transformers. Enable by default.
378 if self.transformers:
378 if self.transformers:
379 for transformer in self.transformers:
379 for transformer in self.transformers:
380 self.register_transformer(transformer, enabled=True)
380 self.register_transformer(transformer, enabled=True)
381
381
382
382
383 def _init_filters(self):
383 def _init_filters(self):
384 """
384 """
385 Register all of the filters required for the exporter.
385 Register all of the filters required for the exporter.
386 """
386 """
387
387
388 #Add default filters to the Jinja2 environment
388 #Add default filters to the Jinja2 environment
389 for key, value in default_filters.items():
389 for key, value in default_filters.items():
390 self.register_filter(key, value)
390 self.register_filter(key, value)
391
391
392 #Load user filters. Overwrite existing filters if need be.
392 #Load user filters. Overwrite existing filters if need be.
393 if self.filters:
393 if self.filters:
394 for key, user_filter in self.filters.items():
394 for key, user_filter in self.filters.items():
395 self.register_filter(key, user_filter)
395 self.register_filter(key, user_filter)
396
396
397
397
398 def _init_resources(self, resources):
398 def _init_resources(self, resources):
399
399
400 #Make sure the resources dict is of ResourcesDict type.
400 #Make sure the resources dict is of ResourcesDict type.
401 if resources is None:
401 if resources is None:
402 resources = ResourcesDict()
402 resources = ResourcesDict()
403 if not isinstance(resources, ResourcesDict):
403 if not isinstance(resources, ResourcesDict):
404 new_resources = ResourcesDict()
404 new_resources = ResourcesDict()
405 new_resources.update(resources)
405 new_resources.update(resources)
406 resources = new_resources
406 resources = new_resources
407
407
408 #Make sure the metadata extension exists in resources
408 #Make sure the metadata extension exists in resources
409 if 'metadata' in resources:
409 if 'metadata' in resources:
410 if not isinstance(resources['metadata'], ResourcesDict):
410 if not isinstance(resources['metadata'], ResourcesDict):
411 resources['metadata'] = ResourcesDict(resources['metadata'])
411 resources['metadata'] = ResourcesDict(resources['metadata'])
412 else:
412 else:
413 resources['metadata'] = ResourcesDict()
413 resources['metadata'] = ResourcesDict()
414 if not resources['metadata']['name']:
414 if not resources['metadata']['name']:
415 resources['metadata']['name'] = 'Notebook'
415 resources['metadata']['name'] = 'Notebook'
416
416
417 #Set the output extension
417 #Set the output extension
418 resources['output_extension'] = self.file_extension
418 resources['output_extension'] = self.file_extension
419 return resources
419 return resources
420
420
421
421
422 def _transform(self, nb, resources):
422 def _transform(self, nb, resources):
423 """
423 """
424 Preprocess the notebook before passing it into the Jinja engine.
424 Preprocess the notebook before passing it into the Jinja engine.
425 To preprocess the notebook is to apply all of the
425 To preprocess the notebook is to apply all of the
426
426
427 Parameters
427 Parameters
428 ----------
428 ----------
429 nb : notebook node
429 nb : notebook node
430 notebook that is being exported.
430 notebook that is being exported.
431 resources : a dict of additional resources that
431 resources : a dict of additional resources that
432 can be accessed read/write by transformers
432 can be accessed read/write by transformers
433 and filters.
433 and filters.
434 """
434 """
435
435
436 # Do a copy.deepcopy first,
436 # Do a copy.deepcopy first,
437 # we are never safe enough with what the transformers could do.
437 # we are never safe enough with what the transformers could do.
438 nbc = copy.deepcopy(nb)
438 nbc = copy.deepcopy(nb)
439 resc = copy.deepcopy(resources)
439 resc = copy.deepcopy(resources)
440
440
441 #Run each transformer on the notebook. Carry the output along
441 #Run each transformer on the notebook. Carry the output along
442 #to each transformer
442 #to each transformer
443 for transformer in self._transformers:
443 for transformer in self._transformers:
444 nbc, resc = transformer(nbc, resc)
444 nbc, resc = transformer(nbc, resc)
445 return nbc, resc
445 return nbc, resc
General Comments 0
You need to be logged in to leave comments. Login now