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