##// END OF EJS Templates
catch pandoc failures in nbconvert handlers
MinRK -
Show More
@@ -1,117 +1,123 b''
1 import io
1 import io
2 import os
2 import os
3 import zipfile
3 import zipfile
4
4
5 from tornado import web
5 from tornado import web
6
6
7 from ..base.handlers import IPythonHandler, notebook_path_regex
7 from ..base.handlers import IPythonHandler, notebook_path_regex
8 from IPython.nbformat.current import to_notebook_json
8 from IPython.nbformat.current import to_notebook_json
9 from IPython.nbconvert.exporters.export import exporter_map
9 from IPython.nbconvert.exporters.export import exporter_map
10 from IPython.utils import tz
10 from IPython.utils import tz
11 from IPython.utils.py3compat import cast_bytes
11 from IPython.utils.py3compat import cast_bytes
12
12
13 import sys
13 import sys
14
14
15 def find_resource_files(output_files_dir):
15 def find_resource_files(output_files_dir):
16 files = []
16 files = []
17 for dirpath, dirnames, filenames in os.walk(output_files_dir):
17 for dirpath, dirnames, filenames in os.walk(output_files_dir):
18 files.extend([os.path.join(dirpath, f) for f in filenames])
18 files.extend([os.path.join(dirpath, f) for f in filenames])
19 return files
19 return files
20
20
21 def respond_zip(handler, name, output, resources):
21 def respond_zip(handler, name, output, resources):
22 """Zip up the output and resource files and respond with the zip file.
22 """Zip up the output and resource files and respond with the zip file.
23
23
24 Returns True if it has served a zip file, False if there are no resource
24 Returns True if it has served a zip file, False if there are no resource
25 files, in which case we serve the plain output file.
25 files, in which case we serve the plain output file.
26 """
26 """
27 # Check if we have resource files we need to zip
27 # Check if we have resource files we need to zip
28 output_files = resources.get('outputs', None)
28 output_files = resources.get('outputs', None)
29 if not output_files:
29 if not output_files:
30 return False
30 return False
31
31
32 # Headers
32 # Headers
33 zip_filename = os.path.splitext(name)[0] + '.zip'
33 zip_filename = os.path.splitext(name)[0] + '.zip'
34 handler.set_header('Content-Disposition',
34 handler.set_header('Content-Disposition',
35 'attachment; filename="%s"' % zip_filename)
35 'attachment; filename="%s"' % zip_filename)
36 handler.set_header('Content-Type', 'application/zip')
36 handler.set_header('Content-Type', 'application/zip')
37
37
38 # Prepare the zip file
38 # Prepare the zip file
39 buffer = io.BytesIO()
39 buffer = io.BytesIO()
40 zipf = zipfile.ZipFile(buffer, mode='w', compression=zipfile.ZIP_DEFLATED)
40 zipf = zipfile.ZipFile(buffer, mode='w', compression=zipfile.ZIP_DEFLATED)
41 output_filename = os.path.splitext(name)[0] + '.' + resources['output_extension']
41 output_filename = os.path.splitext(name)[0] + '.' + resources['output_extension']
42 zipf.writestr(output_filename, cast_bytes(output, 'utf-8'))
42 zipf.writestr(output_filename, cast_bytes(output, 'utf-8'))
43 for filename, data in output_files.items():
43 for filename, data in output_files.items():
44 zipf.writestr(os.path.basename(filename), data)
44 zipf.writestr(os.path.basename(filename), data)
45 zipf.close()
45 zipf.close()
46
46
47 handler.finish(buffer.getvalue())
47 handler.finish(buffer.getvalue())
48 return True
48 return True
49
49
50 class NbconvertFileHandler(IPythonHandler):
50 class NbconvertFileHandler(IPythonHandler):
51
51
52 SUPPORTED_METHODS = ('GET',)
52 SUPPORTED_METHODS = ('GET',)
53
53
54 @web.authenticated
54 @web.authenticated
55 def get(self, format, path='', name=None):
55 def get(self, format, path='', name=None):
56 exporter = exporter_map[format](config=self.config)
56 exporter = exporter_map[format](config=self.config)
57
57
58 path = path.strip('/')
58 path = path.strip('/')
59 os_path = self.notebook_manager.get_os_path(name, path)
59 os_path = self.notebook_manager.get_os_path(name, path)
60 if not os.path.isfile(os_path):
60 if not os.path.isfile(os_path):
61 raise web.HTTPError(404, u'Notebook does not exist: %s' % name)
61 raise web.HTTPError(404, u'Notebook does not exist: %s' % name)
62
62
63 info = os.stat(os_path)
63 info = os.stat(os_path)
64 self.set_header('Last-Modified', tz.utcfromtimestamp(info.st_mtime))
64 self.set_header('Last-Modified', tz.utcfromtimestamp(info.st_mtime))
65
65
66 try:
66 output, resources = exporter.from_filename(os_path)
67 output, resources = exporter.from_filename(os_path)
68 except Exception as e:
69 raise web.HTTPError(500, "nbconvert failed: %s" % e)
67
70
68 if respond_zip(self, name, output, resources):
71 if respond_zip(self, name, output, resources):
69 return
72 return
70
73
71 # Force download if requested
74 # Force download if requested
72 if self.get_argument('download', 'false').lower() == 'true':
75 if self.get_argument('download', 'false').lower() == 'true':
73 filename = os.path.splitext(name)[0] + '.' + resources['output_extension']
76 filename = os.path.splitext(name)[0] + '.' + resources['output_extension']
74 self.set_header('Content-Disposition',
77 self.set_header('Content-Disposition',
75 'attachment; filename="%s"' % filename)
78 'attachment; filename="%s"' % filename)
76
79
77 # MIME type
80 # MIME type
78 if exporter.output_mimetype:
81 if exporter.output_mimetype:
79 self.set_header('Content-Type',
82 self.set_header('Content-Type',
80 '%s; charset=utf-8' % exporter.output_mimetype)
83 '%s; charset=utf-8' % exporter.output_mimetype)
81
84
82 self.finish(output)
85 self.finish(output)
83
86
84 class NbconvertPostHandler(IPythonHandler):
87 class NbconvertPostHandler(IPythonHandler):
85 SUPPORTED_METHODS = ('POST',)
88 SUPPORTED_METHODS = ('POST',)
86
89
87 @web.authenticated
90 @web.authenticated
88 def post(self, format):
91 def post(self, format):
89 exporter = exporter_map[format](config=self.config)
92 exporter = exporter_map[format](config=self.config)
90
93
91 model = self.get_json_body()
94 model = self.get_json_body()
92 nbnode = to_notebook_json(model['content'])
95 nbnode = to_notebook_json(model['content'])
93
96
97 try:
94 output, resources = exporter.from_notebook_node(nbnode)
98 output, resources = exporter.from_notebook_node(nbnode)
99 except Exception as e:
100 raise web.HTTPError(500, "nbconvert failed: %s" % e)
95
101
96 if respond_zip(self, nbnode.metadata.name, output, resources):
102 if respond_zip(self, nbnode.metadata.name, output, resources):
97 return
103 return
98
104
99 # MIME type
105 # MIME type
100 if exporter.output_mimetype:
106 if exporter.output_mimetype:
101 self.set_header('Content-Type',
107 self.set_header('Content-Type',
102 '%s; charset=utf-8' % exporter.output_mimetype)
108 '%s; charset=utf-8' % exporter.output_mimetype)
103
109
104 self.finish(output)
110 self.finish(output)
105
111
106 #-----------------------------------------------------------------------------
112 #-----------------------------------------------------------------------------
107 # URL to handler mappings
113 # URL to handler mappings
108 #-----------------------------------------------------------------------------
114 #-----------------------------------------------------------------------------
109
115
110 _format_regex = r"(?P<format>\w+)"
116 _format_regex = r"(?P<format>\w+)"
111
117
112
118
113 default_handlers = [
119 default_handlers = [
114 (r"/nbconvert/%s%s" % (_format_regex, notebook_path_regex),
120 (r"/nbconvert/%s%s" % (_format_regex, notebook_path_regex),
115 NbconvertFileHandler),
121 NbconvertFileHandler),
116 (r"/nbconvert/%s" % _format_regex, NbconvertPostHandler),
122 (r"/nbconvert/%s" % _format_regex, NbconvertPostHandler),
117 ] No newline at end of file
123 ]
General Comments 0
You need to be logged in to leave comments. Login now