##// END OF EJS Templates
Add kernel name to sessions REST API...
Thomas Kluyver -
Show More
@@ -658,7 +658,9 b' class NotebookApp(BaseIPythonApplication):'
658 658 kls = import_item(self.notebook_manager_class)
659 659 self.notebook_manager = kls(parent=self, log=self.log)
660 660 kls = import_item(self.session_manager_class)
661 self.session_manager = kls(parent=self, log=self.log)
661 self.session_manager = kls(parent=self, log=self.log,
662 kernel_manager=self.kernel_manager,
663 notebook_manager=self.notebook_manager)
662 664 kls = import_item(self.cluster_manager_class)
663 665 self.cluster_manager = kls(parent=self, log=self.log)
664 666 self.cluster_manager.update_profiles()
@@ -45,27 +45,28 b' class SessionRootHandler(IPythonHandler):'
45 45 # Creates a new session
46 46 #(unless a session already exists for the named nb)
47 47 sm = self.session_manager
48 nbm = self.notebook_manager
49 km = self.kernel_manager
48
50 49 model = self.get_json_body()
51 50 if model is None:
52 51 raise web.HTTPError(400, "No JSON data provided")
53 52 try:
54 53 name = model['notebook']['name']
55 54 except KeyError:
56 raise web.HTTPError(400, "Missing field in JSON data: name")
55 raise web.HTTPError(400, "Missing field in JSON data: notebook.name")
57 56 try:
58 57 path = model['notebook']['path']
59 58 except KeyError:
60 raise web.HTTPError(400, "Missing field in JSON data: path")
59 raise web.HTTPError(400, "Missing field in JSON data: notebook.path")
60 try:
61 kernel_name = model['kernel']['name']
62 except KeyError:
63 raise web.HTTPError(400, "Missing field in JSON data: kernel.name")
64
61 65 # Check to see if session exists
62 66 if sm.session_exists(name=name, path=path):
63 67 model = sm.get_session(name=name, path=path)
64 68 else:
65 # allow nbm to specify kernels cwd
66 kernel_path = nbm.get_kernel_path(name=name, path=path)
67 kernel_id = km.start_kernel(path=kernel_path)
68 model = sm.create_session(name=name, path=path, kernel_id=kernel_id)
69 model = sm.create_session(name=name, path=path, kernel_name=kernel_name)
69 70 location = url_path_join(self.base_url, 'api', 'sessions', model['id'])
70 71 self.set_header('Location', url_escape(location))
71 72 self.set_status(201)
@@ -108,10 +109,7 b' class SessionHandler(IPythonHandler):'
108 109 def delete(self, session_id):
109 110 # Deletes the session with given session_id
110 111 sm = self.session_manager
111 km = self.kernel_manager
112 session = sm.get_session(session_id=session_id)
113 112 sm.delete_session(session_id)
114 km.shutdown_kernel(session['kernel']['id'])
115 113 self.set_status(204)
116 114 self.finish()
117 115
@@ -23,12 +23,16 b' from tornado import web'
23 23
24 24 from IPython.config.configurable import LoggingConfigurable
25 25 from IPython.utils.py3compat import unicode_type
26 from IPython.utils.traitlets import Instance
26 27
27 28 #-----------------------------------------------------------------------------
28 29 # Classes
29 30 #-----------------------------------------------------------------------------
30 31
31 32 class SessionManager(LoggingConfigurable):
33
34 kernel_manager = Instance('IPython.html.services.kernels.kernelmanager.MappingKernelManager')
35 notebook_manager = Instance('IPython.html.services.notebooks.nbmanager.NotebookManager', args=())
32 36
33 37 # Session database initialized below
34 38 _cursor = None
@@ -69,10 +73,15 b' class SessionManager(LoggingConfigurable):'
69 73 "Create a uuid for a new session"
70 74 return unicode_type(uuid.uuid4())
71 75
72 def create_session(self, name=None, path=None, kernel_id=None):
76 def create_session(self, name=None, path=None, kernel_name='python'):
73 77 """Creates a session and returns its model"""
74 78 session_id = self.new_session_id()
75 return self.save_session(session_id, name=name, path=path, kernel_id=kernel_id)
79 # allow nbm to specify kernels cwd
80 kernel_path = self.notebook_manager.get_kernel_path(name=name, path=path)
81 kernel_id = self.kernel_manager.start_kernel(path=kernel_path,
82 kernel_name=kernel_name)
83 return self.save_session(session_id, name=name, path=path,
84 kernel_id=kernel_id)
76 85
77 86 def save_session(self, session_id, name=None, path=None, kernel_id=None):
78 87 """Saves the items for the session with the given session_id
@@ -170,8 +179,7 b' class SessionManager(LoggingConfigurable):'
170 179 query = "UPDATE session SET %s WHERE session_id=?" % (', '.join(sets))
171 180 self.cursor.execute(query, list(kwargs.values()) + [session_id])
172 181
173 @staticmethod
174 def row_factory(cursor, row):
182 def row_factory(self, cursor, row):
175 183 """Takes sqlite database session row and turns it into a dictionary"""
176 184 row = sqlite3.Row(cursor, row)
177 185 model = {
@@ -180,9 +188,7 b' class SessionManager(LoggingConfigurable):'
180 188 'name': row['name'],
181 189 'path': row['path']
182 190 },
183 'kernel': {
184 'id': row['kernel_id'],
185 }
191 'kernel': self.kernel_manager.kernel_model(row['kernel_id'])
186 192 }
187 193 return model
188 194
@@ -195,5 +201,6 b' class SessionManager(LoggingConfigurable):'
195 201 def delete_session(self, session_id):
196 202 """Deletes the row in the session database with given session_id"""
197 203 # Check that session exists before deleting
198 self.get_session(session_id=session_id)
204 session = self.get_session(session_id=session_id)
205 self.kernel_manager.shutdown_kernel(session['kernel']['id'])
199 206 self.cursor.execute("DELETE FROM session WHERE session_id=?", (session_id,))
@@ -5,79 +5,101 b' from unittest import TestCase'
5 5 from tornado import web
6 6
7 7 from ..sessionmanager import SessionManager
8 from IPython.html.services.kernels.kernelmanager import MappingKernelManager
9
10 class DummyKernel(object):
11 def __init__(self, kernel_name='python'):
12 self.kernel_name = kernel_name
13
14 class DummyMKM(MappingKernelManager):
15 """MappingKernelManager interface that doesn't start kernels, for testing"""
16 def __init__(self, *args, **kwargs):
17 super(DummyMKM, self).__init__(*args, **kwargs)
18 self.id_letters = iter(u'ABCDEFGHIJK')
19
20 def _new_id(self):
21 return next(self.id_letters)
22
23 def start_kernel(self, kernel_id=None, path=None, kernel_name='python', **kwargs):
24 kernel_id = kernel_id or self._new_id()
25 self._kernels[kernel_id] = DummyKernel(kernel_name=kernel_name)
26 return kernel_id
27
28 def shutdown_kernel(self, kernel_id, now=False):
29 del self._kernels[kernel_id]
8 30
9 31 class TestSessionManager(TestCase):
10 32
11 33 def test_get_session(self):
12 sm = SessionManager()
13 session_id = sm.new_session_id()
14 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678')
34 sm = SessionManager(kernel_manager=DummyMKM())
35 session_id = sm.create_session(name='test.ipynb', path='/path/to/',
36 kernel_name='bar')['id']
15 37 model = sm.get_session(session_id=session_id)
16 expected = {'id':session_id, 'notebook':{'name':u'test.ipynb', 'path': u'/path/to/'}, 'kernel':{'id':u'5678'}}
38 expected = {'id':session_id,
39 'notebook':{'name':u'test.ipynb', 'path': u'/path/to/'},
40 'kernel': {'id':u'A', 'name': 'bar'}}
17 41 self.assertEqual(model, expected)
18 42
19 43 def test_bad_get_session(self):
20 44 # Should raise error if a bad key is passed to the database.
21 sm = SessionManager()
22 session_id = sm.new_session_id()
23 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678')
45 sm = SessionManager(kernel_manager=DummyMKM())
46 session_id = sm.create_session(name='test.ipynb', path='/path/to/',
47 kernel_name='foo')['id']
24 48 self.assertRaises(TypeError, sm.get_session, bad_id=session_id) # Bad keyword
25 49
26 50 def test_list_sessions(self):
27 sm = SessionManager()
28 session_id1 = sm.new_session_id()
29 session_id2 = sm.new_session_id()
30 session_id3 = sm.new_session_id()
31 sm.save_session(session_id=session_id1, name='test1.ipynb', path='/path/to/1/', kernel_id='5678')
32 sm.save_session(session_id=session_id2, name='test2.ipynb', path='/path/to/2/', kernel_id='5678')
33 sm.save_session(session_id=session_id3, name='test3.ipynb', path='/path/to/3/', kernel_id='5678')
51 sm = SessionManager(kernel_manager=DummyMKM())
52 sessions = [
53 sm.create_session(name='test1.ipynb', path='/path/to/1/', kernel_name='python'),
54 sm.create_session(name='test2.ipynb', path='/path/to/2/', kernel_name='python'),
55 sm.create_session(name='test3.ipynb', path='/path/to/3/', kernel_name='python'),
56 ]
34 57 sessions = sm.list_sessions()
35 expected = [{'id':session_id1, 'notebook':{'name':u'test1.ipynb',
36 'path': u'/path/to/1/'}, 'kernel':{'id':u'5678'}},
37 {'id':session_id2, 'notebook': {'name':u'test2.ipynb',
38 'path': u'/path/to/2/'}, 'kernel':{'id':u'5678'}},
39 {'id':session_id3, 'notebook':{'name':u'test3.ipynb',
40 'path': u'/path/to/3/'}, 'kernel':{'id':u'5678'}}]
58 expected = [{'id':sessions[0]['id'], 'notebook':{'name':u'test1.ipynb',
59 'path': u'/path/to/1/'}, 'kernel':{'id':u'A', 'name':'python'}},
60 {'id':sessions[1]['id'], 'notebook': {'name':u'test2.ipynb',
61 'path': u'/path/to/2/'}, 'kernel':{'id':u'B', 'name':'python'}},
62 {'id':sessions[2]['id'], 'notebook':{'name':u'test3.ipynb',
63 'path': u'/path/to/3/'}, 'kernel':{'id':u'C', 'name':'python'}}]
41 64 self.assertEqual(sessions, expected)
42 65
43 66 def test_update_session(self):
44 sm = SessionManager()
45 session_id = sm.new_session_id()
46 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id=None)
47 sm.update_session(session_id, kernel_id='5678')
67 sm = SessionManager(kernel_manager=DummyMKM())
68 session_id = sm.create_session(name='test.ipynb', path='/path/to/',
69 kernel_name='julia')['id']
48 70 sm.update_session(session_id, name='new_name.ipynb')
49 71 model = sm.get_session(session_id=session_id)
50 expected = {'id':session_id, 'notebook':{'name':u'new_name.ipynb', 'path': u'/path/to/'}, 'kernel':{'id':u'5678'}}
72 expected = {'id':session_id,
73 'notebook':{'name':u'new_name.ipynb', 'path': u'/path/to/'},
74 'kernel':{'id':u'A', 'name':'julia'}}
51 75 self.assertEqual(model, expected)
52 76
53 77 def test_bad_update_session(self):
54 78 # try to update a session with a bad keyword ~ raise error
55 sm = SessionManager()
56 session_id = sm.new_session_id()
57 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678')
79 sm = SessionManager(kernel_manager=DummyMKM())
80 session_id = sm.create_session(name='test.ipynb', path='/path/to/',
81 kernel_name='ir')['id']
58 82 self.assertRaises(TypeError, sm.update_session, session_id=session_id, bad_kw='test.ipynb') # Bad keyword
59 83
60 84 def test_delete_session(self):
61 sm = SessionManager()
62 session_id1 = sm.new_session_id()
63 session_id2 = sm.new_session_id()
64 session_id3 = sm.new_session_id()
65 sm.save_session(session_id=session_id1, name='test1.ipynb', path='/path/to/1/', kernel_id='5678')
66 sm.save_session(session_id=session_id2, name='test2.ipynb', path='/path/to/2/', kernel_id='5678')
67 sm.save_session(session_id=session_id3, name='test3.ipynb', path='/path/to/3/', kernel_id='5678')
68 sm.delete_session(session_id2)
69 sessions = sm.list_sessions()
70 expected = [{'id':session_id1, 'notebook':{'name':u'test1.ipynb',
71 'path': u'/path/to/1/'}, 'kernel':{'id':u'5678'}},
72 {'id':session_id3, 'notebook':{'name':u'test3.ipynb',
73 'path': u'/path/to/3/'}, 'kernel':{'id':u'5678'}}]
74 self.assertEqual(sessions, expected)
85 sm = SessionManager(kernel_manager=DummyMKM())
86 sessions = [
87 sm.create_session(name='test1.ipynb', path='/path/to/1/', kernel_name='python'),
88 sm.create_session(name='test2.ipynb', path='/path/to/2/', kernel_name='python'),
89 sm.create_session(name='test3.ipynb', path='/path/to/3/', kernel_name='python'),
90 ]
91 sm.delete_session(sessions[1]['id'])
92 new_sessions = sm.list_sessions()
93 expected = [{'id':sessions[0]['id'], 'notebook':{'name':u'test1.ipynb',
94 'path': u'/path/to/1/'}, 'kernel':{'id':u'A', 'name':'python'}},
95 {'id':sessions[2]['id'], 'notebook':{'name':u'test3.ipynb',
96 'path': u'/path/to/3/'}, 'kernel':{'id':u'C', 'name':'python'}}]
97 self.assertEqual(new_sessions, expected)
75 98
76 99 def test_bad_delete_session(self):
77 100 # try to delete a session that doesn't exist ~ raise error
78 sm = SessionManager()
79 session_id = sm.new_session_id()
80 sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678')
101 sm = SessionManager(kernel_manager=DummyMKM())
102 sm.create_session(name='test.ipynb', path='/path/to/', kernel_name='python')
81 103 self.assertRaises(TypeError, sm.delete_session, bad_kwarg='23424') # Bad keyword
82 104 self.assertRaises(web.HTTPError, sm.delete_session, session_id='23424') # nonexistant
83 105
@@ -37,8 +37,9 b' class SessionAPI(object):'
37 37 def get(self, id):
38 38 return self._req('GET', id)
39 39
40 def create(self, name, path):
41 body = json.dumps({'notebook': {'name':name, 'path':path}})
40 def create(self, name, path, kernel_name='python'):
41 body = json.dumps({'notebook': {'name':name, 'path':path},
42 'kernel': {'name': kernel_name}})
42 43 return self._req('POST', '', body)
43 44
44 45 def modify(self, id, name, path):
General Comments 0
You need to be logged in to leave comments. Login now