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