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