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