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