##// END OF EJS Templates
allow ContentsManager methods to return Futures...
Min RK -
Show More
@@ -19,10 +19,9 b' except ImportError:'
19 from jinja2 import TemplateNotFound
19 from jinja2 import TemplateNotFound
20 from tornado import web
20 from tornado import web
21
21
22 try:
22 from tornado import gen
23 from tornado.log import app_log
23 from tornado.log import app_log
24 except ImportError:
24
25 app_log = logging.getLogger()
26
25
27 import IPython
26 import IPython
28 from IPython.utils.sysinfo import get_sys_info
27 from IPython.utils.sysinfo import get_sys_info
@@ -355,9 +354,10 b' def json_errors(method):'
355 the error in a human readable form.
354 the error in a human readable form.
356 """
355 """
357 @functools.wraps(method)
356 @functools.wraps(method)
357 @gen.coroutine
358 def wrapper(self, *args, **kwargs):
358 def wrapper(self, *args, **kwargs):
359 try:
359 try:
360 result = method(self, *args, **kwargs)
360 result = yield gen.maybe_future(method(self, *args, **kwargs))
361 except web.HTTPError as e:
361 except web.HTTPError as e:
362 status = e.status_code
362 status = e.status_code
363 message = e.log_message
363 message = e.log_message
@@ -5,7 +5,7 b''
5
5
6 import json
6 import json
7
7
8 from tornado import web
8 from tornado import gen, web
9
9
10 from IPython.html.utils import url_path_join, url_escape
10 from IPython.html.utils import url_path_join, url_escape
11 from IPython.utils.jsonutil import date_default
11 from IPython.utils.jsonutil import date_default
@@ -102,6 +102,7 b' class ContentsHandler(IPythonHandler):'
102
102
103 @web.authenticated
103 @web.authenticated
104 @json_errors
104 @json_errors
105 @gen.coroutine
105 def get(self, path=''):
106 def get(self, path=''):
106 """Return a model for a file or directory.
107 """Return a model for a file or directory.
107
108
@@ -117,7 +118,7 b' class ContentsHandler(IPythonHandler):'
117 if format not in {None, 'text', 'base64'}:
118 if format not in {None, 'text', 'base64'}:
118 raise web.HTTPError(400, u'Format %r is invalid' % format)
119 raise web.HTTPError(400, u'Format %r is invalid' % format)
119
120
120 model = self.contents_manager.get(path=path, type=type, format=format)
121 model = yield gen.maybe_future(self.contents_manager.get(path=path, type=type, format=format))
121 if model['type'] == 'directory':
122 if model['type'] == 'directory':
122 # group listing by type, then by name (case-insensitive)
123 # group listing by type, then by name (case-insensitive)
123 # FIXME: sorting should be done in the frontends
124 # FIXME: sorting should be done in the frontends
@@ -127,52 +128,58 b' class ContentsHandler(IPythonHandler):'
127
128
128 @web.authenticated
129 @web.authenticated
129 @json_errors
130 @json_errors
131 @gen.coroutine
130 def patch(self, path=''):
132 def patch(self, path=''):
131 """PATCH renames a file or directory without re-uploading content."""
133 """PATCH renames a file or directory without re-uploading content."""
132 cm = self.contents_manager
134 cm = self.contents_manager
133 model = self.get_json_body()
135 model = self.get_json_body()
134 if model is None:
136 if model is None:
135 raise web.HTTPError(400, u'JSON body missing')
137 raise web.HTTPError(400, u'JSON body missing')
136 model = cm.update(model, path)
138 model = yield gen.maybe_future(cm.update(model, path))
137 validate_model(model, expect_content=False)
139 validate_model(model, expect_content=False)
138 self._finish_model(model)
140 self._finish_model(model)
139
141
142 @gen.coroutine
140 def _copy(self, copy_from, copy_to=None):
143 def _copy(self, copy_from, copy_to=None):
141 """Copy a file, optionally specifying a target directory."""
144 """Copy a file, optionally specifying a target directory."""
142 self.log.info(u"Copying {copy_from} to {copy_to}".format(
145 self.log.info(u"Copying {copy_from} to {copy_to}".format(
143 copy_from=copy_from,
146 copy_from=copy_from,
144 copy_to=copy_to or '',
147 copy_to=copy_to or '',
145 ))
148 ))
146 model = self.contents_manager.copy(copy_from, copy_to)
149 model = yield gen.maybe_future(self.contents_manager.copy(copy_from, copy_to))
147 self.set_status(201)
150 self.set_status(201)
148 validate_model(model, expect_content=False)
151 validate_model(model, expect_content=False)
149 self._finish_model(model)
152 self._finish_model(model)
150
153
154 @gen.coroutine
151 def _upload(self, model, path):
155 def _upload(self, model, path):
152 """Handle upload of a new file to path"""
156 """Handle upload of a new file to path"""
153 self.log.info(u"Uploading file to %s", path)
157 self.log.info(u"Uploading file to %s", path)
154 model = self.contents_manager.new(model, path)
158 model = yield gen.maybe_future(self.contents_manager.new(model, path))
155 self.set_status(201)
159 self.set_status(201)
156 validate_model(model, expect_content=False)
160 validate_model(model, expect_content=False)
157 self._finish_model(model)
161 self._finish_model(model)
158
162
163 @gen.coroutine
159 def _new_untitled(self, path, type='', ext=''):
164 def _new_untitled(self, path, type='', ext=''):
160 """Create a new, empty untitled entity"""
165 """Create a new, empty untitled entity"""
161 self.log.info(u"Creating new %s in %s", type or 'file', path)
166 self.log.info(u"Creating new %s in %s", type or 'file', path)
162 model = self.contents_manager.new_untitled(path=path, type=type, ext=ext)
167 model = yield gen.maybe_future(self.contents_manager.new_untitled(path=path, type=type, ext=ext))
163 self.set_status(201)
168 self.set_status(201)
164 validate_model(model, expect_content=False)
169 validate_model(model, expect_content=False)
165 self._finish_model(model)
170 self._finish_model(model)
166
171
172 @gen.coroutine
167 def _save(self, model, path):
173 def _save(self, model, path):
168 """Save an existing file."""
174 """Save an existing file."""
169 self.log.info(u"Saving file at %s", path)
175 self.log.info(u"Saving file at %s", path)
170 model = self.contents_manager.save(model, path)
176 model = yield gen.maybe_future(self.contents_manager.save(model, path))
171 validate_model(model, expect_content=False)
177 validate_model(model, expect_content=False)
172 self._finish_model(model)
178 self._finish_model(model)
173
179
174 @web.authenticated
180 @web.authenticated
175 @json_errors
181 @json_errors
182 @gen.coroutine
176 def post(self, path=''):
183 def post(self, path=''):
177 """Create a new file in the specified path.
184 """Create a new file in the specified path.
178
185
@@ -200,14 +207,15 b' class ContentsHandler(IPythonHandler):'
200 ext = model.get('ext', '')
207 ext = model.get('ext', '')
201 type = model.get('type', '')
208 type = model.get('type', '')
202 if copy_from:
209 if copy_from:
203 self._copy(copy_from, path)
210 yield self._copy(copy_from, path)
204 else:
211 else:
205 self._new_untitled(path, type=type, ext=ext)
212 yield self._new_untitled(path, type=type, ext=ext)
206 else:
213 else:
207 self._new_untitled(path)
214 yield self._new_untitled(path)
208
215
209 @web.authenticated
216 @web.authenticated
210 @json_errors
217 @json_errors
218 @gen.coroutine
211 def put(self, path=''):
219 def put(self, path=''):
212 """Saves the file in the location specified by name and path.
220 """Saves the file in the location specified by name and path.
213
221
@@ -223,20 +231,22 b' class ContentsHandler(IPythonHandler):'
223 if model:
231 if model:
224 if model.get('copy_from'):
232 if model.get('copy_from'):
225 raise web.HTTPError(400, "Cannot copy with PUT, only POST")
233 raise web.HTTPError(400, "Cannot copy with PUT, only POST")
226 if self.contents_manager.file_exists(path):
234 exists = yield gen.maybe_future(self.contents_manager.file_exists(path))
227 self._save(model, path)
235 if exists:
236 yield gen.maybe_future(self._save(model, path))
228 else:
237 else:
229 self._upload(model, path)
238 yield gen.maybe_future(self._upload(model, path))
230 else:
239 else:
231 self._new_untitled(path)
240 yield gen.maybe_future(self._new_untitled(path))
232
241
233 @web.authenticated
242 @web.authenticated
234 @json_errors
243 @json_errors
244 @gen.coroutine
235 def delete(self, path=''):
245 def delete(self, path=''):
236 """delete a file in the given path"""
246 """delete a file in the given path"""
237 cm = self.contents_manager
247 cm = self.contents_manager
238 self.log.warn('delete %s', path)
248 self.log.warn('delete %s', path)
239 cm.delete(path)
249 yield gen.maybe_future(cm.delete(path))
240 self.set_status(204)
250 self.set_status(204)
241 self.finish()
251 self.finish()
242
252
@@ -247,19 +257,21 b' class CheckpointsHandler(IPythonHandler):'
247
257
248 @web.authenticated
258 @web.authenticated
249 @json_errors
259 @json_errors
260 @gen.coroutine
250 def get(self, path=''):
261 def get(self, path=''):
251 """get lists checkpoints for a file"""
262 """get lists checkpoints for a file"""
252 cm = self.contents_manager
263 cm = self.contents_manager
253 checkpoints = cm.list_checkpoints(path)
264 checkpoints = yield gen.maybe_future(cm.list_checkpoints(path))
254 data = json.dumps(checkpoints, default=date_default)
265 data = json.dumps(checkpoints, default=date_default)
255 self.finish(data)
266 self.finish(data)
256
267
257 @web.authenticated
268 @web.authenticated
258 @json_errors
269 @json_errors
270 @gen.coroutine
259 def post(self, path=''):
271 def post(self, path=''):
260 """post creates a new checkpoint"""
272 """post creates a new checkpoint"""
261 cm = self.contents_manager
273 cm = self.contents_manager
262 checkpoint = cm.create_checkpoint(path)
274 checkpoint = yield gen.maybe_future(cm.create_checkpoint(path))
263 data = json.dumps(checkpoint, default=date_default)
275 data = json.dumps(checkpoint, default=date_default)
264 location = url_path_join(self.base_url, 'api/contents',
276 location = url_path_join(self.base_url, 'api/contents',
265 path, 'checkpoints', checkpoint['id'])
277 path, 'checkpoints', checkpoint['id'])
@@ -274,19 +286,21 b' class ModifyCheckpointsHandler(IPythonHandler):'
274
286
275 @web.authenticated
287 @web.authenticated
276 @json_errors
288 @json_errors
289 @gen.coroutine
277 def post(self, path, checkpoint_id):
290 def post(self, path, checkpoint_id):
278 """post restores a file from a checkpoint"""
291 """post restores a file from a checkpoint"""
279 cm = self.contents_manager
292 cm = self.contents_manager
280 cm.restore_checkpoint(checkpoint_id, path)
293 yield gen.maybe_future(cm.restore_checkpoint(checkpoint_id, path))
281 self.set_status(204)
294 self.set_status(204)
282 self.finish()
295 self.finish()
283
296
284 @web.authenticated
297 @web.authenticated
285 @json_errors
298 @json_errors
299 @gen.coroutine
286 def delete(self, path, checkpoint_id):
300 def delete(self, path, checkpoint_id):
287 """delete clears a checkpoint for a given file"""
301 """delete clears a checkpoint for a given file"""
288 cm = self.contents_manager
302 cm = self.contents_manager
289 cm.delete_checkpoint(checkpoint_id, path)
303 yield gen.maybe_future(cm.delete_checkpoint(checkpoint_id, path))
290 self.set_status(204)
304 self.set_status(204)
291 self.finish()
305 self.finish()
292
306
General Comments 0
You need to be logged in to leave comments. Login now