##// END OF EJS Templates
Download '.py' fixed, deleted debugging output
Zachary Sailer -
Show More
@@ -1,98 +1,94 b''
1 """Tornado handlers for the live notebook view.
1 """Tornado handlers for the live notebook view.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import os
19 import os
20 from tornado import web
20 from tornado import web
21 HTTPError = web.HTTPError
21 HTTPError = web.HTTPError
22
22
23 from ..base.handlers import IPythonHandler
23 from ..base.handlers import IPythonHandler
24 from ..utils import url_path_join
24 from ..utils import url_path_join
25 from urllib import quote
26
25
27 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
28 # Handlers
27 # Handlers
29 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
30
29
31
30
32 class NewPathHandler(IPythonHandler):
31 class NewPathHandler(IPythonHandler):
33
32
34 @web.authenticated
33 @web.authenticated
35 def get(self, notebook_path):
34 def get(self, notebook_path):
36 notebook_name = self.notebook_manager.new_notebook(notebook_path)
35 notebook_name = self.notebook_manager.new_notebook(notebook_path)
37 self.redirect(url_path_join(self.base_project_url,"notebooks", notebook_path, notebook_name))
36 self.redirect(url_path_join(self.base_project_url,"notebooks", notebook_path, notebook_name))
38
37
39
38
40 class NewHandler(IPythonHandler):
39 class NewHandler(IPythonHandler):
41
40
42 @web.authenticated
41 @web.authenticated
43 def get(self):
42 def get(self):
44 notebook_name = self.notebook_manager.new_notebook()
43 notebook_name = self.notebook_manager.new_notebook()
45 self.redirect(url_path_join(self.base_project_url, "notebooks", notebook_name))
44 self.redirect(url_path_join(self.base_project_url, "notebooks", notebook_name))
46
45
47
46
48 class NamedNotebookHandler(IPythonHandler):
47 class NamedNotebookHandler(IPythonHandler):
49
48
50 @web.authenticated
49 @web.authenticated
51 def get(self, notebook_path):
50 def get(self, notebook_path):
52 nbm = self.notebook_manager
51 nbm = self.notebook_manager
53 name, path = nbm.named_notebook_path(notebook_path)
52 name, path = nbm.named_notebook_path(notebook_path)
54 if name != None:
55 name = quote(name)
56 self.log.info(name)
57 if path == None:
53 if path == None:
58 project = self.project + '/' + name
54 project = self.project + '/' + name
59 else:
55 else:
60 project = self.project + '/' + path +'/'+ name
56 project = self.project + '/' + path +'/'+ name
61 #if not nbm.notebook_exists(notebook_path):
57 #if not nbm.notebook_exists(notebook_path):
62 # raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_path)
58 # raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_path)
63 self.write(self.render_template('notebook.html',
59 self.write(self.render_template('notebook.html',
64 project=project,
60 project=project,
65 notebook_path=path,
61 notebook_path=path,
66 notebook_name=name,
62 notebook_name=name,
67 kill_kernel=False,
63 kill_kernel=False,
68 mathjax_url=self.mathjax_url,
64 mathjax_url=self.mathjax_url,
69 )
65 )
70 )
66 )
71
67
72
68
73 class NotebookCopyHandler(IPythonHandler):
69 class NotebookCopyHandler(IPythonHandler):
74
70
75 @web.authenticated
71 @web.authenticated
76 def get(self, notebook_path=None):
72 def get(self, notebook_path=None):
77 nbm = self.notebook_manager
73 nbm = self.notebook_manager
78 name, path = nbm.named_notebook_path(notebook_path)
74 name, path = nbm.named_notebook_path(notebook_path)
79 notebook_name = self.notebook_manager.copy_notebook(name, path)
75 notebook_name = self.notebook_manager.copy_notebook(name, path)
80 if path==None:
76 if path==None:
81 self.redirect(url_path_join(self.base_project_url, "notebooks", notebook_name))
77 self.redirect(url_path_join(self.base_project_url, "notebooks", notebook_name))
82 else:
78 else:
83 self.redirect(url_path_join(self.base_project_url, "notebooks", path, notebook_name))
79 self.redirect(url_path_join(self.base_project_url, "notebooks", path, notebook_name))
84
80
85
81
86 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
87 # URL to handler mappings
83 # URL to handler mappings
88 #-----------------------------------------------------------------------------
84 #-----------------------------------------------------------------------------
89
85
90
86
91 _notebook_path_regex = r"(?P<notebook_path>.+)"
87 _notebook_path_regex = r"(?P<notebook_path>.+)"
92
88
93 default_handlers = [
89 default_handlers = [
94 (r"/notebooks/%s/new" % _notebook_path_regex, NewPathHandler),
90 (r"/notebooks/%s/new" % _notebook_path_regex, NewPathHandler),
95 (r"/notebooks/new", NewHandler),
91 (r"/notebooks/new", NewHandler),
96 (r"/notebooks/%s/copy" % _notebook_path_regex, NotebookCopyHandler),
92 (r"/notebooks/%s/copy" % _notebook_path_regex, NotebookCopyHandler),
97 (r"/notebooks/%s" % _notebook_path_regex, NamedNotebookHandler)
93 (r"/notebooks/%s" % _notebook_path_regex, NamedNotebookHandler)
98 ]
94 ]
@@ -1,199 +1,199 b''
1 """Tornado handlers for the notebooks web service.
1 """Tornado handlers for the notebooks web service.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from tornado import web
19 from tornado import web
20 import ast
20 import ast
21
21
22 from zmq.utils import jsonapi
22 from zmq.utils import jsonapi
23
23
24 from IPython.utils.jsonutil import date_default
24 from IPython.utils.jsonutil import date_default
25
25
26 from ...base.handlers import IPythonHandler
26 from ...base.handlers import IPythonHandler
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Notebook web service handlers
29 # Notebook web service handlers
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32
32
33 class NotebookRootHandler(IPythonHandler):
33 class NotebookRootHandler(IPythonHandler):
34
34
35 @web.authenticated
35 @web.authenticated
36 def get(self):
36 def get(self):
37 nbm = self.notebook_manager
37 nbm = self.notebook_manager
38 km = self.kernel_manager
38 km = self.kernel_manager
39 notebooks = nbm.list_notebooks("")
39 notebooks = nbm.list_notebooks("")
40 self.finish(jsonapi.dumps(notebooks))
40 self.finish(jsonapi.dumps(notebooks))
41
41
42 @web.authenticated
42 @web.authenticated
43 def post(self):
43 def post(self):
44 nbm = self.notebook_manager
44 nbm = self.notebook_manager
45 notebook_name = nbm.new_notebook()
45 notebook_name = nbm.new_notebook()
46 model = nbm.notebook_model(notebook_name)
46 model = nbm.notebook_model(notebook_name)
47 self.set_header('Location', '{0}api/notebooks/{1}'.format(self.base_project_url, notebook_name))
47 self.set_header('Location', '{0}api/notebooks/{1}'.format(self.base_project_url, notebook_name))
48 self.finish(jsonapi.dumps(model))
48 self.finish(jsonapi.dumps(model))
49
49
50
50
51 class NotebookRootRedirect(IPythonHandler):
51 class NotebookRootRedirect(IPythonHandler):
52
52
53 @authenticate_unless_readonly
53 @authenticate_unless_readonly
54 def get(self):
54 def get(self):
55 self.redirect("/api/notebooks")
55 self.redirect("/api/notebooks")
56
56
57
57
58 class NotebookHandler(IPythonHandler):
58 class NotebookHandler(IPythonHandler):
59
59
60 SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH', 'DELETE')
60 SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH', 'DELETE')
61
61
62 @web.authenticated
62 @web.authenticated
63 def get(self, notebook_path):
63 def get(self, notebook_path):
64 nbm = self.notebook_manager
64 nbm = self.notebook_manager
65 name, path = nbm.named_notebook_path(notebook_path)
65 name, path = nbm.named_notebook_path(notebook_path)
66
66
67 if name == None:
67 if name == None:
68 notebooks = nbm.list_notebooks(path)
68 notebooks = nbm.list_notebooks(path)
69 self.finish(jsonapi.dumps(notebooks))
69 self.finish(jsonapi.dumps(notebooks))
70 else:
70 else:
71 format = self.get_argument('format', default='json')
71 format = self.get_argument('format', default='json')
72 model = nbm.notebook_model(name,path)
72 model = nbm.notebook_model(name,path)
73 data, name = nbm.get_notebook(model, format)
73 last_mod, representation, name = nbm.get_notebook(name, path, format)
74
74
75 if format == u'json':
75 if format == u'json':
76 self.set_header('Content-Type', 'application/json')
76 self.set_header('Content-Type', 'application/json')
77 self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name)
77 self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name)
78 elif format == u'py':
78 elif format == u'py':
79 self.set_header('Content-Type', 'application/x-python')
79 self.set_header('Content-Type', 'application/x-python')
80 self.set_header('Content-Disposition','attachment; filename="%s.py"' % name)
80 self.set_header('Content-Disposition','attachment; filename="%s.py"' % name)
81 #self.set_header('Last-Modified', last_mod)
81 #self.set_header('Last-Modified', last_mod)
82 self.finish(jsonapi.dumps(model))
82 self.finish(jsonapi.dumps(model))
83
83
84 @web.authenticated
84 @web.authenticated
85 def patch(self, notebook_path):
85 def patch(self, notebook_path):
86 nbm = self.notebook_manager
86 nbm = self.notebook_manager
87 notebook_name, notebook_path = nbm.named_notebook_path(notebook_path)
87 notebook_name, notebook_path = nbm.named_notebook_path(notebook_path)
88 data = jsonapi.loads(self.request.body)
88 data = jsonapi.loads(self.request.body)
89 model = nbm.change_notebook(data, notebook_name, notebook_path)
89 model = nbm.change_notebook(data, notebook_name, notebook_path)
90 self.finish(jsonapi.dumps(model))
90 self.finish(jsonapi.dumps(model))
91
91
92 @web.authenticated
92 @web.authenticated
93 def put(self, notebook_path):
93 def put(self, notebook_path):
94 nbm = self.notebook_manager
94 nbm = self.notebook_manager
95 notebook_name, notebook_path = nbm.named_notebook_path(notebook_path)
95 notebook_name, notebook_path = nbm.named_notebook_path(notebook_path)
96 if notebook_name == None:
96 if notebook_name == None:
97 body = self.request.body.strip()
97 body = self.request.body.strip()
98 format = self.get_argument('format', default='json')
98 format = self.get_argument('format', default='json')
99 name = self.get_argument('name', default=None)
99 name = self.get_argument('name', default=None)
100 if body:
100 if body:
101 notebook_name = nbm.save_new_notebook(body, notebook_path=notebook_path, name=name, format=format)
101 notebook_name = nbm.save_new_notebook(body, notebook_path=notebook_path, name=name, format=format)
102 else:
102 else:
103 notebook_name = nbm.new_notebook(notebook_path=notebook_path)
103 notebook_name = nbm.new_notebook(notebook_path=notebook_path)
104 if notebook_path==None:
104 if notebook_path==None:
105 self.set_header('Location', nbm.notebook_dir + '/'+ notebook_name)
105 self.set_header('Location', nbm.notebook_dir + '/'+ notebook_name)
106 else:
106 else:
107 self.set_header('Location', nbm.notebook_dir + '/'+ notebook_path + '/' + notebook_name)
107 self.set_header('Location', nbm.notebook_dir + '/'+ notebook_path + '/' + notebook_name)
108 model = nbm.notebook_model(notebook_name, notebook_path)
108 model = nbm.notebook_model(notebook_name, notebook_path)
109 self.finish(jsonapi.dumps(model))
109 self.finish(jsonapi.dumps(model))
110 else:
110 else:
111 format = self.get_argument('format', default='json')
111 format = self.get_argument('format', default='json')
112 name = self.get_argument('name', default=None)
112 name = self.get_argument('name', default=None)
113 nbm.save_notebook(self.request.body, notebook_path=notebook_path, name=name, format=format)
113 nbm.save_notebook(self.request.body, notebook_path=notebook_path, name=name, format=format)
114 model = nbm.notebook_model(notebook_name, notebook_path)
114 model = nbm.notebook_model(notebook_name, notebook_path)
115 self.set_status(204)
115 self.set_status(204)
116 self.finish(jsonapi.dumps(model))
116 self.finish(jsonapi.dumps(model))
117
117
118 @web.authenticated
118 @web.authenticated
119 def delete(self, notebook_path):
119 def delete(self, notebook_path):
120 nbm = self.notebook_manager
120 nbm = self.notebook_manager
121 name, path = nbm.named_notebook_path(notebook_path)
121 name, path = nbm.named_notebook_path(notebook_path)
122 nbm.delete_notebook(name, path)
122 nbm.delete_notebook(name, path)
123 self.set_status(204)
123 self.set_status(204)
124 self.finish()
124 self.finish()
125
125
126
126
127 class NotebookCheckpointsHandler(IPythonHandler):
127 class NotebookCheckpointsHandler(IPythonHandler):
128
128
129 SUPPORTED_METHODS = ('GET', 'POST')
129 SUPPORTED_METHODS = ('GET', 'POST')
130
130
131 @web.authenticated
131 @web.authenticated
132 def get(self, notebook_path):
132 def get(self, notebook_path):
133 """get lists checkpoints for a notebook"""
133 """get lists checkpoints for a notebook"""
134 nbm = self.notebook_manager
134 nbm = self.notebook_manager
135 name, path = nbm.named_notebook_path(notebook_path)
135 name, path = nbm.named_notebook_path(notebook_path)
136 checkpoints = nbm.list_checkpoints(name, path)
136 checkpoints = nbm.list_checkpoints(name, path)
137 data = jsonapi.dumps(checkpoints, default=date_default)
137 data = jsonapi.dumps(checkpoints, default=date_default)
138 self.finish(data)
138 self.finish(data)
139
139
140 @web.authenticated
140 @web.authenticated
141 def post(self, notebook_path):
141 def post(self, notebook_path):
142 """post creates a new checkpoint"""
142 """post creates a new checkpoint"""
143 nbm = self.notebook_manager
143 nbm = self.notebook_manager
144 name, path = nbm.named_notebook_path(notebook_path)
144 name, path = nbm.named_notebook_path(notebook_path)
145 checkpoint = nbm.create_checkpoint(name, path)
145 checkpoint = nbm.create_checkpoint(name, path)
146 data = jsonapi.dumps(checkpoint, default=date_default)
146 data = jsonapi.dumps(checkpoint, default=date_default)
147 if path == None:
147 if path == None:
148 self.set_header('Location', '{0}notebooks/{1}/checkpoints/{2}'.format(
148 self.set_header('Location', '{0}notebooks/{1}/checkpoints/{2}'.format(
149 self.base_project_url, name, checkpoint['checkpoint_id']
149 self.base_project_url, name, checkpoint['checkpoint_id']
150 ))
150 ))
151 else:
151 else:
152 self.set_header('Location', '{0}notebooks/{1}/{2}/checkpoints/{3}'.format(
152 self.set_header('Location', '{0}notebooks/{1}/{2}/checkpoints/{3}'.format(
153 self.base_project_url, path, name, checkpoint['checkpoint_id']
153 self.base_project_url, path, name, checkpoint['checkpoint_id']
154 ))
154 ))
155 self.finish(data)
155 self.finish(data)
156
156
157
157
158 class ModifyNotebookCheckpointsHandler(IPythonHandler):
158 class ModifyNotebookCheckpointsHandler(IPythonHandler):
159
159
160 SUPPORTED_METHODS = ('POST', 'DELETE')
160 SUPPORTED_METHODS = ('POST', 'DELETE')
161
161
162 @web.authenticated
162 @web.authenticated
163 def post(self, notebook_path, checkpoint_id):
163 def post(self, notebook_path, checkpoint_id):
164 """post restores a notebook from a checkpoint"""
164 """post restores a notebook from a checkpoint"""
165 nbm = self.notebook_manager
165 nbm = self.notebook_manager
166 name, path = nbm.named_notebook_path(notebook_path)
166 name, path = nbm.named_notebook_path(notebook_path)
167 nbm.restore_checkpoint(name, checkpoint_id, path)
167 nbm.restore_checkpoint(name, checkpoint_id, path)
168 self.set_status(204)
168 self.set_status(204)
169 self.finish()
169 self.finish()
170
170
171 @web.authenticated
171 @web.authenticated
172 def delete(self, notebook_path, checkpoint_id):
172 def delete(self, notebook_path, checkpoint_id):
173 """delete clears a checkpoint for a given notebook"""
173 """delete clears a checkpoint for a given notebook"""
174 nbm = self.notebook_manager
174 nbm = self.notebook_manager
175 name, path = nbm.named_notebook_path(notebook_path)
175 name, path = nbm.named_notebook_path(notebook_path)
176 nbm.delete_checkpoint(name, checkpoint_id, path)
176 nbm.delete_checkpoint(name, checkpoint_id, path)
177 self.set_status(204)
177 self.set_status(204)
178 self.finish()
178 self.finish()
179
179
180 #-----------------------------------------------------------------------------
180 #-----------------------------------------------------------------------------
181 # URL to handler mappings
181 # URL to handler mappings
182 #-----------------------------------------------------------------------------
182 #-----------------------------------------------------------------------------
183
183
184
184
185 _notebook_path_regex = r"(?P<notebook_path>.+)"
185 _notebook_path_regex = r"(?P<notebook_path>.+)"
186 _checkpoint_id_regex = r"(?P<checkpoint_id>[\w-]+)"
186 _checkpoint_id_regex = r"(?P<checkpoint_id>[\w-]+)"
187
187
188 default_handlers = [
188 default_handlers = [
189 (r"api/notebooks/%s/checkpoints" % _notebook_path_regex, NotebookCheckpointsHandler),
189 (r"api/notebooks/%s/checkpoints" % _notebook_path_regex, NotebookCheckpointsHandler),
190 (r"api/notebooks/%s/checkpoints/%s" % (_notebook_path_regex, _checkpoint_id_regex),
190 (r"api/notebooks/%s/checkpoints/%s" % (_notebook_path_regex, _checkpoint_id_regex),
191 ModifyNotebookCheckpointsHandler),
191 ModifyNotebookCheckpointsHandler),
192 (r"api/notebooks/%s" % _notebook_path_regex, NotebookHandler),
192 (r"api/notebooks/%s" % _notebook_path_regex, NotebookHandler),
193 (r"api/notebooks/", NotebookRootRedirect),
193 (r"api/notebooks/", NotebookRootRedirect),
194 (r"api/notebooks", NotebookRootHandler),
194 (r"api/notebooks", NotebookRootHandler),
195 ]
195 ]
196
196
197
197
198
198
199
199
@@ -1,240 +1,241 b''
1 """A base class notebook manager.
1 """A base class notebook manager.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import os
19 import os
20 import uuid
20 import uuid
21
21
22 from tornado import web
22 from tornado import web
23
23
24 from IPython.config.configurable import LoggingConfigurable
24 from IPython.config.configurable import LoggingConfigurable
25 from IPython.nbformat import current
25 from IPython.nbformat import current
26 from IPython.utils.traitlets import List, Dict, Unicode, TraitError
26 from IPython.utils.traitlets import List, Dict, Unicode, TraitError
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Classes
29 # Classes
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 class NotebookManager(LoggingConfigurable):
32 class NotebookManager(LoggingConfigurable):
33
33
34 # Todo:
34 # Todo:
35 # The notebook_dir attribute is used to mean a couple of different things:
35 # The notebook_dir attribute is used to mean a couple of different things:
36 # 1. Where the notebooks are stored if FileNotebookManager is used.
36 # 1. Where the notebooks are stored if FileNotebookManager is used.
37 # 2. The cwd of the kernel for a project.
37 # 2. The cwd of the kernel for a project.
38 # Right now we use this attribute in a number of different places and
38 # Right now we use this attribute in a number of different places and
39 # we are going to have to disentangle all of this.
39 # we are going to have to disentangle all of this.
40 notebook_dir = Unicode(os.getcwdu(), config=True, help="""
40 notebook_dir = Unicode(os.getcwdu(), config=True, help="""
41 The directory to use for notebooks.
41 The directory to use for notebooks.
42 """)
42 """)
43
43
44 def named_notebook_path(self, notebook_path):
44 def named_notebook_path(self, notebook_path):
45
45
46 l = len(notebook_path)
46 l = len(notebook_path)
47 names = notebook_path.split('/')
47 names = notebook_path.split('/')
48 if len(names) > 1:
48 if len(names) > 1:
49 name = names[len(names)-1]
49 name = names[len(names)-1]
50 if name[(len(name)-6):(len(name))] == ".ipynb":
50 if name[(len(name)-6):(len(name))] == ".ipynb":
51 name = name
51 name = name
52 path = notebook_path[0:l-len(name)-1]+'/'
52 path = notebook_path[0:l-len(name)-1]+'/'
53 else:
53 else:
54 name = None
54 name = None
55 path = notebook_path+'/'
55 path = notebook_path+'/'
56 else:
56 else:
57 name = names[0]
57 name = names[0]
58 if name[(len(name)-6):(len(name))] == ".ipynb":
58 if name[(len(name)-6):(len(name))] == ".ipynb":
59 name = name
59 name = name
60 path = None
60 path = None
61 else:
61 else:
62 name = None
62 name = None
63 path = notebook_path+'/'
63 path = notebook_path+'/'
64 return name, path
64 return name, path
65
65
66 def _notebook_dir_changed(self, new):
66 def _notebook_dir_changed(self, new):
67 """do a bit of validation of the notebook dir"""
67 """do a bit of validation of the notebook dir"""
68 if not os.path.isabs(new):
68 if not os.path.isabs(new):
69 # If we receive a non-absolute path, make it absolute.
69 # If we receive a non-absolute path, make it absolute.
70 abs_new = os.path.abspath(new)
70 abs_new = os.path.abspath(new)
71 #self.notebook_dir = os.path.dirname(abs_new)
71 #self.notebook_dir = os.path.dirname(abs_new)
72 return
72 return
73 if os.path.exists(new) and not os.path.isdir(new):
73 if os.path.exists(new) and not os.path.isdir(new):
74 raise TraitError("notebook dir %r is not a directory" % new)
74 raise TraitError("notebook dir %r is not a directory" % new)
75 if not os.path.exists(new):
75 if not os.path.exists(new):
76 self.log.info("Creating notebook dir %s", new)
76 self.log.info("Creating notebook dir %s", new)
77 try:
77 try:
78 os.mkdir(new)
78 os.mkdir(new)
79 except:
79 except:
80 raise TraitError("Couldn't create notebook dir %r" % new)
80 raise TraitError("Couldn't create notebook dir %r" % new)
81
81
82 allowed_formats = List([u'json',u'py'])
82 allowed_formats = List([u'json',u'py'])
83
83
84
84
85 def load_notebook_names(self, path):
85 def load_notebook_names(self, path):
86 """Load the notebook names into memory.
86 """Load the notebook names into memory.
87
87
88 This should be called once immediately after the notebook manager
88 This should be called once immediately after the notebook manager
89 is created to load the existing notebooks into the mapping in
89 is created to load the existing notebooks into the mapping in
90 memory.
90 memory.
91 """
91 """
92 self.list_notebooks(path)
92 self.list_notebooks(path)
93
93
94 def list_notebooks(self):
94 def list_notebooks(self):
95 """List all notebooks.
95 """List all notebooks.
96
96
97 This returns a list of dicts, each of the form::
97 This returns a list of dicts, each of the form::
98
98
99 dict(notebook_id=notebook,name=name)
99 dict(notebook_id=notebook,name=name)
100
100
101 This list of dicts should be sorted by name::
101 This list of dicts should be sorted by name::
102
102
103 data = sorted(data, key=lambda item: item['name'])
103 data = sorted(data, key=lambda item: item['name'])
104 """
104 """
105 raise NotImplementedError('must be implemented in a subclass')
105 raise NotImplementedError('must be implemented in a subclass')
106
106
107
107
108 def notebook_exists(self, notebook_name):
108 def notebook_exists(self, notebook_name):
109 """Does a notebook exist?"""
109 """Does a notebook exist?"""
110 return notebook_name in self.mapping
110 return notebook_name in self.mapping
111
111
112 def notebook_model(self, notebook_name, notebook_path=None):
112 def notebook_model(self, notebook_name, notebook_path=None):
113 """ Creates the standard notebook model """
113 """ Creates the standard notebook model """
114 last_modified, content = self.read_notebook_object(notebook_name, notebook_path)
114 last_modified, content = self.read_notebook_object(notebook_name, notebook_path)
115 model = {"notebook_name": notebook_name,
115 model = {"notebook_name": notebook_name,
116 "notebook_path": notebook_path,
116 "notebook_path": notebook_path,
117 "content": content}
117 "content": content}
118 return model
118 return model
119
119
120 def get_notebook(self, body, format=u'json'):
120 def get_notebook(self, notebook_name, notebook_path=None, format=u'json'):
121 """Get the representation of a notebook in format by notebook_name."""
121 """Get the representation of a notebook in format by notebook_name."""
122 format = unicode(format)
122 format = unicode(format)
123 if format not in self.allowed_formats:
123 if format not in self.allowed_formats:
124 raise web.HTTPError(415, u'Invalid notebook format: %s' % format)
124 raise web.HTTPError(415, u'Invalid notebook format: %s' % format)
125 kwargs = {}
125 kwargs = {}
126 last_mod, nb = self.read_notebook_object(notebook_name, notebook_path)
126 if format == 'json':
127 if format == 'json':
127 # don't split lines for sending over the wire, because it
128 # don't split lines for sending over the wire, because it
128 # should match the Python in-memory format.
129 # should match the Python in-memory format.
129 kwargs['split_lines'] = False
130 kwargs['split_lines'] = False
130 representation = current.writes(body, format, **kwargs)
131 representation = current.writes(nb, format, **kwargs)
131 name = body['content']['metadata']['name']
132 name = nb.metadata.get('name', 'notebook')
132 return representation, name
133 return last_mod, representation, name
133
134
134 def read_notebook_object(self, notebook_name, notebook_path):
135 def read_notebook_object(self, notebook_name, notebook_path):
135 """Get the object representation of a notebook by notebook_id."""
136 """Get the object representation of a notebook by notebook_id."""
136 raise NotImplementedError('must be implemented in a subclass')
137 raise NotImplementedError('must be implemented in a subclass')
137
138
138 def save_new_notebook(self, data, notebook_path = None, name=None, format=u'json'):
139 def save_new_notebook(self, data, notebook_path = None, name=None, format=u'json'):
139 """Save a new notebook and return its notebook_id.
140 """Save a new notebook and return its notebook_id.
140
141
141 If a name is passed in, it overrides any values in the notebook data
142 If a name is passed in, it overrides any values in the notebook data
142 and the value in the data is updated to use that value.
143 and the value in the data is updated to use that value.
143 """
144 """
144 if format not in self.allowed_formats:
145 if format not in self.allowed_formats:
145 raise web.HTTPError(415, u'Invalid notebook format: %s' % format)
146 raise web.HTTPError(415, u'Invalid notebook format: %s' % format)
146
147
147 try:
148 try:
148 nb = current.reads(data.decode('utf-8'), format)
149 nb = current.reads(data.decode('utf-8'), format)
149 except:
150 except:
150 raise web.HTTPError(400, u'Invalid JSON data')
151 raise web.HTTPError(400, u'Invalid JSON data')
151
152
152 if name is None:
153 if name is None:
153 try:
154 try:
154 name = nb.metadata.name
155 name = nb.metadata.name
155 except AttributeError:
156 except AttributeError:
156 raise web.HTTPError(400, u'Missing notebook name')
157 raise web.HTTPError(400, u'Missing notebook name')
157 nb.metadata.name = name
158 nb.metadata.name = name
158
159
159 notebook_name = self.write_notebook_object(nb, notebook_path=notebook_path)
160 notebook_name = self.write_notebook_object(nb, notebook_path=notebook_path)
160 return notebook_name
161 return notebook_name
161
162
162 def save_notebook(self, data, notebook_path=None, name=None, new_name=None, format=u'json'):
163 def save_notebook(self, data, notebook_path=None, name=None, new_name=None, format=u'json'):
163 """Save an existing notebook by notebook_name."""
164 """Save an existing notebook by notebook_name."""
164 if format not in self.allowed_formats:
165 if format not in self.allowed_formats:
165 raise web.HTTPError(415, u'Invalid notebook format: %s' % format)
166 raise web.HTTPError(415, u'Invalid notebook format: %s' % format)
166
167
167 try:
168 try:
168 nb = current.reads(data.decode('utf-8'), format)
169 nb = current.reads(data.decode('utf-8'), format)
169 except:
170 except:
170 raise web.HTTPError(400, u'Invalid JSON data')
171 raise web.HTTPError(400, u'Invalid JSON data')
171
172
172 if name is not None:
173 if name is not None:
173 nb.metadata.name = name
174 nb.metadata.name = name
174 self.write_notebook_object(nb, name, notebook_path, new_name)
175 self.write_notebook_object(nb, name, notebook_path, new_name)
175
176
176 def write_notebook_object(self, nb, notebook_name=None, notebook_path=None, new_name=None):
177 def write_notebook_object(self, nb, notebook_name=None, notebook_path=None, new_name=None):
177 """Write a notebook object and return its notebook_name.
178 """Write a notebook object and return its notebook_name.
178
179
179 If notebook_name is None, this method should create a new notebook_name.
180 If notebook_name is None, this method should create a new notebook_name.
180 If notebook_name is not None, this method should check to make sure it
181 If notebook_name is not None, this method should check to make sure it
181 exists and is valid.
182 exists and is valid.
182 """
183 """
183 raise NotImplementedError('must be implemented in a subclass')
184 raise NotImplementedError('must be implemented in a subclass')
184
185
185 def delete_notebook(self, notebook_name, notebook_path):
186 def delete_notebook(self, notebook_name, notebook_path):
186 """Delete notebook by notebook_id."""
187 """Delete notebook by notebook_id."""
187 raise NotImplementedError('must be implemented in a subclass')
188 raise NotImplementedError('must be implemented in a subclass')
188
189
189 def increment_filename(self, name):
190 def increment_filename(self, name):
190 """Increment a filename to make it unique.
191 """Increment a filename to make it unique.
191
192
192 This exists for notebook stores that must have unique names. When a notebook
193 This exists for notebook stores that must have unique names. When a notebook
193 is created or copied this method constructs a unique filename, typically
194 is created or copied this method constructs a unique filename, typically
194 by appending an integer to the name.
195 by appending an integer to the name.
195 """
196 """
196 return name
197 return name
197
198
198 def new_notebook(self, notebook_path=None):
199 def new_notebook(self, notebook_path=None):
199 """Create a new notebook and return its notebook_id."""
200 """Create a new notebook and return its notebook_id."""
200 name = self.increment_filename('Untitled', notebook_path)
201 name = self.increment_filename('Untitled', notebook_path)
201 metadata = current.new_metadata(name=name)
202 metadata = current.new_metadata(name=name)
202 nb = current.new_notebook(metadata=metadata)
203 nb = current.new_notebook(metadata=metadata)
203 notebook_name = self.write_notebook_object(nb, notebook_path=notebook_path)
204 notebook_name = self.write_notebook_object(nb, notebook_path=notebook_path)
204 return notebook_name
205 return notebook_name
205
206
206 def copy_notebook(self, name, path):
207 def copy_notebook(self, name, path):
207 """Copy an existing notebook and return its notebook_id."""
208 """Copy an existing notebook and return its notebook_id."""
208 last_mod, nb = self.read_notebook_object(name, path)
209 last_mod, nb = self.read_notebook_object(name, path)
209 name = nb.metadata.name + '-Copy'
210 name = nb.metadata.name + '-Copy'
210 name = self.increment_filename(name, path)
211 name = self.increment_filename(name, path)
211 nb.metadata.name = name
212 nb.metadata.name = name
212 notebook_name = self.write_notebook_object(nb, notebook_path = path)
213 notebook_name = self.write_notebook_object(nb, notebook_path = path)
213 return notebook_name
214 return notebook_name
214
215
215 # Checkpoint-related
216 # Checkpoint-related
216
217
217 def create_checkpoint(self, notebook_name, notebook_path=None):
218 def create_checkpoint(self, notebook_name, notebook_path=None):
218 """Create a checkpoint of the current state of a notebook
219 """Create a checkpoint of the current state of a notebook
219
220
220 Returns a checkpoint_id for the new checkpoint.
221 Returns a checkpoint_id for the new checkpoint.
221 """
222 """
222 raise NotImplementedError("must be implemented in a subclass")
223 raise NotImplementedError("must be implemented in a subclass")
223
224
224 def list_checkpoints(self, notebook_name, notebook_path=None):
225 def list_checkpoints(self, notebook_name, notebook_path=None):
225 """Return a list of checkpoints for a given notebook"""
226 """Return a list of checkpoints for a given notebook"""
226 return []
227 return []
227
228
228 def restore_checkpoint(self, notebook_name, checkpoint_id, notebook_path=None):
229 def restore_checkpoint(self, notebook_name, checkpoint_id, notebook_path=None):
229 """Restore a notebook from one of its checkpoints"""
230 """Restore a notebook from one of its checkpoints"""
230 raise NotImplementedError("must be implemented in a subclass")
231 raise NotImplementedError("must be implemented in a subclass")
231
232
232 def delete_checkpoint(self, notebook_name, checkpoint_id, notebook_path=None):
233 def delete_checkpoint(self, notebook_name, checkpoint_id, notebook_path=None):
233 """delete a checkpoint for a notebook"""
234 """delete a checkpoint for a notebook"""
234 raise NotImplementedError("must be implemented in a subclass")
235 raise NotImplementedError("must be implemented in a subclass")
235
236
236 def log_info(self):
237 def log_info(self):
237 self.log.info(self.info_string())
238 self.log.info(self.info_string())
238
239
239 def info_string(self):
240 def info_string(self):
240 return "Serving notebooks"
241 return "Serving notebooks"
General Comments 0
You need to be logged in to leave comments. Login now