Show More
@@ -0,0 +1,6 b'' | |||
|
1 | Simplifying configurable URLs | |
|
2 | ----------------------------- | |
|
3 | ||
|
4 | - base_kernel_url configurable is removed | |
|
5 | - websocket_url configurable is removed | |
|
6 | - base_project_url is renamed to base_url (base_project_url is kept as a deprecates alias, for now) |
@@ -120,15 +120,6 b' class IPythonHandler(AuthenticatedHandler):' | |||
|
120 | 120 | #--------------------------------------------------------------- |
|
121 | 121 | |
|
122 | 122 | @property |
|
123 | def ws_url(self): | |
|
124 | """websocket url matching the current request | |
|
125 | ||
|
126 | By default, this is just `''`, indicating that it should match | |
|
127 | the same host, protocol, port, etc. | |
|
128 | """ | |
|
129 | return self.settings.get('websocket_url', '') | |
|
130 | ||
|
131 | @property | |
|
132 | 123 | def mathjax_url(self): |
|
133 | 124 | return self.settings.get('mathjax_url', '') |
|
134 | 125 |
@@ -430,14 +430,6 b' class NotebookApp(BaseIPythonApplication):' | |||
|
430 | 430 | self.log.warn("base_project_url is deprecated, use base_url") |
|
431 | 431 | self.base_url = new |
|
432 | 432 | |
|
433 | websocket_url = Unicode("", config=True, | |
|
434 | help="""The base URL for the websocket server, | |
|
435 | if it differs from the HTTP server (hint: it almost certainly doesn't). | |
|
436 | ||
|
437 | Should be in the form of an HTTP origin: ws[s]://hostname[:port] | |
|
438 | """ | |
|
439 | ) | |
|
440 | ||
|
441 | 433 | extra_static_paths = List(Unicode, config=True, |
|
442 | 434 | help="""Extra paths to search for serving static files. |
|
443 | 435 |
@@ -38,14 +38,14 b' class MainKernelHandler(IPythonHandler):' | |||
|
38 | 38 | @json_errors |
|
39 | 39 | def get(self): |
|
40 | 40 | km = self.kernel_manager |
|
41 |
self.finish(jsonapi.dumps(km.list_kernels( |
|
|
41 | self.finish(jsonapi.dumps(km.list_kernels())) | |
|
42 | 42 | |
|
43 | 43 | @web.authenticated |
|
44 | 44 | @json_errors |
|
45 | 45 | def post(self): |
|
46 | 46 | km = self.kernel_manager |
|
47 | 47 | kernel_id = km.start_kernel() |
|
48 |
model = km.kernel_model(kernel_id |
|
|
48 | model = km.kernel_model(kernel_id) | |
|
49 | 49 | location = url_path_join(self.base_url, 'api', 'kernels', kernel_id) |
|
50 | 50 | self.set_header('Location', url_escape(location)) |
|
51 | 51 | self.set_status(201) |
@@ -61,7 +61,7 b' class KernelHandler(IPythonHandler):' | |||
|
61 | 61 | def get(self, kernel_id): |
|
62 | 62 | km = self.kernel_manager |
|
63 | 63 | km._check_kernel_id(kernel_id) |
|
64 |
model = km.kernel_model(kernel_id |
|
|
64 | model = km.kernel_model(kernel_id) | |
|
65 | 65 | self.finish(jsonapi.dumps(model)) |
|
66 | 66 | |
|
67 | 67 | @web.authenticated |
@@ -84,7 +84,7 b' class KernelActionHandler(IPythonHandler):' | |||
|
84 | 84 | self.set_status(204) |
|
85 | 85 | if action == 'restart': |
|
86 | 86 | km.restart_kernel(kernel_id) |
|
87 |
model = km.kernel_model(kernel_id |
|
|
87 | model = km.kernel_model(kernel_id) | |
|
88 | 88 | self.set_header('Location', '{0}api/kernels/{1}'.format(self.base_url, kernel_id)) |
|
89 | 89 | self.write(jsonapi.dumps(model)) |
|
90 | 90 | self.finish() |
@@ -75,19 +75,19 b' class MappingKernelManager(MultiKernelManager):' | |||
|
75 | 75 | self._check_kernel_id(kernel_id) |
|
76 | 76 | super(MappingKernelManager, self).shutdown_kernel(kernel_id, now=now) |
|
77 | 77 | |
|
78 |
def kernel_model(self, kernel_id |
|
|
78 | def kernel_model(self, kernel_id): | |
|
79 | 79 | """Return a dictionary of kernel information described in the |
|
80 | 80 | JSON standard model.""" |
|
81 | 81 | self._check_kernel_id(kernel_id) |
|
82 |
model = {"id":kernel_id |
|
|
82 | model = {"id":kernel_id} | |
|
83 | 83 | return model |
|
84 | 84 | |
|
85 |
def list_kernels(self |
|
|
85 | def list_kernels(self): | |
|
86 | 86 | """Returns a list of kernel_id's of kernels running.""" |
|
87 | 87 | kernels = [] |
|
88 | 88 | kernel_ids = super(MappingKernelManager, self).list_kernel_ids() |
|
89 | 89 | for kernel_id in kernel_ids: |
|
90 |
model = self.kernel_model(kernel_id |
|
|
90 | model = self.kernel_model(kernel_id) | |
|
91 | 91 | kernels.append(model) |
|
92 | 92 | return kernels |
|
93 | 93 |
@@ -93,7 +93,6 b' class KernelAPITest(NotebookTestBase):' | |||
|
93 | 93 | self.assertEqual(r.headers['Location'], '/api/kernels/'+kern2['id']) |
|
94 | 94 | rekern = r.json() |
|
95 | 95 | self.assertEqual(rekern['id'], kern2['id']) |
|
96 | self.assertIn('ws_url', rekern) | |
|
97 | 96 | |
|
98 | 97 | def test_kernel_handler(self): |
|
99 | 98 | # GET kernel with given id |
@@ -103,7 +102,6 b' class KernelAPITest(NotebookTestBase):' | |||
|
103 | 102 | self.assertEqual(r.status_code, 200) |
|
104 | 103 | assert isinstance(kern1, dict) |
|
105 | 104 | self.assertIn('id', kern1) |
|
106 | self.assertIn('ws_url', kern1) | |
|
107 | 105 | self.assertEqual(kern1['id'], kid) |
|
108 | 106 | |
|
109 | 107 | # Request a bad kernel id and check that a JSON |
@@ -63,7 +63,7 b' class SessionRootHandler(IPythonHandler):' | |||
|
63 | 63 | model = sm.get_session(name=name, path=path) |
|
64 | 64 | else: |
|
65 | 65 | kernel_id = km.start_kernel(cwd=nbm.get_os_path(path)) |
|
66 |
model = sm.create_session(name=name, path=path, kernel_id=kernel_id |
|
|
66 | model = sm.create_session(name=name, path=path, kernel_id=kernel_id) | |
|
67 | 67 | location = url_path_join(self.base_url, 'api', 'sessions', model['id']) |
|
68 | 68 | self.set_header('Location', url_escape(location)) |
|
69 | 69 | self.set_status(201) |
@@ -33,7 +33,7 b' class SessionManager(LoggingConfigurable):' | |||
|
33 | 33 | # Session database initialized below |
|
34 | 34 | _cursor = None |
|
35 | 35 | _connection = None |
|
36 |
_columns = {'session_id', 'name', 'path', 'kernel_id' |
|
|
36 | _columns = {'session_id', 'name', 'path', 'kernel_id'} | |
|
37 | 37 | |
|
38 | 38 | @property |
|
39 | 39 | def cursor(self): |
@@ -41,7 +41,7 b' class SessionManager(LoggingConfigurable):' | |||
|
41 | 41 | if self._cursor is None: |
|
42 | 42 | self._cursor = self.connection.cursor() |
|
43 | 43 | self._cursor.execute("""CREATE TABLE session |
|
44 |
(session_id, name, path, kernel_id |
|
|
44 | (session_id, name, path, kernel_id)""") | |
|
45 | 45 | return self._cursor |
|
46 | 46 | |
|
47 | 47 | @property |
@@ -69,12 +69,12 b' class SessionManager(LoggingConfigurable):' | |||
|
69 | 69 | "Create a uuid for a new session" |
|
70 | 70 | return unicode_type(uuid.uuid4()) |
|
71 | 71 | |
|
72 |
def create_session(self, name=None, path=None, kernel_id=None |
|
|
72 | def create_session(self, name=None, path=None, kernel_id=None): | |
|
73 | 73 | """Creates a session and returns its model""" |
|
74 | 74 | session_id = self.new_session_id() |
|
75 |
return self.save_session(session_id, name=name, path=path, kernel_id=kernel_id |
|
|
75 | return self.save_session(session_id, name=name, path=path, kernel_id=kernel_id) | |
|
76 | 76 | |
|
77 |
def save_session(self, session_id, name=None, path=None, kernel_id=None |
|
|
77 | def save_session(self, session_id, name=None, path=None, kernel_id=None): | |
|
78 | 78 | """Saves the items for the session with the given session_id |
|
79 | 79 | |
|
80 | 80 | Given a session_id (and any other of the arguments), this method |
@@ -91,16 +91,14 b' class SessionManager(LoggingConfigurable):' | |||
|
91 | 91 | the path to the named notebook |
|
92 | 92 | kernel_id : str |
|
93 | 93 | a uuid for the kernel associated with this session |
|
94 | ws_url : str | |
|
95 | the websocket url | |
|
96 | ||
|
94 | ||
|
97 | 95 | Returns |
|
98 | 96 | ------- |
|
99 | 97 | model : dict |
|
100 | 98 | a dictionary of the session model |
|
101 | 99 | """ |
|
102 |
self.cursor.execute("INSERT INTO session VALUES (?,?,?,? |
|
|
103 |
(session_id, name, path, kernel_id |
|
|
100 | self.cursor.execute("INSERT INTO session VALUES (?,?,?,?)", | |
|
101 | (session_id, name, path, kernel_id) | |
|
104 | 102 | ) |
|
105 | 103 | return self.get_session(session_id=session_id) |
|
106 | 104 | |
@@ -114,7 +112,7 b' class SessionManager(LoggingConfigurable):' | |||
|
114 | 112 | ---------- |
|
115 | 113 | **kwargs : keyword argument |
|
116 | 114 | must be given one of the keywords and values from the session database |
|
117 |
(i.e. session_id, name, path, kernel_id |
|
|
115 | (i.e. session_id, name, path, kernel_id) | |
|
118 | 116 | |
|
119 | 117 | Returns |
|
120 | 118 | ------- |
@@ -184,7 +182,6 b' class SessionManager(LoggingConfigurable):' | |||
|
184 | 182 | }, |
|
185 | 183 | 'kernel': { |
|
186 | 184 | 'id': row['kernel_id'], |
|
187 | 'ws_url': row['ws_url'] | |
|
188 | 185 | } |
|
189 | 186 | } |
|
190 | 187 | return model |
@@ -11,16 +11,16 b' class TestSessionManager(TestCase):' | |||
|
11 | 11 | def test_get_session(self): |
|
12 | 12 | sm = SessionManager() |
|
13 | 13 | session_id = sm.new_session_id() |
|
14 |
sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678' |
|
|
14 | sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678') | |
|
15 | 15 | 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' |
|
|
16 | expected = {'id':session_id, 'notebook':{'name':u'test.ipynb', 'path': u'/path/to/'}, 'kernel':{'id':u'5678'}} | |
|
17 | 17 | self.assertEqual(model, expected) |
|
18 | 18 | |
|
19 | 19 | def test_bad_get_session(self): |
|
20 | 20 | # Should raise error if a bad key is passed to the database. |
|
21 | 21 | sm = SessionManager() |
|
22 | 22 | session_id = sm.new_session_id() |
|
23 |
sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678' |
|
|
23 | sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678') | |
|
24 | 24 | self.assertRaises(TypeError, sm.get_session, bad_id=session_id) # Bad keyword |
|
25 | 25 | |
|
26 | 26 | def test_list_sessions(self): |
@@ -28,33 +28,33 b' class TestSessionManager(TestCase):' | |||
|
28 | 28 | session_id1 = sm.new_session_id() |
|
29 | 29 | session_id2 = sm.new_session_id() |
|
30 | 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' |
|
|
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') | |
|
34 | 34 | sessions = sm.list_sessions() |
|
35 | 35 | expected = [{'id':session_id1, 'notebook':{'name':u'test1.ipynb', |
|
36 |
'path': u'/path/to/1/'}, 'kernel':{'id':u'5678' |
|
|
36 | 'path': u'/path/to/1/'}, 'kernel':{'id':u'5678'}}, | |
|
37 | 37 | {'id':session_id2, 'notebook': {'name':u'test2.ipynb', |
|
38 |
'path': u'/path/to/2/'}, 'kernel':{'id':u'5678' |
|
|
38 | 'path': u'/path/to/2/'}, 'kernel':{'id':u'5678'}}, | |
|
39 | 39 | {'id':session_id3, 'notebook':{'name':u'test3.ipynb', |
|
40 |
'path': u'/path/to/3/'}, 'kernel':{'id':u'5678' |
|
|
40 | 'path': u'/path/to/3/'}, 'kernel':{'id':u'5678'}}] | |
|
41 | 41 | self.assertEqual(sessions, expected) |
|
42 | 42 | |
|
43 | 43 | def test_update_session(self): |
|
44 | 44 | sm = SessionManager() |
|
45 | 45 | session_id = sm.new_session_id() |
|
46 |
sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id=None |
|
|
46 | sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id=None) | |
|
47 | 47 | sm.update_session(session_id, kernel_id='5678') |
|
48 | 48 | sm.update_session(session_id, name='new_name.ipynb') |
|
49 | 49 | 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' |
|
|
50 | expected = {'id':session_id, 'notebook':{'name':u'new_name.ipynb', 'path': u'/path/to/'}, 'kernel':{'id':u'5678'}} | |
|
51 | 51 | self.assertEqual(model, expected) |
|
52 | 52 | |
|
53 | 53 | def test_bad_update_session(self): |
|
54 | 54 | # try to update a session with a bad keyword ~ raise error |
|
55 | 55 | sm = SessionManager() |
|
56 | 56 | session_id = sm.new_session_id() |
|
57 |
sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678' |
|
|
57 | sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678') | |
|
58 | 58 | self.assertRaises(TypeError, sm.update_session, session_id=session_id, bad_kw='test.ipynb') # Bad keyword |
|
59 | 59 | |
|
60 | 60 | def test_delete_session(self): |
@@ -62,22 +62,22 b' class TestSessionManager(TestCase):' | |||
|
62 | 62 | session_id1 = sm.new_session_id() |
|
63 | 63 | session_id2 = sm.new_session_id() |
|
64 | 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' |
|
|
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 | 68 | sm.delete_session(session_id2) |
|
69 | 69 | sessions = sm.list_sessions() |
|
70 | 70 | expected = [{'id':session_id1, 'notebook':{'name':u'test1.ipynb', |
|
71 |
'path': u'/path/to/1/'}, 'kernel':{'id':u'5678' |
|
|
71 | 'path': u'/path/to/1/'}, 'kernel':{'id':u'5678'}}, | |
|
72 | 72 | {'id':session_id3, 'notebook':{'name':u'test3.ipynb', |
|
73 |
'path': u'/path/to/3/'}, 'kernel':{'id':u'5678' |
|
|
73 | 'path': u'/path/to/3/'}, 'kernel':{'id':u'5678'}}] | |
|
74 | 74 | self.assertEqual(sessions, expected) |
|
75 | 75 | |
|
76 | 76 | def test_bad_delete_session(self): |
|
77 | 77 | # try to delete a session that doesn't exist ~ raise error |
|
78 | 78 | sm = SessionManager() |
|
79 | 79 | session_id = sm.new_session_id() |
|
80 |
sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678' |
|
|
80 | sm.save_session(session_id=session_id, name='test.ipynb', path='/path/to/', kernel_id='5678') | |
|
81 | 81 | self.assertRaises(TypeError, sm.delete_session, bad_kwarg='23424') # Bad keyword |
|
82 | 82 | self.assertRaises(web.HTTPError, sm.delete_session, session_id='23424') # nonexistant |
|
83 | 83 |
@@ -125,16 +125,9 b' var IPython = (function (IPython) {' | |||
|
125 | 125 | console.log("Kernel started: ", json.id); |
|
126 | 126 | this.running = true; |
|
127 | 127 | this.kernel_id = json.id; |
|
128 | var ws_url = json.ws_url; | |
|
129 | if (ws_url.match(/wss?:\/\//) === null) { | |
|
130 | // trailing 's' in https will become wss for secure web sockets | |
|
131 | var prot = location.protocol.replace('http', 'ws') + "//"; | |
|
132 | ws_url = prot + location.host + ws_url; | |
|
133 | } | |
|
134 | var parsed = utils.parse_url(ws_url); | |
|
135 | this.ws_host = parsed.protocol + "//" + parsed.host; | |
|
128 | // trailing 's' in https will become wss for secure web sockets | |
|
129 | this.ws_host = location.protocol.replace('http', 'ws') + "//" + location.host; | |
|
136 | 130 | this.kernel_url = utils.url_path_join(this.kernel_service_url, this.kernel_id); |
|
137 | this.ws_url = utils.url_path_join(parsed.pathname, this.kernel_url); | |
|
138 | 131 | this.start_channels(); |
|
139 | 132 | }; |
|
140 | 133 | |
@@ -155,18 +148,18 b' var IPython = (function (IPython) {' | |||
|
155 | 148 | Kernel.prototype.start_channels = function () { |
|
156 | 149 | var that = this; |
|
157 | 150 | this.stop_channels(); |
|
158 | console.log("Starting WebSockets:", this.ws_host + this.ws_url); | |
|
151 | var ws_host_url = this.ws_host + this.kernel_url; | |
|
152 | console.log("Starting WebSockets:", ws_host_url); | |
|
159 | 153 | this.shell_channel = new this.WebSocket( |
|
160 |
this.ws_host + utils.url_join_encode(this. |
|
|
154 | this.ws_host + utils.url_join_encode(this.kernel_url, "shell") | |
|
161 | 155 | ); |
|
162 | 156 | this.stdin_channel = new this.WebSocket( |
|
163 |
this.ws_host + utils.url_join_encode(this. |
|
|
157 | this.ws_host + utils.url_join_encode(this.kernel_url, "stdin") | |
|
164 | 158 | ); |
|
165 | 159 | this.iopub_channel = new this.WebSocket( |
|
166 |
this.ws_host + utils.url_join_encode(this. |
|
|
160 | this.ws_host + utils.url_join_encode(this.kernel_url, "iopub") | |
|
167 | 161 | ); |
|
168 | 162 | |
|
169 | var ws_host_url = this.ws_host + this.ws_url; | |
|
170 | 163 | var already_called_onclose = false; // only alert once |
|
171 | 164 | var ws_closed_early = function(evt){ |
|
172 | 165 | if (already_called_onclose){ |
General Comments 0
You need to be logged in to leave comments.
Login now