##// END OF EJS Templates
Also renamed local variables in nbconvertapp
Jonathan Frederic -
Show More
@@ -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, preprocessors, writers, postprocessors
36 from IPython.nbconvert import exporters, preprocessors, writers, postprocessors
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.postprocessor_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, preprocessors, 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.postprocessors.base.PostProcessorBase',
169 postprocessor = Instance('IPython.nbconvert.postprocessors.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 postprocessor_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.postprocessors.pdf.PDFPostProcessor',
176 postprocessor_aliases = {'pdf': 'IPython.nbconvert.postprocessors.pdf.PDFPostProcessor',
177 'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'}
177 'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'}
178 post_processor_factory = Type()
178 postprocessor_factory = Type()
179
179
180 def _post_processor_class_changed(self, name, old, new):
180 def _postprocessor_class_changed(self, name, old, new):
181 if new.lower() in self.post_processor_aliases:
181 if new.lower() in self.postprocessor_aliases:
182 new = self.post_processor_aliases[new.lower()]
182 new = self.postprocessor_aliases[new.lower()]
183 if new:
183 if new:
184 self.post_processor_factory = import_item(new)
184 self.postprocessor_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_postprocessor()
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_postprocessor(self):
254 """
254 """
255 Initialize the post_processor (which is stateless)
255 Initialize the postprocessor (which is stateless)
256 """
256 """
257 self._post_processor_class_changed(None, self.post_processor_class,
257 self._postprocessor_class_changed(None, self.postprocessor_class,
258 self.post_processor_class)
258 self.postprocessor_class)
259 if self.post_processor_factory:
259 if self.postprocessor_factory:
260 self.post_processor = self.post_processor_factory(parent=self)
260 self.postprocessor = self.postprocessor_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, 'postprocessor') and self.postprocessor:
310 self.post_processor(write_resultes)
310 self.postprocessor(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
General Comments 0
You need to be logged in to leave comments. Login now