##// END OF EJS Templates
Removed "profiles"... Templates that are shipped with nbconvert by default should...
Jonathan Frederic -
Show More
@@ -1,306 +1,387 b''
1 """Exporter for the notebook conversion pipeline.
1 """Exporter for the notebook conversion pipeline.
2
2
3 This module defines Exporter, a highly configurable converter
3 This module defines Exporter, a highly configurable converter
4 that uses Jinja2 to export notebook files into different format.
4 that uses Jinja2 to export notebook files into different format.
5
5
6 You can register both pre-transformers that will act on the notebook format
6 You can register both pre-transformers that will act on the notebook format
7 befor conversion and jinja filter that would then be availlable in the templates
7 befor conversion and jinja filter that would then be availlable in the templates
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (c) 2013, the IPython Development Team.
11 # Copyright (c) 2013, the IPython Development Team.
12 #
12 #
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14 #
14 #
15 # The full license is in the file COPYING.txt, distributed with this software.
15 # The full license is in the file COPYING.txt, distributed with this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 from __future__ import print_function, absolute_import
21 from __future__ import print_function, absolute_import
22
22
23 # Stdlib imports
23 # Stdlib imports
24 import io
24 import io
25 import os
25 import os
26 import re
26 import re
27
27
28 # IPython imports
28 # IPython imports
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.nbformat import current as nbformat
30 from IPython.nbformat import current as nbformat
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
32 from IPython.utils.text import indent
32 from IPython.utils.text import indent
33
33
34 # other libs/dependencies
34 # other libs/dependencies
35 from jinja2 import Environment, FileSystemLoader
35 from jinja2 import Environment, FileSystemLoader
36 from markdown import markdown
36 from markdown import markdown
37
37
38 # local import (pre-transformers)
38 # local import (pre-transformers)
39 from exceptions import ConversionException
39 from exceptions import ConversionException
40 from . import transformers as trans #TODO
40 from . import transformers as trans #TODO
41 from .latex_transformer import (LatexTransformer) #TODO
41 from .latex_transformer import (LatexTransformer) #TODO
42 from .utils import markdown2rst #TODO
42 from .utils import markdown2rst #TODO
43 from .utils import markdown2latex #TODO
43 from .utils import markdown2latex #TODO
44 from .utils import highlight2latex #TODO
44 from .utils import highlight2latex #TODO
45 from .utils import get_lines #TODO
45 from .utils import get_lines #TODO
46 from .utils import remove_ansi #TODO
46 from .utils import remove_ansi #TODO
47 from .utils import highlight, ansi2html #TODO
47 from .utils import highlight, ansi2html #TODO
48 from .latex_transformer import rm_math_space #TODO
48 from .latex_transformer import rm_math_space #TODO
49 import .utils.strings as strings
49 import .utils.strings as strings
50
50
51 #Jinja2 filters
51 #Jinja2 filters
52 from .jinja_filters import (python_comment,
52 from .jinja_filters import (python_comment,
53 rm_fake,
53 rm_fake,
54 escape_tex, FilterDataType,
54 escape_tex, FilterDataType,
55 rm_dollars
55 rm_dollars
56 )
56 )
57
57
58 #Try to import the Sphinx exporter. If the user doesn't have Sphinx isntalled
58 #Try to import the Sphinx exporter. If the user doesn't have Sphinx isntalled
59 #on his/her machine, fail silently.
59 #on his/her machine, fail silently.
60 try:
60 try:
61 from .sphinx_transformer import (SphinxTransformer) #TODO
61 from .sphinx_transformer import (SphinxTransformer) #TODO
62 except ImportError:
62 except ImportError:
63 SphinxTransformer = None
63 SphinxTransformer = None
64
64
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66 # Globals and constants
66 # Globals and constants
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68
68
69 #Standard Jinja2 environment constants
69 #Standard Jinja2 environment constants
70 TEMPLATE_PATH = "/../templates/"
70 TEMPLATE_PATH = "/../templates/"
71 TEMPLATE_SKELETON_PATH = "/../templates/skeleton/"
71 TEMPLATE_SKELETON_PATH = "/../templates/skeleton/"
72 TEMPLATE_EXTENSION = ".tpl"
72 TEMPLATE_EXTENSION = ".tpl"
73
73
74 #Latex Jinja2 constants
74 #Latex Jinja2 constants
75 LATEX_TEMPLATE_PATH = "/../templates/tex/"
75 LATEX_TEMPLATE_PATH = "/../templates/tex/"
76 LATEX_TEMPLATE_SKELETON_PATH = "/../templates/tex/skeleton/"
76 LATEX_TEMPLATE_SKELETON_PATH = "/../templates/tex/skeleton/"
77 LATEX_TEMPLATE_EXTENSION = ".tplx"
77 LATEX_TEMPLATE_EXTENSION = ".tplx"
78
78
79 #Special Jinja2 syntax that will not conflict when exporting latex.
79 #Special Jinja2 syntax that will not conflict when exporting latex.
80 LATEX_JINJA_COMMENT_BLOCK = ["((=", "=))"]
80 LATEX_JINJA_COMMENT_BLOCK = ["((=", "=))"]
81 LATEX_JINJA_VARIABLE_BLOCK = ["(((", ")))"]
81 LATEX_JINJA_VARIABLE_BLOCK = ["(((", ")))"]
82 LATEX_JINJA_LOGIC_BLOCK = ["((*", "*))"]
82 LATEX_JINJA_LOGIC_BLOCK = ["((*", "*))"]
83
83
84 #Jinja2 extensions to load.
84 #Jinja2 extensions to load.
85 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
85 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
86
86
87 #Latex substitutions for escaping latex.
87 #Latex substitutions for escaping latex.
88 LATEX_SUBS = (
88 LATEX_SUBS = (
89 (re.compile(r'\\'), r'\\textbackslash'),
89 (re.compile(r'\\'), r'\\textbackslash'),
90 (re.compile(r'([{}_#%&$])'), r'\\\1'),
90 (re.compile(r'([{}_#%&$])'), r'\\\1'),
91 (re.compile(r'~'), r'\~{}'),
91 (re.compile(r'~'), r'\~{}'),
92 (re.compile(r'\^'), r'\^{}'),
92 (re.compile(r'\^'), r'\^{}'),
93 (re.compile(r'"'), r"''"),
93 (re.compile(r'"'), r"''"),
94 (re.compile(r'\.\.\.+'), r'\\ldots'),
94 (re.compile(r'\.\.\.+'), r'\\ldots'),
95 )
95 )
96
96
97 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
98 # Classes and functions
98 # Classes and functions
99 #-----------------------------------------------------------------------------
99 #-----------------------------------------------------------------------------
100 class Exporter(Configurable):
100 class Exporter(Configurable):
101 """ A Jinja2 base converter templates
101 """ A Jinja2 base converter templates
102
102
103 Preprocess the ipynb files, feed it throug jinja templates,
103 Preprocess the ipynb files, feed it throug jinja templates,
104 and spit an converted files and a data object with other data
104 and spit an converted files and a data object with other data
105 should be mostly configurable
105 should be mostly configurable
106 """
106 """
107
107
108 pre_transformer_order = List(['haspyout_transformer'],
108 pre_transformer_order = List(['haspyout_transformer'],
109 config=True,
109 config=True,
110 help= """
110 help= """
111 An ordered list of pre transformer to apply to the ipynb
111 An ordered list of pre transformer to apply to the ipynb
112 file before running through templates
112 file before running through templates
113 """
113 """
114 )
114 )
115
115
116 tex_environement = Bool(
116 tex_environement = Bool(
117 False,
117 False,
118 config=True,
118 config=True,
119 help=" Whether or not the user is exporting to latex.")
119 help=" Whether or not the user is exporting to latex.")
120
120
121 template_file = Unicode(
121 template_file = Unicode(
122 '', config=True,
122 '', config=True,
123 help="Name of the template file to use")
123 help="Name of the template file to use")
124
124
125 fileext = Unicode(
126 'txt', config=True,
127 help="Extension of the file that should be written to disk"
128 )
129
130 stdout = Bool(
131 True, config=True,
132 help="""Whether to print the converted ipynb file to stdout
133 "use full do diff files without actually writing a new file"""
134 )
135
136 write = Bool(
137 False, config=True,
138 help="""Should the converted notebook file be written to disk
139 along with potential extracted resources."""
140 )
141
125 #Processors that process the input data prior to the export, set in the
142 #Processors that process the input data prior to the export, set in the
126 #constructor for this class.
143 #constructor for this class.
127 preprocessors = []
144 preprocessors = []
128
145
129 def __init__(self, preprocessors={}, jinja_filters={}, config=None, **kw):
146 def __init__(self, preprocessors={}, jinja_filters={}, config=None, export_format, **kw):
130 """ Init a new converter.
147 """ Init a new converter.
131
148
132 config: the Configurable config object to pass around.
149 config: the Configurable config object to pass around.
133
150
134 preprocessors: dict of **availlable** key/value function to run on
151 preprocessors: dict of **availlable** key/value function to run on
135 ipynb json data before conversion to extract/inline file.
152 ipynb json data before conversion to extract/inline file.
136 See `transformer.py` and `ConfigurableTransformers`
153 See `transformer.py` and `ConfigurableTransformers`
137
154
138 set the order in which the transformers should apply
155 set the order in which the transformers should apply
139 with the `pre_transformer_order` trait of this class
156 with the `pre_transformer_order` trait of this class
140
157
141 transformers registerd by this key will take precedence on
158 transformers registerd by this key will take precedence on
142 default one.
159 default one.
143
160
144 jinja_filters: dict of supplementary jinja filter that should be made
161 jinja_filters: dict of supplementary jinja filter that should be made
145 availlable in template. If those are of Configurable Class type,
162 availlable in template. If those are of Configurable Class type,
146 they will be instanciated with the config object as argument.
163 they will be instanciated with the config object as argument.
147
164
148 user defined filter will overwrite the one availlable by default.
165 user defined filter will overwrite the one availlable by default.
149 """
166 """
150 super(ConverterTemplate, self).__init__(config=config, **kw)
167
168 #Merge default config options with user specific override options.
169 default_config = self._get_default_options()
170 if not config == None:
171 default_config._merge(config)
172 config = default_config
173
174 #Call the base class constructor
175 super(Exporter, self).__init__(config=config, **kw)
151
176
152 #Create a Latex environment if the user is exporting latex.
177 #Create a Latex environment if the user is exporting latex.
153 if self.tex_environement:
178 if self.tex_environement:
154 self.ext = LATEX_TEMPLATE_EXTENSION
179 self.ext = LATEX_TEMPLATE_EXTENSION
155 self.env = Environment(
180 self.env = Environment(
156 loader=FileSystemLoader([
181 loader=FileSystemLoader([
157 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_PATH,
182 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_PATH,
158 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_SKELETON_PATH,
183 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_SKELETON_PATH,
159 ]),
184 ]),
160 extensions=JINJA_EXTENSIONS
185 extensions=JINJA_EXTENSIONS
161 )
186 )
162
187
163 #Set special Jinja2 syntax that will not conflict with latex.
188 #Set special Jinja2 syntax that will not conflict with latex.
164 self.env.block_start_string = LATEX_JINJA_LOGIC_BLOCK[0]
189 self.env.block_start_string = LATEX_JINJA_LOGIC_BLOCK[0]
165 self.env.block_end_string = LATEX_JINJA_LOGIC_BLOCK[1]
190 self.env.block_end_string = LATEX_JINJA_LOGIC_BLOCK[1]
166 self.env.variable_start_string = LATEX_JINJA_VARIABLE_BLOCK[0]
191 self.env.variable_start_string = LATEX_JINJA_VARIABLE_BLOCK[0]
167 self.env.variable_end_string = LATEX_JINJA_VARIABLE_BLOCK[1]
192 self.env.variable_end_string = LATEX_JINJA_VARIABLE_BLOCK[1]
168 self.env.comment_start_string = LATEX_JINJA_COMMENT_BLOCK[0]
193 self.env.comment_start_string = LATEX_JINJA_COMMENT_BLOCK[0]
169 self.env.comment_end_string = LATEX_JINJA_COMMENT_BLOCK[1]
194 self.env.comment_end_string = LATEX_JINJA_COMMENT_BLOCK[1]
170
195
171 else: #Standard environment
196 else: #Standard environment
172 self.ext = TEMPLATE_EXTENSION
197 self.ext = TEMPLATE_EXTENSION
173 self.env = Environment(
198 self.env = Environment(
174 loader=FileSystemLoader([
199 loader=FileSystemLoader([
175 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_PATH,
200 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_PATH,
176 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_SKELETON_PATH,
201 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_SKELETON_PATH,
177 ]),
202 ]),
178 extensions=JINJA_EXTENSIONS
203 extensions=JINJA_EXTENSIONS
179 )
204 )
180
205
181 for name in self.pre_transformer_order:
206 for name in self.pre_transformer_order:
182 # get the user-defined transformer first
207 # get the user-defined transformer first
183 transformer = preprocessors.get(name, getattr(trans, name, None))
208 transformer = preprocessors.get(name, getattr(trans, name, None))
184 if isinstance(transformer, MetaHasTraits):
209 if isinstance(transformer, MetaHasTraits):
185 transformer = transformer(config=config)
210 transformer = transformer(config=config)
186 self.preprocessors.append(transformer)
211 self.preprocessors.append(transformer)
187
212
188 #For compatibility, TODO: remove later.
213 #For compatibility, TODO: remove later.
189 self.preprocessors.append(trans.coalesce_streams)
214 self.preprocessors.append(trans.coalesce_streams)
190 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
215 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
191 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
216 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
192 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
217 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
193 self.preprocessors.append(LatexTransformer(config=config))
218 self.preprocessors.append(LatexTransformer(config=config))
194
219
195 #Only load the sphinx transformer if the file reference worked
220 #Only load the sphinx transformer if the file reference worked
196 #(Sphinx dependencies exist on the user's machine.)
221 #(Sphinx dependencies exist on the user's machine.)
197 if SphinxTransformer:
222 if SphinxTransformer:
198 self.preprocessors.append(SphinxTransformer(config=config))
223 self.preprocessors.append(SphinxTransformer(config=config))
199
224
200 #Add filters to the Jinja2 environment
225 #Add filters to the Jinja2 environment
201 self.env.filters['filter_data_type'] = FilterDataType(config=config)
226 self.env.filters['filter_data_type'] = FilterDataType(config=config)
202 self.env.filters['pycomment'] = _python_comment
227 self.env.filters['pycomment'] = _python_comment
203 self.env.filters['indent'] = indent
228 self.env.filters['indent'] = indent
204 self.env.filters['rm_fake'] = _rm_fake
229 self.env.filters['rm_fake'] = _rm_fake
205 self.env.filters['rm_ansi'] = remove_ansi
230 self.env.filters['rm_ansi'] = remove_ansi
206 self.env.filters['markdown'] = markdown
231 self.env.filters['markdown'] = markdown
207 self.env.filters['ansi2html'] = ansi2html
232 self.env.filters['ansi2html'] = ansi2html
208 self.env.filters['markdown2latex'] = markdown2latex
233 self.env.filters['markdown2latex'] = markdown2latex
209 self.env.filters['markdown2rst'] = markdown2rst
234 self.env.filters['markdown2rst'] = markdown2rst
210 self.env.filters['get_lines'] = get_lines
235 self.env.filters['get_lines'] = get_lines
211 self.env.filters['wrap'] = strings.wrap
236 self.env.filters['wrap'] = strings.wrap
212 self.env.filters['rm_dollars'] = strings.strip_dollars
237 self.env.filters['rm_dollars'] = strings.strip_dollars
213 self.env.filters['rm_math_space'] = rm_math_space
238 self.env.filters['rm_math_space'] = rm_math_space
214 self.env.filters['highlight2html'] = highlight
239 self.env.filters['highlight2html'] = highlight
215 self.env.filters['highlight2latex'] = highlight2latex
240 self.env.filters['highlight2latex'] = highlight2latex
216
241
217 #Latex specific filters
242 #Latex specific filters
218 if self.tex_environement:
243 if self.tex_environement:
219 self.env.filters['escape_tex'] = _escape_tex
244 self.env.filters['escape_tex'] = _escape_tex
220 self.env.filters['highlight'] = highlight2latex
245 self.env.filters['highlight'] = highlight2latex
221 else:
246 else:
222 self.env.filters['highlight'] = highlight
247 self.env.filters['highlight'] = highlight
223
248
224 #Load user filters. Overwrite existing filters if need be.
249 #Load user filters. Overwrite existing filters if need be.
225 for key, user_filter in jinja_filters.iteritems():
250 for key, user_filter in jinja_filters.iteritems():
226 if isinstance(user_filter, MetaHasTraits):
251 if isinstance(user_filter, MetaHasTraits):
227 self.env.filters[key] = user_filter(config=config)
252 self.env.filters[key] = user_filter(config=config)
228 else:
253 else:
229 self.env.filters[key] = user_filter
254 self.env.filters[key] = user_filter
230
255
231 #Load the template file.
256 #Load the template file.
232 self.template = self.env.get_template(self.template_file+self.ext)
257 self.template = self.env.get_template(self.template_file+self.ext)
233
258
234
259
235 def export(self, nb):
260 def export(self, nb):
236 """Export notebook object
261 """Export notebook object
237
262
238 nb: Notebook object to export.
263 nb: Notebook object to export.
239
264
240 Returns both the converted ipynb file and a dict containing the
265 Returns both the converted ipynb file and a dict containing the
241 resources created along the way via the transformers and Jinja2
266 resources created along the way via the transformers and Jinja2
242 processing.
267 processing.
243 """
268 """
244
269
245 nb, resources = self._preprocess(nb)
270 nb, resources = self._preprocess(nb)
246 return self.template.render(nb=nb, resources=resources), resources
271 return self.template.render(nb=nb, resources=resources), resources
247
272
248
273
249 def from_filename(self, filename):
274 def from_filename(self, filename):
250 """Read and export a notebook from a filename
275 """Read and export a notebook from a filename
251
276
252 filename: Filename of the notebook file to export.
277 filename: Filename of the notebook file to export.
253
278
254 Returns both the converted ipynb file and a dict containing the
279 Returns both the converted ipynb file and a dict containing the
255 resources created along the way via the transformers and Jinja2
280 resources created along the way via the transformers and Jinja2
256 processing.
281 processing.
257 """
282 """
258 with io.open(filename) as f:
283 with io.open(filename) as f:
259 return self.export(nbformat.read(f, 'json'))
284 return self.export(nbformat.read(f, 'json'))
260
285
261
286
262 def from_file(self, file_stream):
287 def from_file(self, file_stream):
263 """Read and export a notebook from a filename
288 """Read and export a notebook from a filename
264
289
265 file_stream: File handle of file that contains notebook data.
290 file_stream: File handle of file that contains notebook data.
266
291
267 Returns both the converted ipynb file and a dict containing the
292 Returns both the converted ipynb file and a dict containing the
268 resources created along the way via the transformers and Jinja2
293 resources created along the way via the transformers and Jinja2
269 processing.
294 processing.
270 """
295 """
271
296
272 return self.export(nbformat.read(file_stream, 'json'))
297 return self.export(nbformat.read(file_stream, 'json'))
273
298
274
299
275 def _preprocess(self, nb):
300 def _preprocess(self, nb):
276 """ Preprocess the notebook using the transformers specific
301 """ Preprocess the notebook using the transformers specific
277 for the current export format.
302 for the current export format.
278
303
279 nb: Notebook to preprocess
304 nb: Notebook to preprocess
280 """
305 """
281
306
282 #Dict of 'resources' that can be filled by the preprocessors.
307 #Dict of 'resources' that can be filled by the preprocessors.
283 resources = {}
308 resources = {}
284
309
285 #Run each transformer on the notebook. Carry the output along
310 #Run each transformer on the notebook. Carry the output along
286 #to each transformer
311 #to each transformer
287 for transformer in self.preprocessors:
312 for transformer in self.preprocessors:
288 nb, resources = transformer(nb, resources)
313 nb, resources = transformer(nb, resources)
289 return nb, resources
314 return nb, resources
290
315
291
316
317 def _get_default_options(self, export_format):
318 """ Load the default options for built in formats.
319
320 export_format: Format being exported to.
321 """
322
323 c = get_config()
324
325 #Set default data extraction priorities.
326 c.GlobalConfigurable.display_data_priority =['svg', 'png', 'latex', 'jpg', 'jpeg','text']
327 c.ExtractFigureTransformer.display_data_priority=['svg', 'png', 'latex', 'jpg', 'jpeg','text']
328 c.ConverterTemplate.display_data_priority= ['svg', 'png', 'latex', 'jpg', 'jpeg','text']
329
330 #For most (or all cases), the template file name matches the format name.
331 c.ConverterTemplate.template_file = export_format
332
333 if export_format == "basichtml" or "fullhtml" or "reveal":
334 c.CSSHtmlHeaderTransformer.enabled=True
335 if export_format == 'reveal'
336 c.NbconvertApp.fileext='reveal.html'
337 else:
338 c.NbconvertApp.fileext='html'
339
340 elif export_format == "latex_sphinx_howto" or export_format == "latex_sphinx_manual":
341
342 #Turn on latex environment
343 c.ConverterTemplate.tex_environement=True
344
345 #Standard latex extension
346 c.NbconvertApp.fileext='tex'
347
348 #Prioritize latex extraction for latex exports.
349 c.GlobalConfigurable.display_data_priority =['latex', 'svg', 'png', 'jpg', 'jpeg' , 'text']
350 c.ExtractFigureTransformer.display_data_priority=['latex', 'svg', 'png', 'jpg', 'jpeg']
351 c.ExtractFigureTransformer.extra_ext_map={'svg':'pdf'}
352 c.ExtractFigureTransformer.enabled=True
353
354 # Enable latex transformers (make markdown2latex work with math $.)
355 c.LatexTransformer.enabled=True
356 c.SphinxTransformer.enabled = True
357
358 elif export_format == 'markdown':
359 c.NbconvertApp.fileext='md'
360 c.ExtractFigureTransformer.enabled=True
361
362 elif export_format == 'python':
363 c.NbconvertApp.fileext='py'
364
365
366 elif export_format == 'rst':
367 c.NbconvertApp.fileext='rst'
368 c.ExtractFigureTransformer.enabled=True
369 return c
370
371
292 #TODO: Comment me.
372 #TODO: Comment me.
293 def _rm_fake(strng):
373 def _rm_fake(strng):
294 return strng.replace('/files/', '')
374 return strng.replace('/files/', '')
295
375
376
296 #TODO: Comment me.
377 #TODO: Comment me.
297 def _python_comment(string):
378 def _python_comment(string):
298 return '# '+'\n# '.join(string.split('\n'))
379 return '# '+'\n# '.join(string.split('\n'))
299
380
300
381
301 #TODO: Comment me.
382 #TODO: Comment me.
302 def _escape_tex(value):
383 def _escape_tex(value):
303 newval = value
384 newval = value
304 for pattern, replacement in LATEX_SUBS:
385 for pattern, replacement in LATEX_SUBS:
305 newval = pattern.sub(replacement, newval)
386 newval = pattern.sub(replacement, newval)
306 return newval No newline at end of file
387 return newval
@@ -1,201 +1,154 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 """NBConvert is a utility for conversion of IPYNB files.
3 """NBConvert is a utility for conversion of IPYNB files.
4
4
5 Commandline interface for the NBConvert conversion utility. Read the
5 Commandline interface for the NBConvert conversion utility. Read the
6 readme.rst for usage information
6 readme.rst for usage information
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 #Copyright (c) 2013, the IPython Development Team.
9 #Copyright (c) 2013, the IPython Development Team.
10 #
10 #
11 #Distributed under the terms of the Modified BSD License.
11 #Distributed under the terms of the Modified BSD License.
12 #
12 #
13 #The full license is in the file COPYING.txt, distributed with this software.
13 #The full license is in the file COPYING.txt, distributed with this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 #Imports
17 #Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #Stdlib imports
20 #Stdlib imports
21 from __future__ import print_function
21 from __future__ import print_function
22 import sys
22 import sys
23 import io
23 import io
24 import os
24 import os
25
25
26 #From IPython
26 #From IPython
27 #All the stuff needed for the configurable things
27 #All the stuff needed for the configurable things
28 from IPython.config.application import Application
28 from IPython.config.application import Application
29 from IPython.config.loader import ConfigFileNotFound
29 from IPython.config.loader import ConfigFileNotFound
30 from IPython.utils.traitlets import Unicode, Bool
30 from IPython.utils.traitlets import Unicode, Bool
31
31
32 #Local imports
32 #Local imports
33 from api.exporter import Exporter
33 from api.exporter import Exporter
34 from converters.config import GlobalConfigurable #TODO
34 from converters.config import GlobalConfigurable #TODO
35 from converters.transformers import (ExtractFigureTransformer) #TODO
35 from converters.transformers import (ExtractFigureTransformer) #TODO
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 #Globals and constants
38 #Globals and constants
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 NBCONVERT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
40 NBCONVERT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
41
41
42 #'Keys in resources' user prompt.
42 #'Keys in resources' user prompt.
43 KEYS_PROMPT_HEAD = "====================== Keys in Resources =================================="
43 KEYS_PROMPT_HEAD = "====================== Keys in Resources =================================="
44 KEYS_PROMPT_BODY = """
44 KEYS_PROMPT_BODY = """
45 ===========================================================================
45 ===========================================================================
46 You are responsible for writting these files into the appropriate
46 You are responsible for writting these files into the appropriate
47 directorie(s) if need be. If you do not want to see this message, enable
47 directorie(s) if need be. If you do not want to see this message, enable
48 the 'write' (boolean) flag of the converter.
48 the 'write' (boolean) flag of the converter.
49 ===========================================================================
49 ===========================================================================
50 """
50 """
51
51
52 #Error Messages
52 #Error Messages
53 ERROR_CONFIG_NOT_FOUND = "Config file for profile '%s' not found, giving up."
53 ERROR_CONFIG_NOT_FOUND = "Config file for profile '%s' not found, giving up."
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 #Classes and functions
56 #Classes and functions
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 class NbconvertApp(Application):
58 class NbconvertApp(Application):
59 """A basic application to convert ipynb files"""
59 """A basic application to convert ipynb files"""
60
60
61 stdout = Bool(
62 True, config=True,
63 help="""Whether to print the converted ipynb file to stdout
64 "use full do diff files without actually writing a new file"""
65 )
66
67 write = Bool(
68 False, config=True,
69 help="""Should the converted notebook file be written to disk
70 along with potential extracted resources."""
71 )
72
73 fileext = Unicode(
74 'txt', config=True,
75 help="Extension of the file that should be written to disk"
76 )
77
78 aliases = {
61 aliases = {
79 'stdout':'NbconvertApp.stdout',
62 'stdout':'NbconvertApp.stdout',
80 'write':'NbconvertApp.write'
63 'write':'NbconvertApp.write'
81 }
64 }
82
65
83 flags = {}
66 flags = {}
84 flags['no-stdout'] = (
67 flags['no-stdout'] = (
85 {'NbconvertApp' : {'stdout' : False}},
68 {'NbconvertApp' : {'stdout' : False}},
86 """Do not print converted file to stdout, equivalent to
69 """Do not print converted file to stdout, equivalent to
87 --stdout=False"""
70 --stdout=False"""
88 )
71 )
89
72
90 def __init__(self, **kwargs):
73 def __init__(self, **kwargs):
91 """Public constructor"""
74 """Public constructor"""
92
75
93 #Call base class
76 #Call base class
94 super(NbconvertApp, self).__init__(**kwargs)
77 super(NbconvertApp, self).__init__(**kwargs)
95
78
96 #Register class here to have help with help all
79 #Register class here to have help with help all
97 self.classes.insert(0, ConverterTemplate)
80 self.classes.insert(0, ConverterTemplate)
98 self.classes.insert(0, ExtractFigureTransformer)
81 self.classes.insert(0, ExtractFigureTransformer)
99 self.classes.insert(0, GlobalConfigurable)
82 self.classes.insert(0, GlobalConfigurable)
100
83
101
84
102 def load_config_file(self, profile_name):
103 """Load a config file from the config file dir
104
105 profile_name : {string} name of the profile file to load without file
106 extension.
107 """
108
109 #Try to load the config file. If the file isn't found, catch the
110 #exception.
111 try:
112 Application.load_config_file(
113 self,
114 profile_name + '.py',
115 path=[os.path.join(NBCONVERT_DIR, 'profile')]
116 )
117 return True
118
119 except ConfigFileNotFound:
120 self.log.warn(ERROR_CONFIG_NOT_FOUND, profile_name)
121 return False
122
123
124 def start(self, argv=None):
85 def start(self, argv=None):
125 """Convert a notebook in one step"""
86 """Convert a notebook in one step"""
126
87
127 #Parse the commandline options.
88 #Parse the commandline options.
128 self.parse_command_line(argv)
89 self.parse_command_line(argv)
129
90
130 #Load an addition config file if specified by the user via the
131 #commandline.
132 cl_config = self.config
133 profile_file = argv[1]
134 if not self.load_config_file(profile_file):
135 exit(1)
136 self.update_config(cl_config)
137
138 #Call base
91 #Call base
139 super(NbconvertApp, self).start()
92 super(NbconvertApp, self).start()
140
93
141 #The last arguments in chain of arguments will be used as conversion
94 #The last arguments in chain of arguments will be used as conversion
142 ipynb_file = (self.extra_args or [None])[2]
95 ipynb_file = (self.extra_args or [None])[2]
143
96
144 #If you are writting a custom transformer, append it to the dictionary
97 #If you are writting a custom transformer, append it to the dictionary
145 #below.
98 #below.
146 userpreprocessors = {}
99 userpreprocessors = {}
147
100
148 #Create the Jinja template exporter. TODO: Add ability to
101 #Create the Jinja template exporter. TODO: Add ability to
149 #import in IPYNB aswell
102 #import in IPYNB aswell
150 exporter = Exporter(config=self.config, preprocessors=userpreprocessors)
103 exporter = Exporter(config=self.config, preprocessors=userpreprocessors,export_format=export_format)
151
104
152 #Export
105 #Export
153 output, resources = exporter.from_filename(ipynb_file)
106 output, resources = exporter.from_filename(ipynb_file)
154 if self.stdout :
107 if exporter.stdout :
155 print(output.encode('utf-8'))
108 print(output.encode('utf-8'))
156
109
157 #Get the file name without the '.ipynb' (6 chars) extension and then
110 #Get the file name without the '.ipynb' (6 chars) extension and then
158 #remove any addition periods and spaces. The resulting name will
111 #remove any addition periods and spaces. The resulting name will
159 #be used to create the directory that the files will be exported
112 #be used to create the directory that the files will be exported
160 #into.
113 #into.
161 out_root = ipynb_file[:-6].replace('.', '_').replace(' ', '_')
114 out_root = ipynb_file[:-6].replace('.', '_').replace(' ', '_')
162
115
163 #Write file output from conversion.
116 #Write file output from conversion.
164 if self.write :
117 if exporter.write :
165 with io.open(os.path.join(out_root+'.'+self.fileext), 'w') as f:
118 with io.open(os.path.join(out_root+'.'+exporter.fileext), 'w') as f:
166 f.write(output)
119 f.write(output)
167
120
168 #Output any associate figures into the same "root" directory.
121 #Output any associate figures into the same "root" directory.
169 binkeys = resources.get('figures', {}).get('binary',{}).keys()
122 binkeys = resources.get('figures', {}).get('binary',{}).keys()
170 textkeys = resources.get('figures', {}).get('text',{}).keys()
123 textkeys = resources.get('figures', {}).get('text',{}).keys()
171 if binkeys or textkeys :
124 if binkeys or textkeys :
172 if self.write:
125 if exporter.write:
173 files_dir = out_root+'_files'
126 files_dir = out_root+'_files'
174 if not os.path.exists(out_root+'_files'):
127 if not os.path.exists(out_root+'_files'):
175 os.mkdir(files_dir)
128 os.mkdir(files_dir)
176 for key in binkeys:
129 for key in binkeys:
177 with io.open(os.path.join(files_dir, key), 'wb') as f:
130 with io.open(os.path.join(files_dir, key), 'wb') as f:
178 f.write(resources['figures']['binary'][key])
131 f.write(resources['figures']['binary'][key])
179 for key in textkeys:
132 for key in textkeys:
180 with io.open(os.path.join(files_dir, key), 'w') as f:
133 with io.open(os.path.join(files_dir, key), 'w') as f:
181 f.write(resources['figures']['text'][key])
134 f.write(resources['figures']['text'][key])
182
135
183 #Figures that weren't exported which will need to be created by the
136 #Figures that weren't exported which will need to be created by the
184 #user. Tell the user what figures these are.
137 #user. Tell the user what figures these are.
185 elif self.stdout:
138 elif exporter.stdout:
186 print(KEYS_PROMPT_HEAD)
139 print(KEYS_PROMPT_HEAD)
187 print(resources['figures'].keys())
140 print(resources['figures'].keys())
188 print(KEYS_PROMPT_BODY)
141 print(KEYS_PROMPT_BODY)
189
142
190 #-----------------------------------------------------------------------------
143 #-----------------------------------------------------------------------------
191 #Script main
144 #Script main
192 #-----------------------------------------------------------------------------
145 #-----------------------------------------------------------------------------
193 def main():
146 def main():
194 """Convert a notebook in one step"""
147 """Convert a notebook in one step"""
195
148
196 app = NbconvertApp.instance()
149 app = NbconvertApp.instance()
197 app.description = __doc__
150 app.description = __doc__
198 app.run(argv=sys.argv)
151 app.run(argv=sys.argv)
199
152
200 if __name__ == '__main__':
153 if __name__ == '__main__':
201 main() No newline at end of file
154 main()
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now