Skip to content

Commit 8c81bd4

Browse files
Add type annotations, refactor sync/async (#623)
1 parent 50dff2e commit 8c81bd4

22 files changed

+1495
-1695
lines changed

.github/workflows/main.yml

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ jobs:
3131
pip install --upgrade setuptools pip
3232
pip install --upgrade --upgrade-strategy eager -e .[test] pytest-cov codecov 'coverage<5'
3333
pip freeze
34+
- name: Check types
35+
run: mypy jupyter_client/manager.py jupyter_client/multikernelmanager.py jupyter_client/client.py jupyter_client/blocking/client.py jupyter_client/asynchronous/client.py jupyter_client/channels.py jupyter_client/session.py jupyter_client/adapter.py jupyter_client/connect.py jupyter_client/consoleapp.py jupyter_client/jsonutil.py jupyter_client/kernelapp.py jupyter_client/launcher.py
3436
- name: Run the tests
3537
run: py.test --cov jupyter_client -v jupyter_client
3638
- name: Code coverage

jupyter_client/adapter.py

+128-35
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55

66
import re
77
import json
8+
from typing import List, Tuple, Dict, Any
89

910
from jupyter_client import protocol_version_info
1011

11-
def code_to_line(code, cursor_pos):
12+
def code_to_line(
13+
code: str,
14+
cursor_pos: int
15+
) -> Tuple[str, int]:
1216
"""Turn a multiline code block and cursor position into a single line
1317
and new cursor position.
1418
@@ -29,14 +33,17 @@ def code_to_line(code, cursor_pos):
2933
_end_bracket = re.compile(r'\([^\(]*$', re.UNICODE)
3034
_identifier = re.compile(r'[a-z_][0-9a-z._]*', re.I|re.UNICODE)
3135

32-
def extract_oname_v4(code, cursor_pos):
36+
def extract_oname_v4(
37+
code: str,
38+
cursor_pos: int
39+
) -> str:
3340
"""Reimplement token-finding logic from IPython 2.x javascript
34-
41+
3542
for adapting object_info_request from v5 to v4
3643
"""
37-
44+
3845
line, _ = code_to_line(code, cursor_pos)
39-
46+
4047
oldline = line
4148
line = _match_bracket.sub('', line)
4249
while oldline != line:
@@ -58,29 +65,44 @@ class Adapter(object):
5865
Override message_type(msg) methods to create adapters.
5966
"""
6067

61-
msg_type_map = {}
68+
msg_type_map: Dict[str, str] = {}
6269

63-
def update_header(self, msg):
70+
def update_header(
71+
self,
72+
msg: Dict[str, Any]
73+
) -> Dict[str, Any]:
6474
return msg
6575

66-
def update_metadata(self, msg):
76+
def update_metadata(
77+
self,
78+
msg: Dict[str, Any]
79+
) -> Dict[str, Any]:
6780
return msg
6881

69-
def update_msg_type(self, msg):
82+
def update_msg_type(
83+
self,
84+
msg: Dict[str, Any]
85+
) -> Dict[str, Any]:
7086
header = msg['header']
7187
msg_type = header['msg_type']
7288
if msg_type in self.msg_type_map:
7389
msg['msg_type'] = header['msg_type'] = self.msg_type_map[msg_type]
7490
return msg
7591

76-
def handle_reply_status_error(self, msg):
92+
def handle_reply_status_error(
93+
self,
94+
msg: Dict[str, Any]
95+
) -> Dict[str, Any]:
7796
"""This will be called *instead of* the regular handler
7897
7998
on any reply with status != ok
8099
"""
81100
return msg
82101

83-
def __call__(self, msg):
102+
def __call__(
103+
self,
104+
msg: Dict[str, Any]
105+
):
84106
msg = self.update_header(msg)
85107
msg = self.update_metadata(msg)
86108
msg = self.update_msg_type(msg)
@@ -95,7 +117,9 @@ def __call__(self, msg):
95117
return self.handle_reply_status_error(msg)
96118
return handler(msg)
97119

98-
def _version_str_to_list(version):
120+
def _version_str_to_list(
121+
version: str
122+
) -> List[int]:
99123
"""convert a version string to a list of ints
100124
101125
non-int segments are excluded
@@ -121,14 +145,20 @@ class V5toV4(Adapter):
121145
'inspect_reply' : 'object_info_reply',
122146
}
123147

124-
def update_header(self, msg):
148+
def update_header(
149+
self,
150+
msg: Dict[str, Any]
151+
) -> Dict[str, Any]:
125152
msg['header'].pop('version', None)
126153
msg['parent_header'].pop('version', None)
127154
return msg
128155

129156
# shell channel
130157

131-
def kernel_info_reply(self, msg):
158+
def kernel_info_reply(
159+
self,
160+
msg: Dict[str, Any]
161+
) -> Dict[str, Any]:
132162
v4c = {}
133163
content = msg['content']
134164
for key in ('language_version', 'protocol_version'):
@@ -145,18 +175,27 @@ def kernel_info_reply(self, msg):
145175
msg['content'] = v4c
146176
return msg
147177

148-
def execute_request(self, msg):
178+
def execute_request(
179+
self,
180+
msg: Dict[str, Any]
181+
) -> Dict[str, Any]:
149182
content = msg['content']
150183
content.setdefault('user_variables', [])
151184
return msg
152185

153-
def execute_reply(self, msg):
186+
def execute_reply(
187+
self,
188+
msg: Dict[str, Any]
189+
) -> Dict[str, Any]:
154190
content = msg['content']
155191
content.setdefault('user_variables', {})
156192
# TODO: handle payloads
157193
return msg
158194

159-
def complete_request(self, msg):
195+
def complete_request(
196+
self,
197+
msg: Dict[str, Any]
198+
) -> Dict[str, Any]:
160199
content = msg['content']
161200
code = content['code']
162201
cursor_pos = content['cursor_pos']
@@ -169,7 +208,10 @@ def complete_request(self, msg):
169208
new_content['cursor_pos'] = cursor_pos
170209
return msg
171210

172-
def complete_reply(self, msg):
211+
def complete_reply(
212+
self,
213+
msg: Dict[str, Any]
214+
) -> Dict[str, Any]:
173215
content = msg['content']
174216
cursor_start = content.pop('cursor_start')
175217
cursor_end = content.pop('cursor_end')
@@ -178,7 +220,10 @@ def complete_reply(self, msg):
178220
content.pop('metadata', None)
179221
return msg
180222

181-
def object_info_request(self, msg):
223+
def object_info_request(
224+
self,
225+
msg: Dict[str, Any]
226+
) -> Dict[str, Any]:
182227
content = msg['content']
183228
code = content['code']
184229
cursor_pos = content['cursor_pos']
@@ -189,19 +234,28 @@ def object_info_request(self, msg):
189234
new_content['detail_level'] = content['detail_level']
190235
return msg
191236

192-
def object_info_reply(self, msg):
237+
def object_info_reply(
238+
self,
239+
msg: Dict[str, Any]
240+
) -> Dict[str, Any]:
193241
"""inspect_reply can't be easily backward compatible"""
194242
msg['content'] = {'found' : False, 'oname' : 'unknown'}
195243
return msg
196244

197245
# iopub channel
198246

199-
def stream(self, msg):
247+
def stream(
248+
self,
249+
msg: Dict[str, Any]
250+
) -> Dict[str, Any]:
200251
content = msg['content']
201252
content['data'] = content.pop('text')
202253
return msg
203254

204-
def display_data(self, msg):
255+
def display_data(
256+
self,
257+
msg: Dict[str, Any]
258+
) -> Dict[str, Any]:
205259
content = msg['content']
206260
content.setdefault("source", "display")
207261
data = content['data']
@@ -215,7 +269,10 @@ def display_data(self, msg):
215269

216270
# stdin channel
217271

218-
def input_request(self, msg):
272+
def input_request(
273+
self,
274+
msg: Dict[str, Any]
275+
) -> Dict[str, Any]:
219276
msg['content'].pop('password', None)
220277
return msg
221278

@@ -227,15 +284,21 @@ class V4toV5(Adapter):
227284
# invert message renames above
228285
msg_type_map = {v:k for k,v in V5toV4.msg_type_map.items()}
229286

230-
def update_header(self, msg):
287+
def update_header(
288+
self,
289+
msg: Dict[str, Any]
290+
) -> Dict[str, Any]:
231291
msg['header']['version'] = self.version
232292
if msg['parent_header']:
233293
msg['parent_header']['version'] = self.version
234294
return msg
235295

236296
# shell channel
237297

238-
def kernel_info_reply(self, msg):
298+
def kernel_info_reply(
299+
self,
300+
msg: Dict[str, Any]
301+
) -> Dict[str, Any]:
239302
content = msg['content']
240303
for key in ('protocol_version', 'ipython_version'):
241304
if key in content:
@@ -257,15 +320,21 @@ def kernel_info_reply(self, msg):
257320
content['banner'] = ''
258321
return msg
259322

260-
def execute_request(self, msg):
323+
def execute_request(
324+
self,
325+
msg: Dict[str, Any]
326+
) -> Dict[str, Any]:
261327
content = msg['content']
262328
user_variables = content.pop('user_variables', [])
263329
user_expressions = content.setdefault('user_expressions', {})
264330
for v in user_variables:
265331
user_expressions[v] = v
266332
return msg
267333

268-
def execute_reply(self, msg):
334+
def execute_reply(
335+
self,
336+
msg: Dict[str, Any]
337+
) -> Dict[str, Any]:
269338
content = msg['content']
270339
user_expressions = content.setdefault('user_expressions', {})
271340
user_variables = content.pop('user_variables', {})
@@ -281,15 +350,21 @@ def execute_reply(self, msg):
281350

282351
return msg
283352

284-
def complete_request(self, msg):
353+
def complete_request(
354+
self,
355+
msg: Dict[str, Any]
356+
) -> Dict[str, Any]:
285357
old_content = msg['content']
286358

287359
new_content = msg['content'] = {}
288360
new_content['code'] = old_content['line']
289361
new_content['cursor_pos'] = old_content['cursor_pos']
290362
return msg
291363

292-
def complete_reply(self, msg):
364+
def complete_reply(
365+
self,
366+
msg: Dict[str, Any]
367+
) -> Dict[str, Any]:
293368
# complete_reply needs more context than we have to get cursor_start and end.
294369
# use special end=null to indicate current cursor position and negative offset
295370
# for start relative to the cursor.
@@ -306,7 +381,10 @@ def complete_reply(self, msg):
306381
new_content['metadata'] = {}
307382
return msg
308383

309-
def inspect_request(self, msg):
384+
def inspect_request(
385+
self,
386+
msg: Dict[str, Any]
387+
) -> Dict[str, Any]:
310388
content = msg['content']
311389
name = content['oname']
312390

@@ -316,7 +394,10 @@ def inspect_request(self, msg):
316394
new_content['detail_level'] = content['detail_level']
317395
return msg
318396

319-
def inspect_reply(self, msg):
397+
def inspect_reply(
398+
self,
399+
msg: Dict[str, Any]
400+
) -> Dict[str, Any]:
320401
"""inspect_reply can't be easily backward compatible"""
321402
content = msg['content']
322403
new_content = msg['content'] = {'status' : 'ok'}
@@ -340,12 +421,18 @@ def inspect_reply(self, msg):
340421

341422
# iopub channel
342423

343-
def stream(self, msg):
424+
def stream(
425+
self,
426+
msg: Dict[str, Any]
427+
) -> Dict[str, Any]:
344428
content = msg['content']
345429
content['text'] = content.pop('data')
346430
return msg
347431

348-
def display_data(self, msg):
432+
def display_data(
433+
self,
434+
msg: Dict[str, Any]
435+
) -> Dict[str, Any]:
349436
content = msg['content']
350437
content.pop("source", None)
351438
data = content['data']
@@ -359,13 +446,19 @@ def display_data(self, msg):
359446

360447
# stdin channel
361448

362-
def input_request(self, msg):
449+
def input_request(
450+
self,
451+
msg: Dict[str, Any]
452+
) -> Dict[str, Any]:
363453
msg['content'].setdefault('password', False)
364454
return msg
365455

366456

367457

368-
def adapt(msg, to_version=protocol_version_info[0]):
458+
def adapt(
459+
msg: Dict[str, Any],
460+
to_version: int =protocol_version_info[0]
461+
) -> Dict[str, Any]:
369462
"""Adapt a single message to a target version
370463
371464
Parameters

0 commit comments

Comments
 (0)