handle async in sessions

needed because sessions call kernel methods
Min RK 10 years ago
parent 6024f04698
commit 9043ae145c

@ -8,7 +8,7 @@ Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-16%3A-
import json
from tornado import web
from tornado import gen, web
from ...base.handlers import APIHandler, json_errors
from jupyter_client.jsonutil import date_default
@ -20,20 +20,20 @@ class SessionRootHandler(APIHandler):
@web.authenticated
@json_errors
@gen.coroutine
def get(self):
# Return a list of running sessions
sm = self.session_manager
sessions = sm.list_sessions()
sessions = yield gen.maybe_future(sm.list_sessions())
self.finish(json.dumps(sessions, default=date_default))
@web.authenticated
@json_errors
@gen.coroutine
def post(self):
# Creates a new session
#(unless a session already exists for the named nb)
sm = self.session_manager
cm = self.contents_manager
km = self.kernel_manager
model = self.get_json_body()
if model is None:
@ -49,11 +49,13 @@ class SessionRootHandler(APIHandler):
kernel_name = None
# Check to see if session exists
if sm.session_exists(path=path):
model = sm.get_session(path=path)
exists = yield gen.maybe_future(sm.session_exists(path=path))
if exists:
model = yield gen.maybe_future(sm.get_session(path=path))
else:
try:
model = sm.create_session(path=path, kernel_name=kernel_name)
model = yield gen.maybe_future(
sm.create_session(path=path, kernel_name=kernel_name))
except NoSuchKernel:
msg = ("The '%s' kernel is not available. Please pick another "
"suitable kernel instead, or install that kernel." % kernel_name)
@ -73,14 +75,16 @@ class SessionHandler(APIHandler):
@web.authenticated
@json_errors
@gen.coroutine
def get(self, session_id):
# Returns the JSON model for a single session
sm = self.session_manager
model = sm.get_session(session_id=session_id)
model = yield gen.maybe_future(sm.get_session(session_id=session_id))
self.finish(json.dumps(model, default=date_default))
@web.authenticated
@json_errors
@gen.coroutine
def patch(self, session_id):
# Currently, this handler is strictly for renaming notebooks
sm = self.session_manager
@ -93,17 +97,18 @@ class SessionHandler(APIHandler):
if 'path' in notebook:
changes['path'] = notebook['path']
sm.update_session(session_id, **changes)
model = sm.get_session(session_id=session_id)
yield gen.maybe_future(sm.update_session(session_id, **changes))
model = yield gen.maybe_future(sm.get_session(session_id=session_id))
self.finish(json.dumps(model, default=date_default))
@web.authenticated
@json_errors
@gen.coroutine
def delete(self, session_id):
# Deletes the session with given session_id
sm = self.session_manager
try:
sm.delete_session(session_id)
yield gen.maybe_future(sm.delete_session(session_id))
except KeyError:
# the kernel was deleted but the session wasn't!
raise web.HTTPError(410, "Kernel deleted before session")

