##// END OF EJS Templates
clarify `reveal-prefix` alias name
MinRK -
Show More
@@ -1,324 +1,323 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.core.profiledir import ProfileDir
28 from IPython.core.profiledir import ProfileDir
29 from IPython.config import catch_config_error, Configurable
29 from IPython.config import catch_config_error, Configurable
30 from IPython.utils.traitlets import (
30 from IPython.utils.traitlets import (
31 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
31 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
32 )
32 )
33 from IPython.utils.importstring import import_item
33 from IPython.utils.importstring import import_item
34 from IPython.utils.text import dedent
34 from IPython.utils.text import dedent
35
35
36 from .exporters.export import get_export_names, exporter_map
36 from .exporters.export import get_export_names, exporter_map
37 from IPython.nbconvert import exporters, preprocessors, writers, postprocessors
37 from IPython.nbconvert import exporters, preprocessors, writers, postprocessors
38 from .utils.base import NbConvertBase
38 from .utils.base import NbConvertBase
39 from .utils.exceptions import ConversionException
39 from .utils.exceptions import ConversionException
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 #Classes and functions
42 #Classes and functions
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45 class DottedOrNone(DottedObjectName):
45 class DottedOrNone(DottedObjectName):
46 """
46 """
47 A string holding a valid dotted object name in Python, such as A.b3._c
47 A string holding a valid dotted object name in Python, such as A.b3._c
48 Also allows for None type."""
48 Also allows for None type."""
49
49
50 default_value = u''
50 default_value = u''
51
51
52 def validate(self, obj, value):
52 def validate(self, obj, value):
53 if value is not None and len(value) > 0:
53 if value is not None and len(value) > 0:
54 return super(DottedOrNone, self).validate(obj, value)
54 return super(DottedOrNone, self).validate(obj, value)
55 else:
55 else:
56 return value
56 return value
57
57
58 nbconvert_aliases = {}
58 nbconvert_aliases = {}
59 nbconvert_aliases.update(base_aliases)
59 nbconvert_aliases.update(base_aliases)
60 nbconvert_aliases.update({
60 nbconvert_aliases.update({
61 'to' : 'NbConvertApp.export_format',
61 'to' : 'NbConvertApp.export_format',
62 'template' : 'Exporter.template_file',
62 'template' : 'Exporter.template_file',
63 'writer' : 'NbConvertApp.writer_class',
63 'writer' : 'NbConvertApp.writer_class',
64 'post': 'NbConvertApp.postprocessor_class',
64 'post': 'NbConvertApp.postprocessor_class',
65 'output': 'NbConvertApp.output_base',
65 'output': 'NbConvertApp.output_base',
66 'offline-slides': 'RevealHelpPreprocessor.url_prefix',
66 'reveal-prefix': 'RevealHelpPreprocessor.url_prefix',
67 'slide-notes': 'RevealHelpPreprocessor.speaker_notes'
68 })
67 })
69
68
70 nbconvert_flags = {}
69 nbconvert_flags = {}
71 nbconvert_flags.update(base_flags)
70 nbconvert_flags.update(base_flags)
72 nbconvert_flags.update({
71 nbconvert_flags.update({
73 'stdout' : (
72 'stdout' : (
74 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
73 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
75 "Write notebook output to stdout instead of files."
74 "Write notebook output to stdout instead of files."
76 )
75 )
77 })
76 })
78
77
79
78
80 class NbConvertApp(BaseIPythonApplication):
79 class NbConvertApp(BaseIPythonApplication):
81 """Application used to convert to and from notebook file type (*.ipynb)"""
80 """Application used to convert to and from notebook file type (*.ipynb)"""
82
81
83 name = 'ipython-nbconvert'
82 name = 'ipython-nbconvert'
84 aliases = nbconvert_aliases
83 aliases = nbconvert_aliases
85 flags = nbconvert_flags
84 flags = nbconvert_flags
86
85
87 def _log_level_default(self):
86 def _log_level_default(self):
88 return logging.INFO
87 return logging.INFO
89
88
90 def _classes_default(self):
89 def _classes_default(self):
91 classes = [NbConvertBase, ProfileDir]
90 classes = [NbConvertBase, ProfileDir]
92 for pkg in (exporters, preprocessors, writers):
91 for pkg in (exporters, preprocessors, writers):
93 for name in dir(pkg):
92 for name in dir(pkg):
94 cls = getattr(pkg, name)
93 cls = getattr(pkg, name)
95 if isinstance(cls, type) and issubclass(cls, Configurable):
94 if isinstance(cls, type) and issubclass(cls, Configurable):
96 classes.append(cls)
95 classes.append(cls)
97
96
98 return classes
97 return classes
99
98
100 description = Unicode(
99 description = Unicode(
101 u"""This application is used to convert notebook files (*.ipynb)
100 u"""This application is used to convert notebook files (*.ipynb)
102 to various other formats.
101 to various other formats.
103
102
104 WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""")
103 WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""")
105
104
106 output_base = Unicode('', config=True, help='''overwrite base name use for output files.
105 output_base = Unicode('', config=True, help='''overwrite base name use for output files.
107 can only be use when converting one notebook at a time.
106 can only be use when converting one notebook at a time.
108 ''')
107 ''')
109
108
110 examples = Unicode(u"""
109 examples = Unicode(u"""
111 The simplest way to use nbconvert is
110 The simplest way to use nbconvert is
112
111
113 > ipython nbconvert mynotebook.ipynb
112 > ipython nbconvert mynotebook.ipynb
114
113
115 which will convert mynotebook.ipynb to the default format (probably HTML).
114 which will convert mynotebook.ipynb to the default format (probably HTML).
116
115
117 You can specify the export format with `--to`.
116 You can specify the export format with `--to`.
118 Options include {0}
117 Options include {0}
119
118
120 > ipython nbconvert --to latex mynotebook.ipnynb
119 > ipython nbconvert --to latex mynotebook.ipnynb
121
120
122 Both HTML and LaTeX support multiple output templates. LaTeX includes
121 Both HTML and LaTeX support multiple output templates. LaTeX includes
123 'basic', 'book', and 'article'. HTML includes 'basic' and 'full'. You
122 'basic', 'book', and 'article'. HTML includes 'basic' and 'full'. You
124 can specify the flavor of the format used.
123 can specify the flavor of the format used.
125
124
126 > ipython nbconvert --to html --template basic mynotebook.ipynb
125 > ipython nbconvert --to html --template basic mynotebook.ipynb
127
126
128 You can also pipe the output to stdout, rather than a file
127 You can also pipe the output to stdout, rather than a file
129
128
130 > ipython nbconvert mynotebook.ipynb --stdout
129 > ipython nbconvert mynotebook.ipynb --stdout
131
130
132 A post-processor can be used to compile a PDF
131 A post-processor can be used to compile a PDF
133
132
134 > ipython nbconvert mynotebook.ipynb --to latex --post PDF
133 > ipython nbconvert mynotebook.ipynb --to latex --post PDF
135
134
136 You can get (and serve) a Reveal.js-powered slideshow
135 You can get (and serve) a Reveal.js-powered slideshow
137
136
138 > ipython nbconvert myslides.ipynb --to slides --post serve
137 > ipython nbconvert myslides.ipynb --to slides --post serve
139
138
140 Multiple notebooks can be given at the command line in a couple of
139 Multiple notebooks can be given at the command line in a couple of
141 different ways:
140 different ways:
142
141
143 > ipython nbconvert notebook*.ipynb
142 > ipython nbconvert notebook*.ipynb
144 > ipython nbconvert notebook1.ipynb notebook2.ipynb
143 > ipython nbconvert notebook1.ipynb notebook2.ipynb
145
144
146 or you can specify the notebooks list in a config file, containing::
145 or you can specify the notebooks list in a config file, containing::
147
146
148 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
147 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
149
148
150 > ipython nbconvert --config mycfg.py
149 > ipython nbconvert --config mycfg.py
151 """.format(get_export_names()))
150 """.format(get_export_names()))
152
151
153 # Writer specific variables
152 # Writer specific variables
154 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
153 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
155 help="""Instance of the writer class used to write the
154 help="""Instance of the writer class used to write the
156 results of the conversion.""")
155 results of the conversion.""")
157 writer_class = DottedObjectName('FilesWriter', config=True,
156 writer_class = DottedObjectName('FilesWriter', config=True,
158 help="""Writer class used to write the
157 help="""Writer class used to write the
159 results of the conversion""")
158 results of the conversion""")
160 writer_aliases = {'fileswriter': 'IPython.nbconvert.writers.files.FilesWriter',
159 writer_aliases = {'fileswriter': 'IPython.nbconvert.writers.files.FilesWriter',
161 'debugwriter': 'IPython.nbconvert.writers.debug.DebugWriter',
160 'debugwriter': 'IPython.nbconvert.writers.debug.DebugWriter',
162 'stdoutwriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
161 'stdoutwriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
163 writer_factory = Type()
162 writer_factory = Type()
164
163
165 def _writer_class_changed(self, name, old, new):
164 def _writer_class_changed(self, name, old, new):
166 if new.lower() in self.writer_aliases:
165 if new.lower() in self.writer_aliases:
167 new = self.writer_aliases[new.lower()]
166 new = self.writer_aliases[new.lower()]
168 self.writer_factory = import_item(new)
167 self.writer_factory = import_item(new)
169
168
170 # Post-processor specific variables
169 # Post-processor specific variables
171 postprocessor = Instance('IPython.nbconvert.postprocessors.base.PostProcessorBase',
170 postprocessor = Instance('IPython.nbconvert.postprocessors.base.PostProcessorBase',
172 help="""Instance of the PostProcessor class used to write the
171 help="""Instance of the PostProcessor class used to write the
173 results of the conversion.""")
172 results of the conversion.""")
174
173
175 postprocessor_class = DottedOrNone(config=True,
174 postprocessor_class = DottedOrNone(config=True,
176 help="""PostProcessor class used to write the
175 help="""PostProcessor class used to write the
177 results of the conversion""")
176 results of the conversion""")
178 postprocessor_aliases = {'pdf': 'IPython.nbconvert.postprocessors.pdf.PDFPostProcessor',
177 postprocessor_aliases = {'pdf': 'IPython.nbconvert.postprocessors.pdf.PDFPostProcessor',
179 'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'}
178 'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'}
180 postprocessor_factory = Type()
179 postprocessor_factory = Type()
181
180
182 def _postprocessor_class_changed(self, name, old, new):
181 def _postprocessor_class_changed(self, name, old, new):
183 if new.lower() in self.postprocessor_aliases:
182 if new.lower() in self.postprocessor_aliases:
184 new = self.postprocessor_aliases[new.lower()]
183 new = self.postprocessor_aliases[new.lower()]
185 if new:
184 if new:
186 self.postprocessor_factory = import_item(new)
185 self.postprocessor_factory = import_item(new)
187
186
188
187
189 # Other configurable variables
188 # Other configurable variables
190 export_format = CaselessStrEnum(get_export_names(),
189 export_format = CaselessStrEnum(get_export_names(),
191 default_value="html",
190 default_value="html",
192 config=True,
191 config=True,
193 help="""The export format to be used."""
192 help="""The export format to be used."""
194 )
193 )
195
194
196 notebooks = List([], config=True, help="""List of notebooks to convert.
195 notebooks = List([], config=True, help="""List of notebooks to convert.
197 Wildcards are supported.
196 Wildcards are supported.
198 Filenames passed positionally will be added to the list.
197 Filenames passed positionally will be added to the list.
199 """)
198 """)
200
199
201 @catch_config_error
200 @catch_config_error
202 def initialize(self, argv=None):
201 def initialize(self, argv=None):
203 super(NbConvertApp, self).initialize(argv)
202 super(NbConvertApp, self).initialize(argv)
204 self.init_syspath()
203 self.init_syspath()
205 self.init_notebooks()
204 self.init_notebooks()
206 self.init_writer()
205 self.init_writer()
207 self.init_postprocessor()
206 self.init_postprocessor()
208
207
209
208
210
209
211 def init_syspath(self):
210 def init_syspath(self):
212 """
211 """
213 Add the cwd to the sys.path ($PYTHONPATH)
212 Add the cwd to the sys.path ($PYTHONPATH)
214 """
213 """
215 sys.path.insert(0, os.getcwd())
214 sys.path.insert(0, os.getcwd())
216
215
217
216
218 def init_notebooks(self):
217 def init_notebooks(self):
219 """Construct the list of notebooks.
218 """Construct the list of notebooks.
220 If notebooks are passed on the command-line,
219 If notebooks are passed on the command-line,
221 they override notebooks specified in config files.
220 they override notebooks specified in config files.
222 Glob each notebook to replace notebook patterns with filenames.
221 Glob each notebook to replace notebook patterns with filenames.
223 """
222 """
224
223
225 # Specifying notebooks on the command-line overrides (rather than adds)
224 # Specifying notebooks on the command-line overrides (rather than adds)
226 # the notebook list
225 # the notebook list
227 if self.extra_args:
226 if self.extra_args:
228 patterns = self.extra_args
227 patterns = self.extra_args
229 else:
228 else:
230 patterns = self.notebooks
229 patterns = self.notebooks
231
230
232 # Use glob to replace all the notebook patterns with filenames.
231 # Use glob to replace all the notebook patterns with filenames.
233 filenames = []
232 filenames = []
234 for pattern in patterns:
233 for pattern in patterns:
235
234
236 # Use glob to find matching filenames. Allow the user to convert
235 # Use glob to find matching filenames. Allow the user to convert
237 # notebooks without having to type the extension.
236 # notebooks without having to type the extension.
238 globbed_files = glob.glob(pattern)
237 globbed_files = glob.glob(pattern)
239 globbed_files.extend(glob.glob(pattern + '.ipynb'))
238 globbed_files.extend(glob.glob(pattern + '.ipynb'))
240 if not globbed_files:
239 if not globbed_files:
241 self.log.warn("pattern %r matched no files", pattern)
240 self.log.warn("pattern %r matched no files", pattern)
242
241
243 for filename in globbed_files:
242 for filename in globbed_files:
244 if not filename in filenames:
243 if not filename in filenames:
245 filenames.append(filename)
244 filenames.append(filename)
246 self.notebooks = filenames
245 self.notebooks = filenames
247
246
248 def init_writer(self):
247 def init_writer(self):
249 """
248 """
250 Initialize the writer (which is stateless)
249 Initialize the writer (which is stateless)
251 """
250 """
252 self._writer_class_changed(None, self.writer_class, self.writer_class)
251 self._writer_class_changed(None, self.writer_class, self.writer_class)
253 self.writer = self.writer_factory(parent=self)
252 self.writer = self.writer_factory(parent=self)
254
253
255 def init_postprocessor(self):
254 def init_postprocessor(self):
256 """
255 """
257 Initialize the postprocessor (which is stateless)
256 Initialize the postprocessor (which is stateless)
258 """
257 """
259 self._postprocessor_class_changed(None, self.postprocessor_class,
258 self._postprocessor_class_changed(None, self.postprocessor_class,
260 self.postprocessor_class)
259 self.postprocessor_class)
261 if self.postprocessor_factory:
260 if self.postprocessor_factory:
262 self.postprocessor = self.postprocessor_factory(parent=self)
261 self.postprocessor = self.postprocessor_factory(parent=self)
263
262
264 def start(self):
263 def start(self):
265 """
264 """
266 Ran after initialization completed
265 Ran after initialization completed
267 """
266 """
268 super(NbConvertApp, self).start()
267 super(NbConvertApp, self).start()
269 self.convert_notebooks()
268 self.convert_notebooks()
270
269
271 def convert_notebooks(self):
270 def convert_notebooks(self):
272 """
271 """
273 Convert the notebooks in the self.notebook traitlet
272 Convert the notebooks in the self.notebook traitlet
274 """
273 """
275 # Export each notebook
274 # Export each notebook
276 conversion_success = 0
275 conversion_success = 0
277
276
278 if self.output_base != '' and len(self.notebooks) > 1:
277 if self.output_base != '' and len(self.notebooks) > 1:
279 self.log.error(
278 self.log.error(
280 """UsageError: --output flag or `NbConvertApp.output_base` config option
279 """UsageError: --output flag or `NbConvertApp.output_base` config option
281 cannot be used when converting multiple notebooks.
280 cannot be used when converting multiple notebooks.
282 """)
281 """)
283 self.exit(1)
282 self.exit(1)
284
283
285 exporter = exporter_map[self.export_format](config=self.config)
284 exporter = exporter_map[self.export_format](config=self.config)
286
285
287 for notebook_filename in self.notebooks:
286 for notebook_filename in self.notebooks:
288 self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format)
287 self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format)
289
288
290 # Get a unique key for the notebook and set it in the resources object.
289 # Get a unique key for the notebook and set it in the resources object.
291 basename = os.path.basename(notebook_filename)
290 basename = os.path.basename(notebook_filename)
292 notebook_name = basename[:basename.rfind('.')]
291 notebook_name = basename[:basename.rfind('.')]
293 if self.output_base:
292 if self.output_base:
294 notebook_name = self.output_base
293 notebook_name = self.output_base
295 resources = {}
294 resources = {}
296 resources['unique_key'] = notebook_name
295 resources['unique_key'] = notebook_name
297 resources['output_files_dir'] = '%s_files' % notebook_name
296 resources['output_files_dir'] = '%s_files' % notebook_name
298 self.log.info("Support files will be in %s", os.path.join(resources['output_files_dir'], ''))
297 self.log.info("Support files will be in %s", os.path.join(resources['output_files_dir'], ''))
299
298
300 # Try to export
299 # Try to export
301 try:
300 try:
302 output, resources = exporter.from_filename(notebook_filename, resources=resources)
301 output, resources = exporter.from_filename(notebook_filename, resources=resources)
303 except ConversionException as e:
302 except ConversionException as e:
304 self.log.error("Error while converting '%s'", notebook_filename,
303 self.log.error("Error while converting '%s'", notebook_filename,
305 exc_info=True)
304 exc_info=True)
306 self.exit(1)
305 self.exit(1)
307 else:
306 else:
308 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
307 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
309
308
310 #Post-process if post processor has been defined.
309 #Post-process if post processor has been defined.
311 if hasattr(self, 'postprocessor') and self.postprocessor:
310 if hasattr(self, 'postprocessor') and self.postprocessor:
312 self.postprocessor(write_resultes)
311 self.postprocessor(write_resultes)
313 conversion_success += 1
312 conversion_success += 1
314
313
315 # If nothing was converted successfully, help the user.
314 # If nothing was converted successfully, help the user.
316 if conversion_success == 0:
315 if conversion_success == 0:
317 self.print_help()
316 self.print_help()
318 sys.exit(-1)
317 sys.exit(-1)
319
318
320 #-----------------------------------------------------------------------------
319 #-----------------------------------------------------------------------------
321 # Main entry point
320 # Main entry point
322 #-----------------------------------------------------------------------------
321 #-----------------------------------------------------------------------------
323
322
324 launch_new_instance = NbConvertApp.launch_instance
323 launch_new_instance = NbConvertApp.launch_instance
General Comments 0
You need to be logged in to leave comments. Login now