Skip to content

Commit 80c6367

Browse files
Drop Python 3.8, update Python versions in tests (#1044)
1 parent 79d3150 commit 80c6367

18 files changed

+87
-92
lines changed

.github/workflows/main.yml

+6-7
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,17 @@ jobs:
3939
matrix:
4040
os: [ubuntu-latest, windows-latest, macos-latest]
4141
python-version:
42-
- "3.8"
43-
- "3.12"
44-
- "3.13-dev"
42+
- "3.9"
43+
- "3.13"
4544
include:
4645
- os: windows-latest
47-
python-version: "3.11"
46+
python-version: "3.12"
4847
- os: ubuntu-latest
49-
python-version: "pypy-3.9"
48+
python-version: "pypy-3.10"
5049
- os: ubuntu-latest
51-
python-version: "3.10"
50+
python-version: "3.11"
5251
- os: macos-latest
53-
python-version: "3.9"
52+
python-version: "3.10"
5453
steps:
5554
- uses: actions/checkout@v4
5655
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1

.pre-commit-config.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ repos:
3737
types_or: [yaml, html, json]
3838

3939
- repo: https://github.com/pre-commit/mirrors-mypy
40-
rev: "v1.8.0"
40+
rev: "v1.13.0"
4141
hooks:
4242
- id: mypy
4343
files: jupyter_client
4444
stages: [manual]
45-
args: ["--install-types", "--non-interactive"]
45+
args: ["--install-types", "--non-interactive", "--python-version=3.9"]
4646
additional_dependencies:
4747
["traitlets>=5.13", "ipykernel>=6.26", "jupyter_core>=5.3.2"]
4848

jupyter_client/_version.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
"""The version information for jupyter client."""
22
import re
3-
from typing import List, Union
3+
from typing import Union
44

55
__version__ = "8.6.3"
66

77
# Build up version_info tuple for backwards compatibility
88
pattern = r"(?P<major>\d+).(?P<minor>\d+).(?P<patch>\d+)(?P<rest>.*)"
99
match = re.match(pattern, __version__)
1010
if match:
11-
parts: List[Union[int, str]] = [int(match[part]) for part in ["major", "minor", "patch"]]
11+
parts: list[Union[int, str]] = [int(match[part]) for part in ["major", "minor", "patch"]]
1212
if match["rest"]:
1313
parts.append(match["rest"])
1414
else:

jupyter_client/adapter.py

+32-32
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
# Distributed under the terms of the Modified BSD License.
44
import json
55
import re
6-
from typing import Any, Dict, List, Tuple
6+
from typing import Any
77

88
from ._version import protocol_version_info
99

1010

11-
def code_to_line(code: str, cursor_pos: int) -> Tuple[str, int]:
11+
def code_to_line(code: str, cursor_pos: int) -> tuple[str, int]:
1212
"""Turn a multiline code block and cursor position into a single line
1313
and new cursor position.
1414
@@ -59,32 +59,32 @@ class Adapter:
5959
Override message_type(msg) methods to create adapters.
6060
"""
6161

62-
msg_type_map: Dict[str, str] = {}
62+
msg_type_map: dict[str, str] = {}
6363

64-
def update_header(self, msg: Dict[str, Any]) -> Dict[str, Any]:
64+
def update_header(self, msg: dict[str, Any]) -> dict[str, Any]:
6565
"""Update the header."""
6666
return msg
6767

68-
def update_metadata(self, msg: Dict[str, Any]) -> Dict[str, Any]:
68+
def update_metadata(self, msg: dict[str, Any]) -> dict[str, Any]:
6969
"""Update the metadata."""
7070
return msg
7171

72-
def update_msg_type(self, msg: Dict[str, Any]) -> Dict[str, Any]:
72+
def update_msg_type(self, msg: dict[str, Any]) -> dict[str, Any]:
7373
"""Update the message type."""
7474
header = msg["header"]
7575
msg_type = header["msg_type"]
7676
if msg_type in self.msg_type_map:
7777
msg["msg_type"] = header["msg_type"] = self.msg_type_map[msg_type]
7878
return msg
7979

80-
def handle_reply_status_error(self, msg: Dict[str, Any]) -> Dict[str, Any]:
80+
def handle_reply_status_error(self, msg: dict[str, Any]) -> dict[str, Any]:
8181
"""This will be called *instead of* the regular handler
8282
8383
on any reply with status != ok
8484
"""
8585
return msg
8686

87-
def __call__(self, msg: Dict[str, Any]) -> Dict[str, Any]:
87+
def __call__(self, msg: dict[str, Any]) -> dict[str, Any]:
8888
msg = self.update_header(msg)
8989
msg = self.update_metadata(msg)
9090
msg = self.update_msg_type(msg)
@@ -100,7 +100,7 @@ def __call__(self, msg: Dict[str, Any]) -> Dict[str, Any]:
100100
return handler(msg)
101101

102102

103-
def _version_str_to_list(version: str) -> List[int]:
103+
def _version_str_to_list(version: str) -> list[int]:
104104
"""convert a version string to a list of ints
105105
106106
non-int segments are excluded
@@ -127,15 +127,15 @@ class V5toV4(Adapter):
127127
"inspect_reply": "object_info_reply",
128128
}
129129

130-
def update_header(self, msg: Dict[str, Any]) -> Dict[str, Any]:
130+
def update_header(self, msg: dict[str, Any]) -> dict[str, Any]:
131131
"""Update the header."""
132132
msg["header"].pop("version", None)
133133
msg["parent_header"].pop("version", None)
134134
return msg
135135

136136
# shell channel
137137

138-
def kernel_info_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
138+
def kernel_info_reply(self, msg: dict[str, Any]) -> dict[str, Any]:
139139
"""Handle a kernel info reply."""
140140
v4c = {}
141141
content = msg["content"]
@@ -152,20 +152,20 @@ def kernel_info_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
152152
msg["content"] = v4c
153153
return msg
154154

155-
def execute_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
155+
def execute_request(self, msg: dict[str, Any]) -> dict[str, Any]:
156156
"""Handle an execute request."""
157157
content = msg["content"]
158158
content.setdefault("user_variables", [])
159159
return msg
160160

161-
def execute_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
161+
def execute_reply(self, msg: dict[str, Any]) -> dict[str, Any]:
162162
"""Handle an execute reply."""
163163
content = msg["content"]
164164
content.setdefault("user_variables", {})
165165
# TODO: handle payloads
166166
return msg
167167

168-
def complete_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
168+
def complete_request(self, msg: dict[str, Any]) -> dict[str, Any]:
169169
"""Handle a complete request."""
170170
content = msg["content"]
171171
code = content["code"]
@@ -179,7 +179,7 @@ def complete_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
179179
new_content["cursor_pos"] = cursor_pos
180180
return msg
181181

182-
def complete_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
182+
def complete_reply(self, msg: dict[str, Any]) -> dict[str, Any]:
183183
"""Handle a complete reply."""
184184
content = msg["content"]
185185
cursor_start = content.pop("cursor_start")
@@ -189,7 +189,7 @@ def complete_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
189189
content.pop("metadata", None)
190190
return msg
191191

192-
def object_info_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
192+
def object_info_request(self, msg: dict[str, Any]) -> dict[str, Any]:
193193
"""Handle an object info request."""
194194
content = msg["content"]
195195
code = content["code"]
@@ -201,20 +201,20 @@ def object_info_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
201201
new_content["detail_level"] = content["detail_level"]
202202
return msg
203203

204-
def object_info_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
204+
def object_info_reply(self, msg: dict[str, Any]) -> dict[str, Any]:
205205
"""inspect_reply can't be easily backward compatible"""
206206
msg["content"] = {"found": False, "oname": "unknown"}
207207
return msg
208208

209209
# iopub channel
210210

211-
def stream(self, msg: Dict[str, Any]) -> Dict[str, Any]:
211+
def stream(self, msg: dict[str, Any]) -> dict[str, Any]:
212212
"""Handle a stream message."""
213213
content = msg["content"]
214214
content["data"] = content.pop("text")
215215
return msg
216216

217-
def display_data(self, msg: Dict[str, Any]) -> Dict[str, Any]:
217+
def display_data(self, msg: dict[str, Any]) -> dict[str, Any]:
218218
"""Handle a display data message."""
219219
content = msg["content"]
220220
content.setdefault("source", "display")
@@ -229,7 +229,7 @@ def display_data(self, msg: Dict[str, Any]) -> Dict[str, Any]:
229229

230230
# stdin channel
231231

232-
def input_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
232+
def input_request(self, msg: dict[str, Any]) -> dict[str, Any]:
233233
"""Handle an input request."""
234234
msg["content"].pop("password", None)
235235
return msg
@@ -243,7 +243,7 @@ class V4toV5(Adapter):
243243
# invert message renames above
244244
msg_type_map = {v: k for k, v in V5toV4.msg_type_map.items()}
245245

246-
def update_header(self, msg: Dict[str, Any]) -> Dict[str, Any]:
246+
def update_header(self, msg: dict[str, Any]) -> dict[str, Any]:
247247
"""Update the header."""
248248
msg["header"]["version"] = self.version
249249
if msg["parent_header"]:
@@ -252,7 +252,7 @@ def update_header(self, msg: Dict[str, Any]) -> Dict[str, Any]:
252252

253253
# shell channel
254254

255-
def kernel_info_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
255+
def kernel_info_reply(self, msg: dict[str, Any]) -> dict[str, Any]:
256256
"""Handle a kernel info reply."""
257257
content = msg["content"]
258258
for key in ("protocol_version", "ipython_version"):
@@ -275,7 +275,7 @@ def kernel_info_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
275275
content["banner"] = ""
276276
return msg
277277

278-
def execute_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
278+
def execute_request(self, msg: dict[str, Any]) -> dict[str, Any]:
279279
"""Handle an execute request."""
280280
content = msg["content"]
281281
user_variables = content.pop("user_variables", [])
@@ -284,7 +284,7 @@ def execute_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
284284
user_expressions[v] = v
285285
return msg
286286

287-
def execute_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
287+
def execute_reply(self, msg: dict[str, Any]) -> dict[str, Any]:
288288
"""Handle an execute reply."""
289289
content = msg["content"]
290290
user_expressions = content.setdefault("user_expressions", {})
@@ -301,7 +301,7 @@ def execute_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
301301

302302
return msg
303303

304-
def complete_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
304+
def complete_request(self, msg: dict[str, Any]) -> dict[str, Any]:
305305
"""Handle a complete request."""
306306
old_content = msg["content"]
307307

@@ -310,7 +310,7 @@ def complete_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
310310
new_content["cursor_pos"] = old_content["cursor_pos"]
311311
return msg
312312

313-
def complete_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
313+
def complete_reply(self, msg: dict[str, Any]) -> dict[str, Any]:
314314
"""Handle a complete reply."""
315315
# complete_reply needs more context than we have to get cursor_start and end.
316316
# use special end=null to indicate current cursor position and negative offset
@@ -328,7 +328,7 @@ def complete_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
328328
new_content["metadata"] = {}
329329
return msg
330330

331-
def inspect_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
331+
def inspect_request(self, msg: dict[str, Any]) -> dict[str, Any]:
332332
"""Handle an inspect request."""
333333
content = msg["content"]
334334
name = content["oname"]
@@ -339,7 +339,7 @@ def inspect_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
339339
new_content["detail_level"] = content["detail_level"]
340340
return msg
341341

342-
def inspect_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
342+
def inspect_reply(self, msg: dict[str, Any]) -> dict[str, Any]:
343343
"""inspect_reply can't be easily backward compatible"""
344344
content = msg["content"]
345345
new_content = msg["content"] = {"status": "ok"}
@@ -363,13 +363,13 @@ def inspect_reply(self, msg: Dict[str, Any]) -> Dict[str, Any]:
363363

364364
# iopub channel
365365

366-
def stream(self, msg: Dict[str, Any]) -> Dict[str, Any]:
366+
def stream(self, msg: dict[str, Any]) -> dict[str, Any]:
367367
"""Handle a stream message."""
368368
content = msg["content"]
369369
content["text"] = content.pop("data")
370370
return msg
371371

372-
def display_data(self, msg: Dict[str, Any]) -> Dict[str, Any]:
372+
def display_data(self, msg: dict[str, Any]) -> dict[str, Any]:
373373
"""Handle display data."""
374374
content = msg["content"]
375375
content.pop("source", None)
@@ -384,13 +384,13 @@ def display_data(self, msg: Dict[str, Any]) -> Dict[str, Any]:
384384

385385
# stdin channel
386386

387-
def input_request(self, msg: Dict[str, Any]) -> Dict[str, Any]:
387+
def input_request(self, msg: dict[str, Any]) -> dict[str, Any]:
388388
"""Handle an input request."""
389389
msg["content"].setdefault("password", False)
390390
return msg
391391

392392

393-
def adapt(msg: Dict[str, Any], to_version: int = protocol_version_info[0]) -> Dict[str, Any]:
393+
def adapt(msg: dict[str, Any], to_version: int = protocol_version_info[0]) -> dict[str, Any]:
394394
"""Adapt a single message to a target version
395395
396396
Parameters

jupyter_client/client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ async def _stdin_hook_default(self, msg: t.Dict[str, t.Any]) -> None:
241241
prompt = getpass if content.get("password", False) else input
242242

243243
try:
244-
raw_data = prompt(content["prompt"]) # type:ignore[operator]
244+
raw_data = prompt(content["prompt"])
245245
except EOFError:
246246
# turn EOFError into EOF character
247247
raw_data = "\x04"

jupyter_client/connect.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import tempfile
1717
import warnings
1818
from getpass import getpass
19-
from typing import TYPE_CHECKING, Any, Dict, Union, cast
19+
from typing import TYPE_CHECKING, Any, Union, cast
2020

2121
import zmq
2222
from jupyter_core.paths import jupyter_data_dir, jupyter_runtime_dir, secure_write
@@ -32,7 +32,7 @@
3232
from .session import Session
3333

3434
# Define custom type for kernel connection info
35-
KernelConnectionInfo = Dict[str, Union[int, str, bytes]]
35+
KernelConnectionInfo = dict[str, Union[int, str, bytes]]
3636

3737

3838
def write_connection_file(
@@ -275,7 +275,7 @@ def tunnel_to_kernel(
275275
with open(connection_info) as f:
276276
connection_info = json.loads(f.read())
277277

278-
cf = cast(Dict[str, Any], connection_info)
278+
cf = cast(dict[str, Any], connection_info)
279279

280280
lports = tunnel.select_random_ports(5)
281281
rports = (

jupyter_client/launcher.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
import sys
66
import warnings
77
from subprocess import PIPE, Popen
8-
from typing import Any, Dict, List, Optional
8+
from typing import Any, Optional
99

1010
from traitlets.log import get_logger
1111

1212

1313
def launch_kernel(
14-
cmd: List[str],
14+
cmd: list[str],
1515
stdin: Optional[int] = None,
1616
stdout: Optional[int] = None,
1717
stderr: Optional[int] = None,
18-
env: Optional[Dict[str, str]] = None,
18+
env: Optional[dict[str, str]] = None,
1919
independent: bool = False,
2020
cwd: Optional[str] = None,
2121
**kw: Any,
@@ -65,6 +65,8 @@ def launch_kernel(
6565
# If this process in running on pythonw, we know that stdin, stdout, and
6666
# stderr are all invalid.
6767
redirect_out = sys.executable.endswith("pythonw.exe")
68+
_stdout: Any
69+
_stderr: Any
6870
if redirect_out:
6971
blackhole = open(os.devnull, "w") # noqa
7072
_stdout = blackhole if stdout is None else stdout

jupyter_client/localinterfaces.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
import re
88
import socket
99
import subprocess
10+
from collections.abc import Iterable, Mapping, Sequence
1011
from subprocess import PIPE, Popen
11-
from typing import Any, Callable, Iterable, Mapping, Sequence
12+
from typing import Any, Callable
1213
from warnings import warn
1314

1415
LOCAL_IPS: list[str] = []

0 commit comments

Comments
 (0)