##// END OF EJS Templates
Rename ExtractFigureTransformer to ExtractOutputTransformer
Jonathan Frederic -
Show More
@@ -1,443 +1,443 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_path = Unicode(
105 template_path = Unicode(
106 os.path.join("..", "templates"), config=True,
106 os.path.join("..", "templates"), config=True,
107 help="Path where the template files are located.")
107 help="Path where the template files are located.")
108
108
109 template_skeleton_path = Unicode(
109 template_skeleton_path = Unicode(
110 os.path.join("..", "templates", "skeleton"), config=True,
110 os.path.join("..", "templates", "skeleton"), config=True,
111 help="Path where the template skeleton files are located.")
111 help="Path where the template skeleton files are located.")
112
112
113 #Jinja block definitions
113 #Jinja block definitions
114 jinja_comment_block_start = Unicode("", config=True)
114 jinja_comment_block_start = Unicode("", config=True)
115 jinja_comment_block_end = Unicode("", config=True)
115 jinja_comment_block_end = Unicode("", config=True)
116 jinja_variable_block_start = Unicode("", config=True)
116 jinja_variable_block_start = Unicode("", config=True)
117 jinja_variable_block_end = Unicode("", config=True)
117 jinja_variable_block_end = Unicode("", config=True)
118 jinja_logic_block_start = Unicode("", config=True)
118 jinja_logic_block_start = Unicode("", config=True)
119 jinja_logic_block_end = Unicode("", config=True)
119 jinja_logic_block_end = Unicode("", config=True)
120
120
121 #Extension that the template files use.
121 #Extension that the template files use.
122 template_extension = Unicode(".tpl", config=True)
122 template_extension = Unicode(".tpl", config=True)
123
123
124 #Configurability, allows the user to easily add filters and transformers.
124 #Configurability, allows the user to easily add filters and transformers.
125 transformers = List(config=True,
125 transformers = List(config=True,
126 help="""List of transformers, by name or namespace, to enable.""")
126 help="""List of transformers, by name or namespace, to enable.""")
127
127
128 filters = Dict(config=True,
128 filters = Dict(config=True,
129 help="""Dictionary of filters, by name and namespace, to add to the Jinja
129 help="""Dictionary of filters, by name and namespace, to add to the Jinja
130 environment.""")
130 environment.""")
131
131
132 default_transformers = List([nbtransformers.coalesce_streams,
132 default_transformers = List([nbtransformers.coalesce_streams,
133 nbtransformers.SVG2PDFTransformer,
133 nbtransformers.SVG2PDFTransformer,
134 nbtransformers.ExtractFigureTransformer,
134 nbtransformers.ExtractOutputTransformer,
135 nbtransformers.CSSHTMLHeaderTransformer,
135 nbtransformers.CSSHTMLHeaderTransformer,
136 nbtransformers.RevealHelpTransformer,
136 nbtransformers.RevealHelpTransformer,
137 nbtransformers.LatexTransformer,
137 nbtransformers.LatexTransformer,
138 nbtransformers.SphinxTransformer],
138 nbtransformers.SphinxTransformer],
139 config=True,
139 config=True,
140 help="""List of transformers available by default, by name, namespace,
140 help="""List of transformers available by default, by name, namespace,
141 instance, or type.""")
141 instance, or type.""")
142
142
143
143
144 def __init__(self, config=None, extra_loaders=None, **kw):
144 def __init__(self, config=None, extra_loaders=None, **kw):
145 """
145 """
146 Public constructor
146 Public constructor
147
147
148 Parameters
148 Parameters
149 ----------
149 ----------
150 config : config
150 config : config
151 User configuration instance.
151 User configuration instance.
152 extra_loaders : list[of Jinja Loaders]
152 extra_loaders : list[of Jinja Loaders]
153 ordered list of Jinja loder to find templates. Will be tried in order
153 ordered list of Jinja loder to find templates. Will be tried in order
154 before the default FileSysteme ones.
154 before the default FileSysteme ones.
155 """
155 """
156
156
157 #Call the base class constructor
157 #Call the base class constructor
158 c = self.default_config
158 c = self.default_config
159 if config:
159 if config:
160 c.merge(config)
160 c.merge(config)
161
161
162 super(Exporter, self).__init__(config=c, **kw)
162 super(Exporter, self).__init__(config=c, **kw)
163
163
164 #Init
164 #Init
165 self._init_environment(extra_loaders=extra_loaders)
165 self._init_environment(extra_loaders=extra_loaders)
166 self._init_transformers()
166 self._init_transformers()
167 self._init_filters()
167 self._init_filters()
168
168
169
169
170 @property
170 @property
171 def default_config(self):
171 def default_config(self):
172 return Config()
172 return Config()
173
173
174
174
175 def from_notebook_node(self, nb, resources=None, **kw):
175 def from_notebook_node(self, nb, resources=None, **kw):
176 """
176 """
177 Convert a notebook from a notebook node instance.
177 Convert a notebook from a notebook node instance.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181 nb : Notebook node
181 nb : Notebook node
182 resources : dict (**kw)
182 resources : dict (**kw)
183 of additional resources that can be accessed read/write by
183 of additional resources that can be accessed read/write by
184 transformers and filters.
184 transformers and filters.
185 """
185 """
186 nb_copy = copy.deepcopy(nb)
186 nb_copy = copy.deepcopy(nb)
187 resources = self._init_resources(resources)
187 resources = self._init_resources(resources)
188
188
189 #Preprocess
189 #Preprocess
190 nb_copy, resources = self._transform(nb_copy, resources)
190 nb_copy, resources = self._transform(nb_copy, resources)
191
191
192 #Convert
192 #Convert
193 self.template = self.environment.get_template(self.template_file + self.template_extension)
193 self.template = self.environment.get_template(self.template_file + self.template_extension)
194 output = self.template.render(nb=nb_copy, resources=resources)
194 output = self.template.render(nb=nb_copy, resources=resources)
195 return output, resources
195 return output, resources
196
196
197
197
198 def from_filename(self, filename, resources=None, **kw):
198 def from_filename(self, filename, resources=None, **kw):
199 """
199 """
200 Convert a notebook from a notebook file.
200 Convert a notebook from a notebook file.
201
201
202 Parameters
202 Parameters
203 ----------
203 ----------
204 filename : str
204 filename : str
205 Full filename of the notebook file to open and convert.
205 Full filename of the notebook file to open and convert.
206 """
206 """
207
207
208 #Pull the metadata from the filesystem.
208 #Pull the metadata from the filesystem.
209 if resources is None:
209 if resources is None:
210 resources = ResourcesDict()
210 resources = ResourcesDict()
211 if not 'metadata' in resources or resources['metadata'] == '':
211 if not 'metadata' in resources or resources['metadata'] == '':
212 resources['metadata'] = ResourcesDict()
212 resources['metadata'] = ResourcesDict()
213 basename = os.path.basename(filename)
213 basename = os.path.basename(filename)
214 notebook_name = basename[:basename.rfind('.')]
214 notebook_name = basename[:basename.rfind('.')]
215 resources['metadata']['name'] = notebook_name
215 resources['metadata']['name'] = notebook_name
216
216
217 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
217 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
218 resources['metadata']['modified_date'] = modified_date.strftime("%B %-d, %Y")
218 resources['metadata']['modified_date'] = modified_date.strftime("%B %-d, %Y")
219
219
220 with io.open(filename) as f:
220 with io.open(filename) as f:
221 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
221 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
222
222
223
223
224 def from_file(self, file_stream, resources=None, **kw):
224 def from_file(self, file_stream, resources=None, **kw):
225 """
225 """
226 Convert a notebook from a notebook file.
226 Convert a notebook from a notebook file.
227
227
228 Parameters
228 Parameters
229 ----------
229 ----------
230 file_stream : file-like object
230 file_stream : file-like object
231 Notebook file-like object to convert.
231 Notebook file-like object to convert.
232 """
232 """
233 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
233 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
234
234
235
235
236 def register_transformer(self, transformer, enabled=False):
236 def register_transformer(self, transformer, enabled=False):
237 """
237 """
238 Register a transformer.
238 Register a transformer.
239 Transformers are classes that act upon the notebook before it is
239 Transformers are classes that act upon the notebook before it is
240 passed into the Jinja templating engine. Transformers are also
240 passed into the Jinja templating engine. Transformers are also
241 capable of passing additional information to the Jinja
241 capable of passing additional information to the Jinja
242 templating engine.
242 templating engine.
243
243
244 Parameters
244 Parameters
245 ----------
245 ----------
246 transformer : transformer
246 transformer : transformer
247 """
247 """
248 if transformer is None:
248 if transformer is None:
249 raise TypeError('transformer')
249 raise TypeError('transformer')
250 isclass = isinstance(transformer, type)
250 isclass = isinstance(transformer, type)
251 constructed = not isclass
251 constructed = not isclass
252
252
253 #Handle transformer's registration based on it's type
253 #Handle transformer's registration based on it's type
254 if constructed and isinstance(transformer, py3compat.string_types):
254 if constructed and isinstance(transformer, py3compat.string_types):
255 #Transformer is a string, import the namespace and recursively call
255 #Transformer is a string, import the namespace and recursively call
256 #this register_transformer method
256 #this register_transformer method
257 transformer_cls = import_item(transformer)
257 transformer_cls = import_item(transformer)
258 return self.register_transformer(transformer_cls, enabled)
258 return self.register_transformer(transformer_cls, enabled)
259
259
260 if constructed and hasattr(transformer, '__call__'):
260 if constructed and hasattr(transformer, '__call__'):
261 #Transformer is a function, no need to construct it.
261 #Transformer is a function, no need to construct it.
262 #Register and return the transformer.
262 #Register and return the transformer.
263 if enabled:
263 if enabled:
264 transformer.enabled = True
264 transformer.enabled = True
265 self._transformers.append(transformer)
265 self._transformers.append(transformer)
266 return transformer
266 return transformer
267
267
268 elif isclass and isinstance(transformer, MetaHasTraits):
268 elif isclass and isinstance(transformer, MetaHasTraits):
269 #Transformer is configurable. Make sure to pass in new default for
269 #Transformer is configurable. Make sure to pass in new default for
270 #the enabled flag if one was specified.
270 #the enabled flag if one was specified.
271 self.register_transformer(transformer(parent=self), enabled)
271 self.register_transformer(transformer(parent=self), enabled)
272
272
273 elif isclass:
273 elif isclass:
274 #Transformer is not configurable, construct it
274 #Transformer is not configurable, construct it
275 self.register_transformer(transformer(), enabled)
275 self.register_transformer(transformer(), enabled)
276
276
277 else:
277 else:
278 #Transformer is an instance of something without a __call__
278 #Transformer is an instance of something without a __call__
279 #attribute.
279 #attribute.
280 raise TypeError('transformer')
280 raise TypeError('transformer')
281
281
282
282
283 def register_filter(self, name, jinja_filter):
283 def register_filter(self, name, jinja_filter):
284 """
284 """
285 Register a filter.
285 Register a filter.
286 A filter is a function that accepts and acts on one string.
286 A filter is a function that accepts and acts on one string.
287 The filters are accesible within the Jinja templating engine.
287 The filters are accesible within the Jinja templating engine.
288
288
289 Parameters
289 Parameters
290 ----------
290 ----------
291 name : str
291 name : str
292 name to give the filter in the Jinja engine
292 name to give the filter in the Jinja engine
293 filter : filter
293 filter : filter
294 """
294 """
295 if jinja_filter is None:
295 if jinja_filter is None:
296 raise TypeError('filter')
296 raise TypeError('filter')
297 isclass = isinstance(jinja_filter, type)
297 isclass = isinstance(jinja_filter, type)
298 constructed = not isclass
298 constructed = not isclass
299
299
300 #Handle filter's registration based on it's type
300 #Handle filter's registration based on it's type
301 if constructed and isinstance(jinja_filter, py3compat.string_types):
301 if constructed and isinstance(jinja_filter, py3compat.string_types):
302 #filter is a string, import the namespace and recursively call
302 #filter is a string, import the namespace and recursively call
303 #this register_filter method
303 #this register_filter method
304 filter_cls = import_item(jinja_filter)
304 filter_cls = import_item(jinja_filter)
305 return self.register_filter(name, filter_cls)
305 return self.register_filter(name, filter_cls)
306
306
307 if constructed and hasattr(jinja_filter, '__call__'):
307 if constructed and hasattr(jinja_filter, '__call__'):
308 #filter is a function, no need to construct it.
308 #filter is a function, no need to construct it.
309 self.environment.filters[name] = jinja_filter
309 self.environment.filters[name] = jinja_filter
310 return jinja_filter
310 return jinja_filter
311
311
312 elif isclass and isinstance(jinja_filter, MetaHasTraits):
312 elif isclass and isinstance(jinja_filter, MetaHasTraits):
313 #filter is configurable. Make sure to pass in new default for
313 #filter is configurable. Make sure to pass in new default for
314 #the enabled flag if one was specified.
314 #the enabled flag if one was specified.
315 filter_instance = jinja_filter(parent=self)
315 filter_instance = jinja_filter(parent=self)
316 self.register_filter(name, filter_instance )
316 self.register_filter(name, filter_instance )
317
317
318 elif isclass:
318 elif isclass:
319 #filter is not configurable, construct it
319 #filter is not configurable, construct it
320 filter_instance = jinja_filter()
320 filter_instance = jinja_filter()
321 self.register_filter(name, filter_instance)
321 self.register_filter(name, filter_instance)
322
322
323 else:
323 else:
324 #filter is an instance of something without a __call__
324 #filter is an instance of something without a __call__
325 #attribute.
325 #attribute.
326 raise TypeError('filter')
326 raise TypeError('filter')
327
327
328
328
329 def _init_environment(self, extra_loaders=None):
329 def _init_environment(self, extra_loaders=None):
330 """
330 """
331 Create the Jinja templating environment.
331 Create the Jinja templating environment.
332 """
332 """
333 here = os.path.dirname(os.path.realpath(__file__))
333 here = os.path.dirname(os.path.realpath(__file__))
334 loaders = []
334 loaders = []
335 if extra_loaders:
335 if extra_loaders:
336 loaders.extend(extra_loaders)
336 loaders.extend(extra_loaders)
337
337
338 loaders.append(FileSystemLoader([
338 loaders.append(FileSystemLoader([
339 os.path.join(here, self.template_path),
339 os.path.join(here, self.template_path),
340 os.path.join(here, self.template_skeleton_path),
340 os.path.join(here, self.template_skeleton_path),
341 ]))
341 ]))
342
342
343 self.environment = Environment(
343 self.environment = Environment(
344 loader= ChoiceLoader(loaders),
344 loader= ChoiceLoader(loaders),
345 extensions=JINJA_EXTENSIONS
345 extensions=JINJA_EXTENSIONS
346 )
346 )
347
347
348 #Set special Jinja2 syntax that will not conflict with latex.
348 #Set special Jinja2 syntax that will not conflict with latex.
349 if self.jinja_logic_block_start:
349 if self.jinja_logic_block_start:
350 self.environment.block_start_string = self.jinja_logic_block_start
350 self.environment.block_start_string = self.jinja_logic_block_start
351 if self.jinja_logic_block_end:
351 if self.jinja_logic_block_end:
352 self.environment.block_end_string = self.jinja_logic_block_end
352 self.environment.block_end_string = self.jinja_logic_block_end
353 if self.jinja_variable_block_start:
353 if self.jinja_variable_block_start:
354 self.environment.variable_start_string = self.jinja_variable_block_start
354 self.environment.variable_start_string = self.jinja_variable_block_start
355 if self.jinja_variable_block_end:
355 if self.jinja_variable_block_end:
356 self.environment.variable_end_string = self.jinja_variable_block_end
356 self.environment.variable_end_string = self.jinja_variable_block_end
357 if self.jinja_comment_block_start:
357 if self.jinja_comment_block_start:
358 self.environment.comment_start_string = self.jinja_comment_block_start
358 self.environment.comment_start_string = self.jinja_comment_block_start
359 if self.jinja_comment_block_end:
359 if self.jinja_comment_block_end:
360 self.environment.comment_end_string = self.jinja_comment_block_end
360 self.environment.comment_end_string = self.jinja_comment_block_end
361
361
362
362
363 def _init_transformers(self):
363 def _init_transformers(self):
364 """
364 """
365 Register all of the transformers needed for this exporter, disabled
365 Register all of the transformers needed for this exporter, disabled
366 unless specified explicitly.
366 unless specified explicitly.
367 """
367 """
368 self._transformers = []
368 self._transformers = []
369
369
370 #Load default transformers (not necessarly enabled by default).
370 #Load default transformers (not necessarly enabled by default).
371 if self.default_transformers:
371 if self.default_transformers:
372 for transformer in self.default_transformers:
372 for transformer in self.default_transformers:
373 self.register_transformer(transformer)
373 self.register_transformer(transformer)
374
374
375 #Load user transformers. Enable by default.
375 #Load user transformers. Enable by default.
376 if self.transformers:
376 if self.transformers:
377 for transformer in self.transformers:
377 for transformer in self.transformers:
378 self.register_transformer(transformer, enabled=True)
378 self.register_transformer(transformer, enabled=True)
379
379
380
380
381 def _init_filters(self):
381 def _init_filters(self):
382 """
382 """
383 Register all of the filters required for the exporter.
383 Register all of the filters required for the exporter.
384 """
384 """
385
385
386 #Add default filters to the Jinja2 environment
386 #Add default filters to the Jinja2 environment
387 for key, value in default_filters.items():
387 for key, value in default_filters.items():
388 self.register_filter(key, value)
388 self.register_filter(key, value)
389
389
390 #Load user filters. Overwrite existing filters if need be.
390 #Load user filters. Overwrite existing filters if need be.
391 if self.filters:
391 if self.filters:
392 for key, user_filter in self.filters.items():
392 for key, user_filter in self.filters.items():
393 self.register_filter(key, user_filter)
393 self.register_filter(key, user_filter)
394
394
395
395
396 def _init_resources(self, resources):
396 def _init_resources(self, resources):
397
397
398 #Make sure the resources dict is of ResourcesDict type.
398 #Make sure the resources dict is of ResourcesDict type.
399 if resources is None:
399 if resources is None:
400 resources = ResourcesDict()
400 resources = ResourcesDict()
401 if not isinstance(resources, ResourcesDict):
401 if not isinstance(resources, ResourcesDict):
402 new_resources = ResourcesDict()
402 new_resources = ResourcesDict()
403 new_resources.update(resources)
403 new_resources.update(resources)
404 resources = new_resources
404 resources = new_resources
405
405
406 #Make sure the metadata extension exists in resources
406 #Make sure the metadata extension exists in resources
407 if 'metadata' in resources:
407 if 'metadata' in resources:
408 if not isinstance(resources['metadata'], ResourcesDict):
408 if not isinstance(resources['metadata'], ResourcesDict):
409 resources['metadata'] = ResourcesDict(resources['metadata'])
409 resources['metadata'] = ResourcesDict(resources['metadata'])
410 else:
410 else:
411 resources['metadata'] = ResourcesDict()
411 resources['metadata'] = ResourcesDict()
412 if not resources['metadata']['name']:
412 if not resources['metadata']['name']:
413 resources['metadata']['name'] = 'Notebook'
413 resources['metadata']['name'] = 'Notebook'
414
414
415 #Set the output extension
415 #Set the output extension
416 resources['output_extension'] = self.file_extension
416 resources['output_extension'] = self.file_extension
417 return resources
417 return resources
418
418
419
419
420 def _transform(self, nb, resources):
420 def _transform(self, nb, resources):
421 """
421 """
422 Preprocess the notebook before passing it into the Jinja engine.
422 Preprocess the notebook before passing it into the Jinja engine.
423 To preprocess the notebook is to apply all of the
423 To preprocess the notebook is to apply all of the
424
424
425 Parameters
425 Parameters
426 ----------
426 ----------
427 nb : notebook node
427 nb : notebook node
428 notebook that is being exported.
428 notebook that is being exported.
429 resources : a dict of additional resources that
429 resources : a dict of additional resources that
430 can be accessed read/write by transformers
430 can be accessed read/write by transformers
431 and filters.
431 and filters.
432 """
432 """
433
433
434 # Do a copy.deepcopy first,
434 # Do a copy.deepcopy first,
435 # we are never safe enough with what the transformers could do.
435 # we are never safe enough with what the transformers could do.
436 nbc = copy.deepcopy(nb)
436 nbc = copy.deepcopy(nb)
437 resc = copy.deepcopy(resources)
437 resc = copy.deepcopy(resources)
438
438
439 #Run each transformer on the notebook. Carry the output along
439 #Run each transformer on the notebook. Carry the output along
440 #to each transformer
440 #to each transformer
441 for transformer in self._transformers:
441 for transformer in self._transformers:
442 nbc, resc = transformer(nbc, resc)
442 nbc, resc = transformer(nbc, resc)
443 return nbc, resc
443 return nbc, resc
@@ -1,102 +1,102 b''
1 """
1 """
2 Exporter that allows Latex Jinja templates to work. Contains logic to
2 Exporter that allows Latex Jinja templates to work. Contains logic to
3 appropriately prepare IPYNB files for export to LaTeX. Including but
3 appropriately prepare IPYNB files for export to LaTeX. Including but
4 not limited to escaping LaTeX, fixing math region tags, using special
4 not limited to escaping LaTeX, fixing math region tags, using special
5 tags to circumvent Jinja/Latex syntax conflicts.
5 tags to circumvent Jinja/Latex syntax conflicts.
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2013, the IPython Development Team.
8 # Copyright (c) 2013, the IPython Development Team.
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import os
20 import os
21
21
22 # IPython imports
22 # IPython imports
23 from IPython.utils.traitlets import Unicode, List
23 from IPython.utils.traitlets import Unicode, List
24 from IPython.config import Config
24 from IPython.config import Config
25
25
26 from IPython.nbconvert import filters, transformers
26 from IPython.nbconvert import filters, transformers
27 from .exporter import Exporter
27 from .exporter import Exporter
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Classes and functions
30 # Classes and functions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 class LatexExporter(Exporter):
33 class LatexExporter(Exporter):
34 """
34 """
35 Exports to a Latex template. Inherit from this class if your template is
35 Exports to a Latex template. Inherit from this class if your template is
36 LaTeX based and you need custom tranformers/filters. Inherit from it if
36 LaTeX based and you need custom tranformers/filters. Inherit from it if
37 you are writing your own HTML template and need custom tranformers/filters.
37 you are writing your own HTML template and need custom tranformers/filters.
38 If you don't need custom tranformers/filters, just change the
38 If you don't need custom tranformers/filters, just change the
39 'template_file' config option. Place your template in the special "/latex"
39 'template_file' config option. Place your template in the special "/latex"
40 subfolder of the "../templates" folder.
40 subfolder of the "../templates" folder.
41 """
41 """
42
42
43 file_extension = Unicode(
43 file_extension = Unicode(
44 'tex', config=True,
44 'tex', config=True,
45 help="Extension of the file that should be written to disk")
45 help="Extension of the file that should be written to disk")
46
46
47 template_file = Unicode(
47 template_file = Unicode(
48 'base', config=True,
48 'base', config=True,
49 help="Name of the template file to use")
49 help="Name of the template file to use")
50
50
51 #Latex constants
51 #Latex constants
52 template_path = Unicode(
52 template_path = Unicode(
53 os.path.join("..", "templates", "latex"), config=True,
53 os.path.join("..", "templates", "latex"), config=True,
54 help="Path where the template files are located.")
54 help="Path where the template files are located.")
55
55
56 template_skeleton_path = Unicode(
56 template_skeleton_path = Unicode(
57 os.path.join("..", "templates", "latex", "skeleton"), config=True,
57 os.path.join("..", "templates", "latex", "skeleton"), config=True,
58 help="Path where the template skeleton files are located.")
58 help="Path where the template skeleton files are located.")
59
59
60 #Special Jinja2 syntax that will not conflict when exporting latex.
60 #Special Jinja2 syntax that will not conflict when exporting latex.
61 jinja_comment_block_start = Unicode("((=", config=True)
61 jinja_comment_block_start = Unicode("((=", config=True)
62 jinja_comment_block_end = Unicode("=))", config=True)
62 jinja_comment_block_end = Unicode("=))", config=True)
63 jinja_variable_block_start = Unicode("(((", config=True)
63 jinja_variable_block_start = Unicode("(((", config=True)
64 jinja_variable_block_end = Unicode(")))", config=True)
64 jinja_variable_block_end = Unicode(")))", config=True)
65 jinja_logic_block_start = Unicode("((*", config=True)
65 jinja_logic_block_start = Unicode("((*", config=True)
66 jinja_logic_block_end = Unicode("*))", config=True)
66 jinja_logic_block_end = Unicode("*))", config=True)
67
67
68 #Extension that the template files use.
68 #Extension that the template files use.
69 template_extension = Unicode(".tplx", config=True)
69 template_extension = Unicode(".tplx", config=True)
70
70
71
71
72 def _init_filters(self):
72 def _init_filters(self):
73 """
73 """
74 Register all of the filters required for the exporter.
74 Register all of the filters required for the exporter.
75 """
75 """
76
76
77 #Register the filters of the base class.
77 #Register the filters of the base class.
78 super(LatexExporter, self)._init_filters()
78 super(LatexExporter, self)._init_filters()
79
79
80 #Add latex filters to the Jinja2 environment
80 #Add latex filters to the Jinja2 environment
81 self.register_filter('escape_tex', filters.escape_latex)
81 self.register_filter('escape_tex', filters.escape_latex)
82 self.register_filter('highlight', filters.highlight2latex)
82 self.register_filter('highlight', filters.highlight2latex)
83
83
84
84
85 @property
85 @property
86 def default_config(self):
86 def default_config(self):
87 c = Config({
87 c = Config({
88 'NbConvertBase': {
88 'NbConvertBase': {
89 'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
89 'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
90 },
90 },
91 'ExtractFigureTransformer': {
91 'ExtractOutputTransformer': {
92 'enabled':True
92 'enabled':True
93 },
93 },
94 'SVG2PDFTransformer': {
94 'SVG2PDFTransformer': {
95 'enabled':True
95 'enabled':True
96 },
96 },
97 'LatexTransformer': {
97 'LatexTransformer': {
98 'enabled':True
98 'enabled':True
99 }
99 }
100 })
100 })
101 c.merge(super(LatexExporter,self).default_config)
101 c.merge(super(LatexExporter,self).default_config)
102 return c
102 return c
@@ -1,42 +1,42 b''
1 """
1 """
2 Exporter for exporting notebooks to restructured text.
2 Exporter for exporting notebooks to restructured text.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from IPython.utils.traitlets import Unicode
16 from IPython.utils.traitlets import Unicode
17 from IPython.config import Config
17 from IPython.config import Config
18
18
19 from .exporter import Exporter
19 from .exporter import Exporter
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Classes
22 # Classes
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class RSTExporter(Exporter):
25 class RSTExporter(Exporter):
26 """
26 """
27 Exports restructured text documents.
27 Exports restructured text documents.
28 """
28 """
29
29
30 file_extension = Unicode(
30 file_extension = Unicode(
31 'rst', config=True,
31 'rst', config=True,
32 help="Extension of the file that should be written to disk")
32 help="Extension of the file that should be written to disk")
33
33
34 template_file = Unicode(
34 template_file = Unicode(
35 'rst', config=True,
35 'rst', config=True,
36 help="Name of the template file to use")
36 help="Name of the template file to use")
37
37
38 @property
38 @property
39 def default_config(self):
39 def default_config(self):
40 c = Config({'ExtractFigureTransformer':{'enabled':True}})
40 c = Config({'ExtractOutputTransformer':{'enabled':True}})
41 c.merge(super(RSTExporter,self).default_config)
41 c.merge(super(RSTExporter,self).default_config)
42 return c
42 return c
@@ -1,113 +1,113 b''
1 """
1 """
2 Module with tests for exporter.py
2 Module with tests for exporter.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 IPython.config import Config
17 from IPython.config import Config
18
18
19 from .base import ExportersTestsBase
19 from .base import ExportersTestsBase
20 from .cheese import CheeseTransformer
20 from .cheese import CheeseTransformer
21 from ..exporter import Exporter
21 from ..exporter import Exporter
22
22
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Class
25 # Class
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class TestExporter(ExportersTestsBase):
28 class TestExporter(ExportersTestsBase):
29 """Contains test functions for exporter.py"""
29 """Contains test functions for exporter.py"""
30
30
31
31
32 def test_constructor(self):
32 def test_constructor(self):
33 """
33 """
34 Can an Exporter be constructed?
34 Can an Exporter be constructed?
35 """
35 """
36 Exporter()
36 Exporter()
37
37
38
38
39 def test_export(self):
39 def test_export(self):
40 """
40 """
41 Can an Exporter export something?
41 Can an Exporter export something?
42 """
42 """
43 exporter = self._make_exporter()
43 exporter = self._make_exporter()
44 (output, resources) = exporter.from_filename(self._get_notebook())
44 (output, resources) = exporter.from_filename(self._get_notebook())
45 assert len(output) > 0
45 assert len(output) > 0
46
46
47
47
48 def test_extract_figures(self):
48 def test_extract_figures(self):
49 """
49 """
50 If the ExtractFigureTransformer is enabled, are figures extracted?
50 If the ExtractOutputTransformer is enabled, are figures extracted?
51 """
51 """
52 config = Config({'ExtractFigureTransformer': {'enabled': True}})
52 config = Config({'ExtractOutputTransformer': {'enabled': True}})
53 exporter = self._make_exporter(config=config)
53 exporter = self._make_exporter(config=config)
54 (output, resources) = exporter.from_filename(self._get_notebook())
54 (output, resources) = exporter.from_filename(self._get_notebook())
55 assert resources is not None
55 assert resources is not None
56 assert 'figures' in resources
56 assert 'figures' in resources
57 assert len(resources['figures']) > 0
57 assert len(resources['figures']) > 0
58
58
59
59
60 def test_transformer_class(self):
60 def test_transformer_class(self):
61 """
61 """
62 Can a transformer be added to the transformers list by class type?
62 Can a transformer be added to the transformers list by class type?
63 """
63 """
64 config = Config({'Exporter': {'transformers': [CheeseTransformer]}})
64 config = Config({'Exporter': {'transformers': [CheeseTransformer]}})
65 exporter = self._make_exporter(config=config)
65 exporter = self._make_exporter(config=config)
66 (output, resources) = exporter.from_filename(self._get_notebook())
66 (output, resources) = exporter.from_filename(self._get_notebook())
67 assert resources is not None
67 assert resources is not None
68 assert 'cheese' in resources
68 assert 'cheese' in resources
69 assert resources['cheese'] == 'real'
69 assert resources['cheese'] == 'real'
70
70
71
71
72 def test_transformer_instance(self):
72 def test_transformer_instance(self):
73 """
73 """
74 Can a transformer be added to the transformers list by instance?
74 Can a transformer be added to the transformers list by instance?
75 """
75 """
76 config = Config({'Exporter': {'transformers': [CheeseTransformer()]}})
76 config = Config({'Exporter': {'transformers': [CheeseTransformer()]}})
77 exporter = self._make_exporter(config=config)
77 exporter = self._make_exporter(config=config)
78 (output, resources) = exporter.from_filename(self._get_notebook())
78 (output, resources) = exporter.from_filename(self._get_notebook())
79 assert resources is not None
79 assert resources is not None
80 assert 'cheese' in resources
80 assert 'cheese' in resources
81 assert resources['cheese'] == 'real'
81 assert resources['cheese'] == 'real'
82
82
83
83
84 def test_transformer_dottedobjectname(self):
84 def test_transformer_dottedobjectname(self):
85 """
85 """
86 Can a transformer be added to the transformers list by dotted object name?
86 Can a transformer be added to the transformers list by dotted object name?
87 """
87 """
88 config = Config({'Exporter': {'transformers': ['IPython.nbconvert.exporters.tests.cheese.CheeseTransformer']}})
88 config = Config({'Exporter': {'transformers': ['IPython.nbconvert.exporters.tests.cheese.CheeseTransformer']}})
89 exporter = self._make_exporter(config=config)
89 exporter = self._make_exporter(config=config)
90 (output, resources) = exporter.from_filename(self._get_notebook())
90 (output, resources) = exporter.from_filename(self._get_notebook())
91 assert resources is not None
91 assert resources is not None
92 assert 'cheese' in resources
92 assert 'cheese' in resources
93 assert resources['cheese'] == 'real'
93 assert resources['cheese'] == 'real'
94
94
95
95
96 def test_transformer_via_method(self):
96 def test_transformer_via_method(self):
97 """
97 """
98 Can a transformer be added via the Exporter convinience method?
98 Can a transformer be added via the Exporter convinience method?
99 """
99 """
100 exporter = self._make_exporter()
100 exporter = self._make_exporter()
101 exporter.register_transformer(CheeseTransformer, enabled=True)
101 exporter.register_transformer(CheeseTransformer, enabled=True)
102 (output, resources) = exporter.from_filename(self._get_notebook())
102 (output, resources) = exporter.from_filename(self._get_notebook())
103 assert resources is not None
103 assert resources is not None
104 assert 'cheese' in resources
104 assert 'cheese' in resources
105 assert resources['cheese'] == 'real'
105 assert resources['cheese'] == 'real'
106
106
107
107
108 def _make_exporter(self, config=None):
108 def _make_exporter(self, config=None):
109 #Create the exporter instance, make sure to set a template name since
109 #Create the exporter instance, make sure to set a template name since
110 #the base Exporter doesn't have a template associated with it.
110 #the base Exporter doesn't have a template associated with it.
111 exporter = Exporter(config=config)
111 exporter = Exporter(config=config)
112 exporter.template_file = 'python'
112 exporter.template_file = 'python'
113 return exporter No newline at end of file
113 return exporter
@@ -1,12 +1,12 b''
1 # Class base Transformers
1 # Class base Transformers
2 from .base import Transformer
2 from .base import Transformer
3 from .convertfigures import ConvertFiguresTransformer
3 from .convertfigures import ConvertFiguresTransformer
4 from .svg2pdf import SVG2PDFTransformer
4 from .svg2pdf import SVG2PDFTransformer
5 from .extractfigure import ExtractFigureTransformer
5 from .extractoutput import ExtractOutputTransformer
6 from .revealhelp import RevealHelpTransformer
6 from .revealhelp import RevealHelpTransformer
7 from .latex import LatexTransformer
7 from .latex import LatexTransformer
8 from .sphinx import SphinxTransformer
8 from .sphinx import SphinxTransformer
9 from .csshtmlheader import CSSHTMLHeaderTransformer
9 from .csshtmlheader import CSSHTMLHeaderTransformer
10
10
11 # decorated function Transformers
11 # decorated function Transformers
12 from .coalescestreams import coalesce_streams
12 from .coalescestreams import coalesce_streams
@@ -1,101 +1,101 b''
1 """Module containing a transformer that extracts all of the figures from the
1 """Module containing a transformer that extracts all of the outputs from the
2 notebook file. The extracted figures are returned in the 'resources' dictionary.
2 notebook file. The extracted outputs are returned in the 'resources' dictionary.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 import base64
16 import base64
17 import sys
17 import sys
18 import os
18 import os
19
19
20 from IPython.utils.traitlets import Unicode
20 from IPython.utils.traitlets import Unicode
21 from .base import Transformer
21 from .base import Transformer
22 from IPython.utils import py3compat
22 from IPython.utils import py3compat
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Classes
25 # Classes
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class ExtractFigureTransformer(Transformer):
28 class ExtractOutputTransformer(Transformer):
29 """
29 """
30 Extracts all of the figures from the notebook file. The extracted
30 Extracts all of the outputs from the notebook file. The extracted
31 figures are returned in the 'resources' dictionary.
31 outputs are returned in the 'resources' dictionary.
32 """
32 """
33
33
34 figure_filename_template = Unicode(
34 figure_filename_template = Unicode(
35 "{unique_key}_{cell_index}_{index}.{extension}", config=True)
35 "{unique_key}_{cell_index}_{index}.{extension}", config=True)
36
36
37
37
38 def transform_cell(self, cell, resources, cell_index):
38 def transform_cell(self, cell, resources, cell_index):
39 """
39 """
40 Apply a transformation on each cell,
40 Apply a transformation on each cell,
41
41
42 Parameters
42 Parameters
43 ----------
43 ----------
44 cell : NotebookNode cell
44 cell : NotebookNode cell
45 Notebook cell being processed
45 Notebook cell being processed
46 resources : dictionary
46 resources : dictionary
47 Additional resources used in the conversion process. Allows
47 Additional resources used in the conversion process. Allows
48 transformers to pass variables into the Jinja engine.
48 transformers to pass variables into the Jinja engine.
49 cell_index : int
49 cell_index : int
50 Index of the cell being processed (see base.py)
50 Index of the cell being processed (see base.py)
51 """
51 """
52
52
53 #Get the unique key from the resource dict if it exists. If it does not
53 #Get the unique key from the resource dict if it exists. If it does not
54 #exist, use 'figure' as the default. Also, get files directory if it
54 #exist, use 'figure' as the default. Also, get files directory if it
55 #has been specified
55 #has been specified
56 unique_key = resources.get('unique_key', 'figure')
56 unique_key = resources.get('unique_key', 'figure')
57 output_files_dir = resources.get('output_files_dir', None)
57 output_files_dir = resources.get('output_files_dir', None)
58
58
59 #Make sure figures key exists
59 #Make sure outputs key exists
60 if not 'figures' in resources:
60 if not 'outputs' in resources:
61 resources['figures'] = {}
61 resources['outputs'] = {}
62
62
63 #Loop through all of the outputs in the cell
63 #Loop through all of the outputs in the cell
64 for index, out in enumerate(cell.get('outputs', [])):
64 for index, out in enumerate(cell.get('outputs', [])):
65
65
66 #Get the output in data formats that the template is interested in.
66 #Get the output in data formats that the template is interested in.
67 for out_type in self.display_data_priority:
67 for out_type in self.display_data_priority:
68 if out.hasattr(out_type):
68 if out.hasattr(out_type):
69 data = out[out_type]
69 data = out[out_type]
70
70
71 #Binary files are base64-encoded, SVG is already XML
71 #Binary files are base64-encoded, SVG is already XML
72 if out_type in ('png', 'jpg', 'jpeg', 'pdf'):
72 if out_type in ('png', 'jpg', 'jpeg', 'pdf'):
73 # data is b64-encoded as text (str, unicode)
73 # data is b64-encoded as text (str, unicode)
74 # decodestring only accepts bytes
74 # decodestring only accepts bytes
75 data = py3compat.cast_bytes(data)
75 data = py3compat.cast_bytes(data)
76 data = base64.decodestring(data)
76 data = base64.decodestring(data)
77 elif sys.platform == 'win32':
77 elif sys.platform == 'win32':
78 data = data.replace('\n', '\r\n').encode("UTF-8")
78 data = data.replace('\n', '\r\n').encode("UTF-8")
79 else:
79 else:
80 data = data.encode("UTF-8")
80 data = data.encode("UTF-8")
81
81
82 #Build a figure name
82 #Build a figure name
83 filename = self.figure_filename_template.format(
83 filename = self.figure_filename_template.format(
84 unique_key=unique_key,
84 unique_key=unique_key,
85 cell_index=cell_index,
85 cell_index=cell_index,
86 index=index,
86 index=index,
87 extension=out_type)
87 extension=out_type)
88
88
89 #On the cell, make the figure available via
89 #On the cell, make the figure available via
90 # cell.outputs[i].svg_filename ... etc (svg in example)
90 # cell.outputs[i].svg_filename ... etc (svg in example)
91 # Where
91 # Where
92 # cell.outputs[i].svg contains the data
92 # cell.outputs[i].svg contains the data
93 if output_files_dir is not None:
93 if output_files_dir is not None:
94 filename = os.path.join(output_files_dir, filename)
94 filename = os.path.join(output_files_dir, filename)
95 out[out_type + '_filename'] = filename
95 out[out_type + '_filename'] = filename
96
96
97 #In the resources, make the figure available via
97 #In the resources, make the figure available via
98 # resources['figures']['filename'] = data
98 # resources['outputs']['filename'] = data
99 resources['figures'][filename] = data
99 resources['outputs'][filename] = data
100
100
101 return cell, resources
101 return cell, resources
General Comments 0
You need to be logged in to leave comments. Login now