mirror of
https://github.com/jupyter/notebook.git
synced 2024-12-27 04:20:22 +08:00
Merge pull request #7253 from minrk/async-contents-handlers
allow ContentsManager methods to return Futures
This commit is contained in:
commit
c7f2a8689e
@ -19,10 +19,9 @@ except ImportError:
|
||||
from jinja2 import TemplateNotFound
|
||||
from tornado import web
|
||||
|
||||
try:
|
||||
from tornado.log import app_log
|
||||
except ImportError:
|
||||
app_log = logging.getLogger()
|
||||
from tornado import gen
|
||||
from tornado.log import app_log
|
||||
|
||||
|
||||
import IPython
|
||||
from IPython.utils.sysinfo import get_sys_info
|
||||
@ -355,9 +354,10 @@ def json_errors(method):
|
||||
the error in a human readable form.
|
||||
"""
|
||||
@functools.wraps(method)
|
||||
@gen.coroutine
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
result = method(self, *args, **kwargs)
|
||||
result = yield gen.maybe_future(method(self, *args, **kwargs))
|
||||
except web.HTTPError as e:
|
||||
status = e.status_code
|
||||
message = e.log_message
|
||||
@ -375,7 +375,8 @@ def json_errors(method):
|
||||
reply = dict(message=message, reason=None, traceback=tb_text)
|
||||
self.finish(json.dumps(reply))
|
||||
else:
|
||||
return result
|
||||
# FIXME: can use regular return in generators in py3
|
||||
raise gen.Return(result)
|
||||
return wrapper
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
import json
|
||||
|
||||
from tornado import web
|
||||
from tornado import gen, web
|
||||
|
||||
from IPython.html.utils import url_path_join, url_escape
|
||||
from IPython.utils.jsonutil import date_default
|
||||
@ -102,6 +102,7 @@ class ContentsHandler(IPythonHandler):
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
@gen.coroutine
|
||||
def get(self, path=''):
|
||||
"""Return a model for a file or directory.
|
||||
|
||||
@ -117,7 +118,7 @@ class ContentsHandler(IPythonHandler):
|
||||
if format not in {None, 'text', 'base64'}:
|
||||
raise web.HTTPError(400, u'Format %r is invalid' % format)
|
||||
|
||||
model = self.contents_manager.get(path=path, type=type, format=format)
|
||||
model = yield gen.maybe_future(self.contents_manager.get(path=path, type=type, format=format))
|
||||
if model['type'] == 'directory':
|
||||
# group listing by type, then by name (case-insensitive)
|
||||
# FIXME: sorting should be done in the frontends
|
||||
@ -127,52 +128,58 @@ class ContentsHandler(IPythonHandler):
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
@gen.coroutine
|
||||
def patch(self, path=''):
|
||||
"""PATCH renames a file or directory without re-uploading content."""
|
||||
cm = self.contents_manager
|
||||
model = self.get_json_body()
|
||||
if model is None:
|
||||
raise web.HTTPError(400, u'JSON body missing')
|
||||
model = cm.update(model, path)
|
||||
model = yield gen.maybe_future(cm.update(model, path))
|
||||
validate_model(model, expect_content=False)
|
||||
self._finish_model(model)
|
||||
|
||||
|
||||
@gen.coroutine
|
||||
def _copy(self, copy_from, copy_to=None):
|
||||
"""Copy a file, optionally specifying a target directory."""
|
||||
self.log.info(u"Copying {copy_from} to {copy_to}".format(
|
||||
copy_from=copy_from,
|
||||
copy_to=copy_to or '',
|
||||
))
|
||||
model = self.contents_manager.copy(copy_from, copy_to)
|
||||
model = yield gen.maybe_future(self.contents_manager.copy(copy_from, copy_to))
|
||||
self.set_status(201)
|
||||
validate_model(model, expect_content=False)
|
||||
self._finish_model(model)
|
||||
|
||||
@gen.coroutine
|
||||
def _upload(self, model, path):
|
||||
"""Handle upload of a new file to path"""
|
||||
self.log.info(u"Uploading file to %s", path)
|
||||
model = self.contents_manager.new(model, path)
|
||||
model = yield gen.maybe_future(self.contents_manager.new(model, path))
|
||||
self.set_status(201)
|
||||
validate_model(model, expect_content=False)
|
||||
self._finish_model(model)
|
||||
|
||||
|
||||
@gen.coroutine
|
||||
def _new_untitled(self, path, type='', ext=''):
|
||||
"""Create a new, empty untitled entity"""
|
||||
self.log.info(u"Creating new %s in %s", type or 'file', path)
|
||||
model = self.contents_manager.new_untitled(path=path, type=type, ext=ext)
|
||||
model = yield gen.maybe_future(self.contents_manager.new_untitled(path=path, type=type, ext=ext))
|
||||
self.set_status(201)
|
||||
validate_model(model, expect_content=False)
|
||||
self._finish_model(model)
|
||||
|
||||
|
||||
@gen.coroutine
|
||||
def _save(self, model, path):
|
||||
"""Save an existing file."""
|
||||
self.log.info(u"Saving file at %s", path)
|
||||
model = self.contents_manager.save(model, path)
|
||||
model = yield gen.maybe_future(self.contents_manager.save(model, path))
|
||||
validate_model(model, expect_content=False)
|
||||
self._finish_model(model)
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
@gen.coroutine
|
||||
def post(self, path=''):
|
||||
"""Create a new file in the specified path.
|
||||
|
||||
@ -200,14 +207,15 @@ class ContentsHandler(IPythonHandler):
|
||||
ext = model.get('ext', '')
|
||||
type = model.get('type', '')
|
||||
if copy_from:
|
||||
self._copy(copy_from, path)
|
||||
yield self._copy(copy_from, path)
|
||||
else:
|
||||
self._new_untitled(path, type=type, ext=ext)
|
||||
yield self._new_untitled(path, type=type, ext=ext)
|
||||
else:
|
||||
self._new_untitled(path)
|
||||
yield self._new_untitled(path)
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
@gen.coroutine
|
||||
def put(self, path=''):
|
||||
"""Saves the file in the location specified by name and path.
|
||||
|
||||
@ -223,20 +231,22 @@ class ContentsHandler(IPythonHandler):
|
||||
if model:
|
||||
if model.get('copy_from'):
|
||||
raise web.HTTPError(400, "Cannot copy with PUT, only POST")
|
||||
if self.contents_manager.file_exists(path):
|
||||
self._save(model, path)
|
||||
exists = yield gen.maybe_future(self.contents_manager.file_exists(path))
|
||||
if exists:
|
||||
yield gen.maybe_future(self._save(model, path))
|
||||
else:
|
||||
self._upload(model, path)
|
||||
yield gen.maybe_future(self._upload(model, path))
|
||||
else:
|
||||
self._new_untitled(path)
|
||||
yield gen.maybe_future(self._new_untitled(path))
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
@gen.coroutine
|
||||
def delete(self, path=''):
|
||||
"""delete a file in the given path"""
|
||||
cm = self.contents_manager
|
||||
self.log.warn('delete %s', path)
|
||||
cm.delete(path)
|
||||
yield gen.maybe_future(cm.delete(path))
|
||||
self.set_status(204)
|
||||
self.finish()
|
||||
|
||||
@ -247,19 +257,21 @@ class CheckpointsHandler(IPythonHandler):
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
@gen.coroutine
|
||||
def get(self, path=''):
|
||||
"""get lists checkpoints for a file"""
|
||||
cm = self.contents_manager
|
||||
checkpoints = cm.list_checkpoints(path)
|
||||
checkpoints = yield gen.maybe_future(cm.list_checkpoints(path))
|
||||
data = json.dumps(checkpoints, default=date_default)
|
||||
self.finish(data)
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
@gen.coroutine
|
||||
def post(self, path=''):
|
||||
"""post creates a new checkpoint"""
|
||||
cm = self.contents_manager
|
||||
checkpoint = cm.create_checkpoint(path)
|
||||
checkpoint = yield gen.maybe_future(cm.create_checkpoint(path))
|
||||
data = json.dumps(checkpoint, default=date_default)
|
||||
location = url_path_join(self.base_url, 'api/contents',
|
||||
path, 'checkpoints', checkpoint['id'])
|
||||
@ -274,19 +286,21 @@ class ModifyCheckpointsHandler(IPythonHandler):
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
@gen.coroutine
|
||||
def post(self, path, checkpoint_id):
|
||||
"""post restores a file from a checkpoint"""
|
||||
cm = self.contents_manager
|
||||
cm.restore_checkpoint(checkpoint_id, path)
|
||||
yield gen.maybe_future(cm.restore_checkpoint(checkpoint_id, path))
|
||||
self.set_status(204)
|
||||
self.finish()
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
@gen.coroutine
|
||||
def delete(self, path, checkpoint_id):
|
||||
"""delete clears a checkpoint for a given file"""
|
||||
cm = self.contents_manager
|
||||
cm.delete_checkpoint(checkpoint_id, path)
|
||||
yield gen.maybe_future(cm.delete_checkpoint(checkpoint_id, path))
|
||||
self.set_status(204)
|
||||
self.finish()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user