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