Show More
@@ -54,6 +54,9 class Adapter(object): | |||
|
54 | 54 | handler = getattr(self, header['msg_type'], None) |
|
55 | 55 | if handler is None: |
|
56 | 56 | return msg |
|
57 | # no transform for status=error | |
|
58 | if msg['content'].get('status', None) in {'error', 'aborted'}: | |
|
59 | return msg | |
|
57 | 60 | return handler(msg) |
|
58 | 61 | |
|
59 | 62 | def _version_str_to_list(version): |
@@ -62,7 +65,7 def _version_str_to_list(version): | |||
|
62 | 65 | non-int segments are excluded |
|
63 | 66 | """ |
|
64 | 67 | v = [] |
|
65 |
for part in |
|
|
68 | for part in version.split('.'): | |
|
66 | 69 | try: |
|
67 | 70 | v.append(int(part)) |
|
68 | 71 | except ValueError: |
@@ -121,7 +124,7 class V5toV4(Adapter): | |||
|
121 | 124 | new_content = msg['content'] = {} |
|
122 | 125 | new_content['text'] = '' |
|
123 | 126 | new_content['line'] = line |
|
124 |
new_content['blo |
|
|
127 | new_content['block'] = None | |
|
125 | 128 | new_content['cursor_pos'] = cursor_pos |
|
126 | 129 | return msg |
|
127 | 130 | |
@@ -138,10 +141,10 class V5toV4(Adapter): | |||
|
138 | 141 | content = msg['content'] |
|
139 | 142 | code = content['code'] |
|
140 | 143 | cursor_pos = content['cursor_pos'] |
|
141 |
line, |
|
|
144 | line, _ = code_to_line(code, cursor_pos) | |
|
142 | 145 | |
|
143 | new_content = msg['content'] = {} | |
|
144 | new_content['name'] = token_at_cursor(code, cursor_pos) | |
|
146 | new_content = msg['content'] = {'status' : 'ok'} | |
|
147 | new_content['oname'] = token_at_cursor(code, cursor_pos) | |
|
145 | 148 | new_content['detail_level'] = content['detail_level'] |
|
146 | 149 | return msg |
|
147 | 150 | |
@@ -155,6 +158,13 class V5toV4(Adapter): | |||
|
155 | 158 | def display_data(self, msg): |
|
156 | 159 | content = msg['content'] |
|
157 | 160 | content.setdefault("source", "display") |
|
161 | data = content['data'] | |
|
162 | if 'application/json' in data: | |
|
163 | try: | |
|
164 | data['application/json'] = json.dumps(data['application/json']) | |
|
165 | except Exception: | |
|
166 | # warn? | |
|
167 | pass | |
|
158 | 168 | return msg |
|
159 | 169 | |
|
160 | 170 | # stdin channel |
@@ -219,25 +229,45 class V4toV5(Adapter): | |||
|
219 | 229 | def complete_reply(self, msg): |
|
220 | 230 | # TODO: complete_reply needs more context than we have |
|
221 | 231 | # Maybe strip common prefix and give magic cursor_start = cursor_end = 0? |
|
222 |
content = msg['content'] |
|
|
223 | content['matches'] = [] | |
|
224 | content['cursor_start'] = content['cursor_end'] = 0 | |
|
225 | content['metadata'] = {} | |
|
232 | content = msg['content'] | |
|
233 | new_content = msg['content'] = {'status' : 'ok'} | |
|
234 | n = len(content['matched_text']) | |
|
235 | new_content['matches'] = [ m[n:] for m in content['matches'] ] | |
|
236 | new_content['cursor_start'] = new_content['cursor_end'] = 0 | |
|
237 | new_content['metadata'] = {} | |
|
226 | 238 | return msg |
|
227 | 239 | |
|
228 | 240 | def inspect_request(self, msg): |
|
229 | 241 | content = msg['content'] |
|
230 | name = content['name'] | |
|
242 | name = content['oname'] | |
|
231 | 243 | |
|
232 | 244 | new_content = msg['content'] = {} |
|
233 | 245 | new_content['code'] = name |
|
234 |
new_content['cursor_pos'] = len(name) |
|
|
246 | new_content['cursor_pos'] = len(name) | |
|
235 | 247 | new_content['detail_level'] = content['detail_level'] |
|
236 | 248 | return msg |
|
237 | 249 | |
|
238 | 250 | def inspect_reply(self, msg): |
|
239 | 251 | """inspect_reply can't be easily backward compatible""" |
|
240 | msg['content'] = {'found' : False, 'name' : 'unknown'} | |
|
252 | content = msg['content'] | |
|
253 | new_content = msg['content'] = {'status' : 'ok'} | |
|
254 | found = new_content['found'] = content['found'] | |
|
255 | new_content['name'] = content['name'] | |
|
256 | new_content['data'] = data = {} | |
|
257 | new_content['metadata'] = {} | |
|
258 | if found: | |
|
259 | lines = [] | |
|
260 | for key in ('call_def', 'init_definition', 'definition'): | |
|
261 | if content.get(key, False): | |
|
262 | lines.append(content[key]) | |
|
263 | break | |
|
264 | for key in ('call_docstring', 'init_docstring', 'docstring'): | |
|
265 | if content.get(key, False): | |
|
266 | lines.append(content[key]) | |
|
267 | break | |
|
268 | if not lines: | |
|
269 | lines.append("<empty docstring>") | |
|
270 | data['text/plain'] = '\n'.join(lines) | |
|
241 | 271 | return msg |
|
242 | 272 | |
|
243 | 273 | # iopub channel |
@@ -247,7 +277,11 class V4toV5(Adapter): | |||
|
247 | 277 | content.pop("source", None) |
|
248 | 278 | data = content['data'] |
|
249 | 279 | if 'application/json' in data: |
|
250 | data['application/json'] = json.dumps(data['application/json']) | |
|
280 | try: | |
|
281 | data['application/json'] = json.loads(data['application/json']) | |
|
282 | except Exception: | |
|
283 | # warn? | |
|
284 | pass | |
|
251 | 285 | return msg |
|
252 | 286 | |
|
253 | 287 | # stdin channel |
@@ -4,7 +4,7 | |||
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | import copy |
|
7 | ||
|
7 | import json | |
|
8 | 8 | from unittest import TestCase |
|
9 | 9 | import nose.tools as nt |
|
10 | 10 | |
@@ -18,13 +18,12 def test_default_version(): | |||
|
18 | 18 | msg['header'].pop('version') |
|
19 | 19 | original = copy.deepcopy(msg) |
|
20 | 20 | adapted = adapt(original) |
|
21 |
nt.assert_equal(adapted['header'] |
|
|
21 | nt.assert_equal(adapted['header']['version'], V4toV5.version) | |
|
22 | 22 | |
|
23 | 23 | |
|
24 | 24 | class AdapterTest(TestCase): |
|
25 | 25 | |
|
26 | 26 | def setUp(self): |
|
27 | print("hi") | |
|
28 | 27 | self.session = Session() |
|
29 | 28 | |
|
30 | 29 | def adapt(self, msg, version=None): |
@@ -85,25 +84,90 class V4toV5TestCase(AdapterTest): | |||
|
85 | 84 | v4c = v4['content'] |
|
86 | 85 | v5c = v5['content'] |
|
87 | 86 | self.assertEqual(v5c['user_expressions'], {'a' : 'apple', 'b': 'b'}) |
|
88 |
|
|
|
87 | self.assertNotIn('user_variables', v5c) | |
|
89 | 88 | self.assertEqual(v5c['code'], v4c['code']) |
|
90 | 89 | |
|
91 | 90 | def test_complete_request(self): |
|
92 | pass | |
|
91 | msg = self.msg("complete_request", { | |
|
92 | 'text' : 'a.is', | |
|
93 | 'line' : 'foo = a.is', | |
|
94 | 'block' : None, | |
|
95 | 'cursor_pos' : 10, | |
|
96 | }) | |
|
97 | v4, v5 = self.adapt(msg) | |
|
98 | v4c = v4['content'] | |
|
99 | v5c = v5['content'] | |
|
100 | for key in ('text', 'line', 'block'): | |
|
101 | self.assertNotIn(key, v5c) | |
|
102 | self.assertEqual(v5c['cursor_pos'], v4c['cursor_pos']) | |
|
103 | self.assertEqual(v5c['code'], v4c['line']) | |
|
93 | 104 | |
|
94 | 105 | def test_complete_reply(self): |
|
95 | pass | |
|
106 | msg = self.msg("complete_reply", { | |
|
107 | 'matched_text' : 'a.is', | |
|
108 | 'matches' : ['a.isalnum', | |
|
109 | 'a.isalpha', | |
|
110 | 'a.isdigit', | |
|
111 | 'a.islower', | |
|
112 | ], | |
|
113 | }) | |
|
114 | v4, v5 = self.adapt(msg) | |
|
115 | v4c = v4['content'] | |
|
116 | v5c = v5['content'] | |
|
117 | n = len(v4c['matched_text']) | |
|
118 | expected_matches = [ m[n:] for m in v4c['matches'] ] | |
|
119 | ||
|
120 | self.assertEqual(v5c['matches'], expected_matches) | |
|
121 | self.assertEqual(v5c['metadata'], {}) | |
|
122 | self.assertEqual(v5c['cursor_start'], 0) | |
|
123 | self.assertEqual(v5c['cursor_end'], 0) | |
|
96 | 124 | |
|
97 | 125 | def test_object_info_request(self): |
|
98 | pass | |
|
126 | msg = self.msg("object_info_request", { | |
|
127 | 'oname' : 'foo', | |
|
128 | 'detail_level' : 1, | |
|
129 | }) | |
|
130 | v4, v5 = self.adapt(msg) | |
|
131 | self.assertEqual(v5['header']['msg_type'], 'inspect_request') | |
|
132 | v4c = v4['content'] | |
|
133 | v5c = v5['content'] | |
|
134 | self.assertEqual(v5c['code'], v4c['oname']) | |
|
135 | self.assertEqual(v5c['cursor_pos'], len(v4c['oname'])) | |
|
136 | self.assertEqual(v5c['detail_level'], v4c['detail_level']) | |
|
99 | 137 | |
|
100 | 138 | def test_object_info_reply(self): |
|
101 | pass | |
|
139 | msg = self.msg("object_info_reply", { | |
|
140 | 'name' : 'foo', | |
|
141 | 'found' : True, | |
|
142 | 'status' : 'ok', | |
|
143 | 'definition' : 'foo(a=5)', | |
|
144 | 'docstring' : "the docstring", | |
|
145 | }) | |
|
146 | v4, v5 = self.adapt(msg) | |
|
147 | self.assertEqual(v5['header']['msg_type'], 'inspect_reply') | |
|
148 | v4c = v4['content'] | |
|
149 | v5c = v5['content'] | |
|
150 | self.assertEqual(sorted(v5c), [ 'data', 'found', 'metadata', 'name', 'status']) | |
|
151 | text = v5c['data']['text/plain'] | |
|
152 | self.assertEqual(text, '\n'.join([v4c['definition'], v4c['docstring']])) | |
|
102 | 153 | |
|
103 | 154 | # iopub channel |
|
104 | 155 | |
|
105 | 156 | def test_display_data(self): |
|
106 | pass | |
|
157 | jsondata = dict(a=5) | |
|
158 | msg = self.msg("display_data", { | |
|
159 | 'data' : { | |
|
160 | 'text/plain' : 'some text', | |
|
161 | 'application/json' : json.dumps(jsondata) | |
|
162 | }, | |
|
163 | 'metadata' : {'text/plain' : { 'key' : 'value' }}, | |
|
164 | }) | |
|
165 | v4, v5 = self.adapt(msg) | |
|
166 | v4c = v4['content'] | |
|
167 | v5c = v5['content'] | |
|
168 | self.assertEqual(v5c['metadata'], v4c['metadata']) | |
|
169 | self.assertEqual(v5c['data']['text/plain'], v4c['data']['text/plain']) | |
|
170 | self.assertEqual(v5c['data']['application/json'], jsondata) | |
|
107 | 171 | |
|
108 | 172 | # stdin channel |
|
109 | 173 | |
@@ -162,21 +226,84 class V5toV4TestCase(AdapterTest): | |||
|
162 | 226 | self.assertEqual(v5c['code'], v4c['code']) |
|
163 | 227 | |
|
164 | 228 | def test_complete_request(self): |
|
165 | pass | |
|
229 | msg = self.msg("complete_request", { | |
|
230 | 'code' : 'def foo():\n' | |
|
231 | ' a.is\n' | |
|
232 | 'foo()', | |
|
233 | 'cursor_pos': 19, | |
|
234 | }) | |
|
235 | v5, v4 = self.adapt(msg) | |
|
236 | v4c = v4['content'] | |
|
237 | v5c = v5['content'] | |
|
238 | self.assertNotIn('code', v4c) | |
|
239 | self.assertEqual(v4c['line'], v5c['code'].splitlines(True)[1]) | |
|
240 | self.assertEqual(v4c['cursor_pos'], 8) | |
|
241 | self.assertEqual(v4c['text'], '') | |
|
242 | self.assertEqual(v4c['block'], None) | |
|
166 | 243 | |
|
167 | 244 | def test_complete_reply(self): |
|
168 | pass | |
|
245 | msg = self.msg("complete_reply", { | |
|
246 | 'cursor_start' : 10, | |
|
247 | 'cursor_end' : 14, | |
|
248 | 'matches' : ['a.isalnum', | |
|
249 | 'a.isalpha', | |
|
250 | 'a.isdigit', | |
|
251 | 'a.islower', | |
|
252 | ], | |
|
253 | 'metadata' : {}, | |
|
254 | }) | |
|
255 | v5, v4 = self.adapt(msg) | |
|
256 | v4c = v4['content'] | |
|
257 | v5c = v5['content'] | |
|
258 | self.assertEqual(v4c['matched_text'], 'a.is') | |
|
259 | self.assertEqual(v4c['matches'], v5c['matches']) | |
|
169 | 260 | |
|
170 | 261 | def test_inspect_request(self): |
|
171 | pass | |
|
262 | msg = self.msg("inspect_request", { | |
|
263 | 'code' : 'def foo():\n' | |
|
264 | ' apple\n' | |
|
265 | 'bar()', | |
|
266 | 'cursor_pos': 18, | |
|
267 | 'detail_level' : 1, | |
|
268 | }) | |
|
269 | v5, v4 = self.adapt(msg) | |
|
270 | self.assertEqual(v4['header']['msg_type'], 'object_info_request') | |
|
271 | v4c = v4['content'] | |
|
272 | v5c = v5['content'] | |
|
273 | self.assertEqual(v4c['oname'], 'apple') | |
|
274 | self.assertEqual(v5c['detail_level'], v4c['detail_level']) | |
|
172 | 275 | |
|
173 | 276 | def test_inspect_reply(self): |
|
174 | pass | |
|
277 | msg = self.msg("inspect_reply", { | |
|
278 | 'name' : 'foo', | |
|
279 | 'found' : True, | |
|
280 | 'data' : {'text/plain' : 'some text'}, | |
|
281 | 'metadata' : {}, | |
|
282 | }) | |
|
283 | v5, v4 = self.adapt(msg) | |
|
284 | self.assertEqual(v4['header']['msg_type'], 'object_info_reply') | |
|
285 | v4c = v4['content'] | |
|
286 | v5c = v5['content'] | |
|
287 | self.assertEqual(sorted(v4c), ['found', 'name']) | |
|
288 | self.assertEqual(v4c['found'], False) | |
|
175 | 289 | |
|
176 | 290 | # iopub channel |
|
177 | 291 | |
|
178 | 292 | def test_display_data(self): |
|
179 | pass | |
|
293 | jsondata = dict(a=5) | |
|
294 | msg = self.msg("display_data", { | |
|
295 | 'data' : { | |
|
296 | 'text/plain' : 'some text', | |
|
297 | 'application/json' : jsondata, | |
|
298 | }, | |
|
299 | 'metadata' : {'text/plain' : { 'key' : 'value' }}, | |
|
300 | }) | |
|
301 | v5, v4 = self.adapt(msg) | |
|
302 | v4c = v4['content'] | |
|
303 | v5c = v5['content'] | |
|
304 | self.assertEqual(v5c['metadata'], v4c['metadata']) | |
|
305 | self.assertEqual(v5c['data']['text/plain'], v4c['data']['text/plain']) | |
|
306 | self.assertEqual(v4c['data']['application/json'], json.dumps(jsondata)) | |
|
180 | 307 | |
|
181 | 308 | # stdin channel |
|
182 | 309 |
General Comments 0
You need to be logged in to leave comments.
Login now