##// END OF EJS Templates
replace 'transformer' with 'preprocessor'
Paul Ivanov -
Show More
@@ -1,7 +1,7 b''
1 """Utilities for converting notebooks to and from different formats."""
1 """Utilities for converting notebooks to and from different formats."""
2
2
3 from .exporters import *
3 from .exporters import *
4 import filters
4 import filters
5 import transformers
5 import preprocessors
6 import post_processors
6 import post_processors
7 import writers
7 import writers
@@ -1,518 +1,518 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, TemplateNotFound
28 from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
29
29
30 # IPython imports
30 # IPython imports
31 from IPython.config.configurable import LoggingConfigurable
31 from IPython.config.configurable import LoggingConfigurable
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, Any
34 from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict, Any
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 preprocessors as nbpreprocessors
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 'markdown2html': filters.markdown2html,
51 'markdown2html': 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 'highlight2html': filters.highlight2html,
55 'highlight2html': filters.highlight2html,
56 'highlight2latex': filters.highlight2latex,
56 'highlight2latex': filters.highlight2latex,
57 'ipython2python': filters.ipython2python,
57 'ipython2python': filters.ipython2python,
58 'posix_path': filters.posix_path,
58 'posix_path': filters.posix_path,
59 'markdown2latex': filters.markdown2latex,
59 'markdown2latex': filters.markdown2latex,
60 'markdown2rst': filters.markdown2rst,
60 'markdown2rst': filters.markdown2rst,
61 'comment_lines': filters.comment_lines,
61 'comment_lines': filters.comment_lines,
62 'strip_ansi': filters.strip_ansi,
62 'strip_ansi': filters.strip_ansi,
63 'strip_dollars': filters.strip_dollars,
63 'strip_dollars': filters.strip_dollars,
64 'strip_files_prefix': filters.strip_files_prefix,
64 'strip_files_prefix': filters.strip_files_prefix,
65 'html2text' : filters.html2text,
65 'html2text' : filters.html2text,
66 'add_anchor': filters.add_anchor,
66 'add_anchor': filters.add_anchor,
67 'ansi2latex': filters.ansi2latex,
67 'ansi2latex': filters.ansi2latex,
68 'strip_math_space': filters.strip_math_space,
68 'strip_math_space': filters.strip_math_space,
69 'wrap_text': filters.wrap_text,
69 'wrap_text': filters.wrap_text,
70 'escape_latex': filters.escape_latex,
70 'escape_latex': filters.escape_latex,
71 }
71 }
72
72
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74 # Class
74 # Class
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76
76
77 class ResourcesDict(collections.defaultdict):
77 class ResourcesDict(collections.defaultdict):
78 def __missing__(self, key):
78 def __missing__(self, key):
79 return ''
79 return ''
80
80
81
81
82 class Exporter(LoggingConfigurable):
82 class Exporter(LoggingConfigurable):
83 """
83 """
84 Exports notebooks into other file formats. Uses Jinja 2 templating engine
84 Exports notebooks into other file formats. Uses Jinja 2 templating engine
85 to output new formats. Inherit from this class if you are creating a new
85 to output new formats. Inherit from this class if you are creating a new
86 template type along with new filters/transformers. If the filters/
86 template type along with new filters/preprocessors. If the filters/
87 transformers provided by default suffice, there is no need to inherit from
87 preprocessors provided by default suffice, there is no need to inherit from
88 this class. Instead, override the template_file and file_extension
88 this class. Instead, override the template_file and file_extension
89 traits via a config file.
89 traits via a config file.
90
90
91 {filters}
91 {filters}
92 """
92 """
93
93
94 # finish the docstring
94 # finish the docstring
95 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
95 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
96
96
97
97
98 template_file = Unicode(u'default',
98 template_file = Unicode(u'default',
99 config=True,
99 config=True,
100 help="Name of the template file to use")
100 help="Name of the template file to use")
101 def _template_file_changed(self, name, old, new):
101 def _template_file_changed(self, name, old, new):
102 if new=='default':
102 if new=='default':
103 self.template_file = self.default_template
103 self.template_file = self.default_template
104 else:
104 else:
105 self.template_file = new
105 self.template_file = new
106 self.template = None
106 self.template = None
107 self._load_template()
107 self._load_template()
108
108
109 default_template = Unicode(u'')
109 default_template = Unicode(u'')
110 template = Any()
110 template = Any()
111 environment = Any()
111 environment = Any()
112
112
113 file_extension = Unicode(
113 file_extension = Unicode(
114 'txt', config=True,
114 'txt', config=True,
115 help="Extension of the file that should be written to disk"
115 help="Extension of the file that should be written to disk"
116 )
116 )
117
117
118 template_path = List(['.'], config=True)
118 template_path = List(['.'], config=True)
119 def _template_path_changed(self, name, old, new):
119 def _template_path_changed(self, name, old, new):
120 self._load_template()
120 self._load_template()
121
121
122 default_template_path = Unicode(
122 default_template_path = Unicode(
123 os.path.join("..", "templates"),
123 os.path.join("..", "templates"),
124 help="Path where the template files are located.")
124 help="Path where the template files are located.")
125
125
126 template_skeleton_path = Unicode(
126 template_skeleton_path = Unicode(
127 os.path.join("..", "templates", "skeleton"),
127 os.path.join("..", "templates", "skeleton"),
128 help="Path where the template skeleton files are located.")
128 help="Path where the template skeleton files are located.")
129
129
130 #Jinja block definitions
130 #Jinja block definitions
131 jinja_comment_block_start = Unicode("", config=True)
131 jinja_comment_block_start = Unicode("", config=True)
132 jinja_comment_block_end = Unicode("", config=True)
132 jinja_comment_block_end = Unicode("", config=True)
133 jinja_variable_block_start = Unicode("", config=True)
133 jinja_variable_block_start = Unicode("", config=True)
134 jinja_variable_block_end = Unicode("", config=True)
134 jinja_variable_block_end = Unicode("", config=True)
135 jinja_logic_block_start = Unicode("", config=True)
135 jinja_logic_block_start = Unicode("", config=True)
136 jinja_logic_block_end = Unicode("", config=True)
136 jinja_logic_block_end = Unicode("", config=True)
137
137
138 #Extension that the template files use.
138 #Extension that the template files use.
139 template_extension = Unicode(".tpl", config=True)
139 template_extension = Unicode(".tpl", config=True)
140
140
141 #Configurability, allows the user to easily add filters and transformers.
141 #Configurability, allows the user to easily add filters and preprocessors.
142 transformers = List(config=True,
142 preprocessors = List(config=True,
143 help="""List of transformers, by name or namespace, to enable.""")
143 help="""List of preprocessors, by name or namespace, to enable.""")
144
144
145 filters = Dict(config=True,
145 filters = Dict(config=True,
146 help="""Dictionary of filters, by name and namespace, to add to the Jinja
146 help="""Dictionary of filters, by name and namespace, to add to the Jinja
147 environment.""")
147 environment.""")
148
148
149 default_transformers = List([nbtransformers.coalesce_streams,
149 default_preprocessors = List([nbpreprocessors.coalesce_streams,
150 nbtransformers.SVG2PDFTransformer,
150 nbpreprocessors.SVG2PDFPreprocessor,
151 nbtransformers.ExtractOutputTransformer,
151 nbpreprocessors.ExtractOutputPreprocessor,
152 nbtransformers.CSSHTMLHeaderTransformer,
152 nbpreprocessors.CSSHTMLHeaderPreprocessor,
153 nbtransformers.RevealHelpTransformer,
153 nbpreprocessors.RevealHelpPreprocessor,
154 nbtransformers.LatexTransformer,
154 nbpreprocessors.LatexPreprocessor,
155 nbtransformers.SphinxTransformer],
155 nbpreprocessors.SphinxPreprocessor],
156 config=True,
156 config=True,
157 help="""List of transformers available by default, by name, namespace,
157 help="""List of preprocessors available by default, by name, namespace,
158 instance, or type.""")
158 instance, or type.""")
159
159
160
160
161 def __init__(self, config=None, extra_loaders=None, **kw):
161 def __init__(self, config=None, extra_loaders=None, **kw):
162 """
162 """
163 Public constructor
163 Public constructor
164
164
165 Parameters
165 Parameters
166 ----------
166 ----------
167 config : config
167 config : config
168 User configuration instance.
168 User configuration instance.
169 extra_loaders : list[of Jinja Loaders]
169 extra_loaders : list[of Jinja Loaders]
170 ordered list of Jinja loader to find templates. Will be tried in order
170 ordered list of Jinja loader to find templates. Will be tried in order
171 before the default FileSystem ones.
171 before the default FileSystem ones.
172 template : str (optional, kw arg)
172 template : str (optional, kw arg)
173 Template to use when exporting.
173 Template to use when exporting.
174 """
174 """
175 if not config:
175 if not config:
176 config = self.default_config
176 config = self.default_config
177
177
178 super(Exporter, self).__init__(config=config, **kw)
178 super(Exporter, self).__init__(config=config, **kw)
179
179
180 #Init
180 #Init
181 self._init_template()
181 self._init_template()
182 self._init_environment(extra_loaders=extra_loaders)
182 self._init_environment(extra_loaders=extra_loaders)
183 self._init_transformers()
183 self._init_preprocessors()
184 self._init_filters()
184 self._init_filters()
185
185
186
186
187 @property
187 @property
188 def default_config(self):
188 def default_config(self):
189 return Config()
189 return Config()
190
190
191 def _config_changed(self, name, old, new):
191 def _config_changed(self, name, old, new):
192 """When setting config, make sure to start with our default_config"""
192 """When setting config, make sure to start with our default_config"""
193 c = self.default_config
193 c = self.default_config
194 if new:
194 if new:
195 c.merge(new)
195 c.merge(new)
196 if c != old:
196 if c != old:
197 self.config = c
197 self.config = c
198 super(Exporter, self)._config_changed(name, old, c)
198 super(Exporter, self)._config_changed(name, old, c)
199
199
200
200
201 def _load_template(self):
201 def _load_template(self):
202 """Load the Jinja template object from the template file
202 """Load the Jinja template object from the template file
203
203
204 This is a no-op if the template attribute is already defined,
204 This is a no-op if the template attribute is already defined,
205 or the Jinja environment is not setup yet.
205 or the Jinja environment is not setup yet.
206
206
207 This is triggered by various trait changes that would change the template.
207 This is triggered by various trait changes that would change the template.
208 """
208 """
209 if self.template is not None:
209 if self.template is not None:
210 return
210 return
211 # called too early, do nothing
211 # called too early, do nothing
212 if self.environment is None:
212 if self.environment is None:
213 return
213 return
214 # Try different template names during conversion. First try to load the
214 # Try different template names during conversion. First try to load the
215 # template by name with extension added, then try loading the template
215 # template by name with extension added, then try loading the template
216 # as if the name is explicitly specified, then try the name as a
216 # as if the name is explicitly specified, then try the name as a
217 # 'flavor', and lastly just try to load the template by module name.
217 # 'flavor', and lastly just try to load the template by module name.
218 module_name = self.__module__.rsplit('.', 1)[-1]
218 module_name = self.__module__.rsplit('.', 1)[-1]
219 try_names = []
219 try_names = []
220 if self.template_file:
220 if self.template_file:
221 try_names.extend([
221 try_names.extend([
222 self.template_file + self.template_extension,
222 self.template_file + self.template_extension,
223 self.template_file,
223 self.template_file,
224 module_name + '_' + self.template_file + self.template_extension,
224 module_name + '_' + self.template_file + self.template_extension,
225 ])
225 ])
226 try_names.append(module_name + self.template_extension)
226 try_names.append(module_name + self.template_extension)
227 for try_name in try_names:
227 for try_name in try_names:
228 self.log.debug("Attempting to load template %s", try_name)
228 self.log.debug("Attempting to load template %s", try_name)
229 try:
229 try:
230 self.template = self.environment.get_template(try_name)
230 self.template = self.environment.get_template(try_name)
231 except (TemplateNotFound, IOError):
231 except (TemplateNotFound, IOError):
232 pass
232 pass
233 except Exception as e:
233 except Exception as e:
234 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
234 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
235 else:
235 else:
236 self.log.info("Loaded template %s", try_name)
236 self.log.info("Loaded template %s", try_name)
237 break
237 break
238
238
239 def from_notebook_node(self, nb, resources=None, **kw):
239 def from_notebook_node(self, nb, resources=None, **kw):
240 """
240 """
241 Convert a notebook from a notebook node instance.
241 Convert a notebook from a notebook node instance.
242
242
243 Parameters
243 Parameters
244 ----------
244 ----------
245 nb : Notebook node
245 nb : Notebook node
246 resources : dict (**kw)
246 resources : dict (**kw)
247 of additional resources that can be accessed read/write by
247 of additional resources that can be accessed read/write by
248 transformers and filters.
248 preprocessors and filters.
249 """
249 """
250 nb_copy = copy.deepcopy(nb)
250 nb_copy = copy.deepcopy(nb)
251 resources = self._init_resources(resources)
251 resources = self._init_resources(resources)
252
252
253 # Preprocess
253 # Preprocess
254 nb_copy, resources = self._transform(nb_copy, resources)
254 nb_copy, resources = self._preprocess(nb_copy, resources)
255
255
256 self._load_template()
256 self._load_template()
257
257
258 if self.template is not None:
258 if self.template is not None:
259 output = self.template.render(nb=nb_copy, resources=resources)
259 output = self.template.render(nb=nb_copy, resources=resources)
260 else:
260 else:
261 raise IOError('template file "%s" could not be found' % self.template_file)
261 raise IOError('template file "%s" could not be found' % self.template_file)
262 return output, resources
262 return output, resources
263
263
264
264
265 def from_filename(self, filename, resources=None, **kw):
265 def from_filename(self, filename, resources=None, **kw):
266 """
266 """
267 Convert a notebook from a notebook file.
267 Convert a notebook from a notebook file.
268
268
269 Parameters
269 Parameters
270 ----------
270 ----------
271 filename : str
271 filename : str
272 Full filename of the notebook file to open and convert.
272 Full filename of the notebook file to open and convert.
273 """
273 """
274
274
275 #Pull the metadata from the filesystem.
275 #Pull the metadata from the filesystem.
276 if resources is None:
276 if resources is None:
277 resources = ResourcesDict()
277 resources = ResourcesDict()
278 if not 'metadata' in resources or resources['metadata'] == '':
278 if not 'metadata' in resources or resources['metadata'] == '':
279 resources['metadata'] = ResourcesDict()
279 resources['metadata'] = ResourcesDict()
280 basename = os.path.basename(filename)
280 basename = os.path.basename(filename)
281 notebook_name = basename[:basename.rfind('.')]
281 notebook_name = basename[:basename.rfind('.')]
282 resources['metadata']['name'] = notebook_name
282 resources['metadata']['name'] = notebook_name
283
283
284 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
284 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
285 resources['metadata']['modified_date'] = modified_date.strftime("%B %d, %Y")
285 resources['metadata']['modified_date'] = modified_date.strftime("%B %d, %Y")
286
286
287 with io.open(filename) as f:
287 with io.open(filename) as f:
288 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
288 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
289
289
290
290
291 def from_file(self, file_stream, resources=None, **kw):
291 def from_file(self, file_stream, resources=None, **kw):
292 """
292 """
293 Convert a notebook from a notebook file.
293 Convert a notebook from a notebook file.
294
294
295 Parameters
295 Parameters
296 ----------
296 ----------
297 file_stream : file-like object
297 file_stream : file-like object
298 Notebook file-like object to convert.
298 Notebook file-like object to convert.
299 """
299 """
300 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
300 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
301
301
302
302
303 def register_transformer(self, transformer, enabled=False):
303 def register_preprocessor(self, preprocessor, enabled=False):
304 """
304 """
305 Register a transformer.
305 Register a preprocessor.
306 Transformers are classes that act upon the notebook before it is
306 Preprocessors are classes that act upon the notebook before it is
307 passed into the Jinja templating engine. Transformers are also
307 passed into the Jinja templating engine. Preprocessors are also
308 capable of passing additional information to the Jinja
308 capable of passing additional information to the Jinja
309 templating engine.
309 templating engine.
310
310
311 Parameters
311 Parameters
312 ----------
312 ----------
313 transformer : transformer
313 preprocessor : preprocessor
314 """
314 """
315 if transformer is None:
315 if preprocessor is None:
316 raise TypeError('transformer')
316 raise TypeError('preprocessor')
317 isclass = isinstance(transformer, type)
317 isclass = isinstance(preprocessor, type)
318 constructed = not isclass
318 constructed = not isclass
319
319
320 #Handle transformer's registration based on it's type
320 #Handle preprocessor's registration based on it's type
321 if constructed and isinstance(transformer, py3compat.string_types):
321 if constructed and isinstance(preprocessor, py3compat.string_types):
322 #Transformer is a string, import the namespace and recursively call
322 #Preprocessor is a string, import the namespace and recursively call
323 #this register_transformer method
323 #this register_preprocessor method
324 transformer_cls = import_item(transformer)
324 preprocessor_cls = import_item(preprocessor)
325 return self.register_transformer(transformer_cls, enabled)
325 return self.register_preprocessor(preprocessor_cls, enabled)
326
326
327 if constructed and hasattr(transformer, '__call__'):
327 if constructed and hasattr(preprocessor, '__call__'):
328 #Transformer is a function, no need to construct it.
328 #Preprocessor is a function, no need to construct it.
329 #Register and return the transformer.
329 #Register and return the preprocessor.
330 if enabled:
330 if enabled:
331 transformer.enabled = True
331 preprocessor.enabled = True
332 self._transformers.append(transformer)
332 self._preprocessors.append(preprocessor)
333 return transformer
333 return preprocessor
334
334
335 elif isclass and isinstance(transformer, MetaHasTraits):
335 elif isclass and isinstance(preprocessor, MetaHasTraits):
336 #Transformer is configurable. Make sure to pass in new default for
336 #Preprocessor is configurable. Make sure to pass in new default for
337 #the enabled flag if one was specified.
337 #the enabled flag if one was specified.
338 self.register_transformer(transformer(parent=self), enabled)
338 self.register_preprocessor(preprocessor(parent=self), enabled)
339
339
340 elif isclass:
340 elif isclass:
341 #Transformer is not configurable, construct it
341 #Preprocessor is not configurable, construct it
342 self.register_transformer(transformer(), enabled)
342 self.register_preprocessor(preprocessor(), enabled)
343
343
344 else:
344 else:
345 #Transformer is an instance of something without a __call__
345 #Preprocessor is an instance of something without a __call__
346 #attribute.
346 #attribute.
347 raise TypeError('transformer')
347 raise TypeError('preprocessor')
348
348
349
349
350 def register_filter(self, name, jinja_filter):
350 def register_filter(self, name, jinja_filter):
351 """
351 """
352 Register a filter.
352 Register a filter.
353 A filter is a function that accepts and acts on one string.
353 A filter is a function that accepts and acts on one string.
354 The filters are accesible within the Jinja templating engine.
354 The filters are accesible within the Jinja templating engine.
355
355
356 Parameters
356 Parameters
357 ----------
357 ----------
358 name : str
358 name : str
359 name to give the filter in the Jinja engine
359 name to give the filter in the Jinja engine
360 filter : filter
360 filter : filter
361 """
361 """
362 if jinja_filter is None:
362 if jinja_filter is None:
363 raise TypeError('filter')
363 raise TypeError('filter')
364 isclass = isinstance(jinja_filter, type)
364 isclass = isinstance(jinja_filter, type)
365 constructed = not isclass
365 constructed = not isclass
366
366
367 #Handle filter's registration based on it's type
367 #Handle filter's registration based on it's type
368 if constructed and isinstance(jinja_filter, py3compat.string_types):
368 if constructed and isinstance(jinja_filter, py3compat.string_types):
369 #filter is a string, import the namespace and recursively call
369 #filter is a string, import the namespace and recursively call
370 #this register_filter method
370 #this register_filter method
371 filter_cls = import_item(jinja_filter)
371 filter_cls = import_item(jinja_filter)
372 return self.register_filter(name, filter_cls)
372 return self.register_filter(name, filter_cls)
373
373
374 if constructed and hasattr(jinja_filter, '__call__'):
374 if constructed and hasattr(jinja_filter, '__call__'):
375 #filter is a function, no need to construct it.
375 #filter is a function, no need to construct it.
376 self.environment.filters[name] = jinja_filter
376 self.environment.filters[name] = jinja_filter
377 return jinja_filter
377 return jinja_filter
378
378
379 elif isclass and isinstance(jinja_filter, MetaHasTraits):
379 elif isclass and isinstance(jinja_filter, MetaHasTraits):
380 #filter is configurable. Make sure to pass in new default for
380 #filter is configurable. Make sure to pass in new default for
381 #the enabled flag if one was specified.
381 #the enabled flag if one was specified.
382 filter_instance = jinja_filter(parent=self)
382 filter_instance = jinja_filter(parent=self)
383 self.register_filter(name, filter_instance )
383 self.register_filter(name, filter_instance )
384
384
385 elif isclass:
385 elif isclass:
386 #filter is not configurable, construct it
386 #filter is not configurable, construct it
387 filter_instance = jinja_filter()
387 filter_instance = jinja_filter()
388 self.register_filter(name, filter_instance)
388 self.register_filter(name, filter_instance)
389
389
390 else:
390 else:
391 #filter is an instance of something without a __call__
391 #filter is an instance of something without a __call__
392 #attribute.
392 #attribute.
393 raise TypeError('filter')
393 raise TypeError('filter')
394
394
395
395
396 def _init_template(self):
396 def _init_template(self):
397 """
397 """
398 Make sure a template name is specified. If one isn't specified, try to
398 Make sure a template name is specified. If one isn't specified, try to
399 build one from the information we know.
399 build one from the information we know.
400 """
400 """
401 self._template_file_changed('template_file', self.template_file, self.template_file)
401 self._template_file_changed('template_file', self.template_file, self.template_file)
402
402
403
403
404 def _init_environment(self, extra_loaders=None):
404 def _init_environment(self, extra_loaders=None):
405 """
405 """
406 Create the Jinja templating environment.
406 Create the Jinja templating environment.
407 """
407 """
408 here = os.path.dirname(os.path.realpath(__file__))
408 here = os.path.dirname(os.path.realpath(__file__))
409 loaders = []
409 loaders = []
410 if extra_loaders:
410 if extra_loaders:
411 loaders.extend(extra_loaders)
411 loaders.extend(extra_loaders)
412
412
413 paths = self.template_path
413 paths = self.template_path
414 paths.extend([os.path.join(here, self.default_template_path),
414 paths.extend([os.path.join(here, self.default_template_path),
415 os.path.join(here, self.template_skeleton_path)])
415 os.path.join(here, self.template_skeleton_path)])
416 loaders.append(FileSystemLoader(paths))
416 loaders.append(FileSystemLoader(paths))
417
417
418 self.environment = Environment(
418 self.environment = Environment(
419 loader= ChoiceLoader(loaders),
419 loader= ChoiceLoader(loaders),
420 extensions=JINJA_EXTENSIONS
420 extensions=JINJA_EXTENSIONS
421 )
421 )
422
422
423 #Set special Jinja2 syntax that will not conflict with latex.
423 #Set special Jinja2 syntax that will not conflict with latex.
424 if self.jinja_logic_block_start:
424 if self.jinja_logic_block_start:
425 self.environment.block_start_string = self.jinja_logic_block_start
425 self.environment.block_start_string = self.jinja_logic_block_start
426 if self.jinja_logic_block_end:
426 if self.jinja_logic_block_end:
427 self.environment.block_end_string = self.jinja_logic_block_end
427 self.environment.block_end_string = self.jinja_logic_block_end
428 if self.jinja_variable_block_start:
428 if self.jinja_variable_block_start:
429 self.environment.variable_start_string = self.jinja_variable_block_start
429 self.environment.variable_start_string = self.jinja_variable_block_start
430 if self.jinja_variable_block_end:
430 if self.jinja_variable_block_end:
431 self.environment.variable_end_string = self.jinja_variable_block_end
431 self.environment.variable_end_string = self.jinja_variable_block_end
432 if self.jinja_comment_block_start:
432 if self.jinja_comment_block_start:
433 self.environment.comment_start_string = self.jinja_comment_block_start
433 self.environment.comment_start_string = self.jinja_comment_block_start
434 if self.jinja_comment_block_end:
434 if self.jinja_comment_block_end:
435 self.environment.comment_end_string = self.jinja_comment_block_end
435 self.environment.comment_end_string = self.jinja_comment_block_end
436
436
437
437
438 def _init_transformers(self):
438 def _init_preprocessors(self):
439 """
439 """
440 Register all of the transformers needed for this exporter, disabled
440 Register all of the preprocessors needed for this exporter, disabled
441 unless specified explicitly.
441 unless specified explicitly.
442 """
442 """
443 self._transformers = []
443 self._preprocessors = []
444
444
445 #Load default transformers (not necessarly enabled by default).
445 #Load default preprocessors (not necessarly enabled by default).
446 if self.default_transformers:
446 if self.default_preprocessors:
447 for transformer in self.default_transformers:
447 for preprocessor in self.default_preprocessors:
448 self.register_transformer(transformer)
448 self.register_preprocessor(preprocessor)
449
449
450 #Load user transformers. Enable by default.
450 #Load user preprocessors. Enable by default.
451 if self.transformers:
451 if self.preprocessors:
452 for transformer in self.transformers:
452 for preprocessor in self.preprocessors:
453 self.register_transformer(transformer, enabled=True)
453 self.register_preprocessor(preprocessor, enabled=True)
454
454
455
455
456 def _init_filters(self):
456 def _init_filters(self):
457 """
457 """
458 Register all of the filters required for the exporter.
458 Register all of the filters required for the exporter.
459 """
459 """
460
460
461 #Add default filters to the Jinja2 environment
461 #Add default filters to the Jinja2 environment
462 for key, value in default_filters.items():
462 for key, value in default_filters.items():
463 self.register_filter(key, value)
463 self.register_filter(key, value)
464
464
465 #Load user filters. Overwrite existing filters if need be.
465 #Load user filters. Overwrite existing filters if need be.
466 if self.filters:
466 if self.filters:
467 for key, user_filter in self.filters.items():
467 for key, user_filter in self.filters.items():
468 self.register_filter(key, user_filter)
468 self.register_filter(key, user_filter)
469
469
470
470
471 def _init_resources(self, resources):
471 def _init_resources(self, resources):
472
472
473 #Make sure the resources dict is of ResourcesDict type.
473 #Make sure the resources dict is of ResourcesDict type.
474 if resources is None:
474 if resources is None:
475 resources = ResourcesDict()
475 resources = ResourcesDict()
476 if not isinstance(resources, ResourcesDict):
476 if not isinstance(resources, ResourcesDict):
477 new_resources = ResourcesDict()
477 new_resources = ResourcesDict()
478 new_resources.update(resources)
478 new_resources.update(resources)
479 resources = new_resources
479 resources = new_resources
480
480
481 #Make sure the metadata extension exists in resources
481 #Make sure the metadata extension exists in resources
482 if 'metadata' in resources:
482 if 'metadata' in resources:
483 if not isinstance(resources['metadata'], ResourcesDict):
483 if not isinstance(resources['metadata'], ResourcesDict):
484 resources['metadata'] = ResourcesDict(resources['metadata'])
484 resources['metadata'] = ResourcesDict(resources['metadata'])
485 else:
485 else:
486 resources['metadata'] = ResourcesDict()
486 resources['metadata'] = ResourcesDict()
487 if not resources['metadata']['name']:
487 if not resources['metadata']['name']:
488 resources['metadata']['name'] = 'Notebook'
488 resources['metadata']['name'] = 'Notebook'
489
489
490 #Set the output extension
490 #Set the output extension
491 resources['output_extension'] = self.file_extension
491 resources['output_extension'] = self.file_extension
492 return resources
492 return resources
493
493
494
494
495 def _transform(self, nb, resources):
495 def _preprocess(self, nb, resources):
496 """
496 """
497 Preprocess the notebook before passing it into the Jinja engine.
497 Preprocess the notebook before passing it into the Jinja engine.
498 To preprocess the notebook is to apply all of the
498 To preprocess the notebook is to apply all of the
499
499
500 Parameters
500 Parameters
501 ----------
501 ----------
502 nb : notebook node
502 nb : notebook node
503 notebook that is being exported.
503 notebook that is being exported.
504 resources : a dict of additional resources that
504 resources : a dict of additional resources that
505 can be accessed read/write by transformers
505 can be accessed read/write by preprocessors
506 and filters.
506 and filters.
507 """
507 """
508
508
509 # Do a copy.deepcopy first,
509 # Do a copy.deepcopy first,
510 # we are never safe enough with what the transformers could do.
510 # we are never safe enough with what the preprocessors could do.
511 nbc = copy.deepcopy(nb)
511 nbc = copy.deepcopy(nb)
512 resc = copy.deepcopy(resources)
512 resc = copy.deepcopy(resources)
513
513
514 #Run each transformer on the notebook. Carry the output along
514 #Run each preprocessor on the notebook. Carry the output along
515 #to each transformer
515 #to each preprocessor
516 for transformer in self._transformers:
516 for preprocessor in self._preprocessors:
517 nbc, resc = transformer(nbc, resc)
517 nbc, resc = preprocessor(nbc, resc)
518 return nbc, resc
518 return nbc, resc
@@ -1,52 +1,52 b''
1 """
1 """
2 Exporter that exports Basic HTML.
2 Exporter that exports Basic HTML.
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.utils.traitlets import Unicode, List
17 from IPython.utils.traitlets import Unicode, List
18
18
19 from IPython.nbconvert import transformers
19 from IPython.nbconvert import preprocessors
20 from IPython.config import Config
20 from IPython.config import Config
21
21
22 from .exporter import Exporter
22 from .exporter import Exporter
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Classes
25 # Classes
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class HTMLExporter(Exporter):
28 class HTMLExporter(Exporter):
29 """
29 """
30 Exports a basic HTML document. This exporter assists with the export of
30 Exports a basic HTML document. This exporter assists with the export of
31 HTML. Inherit from it if you are writing your own HTML template and need
31 HTML. Inherit from it if you are writing your own HTML template and need
32 custom transformers/filters. If you don't need custom transformers/
32 custom preprocessors/filters. If you don't need custom preprocessors/
33 filters, just change the 'template_file' config option.
33 filters, just change the 'template_file' config option.
34 """
34 """
35
35
36 file_extension = Unicode(
36 file_extension = Unicode(
37 'html', config=True,
37 'html', config=True,
38 help="Extension of the file that should be written to disk"
38 help="Extension of the file that should be written to disk"
39 )
39 )
40
40
41 default_template = Unicode('full', config=True, help="""Flavor of the data
41 default_template = Unicode('full', config=True, help="""Flavor of the data
42 format to use. I.E. 'full' or 'basic'""")
42 format to use. I.E. 'full' or 'basic'""")
43
43
44 @property
44 @property
45 def default_config(self):
45 def default_config(self):
46 c = Config({
46 c = Config({
47 'CSSHTMLHeaderTransformer':{
47 'CSSHTMLHeaderPreprocessor':{
48 'enabled':True
48 'enabled':True
49 }
49 }
50 })
50 })
51 c.merge(super(HTMLExporter,self).default_config)
51 c.merge(super(HTMLExporter,self).default_config)
52 return c
52 return c
@@ -1,91 +1,91 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, preprocessors
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 default_template = Unicode('article', config=True, help="""Template of the
47 default_template = Unicode('article', config=True, help="""Template of the
48 data format to use. I.E. 'full' or 'basic'""")
48 data format to use. I.E. 'full' or 'basic'""")
49
49
50 #Latex constants
50 #Latex constants
51 default_template_path = Unicode(
51 default_template_path = Unicode(
52 os.path.join("..", "templates", "latex"), config=True,
52 os.path.join("..", "templates", "latex"), config=True,
53 help="Path where the template files are located.")
53 help="Path where the template files are located.")
54
54
55 template_skeleton_path = Unicode(
55 template_skeleton_path = Unicode(
56 os.path.join("..", "templates", "latex", "skeleton"), config=True,
56 os.path.join("..", "templates", "latex", "skeleton"), config=True,
57 help="Path where the template skeleton files are located.")
57 help="Path where the template skeleton files are located.")
58
58
59 #Special Jinja2 syntax that will not conflict when exporting latex.
59 #Special Jinja2 syntax that will not conflict when exporting latex.
60 jinja_comment_block_start = Unicode("((=", config=True)
60 jinja_comment_block_start = Unicode("((=", config=True)
61 jinja_comment_block_end = Unicode("=))", config=True)
61 jinja_comment_block_end = Unicode("=))", config=True)
62 jinja_variable_block_start = Unicode("(((", config=True)
62 jinja_variable_block_start = Unicode("(((", config=True)
63 jinja_variable_block_end = Unicode(")))", config=True)
63 jinja_variable_block_end = Unicode(")))", config=True)
64 jinja_logic_block_start = Unicode("((*", config=True)
64 jinja_logic_block_start = Unicode("((*", config=True)
65 jinja_logic_block_end = Unicode("*))", config=True)
65 jinja_logic_block_end = Unicode("*))", config=True)
66
66
67 #Extension that the template files use.
67 #Extension that the template files use.
68 template_extension = Unicode(".tplx", config=True)
68 template_extension = Unicode(".tplx", config=True)
69
69
70
70
71 @property
71 @property
72 def default_config(self):
72 def default_config(self):
73 c = Config({
73 c = Config({
74 'NbConvertBase': {
74 'NbConvertBase': {
75 'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
75 'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
76 },
76 },
77 'ExtractOutputTransformer': {
77 'ExtractOutputPreprocessor': {
78 'enabled':True
78 'enabled':True
79 },
79 },
80 'SVG2PDFTransformer': {
80 'SVG2PDFPreprocessor': {
81 'enabled':True
81 'enabled':True
82 },
82 },
83 'LatexTransformer': {
83 'LatexPreprocessor': {
84 'enabled':True
84 'enabled':True
85 },
85 },
86 'SphinxTransformer': {
86 'SphinxPreprocessor': {
87 'enabled':True
87 'enabled':True
88 }
88 }
89 })
89 })
90 c.merge(super(LatexExporter,self).default_config)
90 c.merge(super(LatexExporter,self).default_config)
91 return c
91 return c
@@ -1,38 +1,38 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 @property
34 @property
35 def default_config(self):
35 def default_config(self):
36 c = Config({'ExtractOutputTransformer':{'enabled':True}})
36 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
37 c.merge(super(RSTExporter,self).default_config)
37 c.merge(super(RSTExporter,self).default_config)
38 return c
38 return c
@@ -1,52 +1,52 b''
1 """
1 """
2 Contains slide show exporter
2 Contains slide show exporter
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.utils.traitlets import Unicode
17 from IPython.utils.traitlets import Unicode
18
18
19 from IPython.nbconvert import transformers
19 from IPython.nbconvert import preprocessors
20 from IPython.config import Config
20 from IPython.config import Config
21
21
22 from .exporter import Exporter
22 from .exporter import Exporter
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Classes
25 # Classes
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class SlidesExporter(Exporter):
28 class SlidesExporter(Exporter):
29 """
29 """
30 Exports slides
30 Exports slides
31 """
31 """
32
32
33 file_extension = Unicode(
33 file_extension = Unicode(
34 'slides.html', config=True,
34 'slides.html', config=True,
35 help="Extension of the file that should be written to disk"
35 help="Extension of the file that should be written to disk"
36 )
36 )
37
37
38 default_template = Unicode('reveal', config=True, help="""Template of the
38 default_template = Unicode('reveal', config=True, help="""Template of the
39 data format to use. I.E. 'reveal'""")
39 data format to use. I.E. 'reveal'""")
40
40
41 @property
41 @property
42 def default_config(self):
42 def default_config(self):
43 c = Config({
43 c = Config({
44 'CSSHTMLHeaderTransformer':{
44 'CSSHTMLHeaderPreprocessor':{
45 'enabled':True
45 'enabled':True
46 },
46 },
47 'RevealHelpTransformer':{
47 'RevealHelpPreprocessor':{
48 'enabled':True,
48 'enabled':True,
49 },
49 },
50 })
50 })
51 c.merge(super(SlidesExporter,self).default_config)
51 c.merge(super(SlidesExporter,self).default_config)
52 return c
52 return c
@@ -1,48 +1,48 b''
1 """
1 """
2 Contains CheeseTransformer
2 Contains CheesePreprocessor
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 ...transformers.base import Transformer
16 from ...preprocessors.base import Preprocessor
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Classes
19 # Classes
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 class CheeseTransformer(Transformer):
22 class CheesePreprocessor(Preprocessor):
23 """
23 """
24 Adds a cheese tag to the resources object
24 Adds a cheese tag to the resources object
25 """
25 """
26
26
27
27
28 def __init__(self, **kw):
28 def __init__(self, **kw):
29 """
29 """
30 Public constructor
30 Public constructor
31 """
31 """
32 super(CheeseTransformer, self).__init__(**kw)
32 super(CheesePreprocessor, self).__init__(**kw)
33
33
34
34
35 def transform(self, nb, resources):
35 def preprocess(self, nb, resources):
36 """
36 """
37 Sphinx transformation to apply on each notebook.
37 Sphinx preprocessing to apply on each notebook.
38
38
39 Parameters
39 Parameters
40 ----------
40 ----------
41 nb : NotebookNode
41 nb : NotebookNode
42 Notebook being converted
42 Notebook being converted
43 resources : dictionary
43 resources : dictionary
44 Additional resources used in the conversion process. Allows
44 Additional resources used in the conversion process. Allows
45 transformers to pass variables into the Jinja engine.
45 preprocessors to pass variables into the Jinja engine.
46 """
46 """
47 resources['cheese'] = 'real'
47 resources['cheese'] = 'real'
48 return nb, resources
48 return nb, resources
@@ -1,108 +1,108 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 CheesePreprocessor
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_outputs(self):
48 def test_extract_outputs(self):
49 """
49 """
50 If the ExtractOutputTransformer is enabled, are outputs extracted?
50 If the ExtractOutputPreprocessor is enabled, are outputs extracted?
51 """
51 """
52 config = Config({'ExtractOutputTransformer': {'enabled': True}})
52 config = Config({'ExtractOutputPreprocessor': {'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 isinstance(resources['outputs'], dict)
56 assert isinstance(resources['outputs'], dict)
57 assert len(resources['outputs']) > 0
57 assert len(resources['outputs']) > 0
58
58
59
59
60 def test_transformer_class(self):
60 def test_preprocessor_class(self):
61 """
61 """
62 Can a transformer be added to the transformers list by class type?
62 Can a preprocessor be added to the preprocessors list by class type?
63 """
63 """
64 config = Config({'Exporter': {'transformers': [CheeseTransformer]}})
64 config = Config({'Exporter': {'preprocessors': [CheesePreprocessor]}})
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 resources['cheese'] == 'real'
68 assert resources['cheese'] == 'real'
69
69
70
70
71 def test_transformer_instance(self):
71 def test_preprocessor_instance(self):
72 """
72 """
73 Can a transformer be added to the transformers list by instance?
73 Can a preprocessor be added to the preprocessors list by instance?
74 """
74 """
75 config = Config({'Exporter': {'transformers': [CheeseTransformer()]}})
75 config = Config({'Exporter': {'preprocessors': [CheesePreprocessor()]}})
76 exporter = self._make_exporter(config=config)
76 exporter = self._make_exporter(config=config)
77 (output, resources) = exporter.from_filename(self._get_notebook())
77 (output, resources) = exporter.from_filename(self._get_notebook())
78 assert resources is not None
78 assert resources is not None
79 assert resources['cheese'] == 'real'
79 assert resources['cheese'] == 'real'
80
80
81
81
82 def test_transformer_dottedobjectname(self):
82 def test_preprocessor_dottedobjectname(self):
83 """
83 """
84 Can a transformer be added to the transformers list by dotted object name?
84 Can a preprocessor be added to the preprocessors list by dotted object name?
85 """
85 """
86 config = Config({'Exporter': {'transformers': ['IPython.nbconvert.exporters.tests.cheese.CheeseTransformer']}})
86 config = Config({'Exporter': {'preprocessors': ['IPython.nbconvert.exporters.tests.cheese.CheesePreprocessor']}})
87 exporter = self._make_exporter(config=config)
87 exporter = self._make_exporter(config=config)
88 (output, resources) = exporter.from_filename(self._get_notebook())
88 (output, resources) = exporter.from_filename(self._get_notebook())
89 assert resources is not None
89 assert resources is not None
90 assert resources['cheese'] == 'real'
90 assert resources['cheese'] == 'real'
91
91
92
92
93 def test_transformer_via_method(self):
93 def test_preprocessor_via_method(self):
94 """
94 """
95 Can a transformer be added via the Exporter convenience method?
95 Can a preprocessor be added via the Exporter convenience method?
96 """
96 """
97 exporter = self._make_exporter()
97 exporter = self._make_exporter()
98 exporter.register_transformer(CheeseTransformer, enabled=True)
98 exporter.register_preprocessor(CheesePreprocessor, enabled=True)
99 (output, resources) = exporter.from_filename(self._get_notebook())
99 (output, resources) = exporter.from_filename(self._get_notebook())
100 assert resources is not None
100 assert resources is not None
101 assert resources['cheese'] == 'real'
101 assert resources['cheese'] == 'real'
102
102
103
103
104 def _make_exporter(self, config=None):
104 def _make_exporter(self, config=None):
105 #Create the exporter instance, make sure to set a template name since
105 #Create the exporter instance, make sure to set a template name since
106 #the base Exporter doesn't have a template associated with it.
106 #the base Exporter doesn't have a template associated with it.
107 exporter = Exporter(config=config, template_file='python')
107 exporter = Exporter(config=config, template_file='python')
108 return exporter No newline at end of file
108 return exporter
@@ -1,322 +1,322 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """NBConvert is a utility for conversion of .ipynb files.
2 """NBConvert is a utility for conversion of .ipynb files.
3
3
4 Command-line interface for the NbConvert conversion utility.
4 Command-line interface for the NbConvert conversion utility.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 #Copyright (c) 2013, the IPython Development Team.
7 #Copyright (c) 2013, the IPython Development Team.
8 #
8 #
9 #Distributed under the terms of the Modified BSD License.
9 #Distributed under the terms of the Modified BSD License.
10 #
10 #
11 #The full license is in the file COPYING.txt, distributed with this software.
11 #The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 #Imports
15 #Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 # Stdlib imports
18 # Stdlib imports
19 from __future__ import print_function
19 from __future__ import print_function
20
20
21 import logging
21 import logging
22 import sys
22 import sys
23 import os
23 import os
24 import glob
24 import glob
25
25
26 # From IPython
26 # From IPython
27 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
27 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
28 from IPython.config import catch_config_error, Configurable
28 from IPython.config import catch_config_error, Configurable
29 from IPython.utils.traitlets import (
29 from IPython.utils.traitlets import (
30 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
30 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
31 )
31 )
32 from IPython.utils.importstring import import_item
32 from IPython.utils.importstring import import_item
33 from IPython.utils.text import dedent
33 from IPython.utils.text import dedent
34
34
35 from .exporters.export import get_export_names, exporter_map
35 from .exporters.export import get_export_names, exporter_map
36 from IPython.nbconvert import exporters, transformers, writers, post_processors
36 from IPython.nbconvert import exporters, preprocessors, writers, post_processors
37 from .utils.base import NbConvertBase
37 from .utils.base import NbConvertBase
38 from .utils.exceptions import ConversionException
38 from .utils.exceptions import ConversionException
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 #Classes and functions
41 #Classes and functions
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 class DottedOrNone(DottedObjectName):
44 class DottedOrNone(DottedObjectName):
45 """
45 """
46 A string holding a valid dotted object name in Python, such as A.b3._c
46 A string holding a valid dotted object name in Python, such as A.b3._c
47 Also allows for None type."""
47 Also allows for None type."""
48
48
49 default_value = u''
49 default_value = u''
50
50
51 def validate(self, obj, value):
51 def validate(self, obj, value):
52 if value is not None and len(value) > 0:
52 if value is not None and len(value) > 0:
53 return super(DottedOrNone, self).validate(obj, value)
53 return super(DottedOrNone, self).validate(obj, value)
54 else:
54 else:
55 return value
55 return value
56
56
57 nbconvert_aliases = {}
57 nbconvert_aliases = {}
58 nbconvert_aliases.update(base_aliases)
58 nbconvert_aliases.update(base_aliases)
59 nbconvert_aliases.update({
59 nbconvert_aliases.update({
60 'to' : 'NbConvertApp.export_format',
60 'to' : 'NbConvertApp.export_format',
61 'template' : 'Exporter.template_file',
61 'template' : 'Exporter.template_file',
62 'writer' : 'NbConvertApp.writer_class',
62 'writer' : 'NbConvertApp.writer_class',
63 'post': 'NbConvertApp.post_processor_class',
63 'post': 'NbConvertApp.post_processor_class',
64 'output': 'NbConvertApp.output_base',
64 'output': 'NbConvertApp.output_base',
65 'offline-slides': 'RevealHelpTransformer.url_prefix',
65 'offline-slides': 'RevealHelpTransformer.url_prefix',
66 'slide-notes': 'RevealHelpTransformer.speaker_notes'
66 'slide-notes': 'RevealHelpTransformer.speaker_notes'
67 })
67 })
68
68
69 nbconvert_flags = {}
69 nbconvert_flags = {}
70 nbconvert_flags.update(base_flags)
70 nbconvert_flags.update(base_flags)
71 nbconvert_flags.update({
71 nbconvert_flags.update({
72 'stdout' : (
72 'stdout' : (
73 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
73 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
74 "Write notebook output to stdout instead of files."
74 "Write notebook output to stdout instead of files."
75 )
75 )
76 })
76 })
77
77
78
78
79 class NbConvertApp(BaseIPythonApplication):
79 class NbConvertApp(BaseIPythonApplication):
80 """Application used to convert to and from notebook file type (*.ipynb)"""
80 """Application used to convert to and from notebook file type (*.ipynb)"""
81
81
82 name = 'ipython-nbconvert'
82 name = 'ipython-nbconvert'
83 aliases = nbconvert_aliases
83 aliases = nbconvert_aliases
84 flags = nbconvert_flags
84 flags = nbconvert_flags
85
85
86 def _log_level_default(self):
86 def _log_level_default(self):
87 return logging.INFO
87 return logging.INFO
88
88
89 def _classes_default(self):
89 def _classes_default(self):
90 classes = [NbConvertBase]
90 classes = [NbConvertBase]
91 for pkg in (exporters, transformers, writers):
91 for pkg in (exporters, preprocessors, writers):
92 for name in dir(pkg):
92 for name in dir(pkg):
93 cls = getattr(pkg, name)
93 cls = getattr(pkg, name)
94 if isinstance(cls, type) and issubclass(cls, Configurable):
94 if isinstance(cls, type) and issubclass(cls, Configurable):
95 classes.append(cls)
95 classes.append(cls)
96 return classes
96 return classes
97
97
98 description = Unicode(
98 description = Unicode(
99 u"""This application is used to convert notebook files (*.ipynb)
99 u"""This application is used to convert notebook files (*.ipynb)
100 to various other formats.
100 to various other formats.
101
101
102 WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""")
102 WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""")
103
103
104 output_base = Unicode('', config=True, help='''overwrite base name use for output files.
104 output_base = Unicode('', config=True, help='''overwrite base name use for output files.
105 can only be use when converting one notebook at a time.
105 can only be use when converting one notebook at a time.
106 ''')
106 ''')
107
107
108 examples = Unicode(u"""
108 examples = Unicode(u"""
109 The simplest way to use nbconvert is
109 The simplest way to use nbconvert is
110
110
111 > ipython nbconvert mynotebook.ipynb
111 > ipython nbconvert mynotebook.ipynb
112
112
113 which will convert mynotebook.ipynb to the default format (probably HTML).
113 which will convert mynotebook.ipynb to the default format (probably HTML).
114
114
115 You can specify the export format with `--to`.
115 You can specify the export format with `--to`.
116 Options include {0}
116 Options include {0}
117
117
118 > ipython nbconvert --to latex mynotebook.ipnynb
118 > ipython nbconvert --to latex mynotebook.ipnynb
119
119
120 Both HTML and LaTeX support multiple output templates. LaTeX includes
120 Both HTML and LaTeX support multiple output templates. LaTeX includes
121 'basic', 'book', and 'article'. HTML includes 'basic' and 'full'. You
121 'basic', 'book', and 'article'. HTML includes 'basic' and 'full'. You
122 can specify the flavor of the format used.
122 can specify the flavor of the format used.
123
123
124 > ipython nbconvert --to html --template basic mynotebook.ipynb
124 > ipython nbconvert --to html --template basic mynotebook.ipynb
125
125
126 You can also pipe the output to stdout, rather than a file
126 You can also pipe the output to stdout, rather than a file
127
127
128 > ipython nbconvert mynotebook.ipynb --stdout
128 > ipython nbconvert mynotebook.ipynb --stdout
129
129
130 A post-processor can be used to compile a PDF
130 A post-processor can be used to compile a PDF
131
131
132 > ipython nbconvert mynotebook.ipynb --to latex --post PDF
132 > ipython nbconvert mynotebook.ipynb --to latex --post PDF
133
133
134 You can get (and serve) a Reveal.js-powered slideshow
134 You can get (and serve) a Reveal.js-powered slideshow
135
135
136 > ipython nbconvert myslides.ipynb --to slides --post serve
136 > ipython nbconvert myslides.ipynb --to slides --post serve
137
137
138 Multiple notebooks can be given at the command line in a couple of
138 Multiple notebooks can be given at the command line in a couple of
139 different ways:
139 different ways:
140
140
141 > ipython nbconvert notebook*.ipynb
141 > ipython nbconvert notebook*.ipynb
142 > ipython nbconvert notebook1.ipynb notebook2.ipynb
142 > ipython nbconvert notebook1.ipynb notebook2.ipynb
143
143
144 or you can specify the notebooks list in a config file, containing::
144 or you can specify the notebooks list in a config file, containing::
145
145
146 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
146 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
147
147
148 > ipython nbconvert --config mycfg.py
148 > ipython nbconvert --config mycfg.py
149 """.format(get_export_names()))
149 """.format(get_export_names()))
150
150
151 # Writer specific variables
151 # Writer specific variables
152 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
152 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
153 help="""Instance of the writer class used to write the
153 help="""Instance of the writer class used to write the
154 results of the conversion.""")
154 results of the conversion.""")
155 writer_class = DottedObjectName('FilesWriter', config=True,
155 writer_class = DottedObjectName('FilesWriter', config=True,
156 help="""Writer class used to write the
156 help="""Writer class used to write the
157 results of the conversion""")
157 results of the conversion""")
158 writer_aliases = {'fileswriter': 'IPython.nbconvert.writers.files.FilesWriter',
158 writer_aliases = {'fileswriter': 'IPython.nbconvert.writers.files.FilesWriter',
159 'debugwriter': 'IPython.nbconvert.writers.debug.DebugWriter',
159 'debugwriter': 'IPython.nbconvert.writers.debug.DebugWriter',
160 'stdoutwriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
160 'stdoutwriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
161 writer_factory = Type()
161 writer_factory = Type()
162
162
163 def _writer_class_changed(self, name, old, new):
163 def _writer_class_changed(self, name, old, new):
164 if new.lower() in self.writer_aliases:
164 if new.lower() in self.writer_aliases:
165 new = self.writer_aliases[new.lower()]
165 new = self.writer_aliases[new.lower()]
166 self.writer_factory = import_item(new)
166 self.writer_factory = import_item(new)
167
167
168 # Post-processor specific variables
168 # Post-processor specific variables
169 post_processor = Instance('IPython.nbconvert.post_processors.base.PostProcessorBase',
169 post_processor = Instance('IPython.nbconvert.post_processors.base.PostProcessorBase',
170 help="""Instance of the PostProcessor class used to write the
170 help="""Instance of the PostProcessor class used to write the
171 results of the conversion.""")
171 results of the conversion.""")
172
172
173 post_processor_class = DottedOrNone(config=True,
173 post_processor_class = DottedOrNone(config=True,
174 help="""PostProcessor class used to write the
174 help="""PostProcessor class used to write the
175 results of the conversion""")
175 results of the conversion""")
176 post_processor_aliases = {'pdf': 'IPython.nbconvert.post_processors.pdf.PDFPostProcessor',
176 post_processor_aliases = {'pdf': 'IPython.nbconvert.post_processors.pdf.PDFPostProcessor',
177 'serve': 'IPython.nbconvert.post_processors.serve.ServePostProcessor'}
177 'serve': 'IPython.nbconvert.post_processors.serve.ServePostProcessor'}
178 post_processor_factory = Type()
178 post_processor_factory = Type()
179
179
180 def _post_processor_class_changed(self, name, old, new):
180 def _post_processor_class_changed(self, name, old, new):
181 if new.lower() in self.post_processor_aliases:
181 if new.lower() in self.post_processor_aliases:
182 new = self.post_processor_aliases[new.lower()]
182 new = self.post_processor_aliases[new.lower()]
183 if new:
183 if new:
184 self.post_processor_factory = import_item(new)
184 self.post_processor_factory = import_item(new)
185
185
186
186
187 # Other configurable variables
187 # Other configurable variables
188 export_format = CaselessStrEnum(get_export_names(),
188 export_format = CaselessStrEnum(get_export_names(),
189 default_value="html",
189 default_value="html",
190 config=True,
190 config=True,
191 help="""The export format to be used."""
191 help="""The export format to be used."""
192 )
192 )
193
193
194 notebooks = List([], config=True, help="""List of notebooks to convert.
194 notebooks = List([], config=True, help="""List of notebooks to convert.
195 Wildcards are supported.
195 Wildcards are supported.
196 Filenames passed positionally will be added to the list.
196 Filenames passed positionally will be added to the list.
197 """)
197 """)
198
198
199 @catch_config_error
199 @catch_config_error
200 def initialize(self, argv=None):
200 def initialize(self, argv=None):
201 super(NbConvertApp, self).initialize(argv)
201 super(NbConvertApp, self).initialize(argv)
202 self.init_syspath()
202 self.init_syspath()
203 self.init_notebooks()
203 self.init_notebooks()
204 self.init_writer()
204 self.init_writer()
205 self.init_post_processor()
205 self.init_post_processor()
206
206
207
207
208
208
209 def init_syspath(self):
209 def init_syspath(self):
210 """
210 """
211 Add the cwd to the sys.path ($PYTHONPATH)
211 Add the cwd to the sys.path ($PYTHONPATH)
212 """
212 """
213 sys.path.insert(0, os.getcwd())
213 sys.path.insert(0, os.getcwd())
214
214
215
215
216 def init_notebooks(self):
216 def init_notebooks(self):
217 """Construct the list of notebooks.
217 """Construct the list of notebooks.
218 If notebooks are passed on the command-line,
218 If notebooks are passed on the command-line,
219 they override notebooks specified in config files.
219 they override notebooks specified in config files.
220 Glob each notebook to replace notebook patterns with filenames.
220 Glob each notebook to replace notebook patterns with filenames.
221 """
221 """
222
222
223 # Specifying notebooks on the command-line overrides (rather than adds)
223 # Specifying notebooks on the command-line overrides (rather than adds)
224 # the notebook list
224 # the notebook list
225 if self.extra_args:
225 if self.extra_args:
226 patterns = self.extra_args
226 patterns = self.extra_args
227 else:
227 else:
228 patterns = self.notebooks
228 patterns = self.notebooks
229
229
230 # Use glob to replace all the notebook patterns with filenames.
230 # Use glob to replace all the notebook patterns with filenames.
231 filenames = []
231 filenames = []
232 for pattern in patterns:
232 for pattern in patterns:
233
233
234 # Use glob to find matching filenames. Allow the user to convert
234 # Use glob to find matching filenames. Allow the user to convert
235 # notebooks without having to type the extension.
235 # notebooks without having to type the extension.
236 globbed_files = glob.glob(pattern)
236 globbed_files = glob.glob(pattern)
237 globbed_files.extend(glob.glob(pattern + '.ipynb'))
237 globbed_files.extend(glob.glob(pattern + '.ipynb'))
238 if not globbed_files:
238 if not globbed_files:
239 self.log.warn("pattern %r matched no files", pattern)
239 self.log.warn("pattern %r matched no files", pattern)
240
240
241 for filename in globbed_files:
241 for filename in globbed_files:
242 if not filename in filenames:
242 if not filename in filenames:
243 filenames.append(filename)
243 filenames.append(filename)
244 self.notebooks = filenames
244 self.notebooks = filenames
245
245
246 def init_writer(self):
246 def init_writer(self):
247 """
247 """
248 Initialize the writer (which is stateless)
248 Initialize the writer (which is stateless)
249 """
249 """
250 self._writer_class_changed(None, self.writer_class, self.writer_class)
250 self._writer_class_changed(None, self.writer_class, self.writer_class)
251 self.writer = self.writer_factory(parent=self)
251 self.writer = self.writer_factory(parent=self)
252
252
253 def init_post_processor(self):
253 def init_post_processor(self):
254 """
254 """
255 Initialize the post_processor (which is stateless)
255 Initialize the post_processor (which is stateless)
256 """
256 """
257 self._post_processor_class_changed(None, self.post_processor_class,
257 self._post_processor_class_changed(None, self.post_processor_class,
258 self.post_processor_class)
258 self.post_processor_class)
259 if self.post_processor_factory:
259 if self.post_processor_factory:
260 self.post_processor = self.post_processor_factory(parent=self)
260 self.post_processor = self.post_processor_factory(parent=self)
261
261
262 def start(self):
262 def start(self):
263 """
263 """
264 Ran after initialization completed
264 Ran after initialization completed
265 """
265 """
266 super(NbConvertApp, self).start()
266 super(NbConvertApp, self).start()
267 self.convert_notebooks()
267 self.convert_notebooks()
268
268
269 def convert_notebooks(self):
269 def convert_notebooks(self):
270 """
270 """
271 Convert the notebooks in the self.notebook traitlet
271 Convert the notebooks in the self.notebook traitlet
272 """
272 """
273 # Export each notebook
273 # Export each notebook
274 conversion_success = 0
274 conversion_success = 0
275
275
276 if self.output_base != '' and len(self.notebooks) > 1:
276 if self.output_base != '' and len(self.notebooks) > 1:
277 self.log.error(
277 self.log.error(
278 """UsageError: --output flag or `NbConvertApp.output_base` config option
278 """UsageError: --output flag or `NbConvertApp.output_base` config option
279 cannot be used when converting multiple notebooks.
279 cannot be used when converting multiple notebooks.
280 """)
280 """)
281 self.exit(1)
281 self.exit(1)
282
282
283 exporter = exporter_map[self.export_format](config=self.config)
283 exporter = exporter_map[self.export_format](config=self.config)
284
284
285 for notebook_filename in self.notebooks:
285 for notebook_filename in self.notebooks:
286 self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format)
286 self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format)
287
287
288 # Get a unique key for the notebook and set it in the resources object.
288 # Get a unique key for the notebook and set it in the resources object.
289 basename = os.path.basename(notebook_filename)
289 basename = os.path.basename(notebook_filename)
290 notebook_name = basename[:basename.rfind('.')]
290 notebook_name = basename[:basename.rfind('.')]
291 if self.output_base:
291 if self.output_base:
292 notebook_name = self.output_base
292 notebook_name = self.output_base
293 resources = {}
293 resources = {}
294 resources['unique_key'] = notebook_name
294 resources['unique_key'] = notebook_name
295 resources['output_files_dir'] = '%s_files' % notebook_name
295 resources['output_files_dir'] = '%s_files' % notebook_name
296 self.log.info("Support files will be in %s", os.path.join(resources['output_files_dir'], ''))
296 self.log.info("Support files will be in %s", os.path.join(resources['output_files_dir'], ''))
297
297
298 # Try to export
298 # Try to export
299 try:
299 try:
300 output, resources = exporter.from_filename(notebook_filename, resources=resources)
300 output, resources = exporter.from_filename(notebook_filename, resources=resources)
301 except ConversionException as e:
301 except ConversionException as e:
302 self.log.error("Error while converting '%s'", notebook_filename,
302 self.log.error("Error while converting '%s'", notebook_filename,
303 exc_info=True)
303 exc_info=True)
304 self.exit(1)
304 self.exit(1)
305 else:
305 else:
306 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
306 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
307
307
308 #Post-process if post processor has been defined.
308 #Post-process if post processor has been defined.
309 if hasattr(self, 'post_processor') and self.post_processor:
309 if hasattr(self, 'post_processor') and self.post_processor:
310 self.post_processor(write_resultes)
310 self.post_processor(write_resultes)
311 conversion_success += 1
311 conversion_success += 1
312
312
313 # If nothing was converted successfully, help the user.
313 # If nothing was converted successfully, help the user.
314 if conversion_success == 0:
314 if conversion_success == 0:
315 self.print_help()
315 self.print_help()
316 sys.exit(-1)
316 sys.exit(-1)
317
317
318 #-----------------------------------------------------------------------------
318 #-----------------------------------------------------------------------------
319 # Main entry point
319 # Main entry point
320 #-----------------------------------------------------------------------------
320 #-----------------------------------------------------------------------------
321
321
322 launch_new_instance = NbConvertApp.launch_instance
322 launch_new_instance = NbConvertApp.launch_instance
@@ -1,12 +1,12 b''
1 # Class base Transformers
1 # Class base Preprocessors
2 from .base import Transformer
2 from .base import Preprocessor
3 from .convertfigures import ConvertFiguresTransformer
3 from .convertfigures import ConvertFiguresPreprocessor
4 from .svg2pdf import SVG2PDFTransformer
4 from .svg2pdf import SVG2PDFPreprocessor
5 from .extractoutput import ExtractOutputTransformer
5 from .extractoutput import ExtractOutputPreprocessor
6 from .revealhelp import RevealHelpTransformer
6 from .revealhelp import RevealHelpPreprocessor
7 from .latex import LatexTransformer
7 from .latex import LatexPreprocessor
8 from .sphinx import SphinxTransformer
8 from .sphinx import SphinxPreprocessor
9 from .csshtmlheader import CSSHTMLHeaderTransformer
9 from .csshtmlheader import CSSHTMLHeaderPreprocessor
10
10
11 # decorated function Transformers
11 # decorated function Preprocessors
12 from .coalescestreams import coalesce_streams
12 from .coalescestreams import coalesce_streams
@@ -1,110 +1,110 b''
1 """
1 """
2 Module that re-groups transformer that would be applied to ipynb files
2 Module that re-groups preprocessor that would be applied to ipynb files
3 before going through the templating machinery.
3 before going through the templating machinery.
4
4
5 It exposes a convenient class to inherit from to access configurability.
5 It exposes a convenient class to inherit from to access configurability.
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 from ..utils.base import NbConvertBase
19 from ..utils.base import NbConvertBase
20 from IPython.utils.traitlets import Bool
20 from IPython.utils.traitlets import Bool
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Classes and Functions
23 # Classes and Functions
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 class Transformer(NbConvertBase):
26 class Preprocessor(NbConvertBase):
27 """ A configurable transformer
27 """ A configurable preprocessor
28
28
29 Inherit from this class if you wish to have configurability for your
29 Inherit from this class if you wish to have configurability for your
30 transformer.
30 preprocessor.
31
31
32 Any configurable traitlets this class exposed will be configurable in profiles
32 Any configurable traitlets this class exposed will be configurable in profiles
33 using c.SubClassName.atribute=value
33 using c.SubClassName.atribute=value
34
34
35 you can overwrite :meth:`transform_cell` to apply a transformation independently on each cell
35 you can overwrite :meth:`preprocess_cell` to apply a preprocessation independently on each cell
36 or :meth:`transform` if you prefer your own logic. See corresponding docstring for informations.
36 or :meth:`preprocess` if you prefer your own logic. See corresponding docstring for informations.
37
37
38 Disabled by default and can be enabled via the config by
38 Disabled by default and can be enabled via the config by
39 'c.YourTransformerName.enabled = True'
39 'c.YourPreprocessorName.enabled = True'
40 """
40 """
41
41
42 enabled = Bool(False, config=True)
42 enabled = Bool(False, config=True)
43
43
44 def __init__(self, **kw):
44 def __init__(self, **kw):
45 """
45 """
46 Public constructor
46 Public constructor
47
47
48 Parameters
48 Parameters
49 ----------
49 ----------
50 config : Config
50 config : Config
51 Configuration file structure
51 Configuration file structure
52 **kw : misc
52 **kw : misc
53 Additional arguments
53 Additional arguments
54 """
54 """
55
55
56 super(Transformer, self).__init__(**kw)
56 super(Preprocessor, self).__init__(**kw)
57
57
58
58
59 def __call__(self, nb, resources):
59 def __call__(self, nb, resources):
60 if self.enabled:
60 if self.enabled:
61 return self.transform(nb,resources)
61 return self.preprocess(nb,resources)
62 else:
62 else:
63 return nb, resources
63 return nb, resources
64
64
65
65
66 def transform(self, nb, resources):
66 def preprocess(self, nb, resources):
67 """
67 """
68 Transformation to apply on each notebook.
68 preprocessation to apply on each notebook.
69
69
70 You should return modified nb, resources.
70 You should return modified nb, resources.
71 If you wish to apply your transform on each cell, you might want to
71 If you wish to apply your preprocess on each cell, you might want to
72 overwrite transform_cell method instead.
72 overwrite preprocess_cell method instead.
73
73
74 Parameters
74 Parameters
75 ----------
75 ----------
76 nb : NotebookNode
76 nb : NotebookNode
77 Notebook being converted
77 Notebook being converted
78 resources : dictionary
78 resources : dictionary
79 Additional resources used in the conversion process. Allows
79 Additional resources used in the conversion process. Allows
80 transformers to pass variables into the Jinja engine.
80 preprocessors to pass variables into the Jinja engine.
81 """
81 """
82 self.log.debug("Applying transform: %s", self.__class__.__name__)
82 self.log.debug("Applying preprocess: %s", self.__class__.__name__)
83 try :
83 try :
84 for worksheet in nb.worksheets:
84 for worksheet in nb.worksheets:
85 for index, cell in enumerate(worksheet.cells):
85 for index, cell in enumerate(worksheet.cells):
86 worksheet.cells[index], resources = self.transform_cell(cell, resources, index)
86 worksheet.cells[index], resources = self.preprocess_cell(cell, resources, index)
87 return nb, resources
87 return nb, resources
88 except NotImplementedError:
88 except NotImplementedError:
89 raise NotImplementedError('should be implemented by subclass')
89 raise NotImplementedError('should be implemented by subclass')
90
90
91
91
92 def transform_cell(self, cell, resources, index):
92 def preprocess_cell(self, cell, resources, index):
93 """
93 """
94 Overwrite if you want to apply a transformation on each cell. You
94 Overwrite if you want to apply a preprocessation on each cell. You
95 should return modified cell and resource dictionary.
95 should return modified cell and resource dictionary.
96
96
97 Parameters
97 Parameters
98 ----------
98 ----------
99 cell : NotebookNode cell
99 cell : NotebookNode cell
100 Notebook cell being processed
100 Notebook cell being processed
101 resources : dictionary
101 resources : dictionary
102 Additional resources used in the conversion process. Allows
102 Additional resources used in the conversion process. Allows
103 transformers to pass variables into the Jinja engine.
103 preprocessors to pass variables into the Jinja engine.
104 index : int
104 index : int
105 Index of the cell being processed
105 Index of the cell being processed
106 """
106 """
107
107
108 raise NotImplementedError('should be implemented by subclass')
108 raise NotImplementedError('should be implemented by subclass')
109 return cell, resources
109 return cell, resources
110
110
@@ -1,75 +1,75 b''
1 """Module that allows latex output notebooks to be conditioned before
1 """Module that allows latex output notebooks to be conditioned before
2 they are converted. Exposes a decorator (@cell_preprocessor) in
2 they are converted. Exposes a decorator (@cell_preprocessor) in
3 addition to the coalesce_streams pre-proccessor.
3 addition to the coalesce_streams pre-proccessor.
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 # Functions
14 # Functions
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 def cell_preprocessor(function):
17 def cell_preprocessor(function):
18 """
18 """
19 Wrap a function to be executed on all cells of a notebook
19 Wrap a function to be executed on all cells of a notebook
20
20
21 Wrapped Parameters
21 Wrapped Parameters
22 ----------
22 ----------
23 cell : NotebookNode cell
23 cell : NotebookNode cell
24 Notebook cell being processed
24 Notebook cell being processed
25 resources : dictionary
25 resources : dictionary
26 Additional resources used in the conversion process. Allows
26 Additional resources used in the conversion process. Allows
27 transformers to pass variables into the Jinja engine.
27 preprocessors to pass variables into the Jinja engine.
28 index : int
28 index : int
29 Index of the cell being processed
29 Index of the cell being processed
30 """
30 """
31
31
32 def wrappedfunc(nb, resources):
32 def wrappedfunc(nb, resources):
33 for worksheet in nb.worksheets :
33 for worksheet in nb.worksheets :
34 for index, cell in enumerate(worksheet.cells):
34 for index, cell in enumerate(worksheet.cells):
35 worksheet.cells[index], resources = function(cell, resources, index)
35 worksheet.cells[index], resources = function(cell, resources, index)
36 return nb, resources
36 return nb, resources
37 return wrappedfunc
37 return wrappedfunc
38
38
39
39
40 @cell_preprocessor
40 @cell_preprocessor
41 def coalesce_streams(cell, resources, index):
41 def coalesce_streams(cell, resources, index):
42 """
42 """
43 Merge consecutive sequences of stream output into single stream
43 Merge consecutive sequences of stream output into single stream
44 to prevent extra newlines inserted at flush calls
44 to prevent extra newlines inserted at flush calls
45
45
46 Parameters
46 Parameters
47 ----------
47 ----------
48 cell : NotebookNode cell
48 cell : NotebookNode cell
49 Notebook cell being processed
49 Notebook cell being processed
50 resources : dictionary
50 resources : dictionary
51 Additional resources used in the conversion process. Allows
51 Additional resources used in the conversion process. Allows
52 transformers to pass variables into the Jinja engine.
52 transformers to pass variables into the Jinja engine.
53 index : int
53 index : int
54 Index of the cell being processed
54 Index of the cell being processed
55 """
55 """
56
56
57 outputs = cell.get('outputs', [])
57 outputs = cell.get('outputs', [])
58 if not outputs:
58 if not outputs:
59 return cell, resources
59 return cell, resources
60
60
61 last = outputs[0]
61 last = outputs[0]
62 new_outputs = [last]
62 new_outputs = [last]
63
63
64 for output in outputs[1:]:
64 for output in outputs[1:]:
65 if (output.output_type == 'stream' and
65 if (output.output_type == 'stream' and
66 last.output_type == 'stream' and
66 last.output_type == 'stream' and
67 last.stream == output.stream
67 last.stream == output.stream
68 ):
68 ):
69 last.text += output.text
69 last.text += output.text
70 else:
70 else:
71 new_outputs.append(output)
71 new_outputs.append(output)
72 last = output
72 last = output
73
73
74 cell.outputs = new_outputs
74 cell.outputs = new_outputs
75 return cell, resources
75 return cell, resources
@@ -1,64 +1,64 b''
1 """Module containing a transformer that converts outputs in the notebook from
1 """Module containing a preprocessor that converts outputs in the notebook from
2 one format to another.
2 one format to another.
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 .base import Transformer
16 from .base import Preprocessor
17 from IPython.utils.traitlets import Unicode
17 from IPython.utils.traitlets import Unicode
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Classes
20 # Classes
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 class ConvertFiguresTransformer(Transformer):
23 class ConvertFiguresPreprocessor(Preprocessor):
24 """
24 """
25 Converts all of the outputs in a notebook from one format to another.
25 Converts all of the outputs in a notebook from one format to another.
26 """
26 """
27
27
28 from_format = Unicode(config=True, help='Format the converter accepts')
28 from_format = Unicode(config=True, help='Format the converter accepts')
29 to_format = Unicode(config=True, help='Format the converter writes')
29 to_format = Unicode(config=True, help='Format the converter writes')
30
30
31 def __init__(self, **kw):
31 def __init__(self, **kw):
32 """
32 """
33 Public constructor
33 Public constructor
34 """
34 """
35 super(ConvertFiguresTransformer, self).__init__(**kw)
35 super(ConvertFiguresPreprocessor, self).__init__(**kw)
36
36
37
37
38 def convert_figure(self, data_format, data):
38 def convert_figure(self, data_format, data):
39 raise NotImplementedError()
39 raise NotImplementedError()
40
40
41
41
42 def transform_cell(self, cell, resources, cell_index):
42 def preprocess_cell(self, cell, resources, cell_index):
43 """
43 """
44 Apply a transformation on each cell,
44 Apply a transformation on each cell,
45
45
46 See base.py
46 See base.py
47 """
47 """
48
48
49 # Loop through all of the datatypes of the outputs in the cell.
49 # Loop through all of the datatypes of the outputs in the cell.
50 for index, cell_out in enumerate(cell.get('outputs', [])):
50 for index, cell_out in enumerate(cell.get('outputs', [])):
51 for data_type, data in cell_out.items():
51 for data_type, data in cell_out.items():
52 # this must run *before* extract outputs,
52 # this must run *before* extract outputs,
53 # so figure_name and filename do not exist
53 # so figure_name and filename do not exist
54 self._convert_figure(cell_out, resources, data_type, data)
54 self._convert_figure(cell_out, resources, data_type, data)
55 return cell, resources
55 return cell, resources
56
56
57
57
58 def _convert_figure(self, cell_out, resources, data_type, data):
58 def _convert_figure(self, cell_out, resources, data_type, data):
59 """
59 """
60 Convert a figure and output the results to the cell output
60 Convert a figure and output the results to the cell output
61 """
61 """
62 if not self.to_format in cell_out and data_type == self.from_format:
62 if not self.to_format in cell_out and data_type == self.from_format:
63 data = self.convert_figure(data_type, data)
63 data = self.convert_figure(data_type, data)
64 cell_out[self.to_format] = data
64 cell_out[self.to_format] = data
@@ -1,106 +1,106 b''
1 """Module that pre-processes the notebook for export to HTML.
1 """Module that pre-processes the notebook for export to HTML.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import os
15 import os
16 import io
16 import io
17
17
18 from pygments.formatters import HtmlFormatter
18 from pygments.formatters import HtmlFormatter
19
19
20 from IPython.utils import path
20 from IPython.utils import path
21
21
22 from .base import Transformer
22 from .base import Preprocessor
23
23
24 from IPython.utils.traitlets import Unicode
24 from IPython.utils.traitlets import Unicode
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Classes and functions
27 # Classes and functions
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class CSSHTMLHeaderTransformer(Transformer):
30 class CSSHTMLHeaderPreprocessor(Preprocessor):
31 """
31 """
32 Transformer used to pre-process notebook for HTML output. Adds IPython notebook
32 Preprocessor used to pre-process notebook for HTML output. Adds IPython notebook
33 front-end CSS and Pygments CSS to HTML output.
33 front-end CSS and Pygments CSS to HTML output.
34 """
34 """
35
35
36 header = []
36 header = []
37
37
38 highlight_class = Unicode('.highlight', config=True,
38 highlight_class = Unicode('.highlight', config=True,
39 help="CSS highlight class identifier")
39 help="CSS highlight class identifier")
40
40
41 def __init__(self, config=None, **kw):
41 def __init__(self, config=None, **kw):
42 """
42 """
43 Public constructor
43 Public constructor
44
44
45 Parameters
45 Parameters
46 ----------
46 ----------
47 config : Config
47 config : Config
48 Configuration file structure
48 Configuration file structure
49 **kw : misc
49 **kw : misc
50 Additional arguments
50 Additional arguments
51 """
51 """
52
52
53 super(CSSHTMLHeaderTransformer, self).__init__(config=config, **kw)
53 super(CSSHTMLHeaderPreprocessor, self).__init__(config=config, **kw)
54
54
55 if self.enabled :
55 if self.enabled :
56 self._regen_header()
56 self._regen_header()
57
57
58
58
59 def transform(self, nb, resources):
59 def preprocess(self, nb, resources):
60 """Fetch and add CSS to the resource dictionary
60 """Fetch and add CSS to the resource dictionary
61
61
62 Fetch CSS from IPython and Pygments to add at the beginning
62 Fetch CSS from IPython and Pygments to add at the beginning
63 of the html files. Add this css in resources in the
63 of the html files. Add this css in resources in the
64 "inlining.css" key
64 "inlining.css" key
65
65
66 Parameters
66 Parameters
67 ----------
67 ----------
68 nb : NotebookNode
68 nb : NotebookNode
69 Notebook being converted
69 Notebook being converted
70 resources : dictionary
70 resources : dictionary
71 Additional resources used in the conversion process. Allows
71 Additional resources used in the conversion process. Allows
72 transformers to pass variables into the Jinja engine.
72 preprocessors to pass variables into the Jinja engine.
73 """
73 """
74
74
75 resources['inlining'] = {}
75 resources['inlining'] = {}
76 resources['inlining']['css'] = self.header
76 resources['inlining']['css'] = self.header
77
77
78 return nb, resources
78 return nb, resources
79
79
80
80
81 def _regen_header(self):
81 def _regen_header(self):
82 """
82 """
83 Fills self.header with lines of CSS extracted from IPython
83 Fills self.header with lines of CSS extracted from IPython
84 and Pygments.
84 and Pygments.
85 """
85 """
86
86
87 #Clear existing header.
87 #Clear existing header.
88 header = []
88 header = []
89
89
90 #Construct path to IPy CSS
90 #Construct path to IPy CSS
91 sheet_filename = os.path.join(path.get_ipython_package_dir(),
91 sheet_filename = os.path.join(path.get_ipython_package_dir(),
92 'html', 'static', 'style', 'style.min.css')
92 'html', 'static', 'style', 'style.min.css')
93
93
94 #Load style CSS file.
94 #Load style CSS file.
95 with io.open(sheet_filename, encoding='utf-8') as file:
95 with io.open(sheet_filename, encoding='utf-8') as file:
96 file_text = file.read()
96 file_text = file.read()
97 header.append(file_text)
97 header.append(file_text)
98
98
99 #Add pygments CSS
99 #Add pygments CSS
100 formatter = HtmlFormatter()
100 formatter = HtmlFormatter()
101 pygments_css = formatter.get_style_defs(self.highlight_class)
101 pygments_css = formatter.get_style_defs(self.highlight_class)
102 header.append(pygments_css)
102 header.append(pygments_css)
103
103
104 #Set header
104 #Set header
105 self.header = header
105 self.header = header
106
106
@@ -1,102 +1,102 b''
1 """Module containing a transformer that extracts all of the outputs from the
1 """Module containing a preprocessor that extracts all of the outputs from the
2 notebook file. The extracted outputs 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 Preprocessor
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 ExtractOutputTransformer(Transformer):
28 class ExtractOutputPreprocessor(Preprocessor):
29 """
29 """
30 Extracts all of the outputs from the notebook file. The extracted
30 Extracts all of the outputs from the notebook file. The extracted
31 outputs are returned in the 'resources' dictionary.
31 outputs are returned in the 'resources' dictionary.
32 """
32 """
33
33
34 output_filename_template = Unicode(
34 output_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 preprocess_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 preprocessors 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 'output' as the default. Also, get files directory if it
54 #exist, use 'output' as the default. Also, get files directory if it
55 #has been specified
55 #has been specified
56 unique_key = resources.get('unique_key', 'output')
56 unique_key = resources.get('unique_key', 'output')
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 outputs key exists
59 #Make sure outputs key exists
60 if not isinstance(resources['outputs'], dict):
60 if not isinstance(resources['outputs'], dict):
61 resources['outputs'] = {}
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
73
74 # data is b64-encoded as text (str, unicode)
74 # data is b64-encoded as text (str, unicode)
75 # decodestring only accepts bytes
75 # decodestring only accepts bytes
76 data = py3compat.cast_bytes(data)
76 data = py3compat.cast_bytes(data)
77 data = base64.decodestring(data)
77 data = base64.decodestring(data)
78 elif sys.platform == 'win32':
78 elif sys.platform == 'win32':
79 data = data.replace('\n', '\r\n').encode("UTF-8")
79 data = data.replace('\n', '\r\n').encode("UTF-8")
80 else:
80 else:
81 data = data.encode("UTF-8")
81 data = data.encode("UTF-8")
82
82
83 #Build an output name
83 #Build an output name
84 filename = self.output_filename_template.format(
84 filename = self.output_filename_template.format(
85 unique_key=unique_key,
85 unique_key=unique_key,
86 cell_index=cell_index,
86 cell_index=cell_index,
87 index=index,
87 index=index,
88 extension=out_type)
88 extension=out_type)
89
89
90 #On the cell, make the figure available via
90 #On the cell, make the figure available via
91 # cell.outputs[i].svg_filename ... etc (svg in example)
91 # cell.outputs[i].svg_filename ... etc (svg in example)
92 # Where
92 # Where
93 # cell.outputs[i].svg contains the data
93 # cell.outputs[i].svg contains the data
94 if output_files_dir is not None:
94 if output_files_dir is not None:
95 filename = os.path.join(output_files_dir, filename)
95 filename = os.path.join(output_files_dir, filename)
96 out[out_type + '_filename'] = filename
96 out[out_type + '_filename'] = filename
97
97
98 #In the resources, make the figure available via
98 #In the resources, make the figure available via
99 # resources['outputs']['filename'] = data
99 # resources['outputs']['filename'] = data
100 resources['outputs'][filename] = data
100 resources['outputs'][filename] = data
101
101
102 return cell, resources
102 return cell, resources
@@ -1,53 +1,53 b''
1 """Module that allows latex output notebooks to be conditioned before
1 """Module that allows latex output notebooks to be conditioned before
2 they are converted.
2 they are converted.
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 __future__ import print_function, absolute_import
16 from __future__ import print_function, absolute_import
17
17
18 # Our own imports
18 # Our own imports
19 # Needed to override transformer
19 # Needed to override preprocessor
20 from .base import (Transformer)
20 from .base import (Preprocessor)
21 from IPython.nbconvert import filters
21 from IPython.nbconvert import filters
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Classes
24 # Classes
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 class LatexTransformer(Transformer):
27 class LatexPreprocessor(Preprocessor):
28 """
28 """
29 Converter for latex destined documents.
29 Converter for latex destined documents.
30 """
30 """
31
31
32 def transform_cell(self, cell, resources, index):
32 def preprocess_cell(self, cell, resources, index):
33 """
33 """
34 Apply a transformation on each cell,
34 Apply a preprocessation on each cell,
35
35
36 Parameters
36 Parameters
37 ----------
37 ----------
38 cell : NotebookNode cell
38 cell : NotebookNode cell
39 Notebook cell being processed
39 Notebook cell being processed
40 resources : dictionary
40 resources : dictionary
41 Additional resources used in the conversion process. Allows
41 Additional resources used in the conversion process. Allows
42 transformers to pass variables into the Jinja engine.
42 preprocessors to pass variables into the Jinja engine.
43 index : int
43 index : int
44 Modified index of the cell being processed (see base.py)
44 Modified index of the cell being processed (see base.py)
45 """
45 """
46
46
47 #If the cell is a markdown cell, preprocess the ampersands used to
47 #If the cell is a markdown cell, preprocess the ampersands used to
48 #remove the space between them and their contents. Latex will complain
48 #remove the space between them and their contents. Latex will complain
49 #if spaces exist between the ampersands and the math content.
49 #if spaces exist between the ampersands and the math content.
50 #See filters.latex.rm_math_space for more information.
50 #See filters.latex.rm_math_space for more information.
51 if hasattr(cell, "source") and cell.cell_type == "markdown":
51 if hasattr(cell, "source") and cell.cell_type == "markdown":
52 cell.source = filters.strip_math_space(cell.source)
52 cell.source = filters.strip_math_space(cell.source)
53 return cell, resources
53 return cell, resources
@@ -1,94 +1,94 b''
1 """Module that pre-processes the notebook for export via Reveal.
1 """Module that pre-processes the notebook for export via Reveal.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import os
15 import os
16 import urllib2
16 import urllib2
17
17
18 from .base import Transformer
18 from .base import Preprocessor
19 from IPython.utils.traitlets import Unicode, Bool
19 from IPython.utils.traitlets import Unicode, Bool
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Classes and functions
22 # Classes and functions
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class RevealHelpTransformer(Transformer):
25 class RevealHelpPreprocessor(Preprocessor):
26
26
27 url_prefix = Unicode('//cdn.jsdelivr.net/reveal.js/2.4.0',
27 url_prefix = Unicode('//cdn.jsdelivr.net/reveal.js/2.4.0',
28 config=True,
28 config=True,
29 help="""If you want to use a local reveal.js library,
29 help="""If you want to use a local reveal.js library,
30 use 'url_prefix':'reveal.js' in your config object.""")
30 use 'url_prefix':'reveal.js' in your config object.""")
31
31
32 speaker_notes = Bool(False,
32 speaker_notes = Bool(False,
33 config=True,
33 config=True,
34 help="""If you want to use the speaker notes
34 help="""If you want to use the speaker notes
35 set this to True.""")
35 set this to True.""")
36
36
37 def transform(self, nb, resources):
37 def preprocess(self, nb, resources):
38 """
38 """
39 Called once to 'transform' contents of the notebook.
39 Called once to 'preprocess' contents of the notebook.
40
40
41 Parameters
41 Parameters
42 ----------
42 ----------
43 nb : NotebookNode
43 nb : NotebookNode
44 Notebook being converted
44 Notebook being converted
45 resources : dictionary
45 resources : dictionary
46 Additional resources used in the conversion process. Allows
46 Additional resources used in the conversion process. Allows
47 transformers to pass variables into the Jinja engine.
47 preprocessors to pass variables into the Jinja engine.
48 """
48 """
49
49
50 for worksheet in nb.worksheets :
50 for worksheet in nb.worksheets :
51 for index, cell in enumerate(worksheet.cells):
51 for index, cell in enumerate(worksheet.cells):
52
52
53 #Make sure the cell has slideshow metadata.
53 #Make sure the cell has slideshow metadata.
54 cell.metadata.align_type = cell.get('metadata', {}).get('slideshow', {}).get('align_type', 'Left')
54 cell.metadata.align_type = cell.get('metadata', {}).get('slideshow', {}).get('align_type', 'Left')
55 cell.metadata.slide_type = cell.get('metadata', {}).get('slideshow', {}).get('slide_type', '-')
55 cell.metadata.slide_type = cell.get('metadata', {}).get('slideshow', {}).get('slide_type', '-')
56
56
57 #Get the slide type. If type is start of subslide or slide,
57 #Get the slide type. If type is start of subslide or slide,
58 #end the last subslide/slide.
58 #end the last subslide/slide.
59 if cell.metadata.slide_type in ['slide']:
59 if cell.metadata.slide_type in ['slide']:
60 worksheet.cells[index - 1].metadata.slide_helper = 'slide_end'
60 worksheet.cells[index - 1].metadata.slide_helper = 'slide_end'
61 if cell.metadata.slide_type in ['subslide']:
61 if cell.metadata.slide_type in ['subslide']:
62 worksheet.cells[index - 1].metadata.slide_helper = 'subslide_end'
62 worksheet.cells[index - 1].metadata.slide_helper = 'subslide_end'
63
63
64
64
65 if not isinstance(resources['reveal'], dict):
65 if not isinstance(resources['reveal'], dict):
66 resources['reveal'] = {}
66 resources['reveal'] = {}
67 resources['reveal']['url_prefix'] = self.url_prefix
67 resources['reveal']['url_prefix'] = self.url_prefix
68 resources['reveal']['notes_prefix'] = self.url_prefix
68 resources['reveal']['notes_prefix'] = self.url_prefix
69
69
70 cdn = 'http://cdn.jsdelivr.net/reveal.js/2.4.0'
70 cdn = 'http://cdn.jsdelivr.net/reveal.js/2.4.0'
71 local = 'local'
71 local = 'local'
72 html_path = 'plugin/notes/notes.html'
72 html_path = 'plugin/notes/notes.html'
73 js_path = 'plugin/notes/notes.js'
73 js_path = 'plugin/notes/notes.js'
74
74
75 html_infile = os.path.join(cdn, html_path)
75 html_infile = os.path.join(cdn, html_path)
76 js_infile = os.path.join(cdn, js_path)
76 js_infile = os.path.join(cdn, js_path)
77 html_outfile = os.path.join(local, html_path)
77 html_outfile = os.path.join(local, html_path)
78 js_outfile = os.path.join(local, js_path)
78 js_outfile = os.path.join(local, js_path)
79
79
80 if self.speaker_notes:
80 if self.speaker_notes:
81 if 'outputs' not in resources:
81 if 'outputs' not in resources:
82 resources['outputs'] = {}
82 resources['outputs'] = {}
83 resources['outputs'][html_outfile] = self.notes_helper(html_infile)
83 resources['outputs'][html_outfile] = self.notes_helper(html_infile)
84 resources['outputs'][js_outfile] = self.notes_helper(js_infile)
84 resources['outputs'][js_outfile] = self.notes_helper(js_infile)
85 resources['reveal']['notes_prefix'] = local
85 resources['reveal']['notes_prefix'] = local
86
86
87 return nb, resources
87 return nb, resources
88
88
89 def notes_helper(self, infile):
89 def notes_helper(self, infile):
90 """Helper function to get the content from an url."""
90 """Helper function to get the content from an url."""
91
91
92 content = urllib2.urlopen(infile).read()
92 content = urllib2.urlopen(infile).read()
93
93
94 return content
94 return content
@@ -1,264 +1,264 b''
1 """Module that allows custom Sphinx parameters to be set on the notebook and
1 """Module that allows custom Sphinx parameters to be set on the notebook and
2 on the 'other' object passed into Jinja. Called prior to Jinja conversion
2 on the 'other' object passed into Jinja. Called prior to Jinja conversion
3 process.
3 process.
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 os.path
20 import os.path
21
21
22 # Used to set the default date to today's date
22 # Used to set the default date to today's date
23 from datetime import date
23 from datetime import date
24
24
25 # Third-party imports
25 # Third-party imports
26 # Needed for Pygments latex definitions.
26 # Needed for Pygments latex definitions.
27 from pygments.formatters import LatexFormatter
27 from pygments.formatters import LatexFormatter
28
28
29 # Our own imports
29 # Our own imports
30 # Configurable traitlets
30 # Configurable traitlets
31 from IPython.utils.traitlets import Unicode, Bool
31 from IPython.utils.traitlets import Unicode, Bool
32
32
33 # Needed to override transformer
33 # Needed to override preprocessor
34 from .base import (Transformer)
34 from .base import (Preprocessor)
35
35
36 from IPython.nbconvert.utils import console
36 from IPython.nbconvert.utils import console
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Classes and functions
39 # Classes and functions
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 class SphinxTransformer(Transformer):
42 class SphinxPreprocessor(Preprocessor):
43 """
43 """
44 Sphinx utility transformer.
44 Sphinx utility preprocessor.
45
45
46 This transformer is used to set variables needed by the latex to build
46 This preprocessor is used to set variables needed by the latex to build
47 Sphinx stylized templates.
47 Sphinx stylized templates.
48 """
48 """
49
49
50 interactive = Bool(False, config=True, help="""
50 interactive = Bool(False, config=True, help="""
51 Allows you to define whether or not the Sphinx exporter will prompt
51 Allows you to define whether or not the Sphinx exporter will prompt
52 you for input during the conversion process. If this is set to false,
52 you for input during the conversion process. If this is set to false,
53 the author, version, release, date, and chapter_style traits should
53 the author, version, release, date, and chapter_style traits should
54 be set.
54 be set.
55 """)
55 """)
56
56
57 author = Unicode("Unknown Author", config=True, help="Author name")
57 author = Unicode("Unknown Author", config=True, help="Author name")
58
58
59 version = Unicode("", config=True, help="""
59 version = Unicode("", config=True, help="""
60 Version number
60 Version number
61 You can leave this blank if you do not want to render a version number.
61 You can leave this blank if you do not want to render a version number.
62 Example: "1.0.0"
62 Example: "1.0.0"
63 """)
63 """)
64
64
65 release = Unicode("", config=True, help="""
65 release = Unicode("", config=True, help="""
66 Release name
66 Release name
67 You can leave this blank if you do not want to render a release name.
67 You can leave this blank if you do not want to render a release name.
68 Example: "Rough Draft"
68 Example: "Rough Draft"
69 """)
69 """)
70
70
71 publish_date = Unicode("", config=True, help="""
71 publish_date = Unicode("", config=True, help="""
72 Publish date
72 Publish date
73 This is the date to render on the document as the publish date.
73 This is the date to render on the document as the publish date.
74 Leave this blank to default to todays date.
74 Leave this blank to default to todays date.
75 Example: "June 12, 1990"
75 Example: "June 12, 1990"
76 """)
76 """)
77
77
78 chapter_style = Unicode("Bjarne", config=True, help="""
78 chapter_style = Unicode("Bjarne", config=True, help="""
79 Sphinx chapter style
79 Sphinx chapter style
80 This is the style to use for the chapter headers in the document.
80 This is the style to use for the chapter headers in the document.
81 You may choose one of the following:
81 You may choose one of the following:
82 "Bjarne" (default)
82 "Bjarne" (default)
83 "Lenny"
83 "Lenny"
84 "Glenn"
84 "Glenn"
85 "Conny"
85 "Conny"
86 "Rejne"
86 "Rejne"
87 "Sonny" (used for international documents)
87 "Sonny" (used for international documents)
88 """)
88 """)
89
89
90 output_style = Unicode("notebook", config=True, help="""
90 output_style = Unicode("notebook", config=True, help="""
91 Nbconvert Ipython
91 Nbconvert Ipython
92 notebook input/output formatting style.
92 notebook input/output formatting style.
93 You may choose one of the following:
93 You may choose one of the following:
94 "simple (recommended for long code segments)"
94 "simple (recommended for long code segments)"
95 "notebook" (default)
95 "notebook" (default)
96 """)
96 """)
97
97
98 center_output = Bool(False, config=True, help="""
98 center_output = Bool(False, config=True, help="""
99 Optional attempt to center all output. If this is false, no additional
99 Optional attempt to center all output. If this is false, no additional
100 formatting is applied.
100 formatting is applied.
101 """)
101 """)
102
102
103 use_headers = Bool(True, config=True, help="""
103 use_headers = Bool(True, config=True, help="""
104 Whether not a header should be added to the document.
104 Whether not a header should be added to the document.
105 """)
105 """)
106
106
107 #Allow the user to override the title of the notebook (useful for
107 #Allow the user to override the title of the notebook (useful for
108 #fancy document titles that the file system doesn't support.)
108 #fancy document titles that the file system doesn't support.)
109 overridetitle = Unicode("", config=True, help="")
109 overridetitle = Unicode("", config=True, help="")
110
110
111
111
112 def transform(self, nb, resources):
112 def preprocess(self, nb, resources):
113 """
113 """
114 Sphinx transformation to apply on each notebook.
114 Sphinx preprocessing to apply on each notebook.
115
115
116 Parameters
116 Parameters
117 ----------
117 ----------
118 nb : NotebookNode
118 nb : NotebookNode
119 Notebook being converted
119 Notebook being converted
120 resources : dictionary
120 resources : dictionary
121 Additional resources used in the conversion process. Allows
121 Additional resources used in the conversion process. Allows
122 transformers to pass variables into the Jinja engine.
122 preprocessors to pass variables into the Jinja engine.
123 """
123 """
124 # import sphinx here, so that sphinx is not a dependency when it's not used
124 # import sphinx here, so that sphinx is not a dependency when it's not used
125 import sphinx
125 import sphinx
126
126
127 # TODO: Add versatile method of additional notebook metadata. Include
127 # TODO: Add versatile method of additional notebook metadata. Include
128 # handling of multiple files. For now use a temporay namespace,
128 # handling of multiple files. For now use a temporay namespace,
129 # '_draft' to signify that this needs to change.
129 # '_draft' to signify that this needs to change.
130 if not isinstance(resources["sphinx"], dict):
130 if not isinstance(resources["sphinx"], dict):
131 resources["sphinx"] = {}
131 resources["sphinx"] = {}
132
132
133 if self.interactive:
133 if self.interactive:
134
134
135 # Prompt the user for additional meta data that doesn't exist currently
135 # Prompt the user for additional meta data that doesn't exist currently
136 # but would be usefull for Sphinx.
136 # but would be usefull for Sphinx.
137 resources["sphinx"]["author"] = self._prompt_author()
137 resources["sphinx"]["author"] = self._prompt_author()
138 resources["sphinx"]["version"] = self._prompt_version()
138 resources["sphinx"]["version"] = self._prompt_version()
139 resources["sphinx"]["release"] = self._prompt_release()
139 resources["sphinx"]["release"] = self._prompt_release()
140 resources["sphinx"]["date"] = self._prompt_date()
140 resources["sphinx"]["date"] = self._prompt_date()
141
141
142 # Prompt the user for the document style.
142 # Prompt the user for the document style.
143 resources["sphinx"]["chapterstyle"] = self._prompt_chapter_title_style()
143 resources["sphinx"]["chapterstyle"] = self._prompt_chapter_title_style()
144 resources["sphinx"]["outputstyle"] = self._prompt_output_style()
144 resources["sphinx"]["outputstyle"] = self._prompt_output_style()
145
145
146 # Small options
146 # Small options
147 resources["sphinx"]["centeroutput"] = console.prompt_boolean("Do you want to center the output? (false)", False)
147 resources["sphinx"]["centeroutput"] = console.prompt_boolean("Do you want to center the output? (false)", False)
148 resources["sphinx"]["header"] = console.prompt_boolean("Should a Sphinx document header be used? (true)", True)
148 resources["sphinx"]["header"] = console.prompt_boolean("Should a Sphinx document header be used? (true)", True)
149 else:
149 else:
150
150
151 # Try to use the traitlets.
151 # Try to use the traitlets.
152 resources["sphinx"]["author"] = self.author
152 resources["sphinx"]["author"] = self.author
153 resources["sphinx"]["version"] = self.version
153 resources["sphinx"]["version"] = self.version
154 resources["sphinx"]["release"] = self.release
154 resources["sphinx"]["release"] = self.release
155
155
156 # Use todays date if none is provided.
156 # Use todays date if none is provided.
157 if self.publish_date:
157 if self.publish_date:
158 resources["sphinx"]["date"] = self.publish_date
158 resources["sphinx"]["date"] = self.publish_date
159 elif len(resources['metadata']['modified_date'].strip()) == 0:
159 elif len(resources['metadata']['modified_date'].strip()) == 0:
160 resources["sphinx"]["date"] = date.today().strftime("%B %-d, %Y")
160 resources["sphinx"]["date"] = date.today().strftime("%B %-d, %Y")
161 else:
161 else:
162 resources["sphinx"]["date"] = resources['metadata']['modified_date']
162 resources["sphinx"]["date"] = resources['metadata']['modified_date']
163
163
164 # Sphinx traitlets.
164 # Sphinx traitlets.
165 resources["sphinx"]["chapterstyle"] = self.chapter_style
165 resources["sphinx"]["chapterstyle"] = self.chapter_style
166 resources["sphinx"]["outputstyle"] = self.output_style
166 resources["sphinx"]["outputstyle"] = self.output_style
167 resources["sphinx"]["centeroutput"] = self.center_output
167 resources["sphinx"]["centeroutput"] = self.center_output
168 resources["sphinx"]["header"] = self.use_headers
168 resources["sphinx"]["header"] = self.use_headers
169
169
170 # Find and pass in the path to the Sphinx dependencies.
170 # Find and pass in the path to the Sphinx dependencies.
171 resources["sphinx"]["texinputs"] = os.path.realpath(os.path.join(sphinx.package_dir, "texinputs"))
171 resources["sphinx"]["texinputs"] = os.path.realpath(os.path.join(sphinx.package_dir, "texinputs"))
172
172
173 # Generate Pygments definitions for Latex
173 # Generate Pygments definitions for Latex
174 resources["sphinx"]["pygment_definitions"] = self._generate_pygments_latex_def()
174 resources["sphinx"]["pygment_definitions"] = self._generate_pygments_latex_def()
175
175
176 if not (self.overridetitle == None or len(self.overridetitle.strip()) == 0):
176 if not (self.overridetitle == None or len(self.overridetitle.strip()) == 0):
177 resources['metadata']['name'] = self.overridetitle
177 resources['metadata']['name'] = self.overridetitle
178
178
179 # End
179 # End
180 return nb, resources
180 return nb, resources
181
181
182
182
183 def _generate_pygments_latex_def(self):
183 def _generate_pygments_latex_def(self):
184 """
184 """
185 Generate the pygments latex definitions that allows pygments
185 Generate the pygments latex definitions that allows pygments
186 to work in latex.
186 to work in latex.
187 """
187 """
188
188
189 return LatexFormatter().get_style_defs()
189 return LatexFormatter().get_style_defs()
190
190
191
191
192 def _prompt_author(self):
192 def _prompt_author(self):
193 """
193 """
194 Prompt the user to input an Author name
194 Prompt the user to input an Author name
195 """
195 """
196 return console.input("Author name: ")
196 return console.input("Author name: ")
197
197
198
198
199 def _prompt_version(self):
199 def _prompt_version(self):
200 """
200 """
201 prompt the user to enter a version number
201 prompt the user to enter a version number
202 """
202 """
203 return console.input("Version (ie ""1.0.0""): ")
203 return console.input("Version (ie ""1.0.0""): ")
204
204
205
205
206 def _prompt_release(self):
206 def _prompt_release(self):
207 """
207 """
208 Prompt the user to input a release name
208 Prompt the user to input a release name
209 """
209 """
210
210
211 return console.input("Release Name (ie ""Rough draft""): ")
211 return console.input("Release Name (ie ""Rough draft""): ")
212
212
213
213
214 def _prompt_date(self, resources):
214 def _prompt_date(self, resources):
215 """
215 """
216 Prompt the user to enter a date
216 Prompt the user to enter a date
217 """
217 """
218
218
219 if resources['metadata']['modified_date']:
219 if resources['metadata']['modified_date']:
220 default_date = resources['metadata']['modified_date']
220 default_date = resources['metadata']['modified_date']
221 else:
221 else:
222 default_date = date.today().strftime("%B %-d, %Y")
222 default_date = date.today().strftime("%B %-d, %Y")
223
223
224 user_date = console.input("Date (deafults to \"" + default_date + "\"): ")
224 user_date = console.input("Date (deafults to \"" + default_date + "\"): ")
225 if len(user_date.strip()) == 0:
225 if len(user_date.strip()) == 0:
226 user_date = default_date
226 user_date = default_date
227 return user_date
227 return user_date
228
228
229
229
230 def _prompt_output_style(self):
230 def _prompt_output_style(self):
231 """
231 """
232 Prompts the user to pick an IPython output style.
232 Prompts the user to pick an IPython output style.
233 """
233 """
234
234
235 # Dictionary of available output styles
235 # Dictionary of available output styles
236 styles = {1: "simple",
236 styles = {1: "simple",
237 2: "notebook"}
237 2: "notebook"}
238
238
239 #Append comments to the menu when displaying it to the user.
239 #Append comments to the menu when displaying it to the user.
240 comments = {1: "(recommended for long code segments)",
240 comments = {1: "(recommended for long code segments)",
241 2: "(default)"}
241 2: "(default)"}
242
242
243 return console.prompt_dictionary(styles, default_style=2, menu_comments=comments)
243 return console.prompt_dictionary(styles, default_style=2, menu_comments=comments)
244
244
245
245
246 def _prompt_chapter_title_style(self):
246 def _prompt_chapter_title_style(self):
247 """
247 """
248 Prompts the user to pick a Sphinx chapter style
248 Prompts the user to pick a Sphinx chapter style
249 """
249 """
250
250
251 # Dictionary of available Sphinx styles
251 # Dictionary of available Sphinx styles
252 styles = {1: "Bjarne",
252 styles = {1: "Bjarne",
253 2: "Lenny",
253 2: "Lenny",
254 3: "Glenn",
254 3: "Glenn",
255 4: "Conny",
255 4: "Conny",
256 5: "Rejne",
256 5: "Rejne",
257 6: "Sonny"}
257 6: "Sonny"}
258
258
259 #Append comments to the menu when displaying it to the user.
259 #Append comments to the menu when displaying it to the user.
260 comments = {1: "(default)",
260 comments = {1: "(default)",
261 6: "(for international documents)"}
261 6: "(for international documents)"}
262
262
263 return console.prompt_dictionary(styles, menu_comments=comments)
263 return console.prompt_dictionary(styles, menu_comments=comments)
264
264
@@ -1,95 +1,95 b''
1 """Module containing a transformer that converts outputs in the notebook from
1 """Module containing a preprocessor that converts outputs in the notebook from
2 one format to another.
2 one format to another.
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 io
17 import io
18 import os
18 import os
19 import sys
19 import sys
20 import subprocess
20 import subprocess
21
21
22 from IPython.utils.tempdir import TemporaryDirectory
22 from IPython.utils.tempdir import TemporaryDirectory
23 from IPython.utils.traitlets import Unicode
23 from IPython.utils.traitlets import Unicode
24
24
25 from .convertfigures import ConvertFiguresTransformer
25 from .convertfigures import ConvertFiguresPreprocessor
26
26
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Constants
29 # Constants
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 INKSCAPE_APP = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
32 INKSCAPE_APP = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Classes
35 # Classes
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 class SVG2PDFTransformer(ConvertFiguresTransformer):
38 class SVG2PDFPreprocessor(ConvertFiguresPreprocessor):
39 """
39 """
40 Converts all of the outputs in a notebook from SVG to PDF.
40 Converts all of the outputs in a notebook from SVG to PDF.
41 """
41 """
42
42
43 from_format = Unicode('svg', config=True, help='Format the converter accepts')
43 from_format = Unicode('svg', config=True, help='Format the converter accepts')
44 to_format = Unicode('pdf', config=False, help='Format the converter writes')
44 to_format = Unicode('pdf', config=False, help='Format the converter writes')
45
45
46 command = Unicode(config=True,
46 command = Unicode(config=True,
47 help="""The command to use for converting SVG to PDF
47 help="""The command to use for converting SVG to PDF
48
48
49 This string is a template, which will be formatted with the keys
49 This string is a template, which will be formatted with the keys
50 to_filename and from_filename.
50 to_filename and from_filename.
51
51
52 The conversion call must read the SVG from {from_flename},
52 The conversion call must read the SVG from {from_flename},
53 and write a PDF to {to_filename}.
53 and write a PDF to {to_filename}.
54 """)
54 """)
55
55
56 def _command_default(self):
56 def _command_default(self):
57 return self.inkscape + \
57 return self.inkscape + \
58 ' --without-gui --export-pdf="{to_filename}" "{from_filename}"'
58 ' --without-gui --export-pdf="{to_filename}" "{from_filename}"'
59
59
60 inkscape = Unicode(config=True, help="The path to Inkscape, if necessary")
60 inkscape = Unicode(config=True, help="The path to Inkscape, if necessary")
61 def _inkscape_default(self):
61 def _inkscape_default(self):
62 if sys.platform == "darwin":
62 if sys.platform == "darwin":
63 if os.path.isfile(INKSCAPE_APP):
63 if os.path.isfile(INKSCAPE_APP):
64 return INKSCAPE_APP
64 return INKSCAPE_APP
65 return "inkscape"
65 return "inkscape"
66
66
67
67
68 def convert_figure(self, data_format, data):
68 def convert_figure(self, data_format, data):
69 """
69 """
70 Convert a single SVG figure to PDF. Returns converted data.
70 Convert a single SVG figure to PDF. Returns converted data.
71 """
71 """
72
72
73 #Work in a temporary directory
73 #Work in a temporary directory
74 with TemporaryDirectory() as tmpdir:
74 with TemporaryDirectory() as tmpdir:
75
75
76 #Write fig to temp file
76 #Write fig to temp file
77 input_filename = os.path.join(tmpdir, 'figure.' + data_format)
77 input_filename = os.path.join(tmpdir, 'figure.' + data_format)
78 # SVG data is unicode text
78 # SVG data is unicode text
79 with io.open(input_filename, 'w', encoding='utf8') as f:
79 with io.open(input_filename, 'w', encoding='utf8') as f:
80 f.write(data)
80 f.write(data)
81
81
82 #Call conversion application
82 #Call conversion application
83 output_filename = os.path.join(tmpdir, 'figure.pdf')
83 output_filename = os.path.join(tmpdir, 'figure.pdf')
84 shell = self.command.format(from_filename=input_filename,
84 shell = self.command.format(from_filename=input_filename,
85 to_filename=output_filename)
85 to_filename=output_filename)
86 subprocess.call(shell, shell=True) #Shell=True okay since input is trusted.
86 subprocess.call(shell, shell=True) #Shell=True okay since input is trusted.
87
87
88 #Read output from drive
88 #Read output from drive
89 # return value expects a filename
89 # return value expects a filename
90 if os.path.isfile(output_filename):
90 if os.path.isfile(output_filename):
91 with open(output_filename, 'rb') as f:
91 with open(output_filename, 'rb') as f:
92 # PDF is a nb supported binary, data type, so base64 encode.
92 # PDF is a nb supported binary, data type, so base64 encode.
93 return base64.encodestring(f.read())
93 return base64.encodestring(f.read())
94 else:
94 else:
95 raise TypeError("Inkscape svg to png conversion failed")
95 raise TypeError("Inkscape svg to png conversion failed")
@@ -1,53 +1,53 b''
1 """
1 """
2 Module with utility functions for transformer tests
2 Module with utility functions for preprocessor tests
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.nbformat import current as nbformat
17 from IPython.nbformat import current as nbformat
18
18
19 from ...tests.base import TestsBase
19 from ...tests.base import TestsBase
20 from ...exporters.exporter import ResourcesDict
20 from ...exporters.exporter import ResourcesDict
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Class
23 # Class
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 class TransformerTestsBase(TestsBase):
26 class PreprocessorTestsBase(TestsBase):
27 """Contains test functions transformer tests"""
27 """Contains test functions preprocessor tests"""
28
28
29
29
30 def build_notebook(self):
30 def build_notebook(self):
31 """Build a notebook in memory for use with transformer tests"""
31 """Build a notebook in memory for use with preprocessor tests"""
32
32
33 outputs = [nbformat.new_output(output_type="stream", stream="stdout", output_text="a"),
33 outputs = [nbformat.new_output(output_type="stream", stream="stdout", output_text="a"),
34 nbformat.new_output(output_type="text", output_text="b"),
34 nbformat.new_output(output_type="text", output_text="b"),
35 nbformat.new_output(output_type="stream", stream="stdout", output_text="c"),
35 nbformat.new_output(output_type="stream", stream="stdout", output_text="c"),
36 nbformat.new_output(output_type="stream", stream="stdout", output_text="d"),
36 nbformat.new_output(output_type="stream", stream="stdout", output_text="d"),
37 nbformat.new_output(output_type="stream", stream="stderr", output_text="e"),
37 nbformat.new_output(output_type="stream", stream="stderr", output_text="e"),
38 nbformat.new_output(output_type="stream", stream="stderr", output_text="f"),
38 nbformat.new_output(output_type="stream", stream="stderr", output_text="f"),
39 nbformat.new_output(output_type="png", output_png=b'Zw==')] #g
39 nbformat.new_output(output_type="png", output_png=b'Zw==')] #g
40
40
41 cells=[nbformat.new_code_cell(input="$ e $", prompt_number=1,outputs=outputs),
41 cells=[nbformat.new_code_cell(input="$ e $", prompt_number=1,outputs=outputs),
42 nbformat.new_text_cell('markdown', source="$ e $")]
42 nbformat.new_text_cell('markdown', source="$ e $")]
43 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
43 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
44
44
45 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
45 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
46
46
47
47
48 def build_resources(self):
48 def build_resources(self):
49 """Build an empty resources dictionary."""
49 """Build an empty resources dictionary."""
50
50
51 res = ResourcesDict()
51 res = ResourcesDict()
52 res['metadata'] = ResourcesDict()
52 res['metadata'] = ResourcesDict()
53 return res No newline at end of file
53 return res
@@ -1,38 +1,38 b''
1 """
1 """
2 Module with tests for the coalescestreams transformer
2 Module with tests for the coalescestreams preprocessor
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 .base import TransformerTestsBase
17 from .base import PreprocessorTestsBase
18 from ..coalescestreams import coalesce_streams
18 from ..coalescestreams import coalesce_streams
19
19
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Class
22 # Class
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class TestCoalesceStreams(TransformerTestsBase):
25 class TestCoalesceStreams(PreprocessorTestsBase):
26 """Contains test functions for coalescestreams.py"""
26 """Contains test functions for coalescestreams.py"""
27
27
28 def test_coalesce_streams(self):
28 def test_coalesce_streams(self):
29 """coalesce_streams transformer output test"""
29 """coalesce_streams preprocessor output test"""
30 nb = self.build_notebook()
30 nb = self.build_notebook()
31 res = self.build_resources()
31 res = self.build_resources()
32 nb, res = coalesce_streams(nb, res)
32 nb, res = coalesce_streams(nb, res)
33 outputs = nb.worksheets[0].cells[0].outputs
33 outputs = nb.worksheets[0].cells[0].outputs
34 self.assertEqual(outputs[0].text, "a")
34 self.assertEqual(outputs[0].text, "a")
35 self.assertEqual(outputs[1].output_type, "text")
35 self.assertEqual(outputs[1].output_type, "text")
36 self.assertEqual(outputs[2].text, "cd")
36 self.assertEqual(outputs[2].text, "cd")
37 self.assertEqual(outputs[3].text, "ef")
37 self.assertEqual(outputs[3].text, "ef")
38 No newline at end of file
38
@@ -1,47 +1,47 b''
1 """
1 """
2 Module with tests for the csshtmlheader transformer
2 Module with tests for the csshtmlheader preprocessor
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 .base import TransformerTestsBase
17 from .base import PreprocessorTestsBase
18 from ..csshtmlheader import CSSHTMLHeaderTransformer
18 from ..csshtmlheader import CSSHTMLHeaderPreprocessor
19
19
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Class
22 # Class
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class TestCSSHTMLHeader(TransformerTestsBase):
25 class TestCSSHTMLHeader(PreprocessorTestsBase):
26 """Contains test functions for csshtmlheader.py"""
26 """Contains test functions for csshtmlheader.py"""
27
27
28
28
29 def build_transformer(self):
29 def build_preprocessor(self):
30 """Make an instance of a transformer"""
30 """Make an instance of a preprocessor"""
31 transformer = CSSHTMLHeaderTransformer()
31 preprocessor = CSSHTMLHeaderPreprocessor()
32 transformer.enabled = True
32 preprocessor.enabled = True
33 return transformer
33 return preprocessor
34
34
35
35
36 def test_constructor(self):
36 def test_constructor(self):
37 """Can a CSSHTMLHeaderTransformer be constructed?"""
37 """Can a CSSHTMLHeaderPreprocessor be constructed?"""
38 self.build_transformer()
38 self.build_preprocessor()
39
39
40
40
41 def test_output(self):
41 def test_output(self):
42 """Test the output of the CSSHTMLHeaderTransformer"""
42 """Test the output of the CSSHTMLHeaderPreprocessor"""
43 nb = self.build_notebook()
43 nb = self.build_notebook()
44 res = self.build_resources()
44 res = self.build_resources()
45 transformer = self.build_transformer()
45 preprocessor = self.build_preprocessor()
46 nb, res = transformer(nb, res)
46 nb, res = preprocessor(nb, res)
47 assert 'css' in res['inlining'] No newline at end of file
47 assert 'css' in res['inlining']
@@ -1,62 +1,62 b''
1 """
1 """
2 Module with tests for the extractoutput transformer
2 Module with tests for the extractoutput preprocessor
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 .base import TransformerTestsBase
17 from .base import PreprocessorTestsBase
18 from ..extractoutput import ExtractOutputTransformer
18 from ..extractoutput import ExtractOutputPreprocessor
19
19
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Class
22 # Class
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class TestExtractOutput(TransformerTestsBase):
25 class TestExtractOutput(PreprocessorTestsBase):
26 """Contains test functions for extractoutput.py"""
26 """Contains test functions for extractoutput.py"""
27
27
28
28
29 def build_transformer(self):
29 def build_preprocessor(self):
30 """Make an instance of a transformer"""
30 """Make an instance of a preprocessor"""
31 transformer = ExtractOutputTransformer()
31 preprocessor = ExtractOutputPreprocessor()
32 transformer.enabled = True
32 preprocessor.enabled = True
33 return transformer
33 return preprocessor
34
34
35
35
36 def test_constructor(self):
36 def test_constructor(self):
37 """Can a ExtractOutputTransformer be constructed?"""
37 """Can a ExtractOutputPreprocessor be constructed?"""
38 self.build_transformer()
38 self.build_preprocessor()
39
39
40
40
41 def test_output(self):
41 def test_output(self):
42 """Test the output of the ExtractOutputTransformer"""
42 """Test the output of the ExtractOutputPreprocessor"""
43 nb = self.build_notebook()
43 nb = self.build_notebook()
44 res = self.build_resources()
44 res = self.build_resources()
45 transformer = self.build_transformer()
45 preprocessor = self.build_preprocessor()
46 nb, res = transformer(nb, res)
46 nb, res = preprocessor(nb, res)
47
47
48 # Check if text was extracted.
48 # Check if text was extracted.
49 assert 'text_filename' in nb.worksheets[0].cells[0].outputs[1]
49 assert 'text_filename' in nb.worksheets[0].cells[0].outputs[1]
50 text_filename = nb.worksheets[0].cells[0].outputs[1]['text_filename']
50 text_filename = nb.worksheets[0].cells[0].outputs[1]['text_filename']
51
51
52 # Check if png was extracted.
52 # Check if png was extracted.
53 assert 'png_filename' in nb.worksheets[0].cells[0].outputs[6]
53 assert 'png_filename' in nb.worksheets[0].cells[0].outputs[6]
54 png_filename = nb.worksheets[0].cells[0].outputs[6]['png_filename']
54 png_filename = nb.worksheets[0].cells[0].outputs[6]['png_filename']
55
55
56 # Verify text output
56 # Verify text output
57 assert text_filename in res['outputs']
57 assert text_filename in res['outputs']
58 self.assertEqual(res['outputs'][text_filename], b'b')
58 self.assertEqual(res['outputs'][text_filename], b'b')
59
59
60 # Verify png output
60 # Verify png output
61 assert png_filename in res['outputs']
61 assert png_filename in res['outputs']
62 self.assertEqual(res['outputs'][png_filename], b'g')
62 self.assertEqual(res['outputs'][png_filename], b'g')
@@ -1,51 +1,51 b''
1 """
1 """
2 Module with tests for the latex transformer
2 Module with tests for the latex preprocessor
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 .base import TransformerTestsBase
17 from .base import PreprocessorTestsBase
18 from ..latex import LatexTransformer
18 from ..latex import LatexPreprocessor
19
19
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Class
22 # Class
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class TestLatex(TransformerTestsBase):
25 class TestLatex(PreprocessorTestsBase):
26 """Contains test functions for latex.py"""
26 """Contains test functions for latex.py"""
27
27
28
28
29 def build_transformer(self):
29 def build_preprocessor(self):
30 """Make an instance of a transformer"""
30 """Make an instance of a preprocessor"""
31 transformer = LatexTransformer()
31 preprocessor = LatexPreprocessor()
32 transformer.enabled = True
32 preprocessor.enabled = True
33 return transformer
33 return preprocessor
34
34
35 def test_constructor(self):
35 def test_constructor(self):
36 """Can a LatexTransformer be constructed?"""
36 """Can a LatexPreprocessor be constructed?"""
37 self.build_transformer()
37 self.build_preprocessor()
38
38
39
39
40 def test_output(self):
40 def test_output(self):
41 """Test the output of the LatexTransformer"""
41 """Test the output of the LatexPreprocessor"""
42 nb = self.build_notebook()
42 nb = self.build_notebook()
43 res = self.build_resources()
43 res = self.build_resources()
44 transformer = self.build_transformer()
44 preprocessor = self.build_preprocessor()
45 nb, res = transformer(nb, res)
45 nb, res = preprocessor(nb, res)
46
46
47 # Make sure the code cell wasn't modified.
47 # Make sure the code cell wasn't modified.
48 self.assertEqual(nb.worksheets[0].cells[0].input, '$ e $')
48 self.assertEqual(nb.worksheets[0].cells[0].input, '$ e $')
49
49
50 # Verify that the markdown cell was processed.
50 # Verify that the markdown cell was processed.
51 self.assertEqual(nb.worksheets[0].cells[1].source, '$e$')
51 self.assertEqual(nb.worksheets[0].cells[1].source, '$e$')
@@ -1,94 +1,94 b''
1 """
1 """
2 Module with tests for the revealhelp transformer
2 Module with tests for the revealhelp preprocessor
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.nbformat import current as nbformat
17 from IPython.nbformat import current as nbformat
18
18
19 from .base import TransformerTestsBase
19 from .base import PreprocessorTestsBase
20 from ..revealhelp import RevealHelpTransformer
20 from ..revealhelp import RevealHelpPreprocessor
21
21
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Class
24 # Class
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 class Testrevealhelp(TransformerTestsBase):
27 class Testrevealhelp(PreprocessorTestsBase):
28 """Contains test functions for revealhelp.py"""
28 """Contains test functions for revealhelp.py"""
29
29
30 def build_notebook(self):
30 def build_notebook(self):
31 """Build a reveal slides notebook in memory for use with tests.
31 """Build a reveal slides notebook in memory for use with tests.
32 Overrides base in TransformerTestsBase"""
32 Overrides base in PreprocessorTestsBase"""
33
33
34 outputs = [nbformat.new_output(output_type="stream", stream="stdout", output_text="a")]
34 outputs = [nbformat.new_output(output_type="stream", stream="stdout", output_text="a")]
35
35
36 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
36 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
37 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
37 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
38
38
39 cells=[nbformat.new_code_cell(input="", prompt_number=1, outputs=outputs),
39 cells=[nbformat.new_code_cell(input="", prompt_number=1, outputs=outputs),
40 nbformat.new_text_cell('markdown', source="", metadata=slide_metadata),
40 nbformat.new_text_cell('markdown', source="", metadata=slide_metadata),
41 nbformat.new_code_cell(input="", prompt_number=2, outputs=outputs),
41 nbformat.new_code_cell(input="", prompt_number=2, outputs=outputs),
42 nbformat.new_text_cell('markdown', source="", metadata=slide_metadata),
42 nbformat.new_text_cell('markdown', source="", metadata=slide_metadata),
43 nbformat.new_text_cell('markdown', source="", metadata=subslide_metadata)]
43 nbformat.new_text_cell('markdown', source="", metadata=subslide_metadata)]
44 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
44 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
45
45
46 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
46 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
47
47
48
48
49 def build_transformer(self):
49 def build_preprocessor(self):
50 """Make an instance of a transformer"""
50 """Make an instance of a preprocessor"""
51 transformer = RevealHelpTransformer()
51 preprocessor = RevealHelpPreprocessor()
52 transformer.enabled = True
52 preprocessor.enabled = True
53 return transformer
53 return preprocessor
54
54
55
55
56 def test_constructor(self):
56 def test_constructor(self):
57 """Can a RevealHelpTransformer be constructed?"""
57 """Can a RevealHelpPreprocessor be constructed?"""
58 self.build_transformer()
58 self.build_preprocessor()
59
59
60
60
61 def test_reveal_attribute(self):
61 def test_reveal_attribute(self):
62 """Make sure the reveal url_prefix resources is set"""
62 """Make sure the reveal url_prefix resources is set"""
63 nb = self.build_notebook()
63 nb = self.build_notebook()
64 res = self.build_resources()
64 res = self.build_resources()
65 transformer = self.build_transformer()
65 preprocessor = self.build_preprocessor()
66 nb, res = transformer(nb, res)
66 nb, res = preprocessor(nb, res)
67 assert 'reveal' in res
67 assert 'reveal' in res
68 assert 'url_prefix' in res['reveal']
68 assert 'url_prefix' in res['reveal']
69
69
70
70
71 def test_reveal_output(self):
71 def test_reveal_output(self):
72 """Make sure that the reveal transformer """
72 """Make sure that the reveal preprocessor """
73 nb = self.build_notebook()
73 nb = self.build_notebook()
74 res = self.build_resources()
74 res = self.build_resources()
75 transformer = self.build_transformer()
75 preprocessor = self.build_preprocessor()
76 nb, res = transformer(nb, res)
76 nb, res = preprocessor(nb, res)
77 cells = nb.worksheets[0].cells
77 cells = nb.worksheets[0].cells
78
78
79 # Make sure correct metadata tags are available on every cell.
79 # Make sure correct metadata tags are available on every cell.
80 for cell in cells:
80 for cell in cells:
81 assert 'slide_type' in cell.metadata
81 assert 'slide_type' in cell.metadata
82 assert 'align_type' in cell.metadata
82 assert 'align_type' in cell.metadata
83
83
84 # Make sure slide end is only applied to the cells preceeding slide
84 # Make sure slide end is only applied to the cells preceeding slide
85 # cells.
85 # cells.
86 assert 'slide_helper' not in cells[1].metadata
86 assert 'slide_helper' not in cells[1].metadata
87
87
88 # Verify 'slide-end'
88 # Verify 'slide-end'
89 assert 'slide_helper' in cells[0].metadata
89 assert 'slide_helper' in cells[0].metadata
90 self.assertEqual(cells[0].metadata['slide_helper'], 'slide_end')
90 self.assertEqual(cells[0].metadata['slide_helper'], 'slide_end')
91 assert 'slide_helper' in cells[2].metadata
91 assert 'slide_helper' in cells[2].metadata
92 self.assertEqual(cells[2].metadata['slide_helper'], 'slide_end')
92 self.assertEqual(cells[2].metadata['slide_helper'], 'slide_end')
93 assert 'slide_helper' in cells[3].metadata
93 assert 'slide_helper' in cells[3].metadata
94 self.assertEqual(cells[3].metadata['slide_helper'], 'subslide_end')
94 self.assertEqual(cells[3].metadata['slide_helper'], 'subslide_end')
@@ -1,57 +1,57 b''
1 """
1 """
2 Module with tests for the sphinx transformer
2 Module with tests for the sphinx preprocessor
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 .base import TransformerTestsBase
17 from .base import PreprocessorTestsBase
18 from ..sphinx import SphinxTransformer
18 from ..sphinx import SphinxPreprocessor
19
19
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Class
22 # Class
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class TestSphinx(TransformerTestsBase):
25 class TestSphinx(PreprocessorTestsBase):
26 """Contains test functions for sphinx.py"""
26 """Contains test functions for sphinx.py"""
27
27
28
28
29 def build_transformer(self):
29 def build_preprocessor(self):
30 """Make an instance of a transformer"""
30 """Make an instance of a preprocessor"""
31 transformer = SphinxTransformer()
31 preprocessor = SphinxPreprocessor()
32 transformer.enabled = True
32 preprocessor.enabled = True
33 return transformer
33 return preprocessor
34
34
35
35
36 def test_constructor(self):
36 def test_constructor(self):
37 """Can a SphinxTransformer be constructed?"""
37 """Can a SphinxPreprocessor be constructed?"""
38 self.build_transformer()
38 self.build_preprocessor()
39
39
40
40
41 def test_resources(self):
41 def test_resources(self):
42 """Make sure the SphinxTransformer adds the appropriate resources to the
42 """Make sure the SphinxPreprocessor adds the appropriate resources to the
43 resources dict."""
43 resources dict."""
44 nb = self.build_notebook()
44 nb = self.build_notebook()
45 res = self.build_resources()
45 res = self.build_resources()
46 transformer = self.build_transformer()
46 preprocessor = self.build_preprocessor()
47 nb, res = transformer(nb, res)
47 nb, res = preprocessor(nb, res)
48 assert "author" in res['sphinx']
48 assert "author" in res['sphinx']
49 assert "version" in res['sphinx']
49 assert "version" in res['sphinx']
50 assert "release" in res['sphinx']
50 assert "release" in res['sphinx']
51 assert "date" in res['sphinx']
51 assert "date" in res['sphinx']
52 assert "chapterstyle" in res['sphinx']
52 assert "chapterstyle" in res['sphinx']
53 assert "outputstyle" in res['sphinx']
53 assert "outputstyle" in res['sphinx']
54 assert "centeroutput" in res['sphinx']
54 assert "centeroutput" in res['sphinx']
55 assert "header" in res['sphinx']
55 assert "header" in res['sphinx']
56 assert "texinputs" in res['sphinx']
56 assert "texinputs" in res['sphinx']
57 assert "pygment_definitions" in res['sphinx']
57 assert "pygment_definitions" in res['sphinx']
@@ -1,90 +1,90 b''
1 """
1 """
2 Module with tests for the svg2pdf transformer
2 Module with tests for the svg2pdf preprocessor
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.testing import decorators as dec
17 from IPython.testing import decorators as dec
18 from IPython.nbformat import current as nbformat
18 from IPython.nbformat import current as nbformat
19
19
20 from .base import TransformerTestsBase
20 from .base import PreprocessorTestsBase
21 from ..svg2pdf import SVG2PDFTransformer
21 from ..svg2pdf import SVG2PDFPreprocessor
22
22
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Class
25 # Class
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class Testsvg2pdf(TransformerTestsBase):
28 class Testsvg2pdf(PreprocessorTestsBase):
29 """Contains test functions for svg2pdf.py"""
29 """Contains test functions for svg2pdf.py"""
30
30
31 simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
31 simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
32 <!-- Created with Inkscape (http://www.inkscape.org/) -->
32 <!-- Created with Inkscape (http://www.inkscape.org/) -->
33 <svg
33 <svg
34 xmlns:svg="http://www.w3.org/2000/svg"
34 xmlns:svg="http://www.w3.org/2000/svg"
35 xmlns="http://www.w3.org/2000/svg"
35 xmlns="http://www.w3.org/2000/svg"
36 version="1.0"
36 version="1.0"
37 x="0.00000000"
37 x="0.00000000"
38 y="0.00000000"
38 y="0.00000000"
39 width="500.00000"
39 width="500.00000"
40 height="500.00000"
40 height="500.00000"
41 id="svg2">
41 id="svg2">
42 <defs
42 <defs
43 id="defs4" />
43 id="defs4" />
44 <g
44 <g
45 id="layer1">
45 id="layer1">
46 <rect
46 <rect
47 width="300.00000"
47 width="300.00000"
48 height="300.00000"
48 height="300.00000"
49 x="100.00000"
49 x="100.00000"
50 y="100.00000"
50 y="100.00000"
51 style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000"
51 style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000"
52 id="rect5719" />
52 id="rect5719" />
53 </g>
53 </g>
54 </svg>"""
54 </svg>"""
55
55
56 def build_notebook(self):
56 def build_notebook(self):
57 """Build a reveal slides notebook in memory for use with tests.
57 """Build a reveal slides notebook in memory for use with tests.
58 Overrides base in TransformerTestsBase"""
58 Overrides base in PreprocessorTestsBase"""
59
59
60 outputs = [nbformat.new_output(output_type="svg", output_svg=self.simple_svg)]
60 outputs = [nbformat.new_output(output_type="svg", output_svg=self.simple_svg)]
61
61
62 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
62 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
63 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
63 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
64
64
65 cells=[nbformat.new_code_cell(input="", prompt_number=1, outputs=outputs)]
65 cells=[nbformat.new_code_cell(input="", prompt_number=1, outputs=outputs)]
66 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
66 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
67
67
68 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
68 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
69
69
70
70
71 def build_transformer(self):
71 def build_preprocessor(self):
72 """Make an instance of a transformer"""
72 """Make an instance of a preprocessor"""
73 transformer = SVG2PDFTransformer()
73 preprocessor = SVG2PDFPreprocessor()
74 transformer.enabled = True
74 preprocessor.enabled = True
75 return transformer
75 return preprocessor
76
76
77
77
78 def test_constructor(self):
78 def test_constructor(self):
79 """Can a SVG2PDFTransformer be constructed?"""
79 """Can a SVG2PDFPreprocessor be constructed?"""
80 self.build_transformer()
80 self.build_preprocessor()
81
81
82
82
83 @dec.onlyif_cmds_exist('inkscape')
83 @dec.onlyif_cmds_exist('inkscape')
84 def test_output(self):
84 def test_output(self):
85 """Test the output of the SVG2PDFTransformer"""
85 """Test the output of the SVG2PDFPreprocessor"""
86 nb = self.build_notebook()
86 nb = self.build_notebook()
87 res = self.build_resources()
87 res = self.build_resources()
88 transformer = self.build_transformer()
88 preprocessor = self.build_preprocessor()
89 nb, res = transformer(nb, res)
89 nb, res = preprocessor(nb, res)
90 assert 'svg' in nb.worksheets[0].cells[0].outputs[0]
90 assert 'svg' in nb.worksheets[0].cells[0].outputs[0]
@@ -1,115 +1,115 b''
1 """
1 """
2 Contains writer for writing nbconvert output to filesystem.
2 Contains writer for writing nbconvert output to filesystem.
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 io
16 import io
17 import os
17 import os
18 import glob
18 import glob
19
19
20 from IPython.utils.traitlets import Unicode
20 from IPython.utils.traitlets import Unicode
21 from IPython.utils.path import link_or_copy
21 from IPython.utils.path import link_or_copy
22
22
23 from .base import WriterBase
23 from .base import WriterBase
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Classes
26 # Classes
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 class FilesWriter(WriterBase):
29 class FilesWriter(WriterBase):
30 """Consumes nbconvert output and produces files."""
30 """Consumes nbconvert output and produces files."""
31
31
32
32
33 build_directory = Unicode("", config=True,
33 build_directory = Unicode("", config=True,
34 help="""Directory to write output to. Leave blank
34 help="""Directory to write output to. Leave blank
35 to output to the current directory""")
35 to output to the current directory""")
36
36
37
37
38 # Make sure that the output directory exists.
38 # Make sure that the output directory exists.
39 def _build_directory_changed(self, name, old, new):
39 def _build_directory_changed(self, name, old, new):
40 if new and not os.path.isdir(new):
40 if new and not os.path.isdir(new):
41 os.makedirs(new)
41 os.makedirs(new)
42
42
43
43
44 def __init__(self, **kw):
44 def __init__(self, **kw):
45 super(FilesWriter, self).__init__(**kw)
45 super(FilesWriter, self).__init__(**kw)
46 self._build_directory_changed('build_directory', self.build_directory,
46 self._build_directory_changed('build_directory', self.build_directory,
47 self.build_directory)
47 self.build_directory)
48
48
49 def _makedir(self, path):
49 def _makedir(self, path):
50 """Make a directory if it doesn't already exist"""
50 """Make a directory if it doesn't already exist"""
51 if path and not os.path.isdir(path):
51 if path and not os.path.isdir(path):
52 self.log.info("Making directory %s", path)
52 self.log.info("Making directory %s", path)
53 os.makedirs(path)
53 os.makedirs(path)
54
54
55 def write(self, output, resources, notebook_name=None, **kw):
55 def write(self, output, resources, notebook_name=None, **kw):
56 """
56 """
57 Consume and write Jinja output to the file system. Output directory
57 Consume and write Jinja output to the file system. Output directory
58 is set via the 'build_directory' variable of this instance (a
58 is set via the 'build_directory' variable of this instance (a
59 configurable).
59 configurable).
60
60
61 See base for more...
61 See base for more...
62 """
62 """
63
63
64 # Verify that a notebook name is provided.
64 # Verify that a notebook name is provided.
65 if notebook_name is None:
65 if notebook_name is None:
66 raise TypeError('notebook_name')
66 raise TypeError('notebook_name')
67
67
68 # Pull the extension and subdir from the resources dict.
68 # Pull the extension and subdir from the resources dict.
69 output_extension = resources.get('output_extension', None)
69 output_extension = resources.get('output_extension', None)
70
70
71 # Write all of the extracted resources to the destination directory.
71 # Write all of the extracted resources to the destination directory.
72 # NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
72 # NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
73 # TRANSFORMER SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
73 # PREPROCESSOR SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
74 for filename, data in resources.get('outputs', {}).items():
74 for filename, data in resources.get('outputs', {}).items():
75
75
76 # Determine where to write the file to
76 # Determine where to write the file to
77 dest = os.path.join(self.build_directory, filename)
77 dest = os.path.join(self.build_directory, filename)
78 path = os.path.dirname(dest)
78 path = os.path.dirname(dest)
79 self._makedir(path)
79 self._makedir(path)
80
80
81 # Write file
81 # Write file
82 self.log.debug("Writing %i bytes to support file %s", len(data), dest)
82 self.log.debug("Writing %i bytes to support file %s", len(data), dest)
83 with io.open(dest, 'wb') as f:
83 with io.open(dest, 'wb') as f:
84 f.write(data)
84 f.write(data)
85
85
86 # Copy referenced files to output directory
86 # Copy referenced files to output directory
87 if self.build_directory:
87 if self.build_directory:
88 for filename in self.files:
88 for filename in self.files:
89
89
90 # Copy files that match search pattern
90 # Copy files that match search pattern
91 for matching_filename in glob.glob(filename):
91 for matching_filename in glob.glob(filename):
92
92
93 # Make sure folder exists.
93 # Make sure folder exists.
94 dest = os.path.join(self.build_directory, filename)
94 dest = os.path.join(self.build_directory, filename)
95 path = os.path.dirname(dest)
95 path = os.path.dirname(dest)
96 self._makedir(path)
96 self._makedir(path)
97
97
98 # Copy if destination is different.
98 # Copy if destination is different.
99 if not os.path.normpath(dest) == os.path.normpath(matching_filename):
99 if not os.path.normpath(dest) == os.path.normpath(matching_filename):
100 self.log.info("Linking %s -> %s", matching_filename, dest)
100 self.log.info("Linking %s -> %s", matching_filename, dest)
101 link_or_copy(matching_filename, dest)
101 link_or_copy(matching_filename, dest)
102
102
103 # Determine where to write conversion results.
103 # Determine where to write conversion results.
104 if output_extension is not None:
104 if output_extension is not None:
105 dest = notebook_name + '.' + output_extension
105 dest = notebook_name + '.' + output_extension
106 else:
106 else:
107 dest = notebook_name
107 dest = notebook_name
108 if self.build_directory:
108 if self.build_directory:
109 dest = os.path.join(self.build_directory, dest)
109 dest = os.path.join(self.build_directory, dest)
110
110
111 # Write conversion results.
111 # Write conversion results.
112 self.log.info("Writing %i bytes to %s", len(output), dest)
112 self.log.info("Writing %i bytes to %s", len(output), dest)
113 with io.open(dest, 'w', encoding='utf-8') as f:
113 with io.open(dest, 'w', encoding='utf-8') as f:
114 f.write(output)
114 f.write(output)
115 return dest No newline at end of file
115 return dest
@@ -1,16 +1,16 b''
1 =====================
1 =====================
2 Development version
2 Development version
3 =====================
3 =====================
4
4
5 This document describes in-flight development work.
5 This document describes in-flight development work.
6
6
7
7
8 Backwards incompatible changes
8 Backwards incompatible changes
9 ------------------------------
9 ------------------------------
10
10
11 * Python 2.6 and 3.2 are no longer supported: the minimum required
11 * Python 2.6 and 3.2 are no longer supported: the minimum required
12 Python versions are now 2.7 and 3.3.
12 Python versions are now 2.7 and 3.3.
13 * The `call` methods for nbconvert transformers has been renamed to
13 * The Transformer classes have been renamed to Preprocessor in nbconvert and
14 `transform`.
14 their `call` methods for them have been renamed to `preprocess`.
15 * The `call` methods of nbconvert post-processsors have been renamed to
15 * The `call` methods of nbconvert post-processsors have been renamed to
16 `postprocess`.
16 `postprocess`.
General Comments 0
You need to be logged in to leave comments. Login now