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,6 +23,7 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 |
@@ -30,6 +31,9 b' from IPython.utils.py3compat import unicode_type' | |||
|
30 | 31 | |
|
31 | 32 | class SessionManager(LoggingConfigurable): |
|
32 | 33 | |
|
34 | kernel_manager = Instance('IPython.html.services.kernels.kernelmanager.MappingKernelManager') | |
|
35 | notebook_manager = Instance('IPython.html.services.notebooks.nbmanager.NotebookManager', args=()) | |
|
36 | ||
|
33 | 37 | # Session database initialized below |
|
34 | 38 | _cursor = None |
|
35 | 39 | _connection = 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_ |
|
|
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. |
|
|
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 |
|
|
36 |
'path': u'/path/to/1/'}, 'kernel':{'id':u' |
|
|
37 |
{'id':session |
|
|
38 |
'path': u'/path/to/2/'}, 'kernel':{'id':u' |
|
|
39 |
{'id':session |
|
|
40 |
'path': u'/path/to/3/'}, 'kernel':{'id':u' |
|
|
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. |
|
|
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. |
|
|
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