@ -6,7 +6,7 @@
import uuid
import sqlite3
from tornado import web
from tornado import gen, web
from traitlets.config.configurable import LoggingConfigurable
from ipython_genutils.py3compat import unicode_type
@ -56,17 +56,22 @@ class SessionManager(LoggingConfigurable):
def new_session_id(self):
"Create a uuid for a new session"
return unicode_type(uuid.uuid4())
@gen.coroutine
def create_session(self, path=None, kernel_name=None):
"""Creates a session and returns its model"""
session_id = self.new_session_id()
# allow nbm to specify kernels cwd
kernel_path = self.contents_manager.get_kernel_path(path=path)
kernel_id = self.kernel_manager.start_kernel(path=kernel_path,
kernel_name=kernel_name)
return self.save_session(session_id, path=path,
kernel_id=kernel_id)
kernel_id = yield gen.maybe_future(
self.kernel_manager.start_kernel(path=kernel_path, kernel_name=kernel_name)
)
result = yield gen.maybe_future(
self.save_session(session_id, path=path, kernel_id=kernel_id)
)
# py2-compat
raise gen.Return(result)
def save_session(self, session_id, path=None, kernel_id=None):
"""Saves the items for the session with the given session_id

@ -2,7 +2,8 @@
from unittest import TestCase
from tornado import web
from tornado import gen, web
from tornado.ioloop import IOLoop
from ..sessionmanager import SessionManager
from notebook.services.kernels.kernelmanager import MappingKernelManager
@ -37,12 +38,31 @@ class TestSessionManager(TestCase):
kernel_manager=DummyMKM(),
contents_manager=ContentsManager(),
)
self.loop = IOLoop()
def tearDown(self):
self.loop.close(all_fds=True)
def create_sessions(self, *kwarg_list):
@gen.coroutine
def co_add():
sessions = []
for kwargs in kwarg_list:
session = yield self.sm.create_session(**kwargs)
sessions.append(session)
raise gen.Return(sessions)
return self.loop.run_sync(co_add)
def create_session(self, **kwargs):
return self.create_sessions(kwargs)[0]
def get_session(self, **kwargs):
return self.loop.run_sync(lambda : self.sm.get_session(**kwargs))
def test_get_session(self):
sm = self.sm
session_id = sm.create_session(path='/path/to/test.ipynb',
kernel_name='bar')['id']
model = sm.get_session(session_id=session_id)
session_id = self.create_session(path='/path/to/test.ipynb', kernel_name='bar')['id']
model = self.get_session(session_id=session_id)
expected = {'id':session_id,
'notebook':{'path': u'/path/to/test.ipynb'},
'kernel': {'id':u'A', 'name': 'bar'}}
@ -51,13 +71,13 @@ class TestSessionManager(TestCase):
def test_bad_get_session(self):
# Should raise error if a bad key is passed to the database.
sm = self.sm
session_id = sm.create_session(path='/path/to/test.ipynb',
session_id = self.create_session(path='/path/to/test.ipynb',
kernel_name='foo')['id']
self.assertRaises(TypeError, sm.get_session, bad_id=session_id) # Bad keyword
def test_get_session_dead_kernel(self):
sm = self.sm
session = sm.create_session(path='/path/to/1/test1.ipynb', kernel_name='python')
session = self.create_session(path='/path/to/1/test1.ipynb', kernel_name='python')
# kill the kernel
sm.kernel_manager.shutdown_kernel(session['kernel']['id'])
with self.assertRaises(KeyError):
@ -68,11 +88,12 @@ class TestSessionManager(TestCase):
def test_list_sessions(self):
sm = self.sm
sessions = [
sm.create_session(path='/path/to/1/test1.ipynb', kernel_name='python'),
sm.create_session(path='/path/to/2/test2.ipynb', kernel_name='python'),
sm.create_session(path='/path/to/3/test3.ipynb', kernel_name='python'),
]
sessions = self.create_sessions(
dict(path='/path/to/1/test1.ipynb', kernel_name='python'),
dict(path='/path/to/2/test2.ipynb', kernel_name='python'),
dict(path='/path/to/3/test3.ipynb', kernel_name='python'),
)
sessions = sm.list_sessions()
expected = [
{
@ -93,10 +114,10 @@ class TestSessionManager(TestCase):
def test_list_sessions_dead_kernel(self):
sm = self.sm
sessions = [
sm.create_session(path='/path/to/1/test1.ipynb', kernel_name='python'),
sm.create_session(path='/path/to/2/test2.ipynb', kernel_name='python'),
]
sessions = self.create_sessions(
dict(path='/path/to/1/test1.ipynb', kernel_name='python'),
dict(path='/path/to/2/test2.ipynb', kernel_name='python'),
)
# kill one of the kernels
sm.kernel_manager.shutdown_kernel(sessions[0]['kernel']['id'])
listed = sm.list_sessions()
@ -116,10 +137,10 @@ class TestSessionManager(TestCase):
def test_update_session(self):
sm = self.sm
session_id = sm.create_session(path='/path/to/test.ipynb',
session_id = self.create_session(path='/path/to/test.ipynb',
kernel_name='julia')['id']
sm.update_session(session_id, path='/path/to/new_name.ipynb')
model = sm.get_session(session_id=session_id)
model = self.loop.run_sync(lambda : sm.get_session(session_id=session_id))
expected = {'id':session_id,
'notebook':{'path': u'/path/to/new_name.ipynb'},
'kernel':{'id':u'A', 'name':'julia'}}
@ -128,17 +149,17 @@ class TestSessionManager(TestCase):
def test_bad_update_session(self):
# try to update a session with a bad keyword ~ raise error
sm = self.sm
session_id = sm.create_session(path='/path/to/test.ipynb',
session_id = self.create_session(path='/path/to/test.ipynb',
kernel_name='ir')['id']
self.assertRaises(TypeError, sm.update_session, session_id=session_id, bad_kw='test.ipynb') # Bad keyword
def test_delete_session(self):
sm = self.sm
sessions = [
sm.create_session(path='/path/to/1/test1.ipynb', kernel_name='python'),
sm.create_session(path='/path/to/2/test2.ipynb', kernel_name='python'),
sm.create_session(path='/path/to/3/test3.ipynb', kernel_name='python'),
]
sessions = self.create_sessions(
dict(path='/path/to/1/test1.ipynb', kernel_name='python'),
dict(path='/path/to/2/test2.ipynb', kernel_name='python'),
dict(path='/path/to/3/test3.ipynb', kernel_name='python'),
)
sm.delete_session(sessions[1]['id'])
new_sessions = sm.list_sessions()
expected = [{
@ -156,7 +177,7 @@ class TestSessionManager(TestCase):
def test_bad_delete_session(self):
# try to delete a session that doesn't exist ~ raise error
sm = self.sm
sm.create_session(path='/path/to/test.ipynb', kernel_name='python')
self.create_session(path='/path/to/test.ipynb', kernel_name='python')
self.assertRaises(TypeError, sm.delete_session, bad_kwarg='23424') # Bad keyword
self.assertRaises(web.HTTPError, sm.delete_session, session_id='23424') # nonexistant

Loading…
Cancel
Save