##// END OF EJS Templates
tweak support-file output...
MinRK -
Show More
@@ -1,328 +1,328 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 export_by_name, get_export_names, ExporterNameError
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 163 if new in self.writer_aliases:
164 164 new = self.writer_aliases[new]
165 165 self.writer_factory = import_item(new)
166 166
167 167 # Post-processor specific variables
168 168 post_processor = Instance('IPython.nbconvert.post_processors.base.PostProcessorBase',
169 169 help="""Instance of the PostProcessor class used to write the
170 170 results of the conversion.""")
171 171
172 172 post_processor_class = DottedOrNone(config=True,
173 173 help="""PostProcessor class used to write the
174 174 results of the conversion""")
175 175 post_processor_aliases = {'PDF': 'IPython.nbconvert.post_processors.pdf.PDFPostProcessor',
176 176 'serve': 'IPython.nbconvert.post_processors.serve.ServePostProcessor'}
177 177 post_processor_factory = Type()
178 178
179 179 def _post_processor_class_changed(self, name, old, new):
180 180 if new in self.post_processor_aliases:
181 181 new = self.post_processor_aliases[new]
182 182 if new:
183 183 self.post_processor_factory = import_item(new)
184 184
185 185
186 186 # Other configurable variables
187 187 export_format = CaselessStrEnum(get_export_names(),
188 188 default_value="html",
189 189 config=True,
190 190 help="""The export format to be used."""
191 191 )
192 192
193 193 notebooks = List([], config=True, help="""List of notebooks to convert.
194 194 Wildcards are supported.
195 195 Filenames passed positionally will be added to the list.
196 196 """)
197 197
198 198 @catch_config_error
199 199 def initialize(self, argv=None):
200 200 super(NbConvertApp, self).initialize(argv)
201 201 self.init_syspath()
202 202 self.init_notebooks()
203 203 self.init_writer()
204 204 self.init_post_processor()
205 205
206 206
207 207
208 208 def init_syspath(self):
209 209 """
210 210 Add the cwd to the sys.path ($PYTHONPATH)
211 211 """
212 212 sys.path.insert(0, os.getcwd())
213 213
214 214
215 215 def init_notebooks(self):
216 216 """Construct the list of notebooks.
217 217 If notebooks are passed on the command-line,
218 218 they override notebooks specified in config files.
219 219 Glob each notebook to replace notebook patterns with filenames.
220 220 """
221 221
222 222 # Specifying notebooks on the command-line overrides (rather than adds)
223 223 # the notebook list
224 224 if self.extra_args:
225 225 patterns = self.extra_args
226 226 else:
227 227 patterns = self.notebooks
228 228
229 229 # Use glob to replace all the notebook patterns with filenames.
230 230 filenames = []
231 231 for pattern in patterns:
232 232
233 233 # Use glob to find matching filenames. Allow the user to convert
234 234 # notebooks without having to type the extension.
235 235 globbed_files = glob.glob(pattern)
236 236 globbed_files.extend(glob.glob(pattern + '.ipynb'))
237 237
238 238 for filename in globbed_files:
239 239 if not filename in filenames:
240 240 filenames.append(filename)
241 241 self.notebooks = filenames
242 242
243 243 def init_writer(self):
244 244 """
245 245 Initialize the writer (which is stateless)
246 246 """
247 247 self._writer_class_changed(None, self.writer_class, self.writer_class)
248 248 self.writer = self.writer_factory(parent=self)
249 249
250 250 def init_post_processor(self):
251 251 """
252 252 Initialize the post_processor (which is stateless)
253 253 """
254 254 self._post_processor_class_changed(None, self.post_processor_class,
255 255 self.post_processor_class)
256 256 if self.post_processor_factory:
257 257 self.post_processor = self.post_processor_factory(parent=self)
258 258
259 259 def start(self):
260 260 """
261 261 Ran after initialization completed
262 262 """
263 263 super(NbConvertApp, self).start()
264 264 self.convert_notebooks()
265 265
266 266 def convert_notebooks(self):
267 267 """
268 268 Convert the notebooks in the self.notebook traitlet
269 269 """
270 270 # Export each notebook
271 271 conversion_success = 0
272 272
273 273 if self.output_base != '' and len(self.notebooks) > 1:
274 274 print(dedent(
275 275 """UsageError: --output flag or `NbConvertApp.output_base` config option
276 276 cannot be used when converting multiple notebooks.
277 277 """))
278 278 self.exit(1)
279 279
280 280 for notebook_filename in self.notebooks:
281 281 self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format)
282 282
283 283 # Get a unique key for the notebook and set it in the resources object.
284 284 basename = os.path.basename(notebook_filename)
285 285 notebook_name = basename[:basename.rfind('.')]
286 286 if self.output_base:
287 287 notebook_name = self.output_base
288 288 resources = {}
289 289 resources['unique_key'] = notebook_name
290 290 resources['output_files_dir'] = '%s_files' % notebook_name
291 self.log.debug("Writing extra files to %s", resources['output_files_dir'])
291 self.log.info("Support files will be in %s", os.path.join(resources['output_files_dir'], ''))
292 292
293 293 # Try to export
294 294 try:
295 295 output, resources = export_by_name(self.export_format,
296 296 notebook_filename,
297 297 resources=resources,
298 298 config=self.config)
299 299 except ExporterNameError as e:
300 300 print("Error while converting '%s': '%s' exporter not found."
301 301 %(notebook_filename, self.export_format),
302 302 file=sys.stderr)
303 303 print("Known exporters are:",
304 304 "\n\t" + "\n\t".join(get_export_names()),
305 305 file=sys.stderr)
306 306 self.exit(1)
307 307 except ConversionException as e:
308 308 print("Error while converting '%s': %s" %(notebook_filename, e),
309 309 file=sys.stderr)
310 310 self.exit(1)
311 311 else:
312 312 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
313 313
314 314 #Post-process if post processor has been defined.
315 315 if hasattr(self, 'post_processor') and self.post_processor:
316 316 self.post_processor(write_resultes)
317 317 conversion_success += 1
318 318
319 319 # If nothing was converted successfully, help the user.
320 320 if conversion_success == 0:
321 321 self.print_help()
322 322 sys.exit(-1)
323 323
324 324 #-----------------------------------------------------------------------------
325 325 # Main entry point
326 326 #-----------------------------------------------------------------------------
327 327
328 328 launch_new_instance = NbConvertApp.launch_instance
@@ -1,108 +1,108 b''
1 1 """
2 2 Contains writer for writing nbconvert output to filesystem.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 #Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 #Distributed under the terms of the Modified BSD License.
8 8 #
9 9 #The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 import io
17 17 import os
18 18 import glob
19 19
20 20 from IPython.utils.traitlets import Unicode
21 21 from IPython.utils.path import link_or_copy
22 22
23 23 from .base import WriterBase
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Classes
27 27 #-----------------------------------------------------------------------------
28 28
29 29 class FilesWriter(WriterBase):
30 30 """Consumes nbconvert output and produces files."""
31 31
32 32
33 33 build_directory = Unicode(".", config=True,
34 34 help="""Directory to write output to. Leave blank
35 35 to output to the current directory""")
36 36
37 37
38 38 # Make sure that the output directory exists.
39 39 def _build_directory_changed(self, name, old, new):
40 40 if new and not os.path.isdir(new):
41 41 os.makedirs(new)
42 42
43 43
44 44 def __init__(self, **kw):
45 45 super(FilesWriter, self).__init__(**kw)
46 46 self._build_directory_changed('build_directory', self.build_directory,
47 47 self.build_directory)
48 48
49 49 def _makedir(self, path):
50 50 """Make a directory if it doesn't already exist"""
51 51 if not os.path.isdir(path):
52 52 self.log.info("Making directory %s", path)
53 53 os.makedirs(path)
54 54
55 55 def write(self, output, resources, notebook_name=None, **kw):
56 56 """
57 57 Consume and write Jinja output to the file system. Output directory
58 58 is set via the 'build_directory' variable of this instance (a
59 59 configurable).
60 60
61 61 See base for more...
62 62 """
63 63
64 64 # Pull the extension and subdir from the resources dict.
65 65 output_extension = resources['output_extension']
66 66
67 67 # Write all of the extracted resources to the destination directory.
68 68 # NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
69 69 # TRANSFORMER SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
70 70 for filename, data in resources.get('outputs', {}).items():
71 71
72 72 # Determine where to write the file to
73 73 dest = os.path.join(self.build_directory, filename)
74 74 path = os.path.dirname(dest)
75 75 self._makedir(path)
76 76
77 77 # Write file
78 self.log.info("Writing support file %s", dest)
78 self.log.debug("Writing %i bytes to support file %s", len(data), dest)
79 79 with io.open(dest, 'wb') as f:
80 80 f.write(data)
81 81
82 82 # Copy referenced files to output directory
83 83 if self.build_directory:
84 84 for filename in self.files:
85 85
86 86 # Copy files that match search pattern
87 87 for matching_filename in glob.glob(filename):
88 88
89 89 # Make sure folder exists.
90 90 dest = os.path.join(self.build_directory, filename)
91 91 path = os.path.dirname(dest)
92 92 self._makedir(path)
93 93
94 94 # Copy if destination is different.
95 95 if not os.path.normpath(dest) == os.path.normpath(matching_filename):
96 96 self.log.info("Linking %s -> %s", matching_filename, dest)
97 97 link_or_copy(matching_filename, dest)
98 98
99 99 # Determine where to write conversion results.
100 100 dest = notebook_name + '.' + output_extension
101 101 if self.build_directory:
102 102 dest = os.path.join(self.build_directory, dest)
103 103
104 104 # Write conversion results.
105 self.log.info("Writing %s", dest)
105 self.log.info("Writing %i bytes to support file %s", len(output), dest)
106 106 with io.open(dest, 'w') as f:
107 107 f.write(output)
108 108 return dest No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now