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 |
|
|
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 | |
@@ -375,7 +375,8 b' def json_errors(method):' | |||||
375 | reply = dict(message=message, reason=None, traceback=tb_text) |
|
375 | reply = dict(message=message, reason=None, traceback=tb_text) | |
376 | self.finish(json.dumps(reply)) |
|
376 | self.finish(json.dumps(reply)) | |
377 | else: |
|
377 | else: | |
378 | return result |
|
378 | # FIXME: can use regular return in generators in py3 | |
|
379 | raise gen.Return(result) | |||
379 | return wrapper |
|
380 | return wrapper | |
380 |
|
381 | |||
381 |
|
382 |
@@ -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 |
|
|
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