Skip to content

Commit a12840a

Browse files
authored
Bump minimum Python to 3.11, update linting, drop dead branches (#1553)
- requires-python = ">=3.11"; drop Python 3.10 from CI matrices - remove code paths that only existed to support Python < 3.11: Dropping 3.10 was done September of last year, so we are in schedule for this to be merged just one year after and a bit before the release of 3.15, and just about when Python 3.10 will drop out out security-only fixes. note, 3.10 is also the first version that was released 12 month after it's predecessor, before that it was 18 month. --- IPython is already 3.11+, and this will drop quite a number of CI items to make the CI time bearable, until we start enabling 3.15 that will be out in about a month.
2 parents ddead86 + 776d8b5 commit a12840a

9 files changed

Lines changed: 15 additions & 63 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ jobs:
2626
- qt5
2727
- qt6
2828
python-version:
29-
- "3.10"
3029
- "3.11"
3130
- "3.12"
3231
- "3.13"
@@ -153,7 +152,7 @@ jobs:
153152
fail-fast: false
154153
matrix:
155154
os: [ubuntu-latest]
156-
python-version: ["3.10"]
155+
python-version: ["3.11"]
157156
steps:
158157
- name: Checkout
159158
uses: actions/checkout@v7
@@ -183,7 +182,7 @@ jobs:
183182

184183
- uses: actions/setup-python@v7
185184
with:
186-
python-version: "3.10"
185+
python-version: "3.11"
187186

188187
- name: Base Setup
189188
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1

.pre-commit-config.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ repos:
7373
additional_dependencies:
7474
- "pyyaml"
7575
- "packaging"
76-
- "tomli; python_version < '3.11'"
7776

7877
- repo: https://github.com/adamchainz/blacken-docs
7978
rev: "1.20.0"

ipykernel/kernelbase.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -551,24 +551,14 @@ def schedule_next():
551551
# begin polling the eventloop
552552
schedule_next()
553553

554-
async def _create_control_lock(self):
555-
# This can be removed when minimum python increases to 3.10
556-
self._control_lock = asyncio.Lock()
557-
558554
def start(self):
559555
"""register dispatchers for streams"""
560556
self.io_loop = ioloop.IOLoop.current()
561557

562558
if self.control_stream:
563559
self.control_stream.on_recv(self.dispatch_control, copy=False)
564560

565-
if self.control_thread and sys.version_info < (3, 10):
566-
# Before Python 3.10 we need to ensure the _control_lock is created in the
567-
# thread that uses it. When our minimum python is 3.10 we can remove this
568-
# and always use the else below, or just assign it where it is declared.
569-
self.control_thread.io_loop.add_callback(self._create_control_lock)
570-
else:
571-
self._control_lock = asyncio.Lock()
561+
self._control_lock = asyncio.Lock()
572562

573563
if self.shell_stream:
574564
if self.shell_channel_thread:

ipykernel/kernelspec.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def install(
174174
python_arguments = None
175175

176176
# addresses the debugger warning from debugpy about frozen modules
177-
if sys.version_info >= (3, 11) and platform.python_implementation() == "CPython":
177+
if platform.python_implementation() == "CPython":
178178
if not frozen_modules:
179179
# disable frozen modules
180180
python_arguments = ["-Xfrozen_modules=off"]

ipykernel/utils.py

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
from __future__ import annotations
44

55
import asyncio
6-
import sys
76
import typing as t
87
from collections.abc import Mapping
98
from contextvars import copy_context
10-
from functools import partial, wraps
9+
from functools import wraps
1110

1211
if t.TYPE_CHECKING:
1312
from collections.abc import Callable
@@ -46,36 +45,13 @@ def _async_in_context(
4645
) -> Callable[..., t.Coroutine[T, U, V]]:
4746
"""
4847
Wrapper to run a coroutine in a persistent ContextVar Context.
49-
50-
Backports asyncio.create_task(context=...) behavior from Python 3.11
5148
"""
5249
if context is None:
5350
context = copy_context()
5451

55-
if sys.version_info >= (3, 11):
56-
57-
@wraps(f)
58-
async def run_in_context(*args, **kwargs):
59-
coro = f(*args, **kwargs)
60-
return await asyncio.create_task(coro, context=context)
61-
62-
return run_in_context
63-
64-
# don't need this backport when we require 3.11
65-
# context_holder so we have a modifiable container for later calls
66-
context_holder = [context] # type: ignore[unreachable]
67-
68-
async def preserve_context(f, *args, **kwargs):
69-
"""call a coroutine, preserving the context after it is called"""
70-
try:
71-
return await f(*args, **kwargs)
72-
finally:
73-
# persist changes to the context for future calls
74-
context_holder[0] = copy_context()
75-
7652
@wraps(f)
77-
async def run_in_context_pre311(*args, **kwargs):
78-
ctx = context_holder[0]
79-
return await ctx.run(partial(asyncio.create_task, preserve_context(f, *args, **kwargs)))
53+
async def run_in_context(*args, **kwargs):
54+
coro = f(*args, **kwargs)
55+
return await asyncio.create_task(coro, context=context)
8056

81-
return run_in_context_pre311
57+
return run_in_context

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ classifiers = [
1717
"Programming Language :: Python",
1818
"Programming Language :: Python :: 3",
1919
]
20-
requires-python = ">=3.10"
20+
requires-python = ">=3.11"
2121
dependencies = [
2222
"debugpy>=1.6.5",
2323
"ipython>=7.23.1",

scripts/check_mypy_deps.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88
from __future__ import annotations
99

1010
import sys
11-
12-
try:
13-
import tomllib
14-
except ImportError:
15-
import tomli as tomllib # type: ignore[no-reuse-def]
11+
import tomllib
1612

1713
import yaml
1814
from packaging.requirements import Requirement

tests/test_eventloop.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,6 @@ def test_cocoa_loop(kernel):
107107
def test_qt_enable_gui(gui, kernel, capsys):
108108
if os.getenv("GITHUB_ACTIONS", None) == "true" and gui == "qt5":
109109
pytest.skip("Qt5 and GitHub action crash CPython")
110-
if gui == "qt6" and sys.version_info < (3, 10):
111-
pytest.skip(
112-
"qt6 fails on 3.9 with AttributeError: module 'PySide6.QtPrintSupport' has no attribute 'QApplication'"
113-
)
114110
if sys.platform == "linux" and gui == "qt6" and os.getenv("GITHUB_ACTIONS", None) == "true":
115111
pytest.skip("qt6 fails on github CI with missing libEGL.so.1")
116112
enable_gui(gui, kernel)

tests/test_kernelspec.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ def test_install_env(tmp_path, env):
154154
assert "env" not in spec
155155

156156

157-
@pytest.mark.skipif(sys.version_info < (3, 11) or not is_cpython, reason="requires cPython 3.11")
157+
@pytest.mark.skipif(not is_cpython, reason="requires CPython")
158158
def test_install_frozen_modules_on():
159159
system_jupyter_dir = tempfile.mkdtemp()
160160

@@ -168,7 +168,7 @@ def test_install_frozen_modules_on():
168168
assert "-Xfrozen_modules=off" not in spec["argv"]
169169

170170

171-
@pytest.mark.skipif(sys.version_info < (3, 11) or not is_cpython, reason="requires cPython 3.11")
171+
@pytest.mark.skipif(not is_cpython, reason="requires CPython")
172172
def test_install_frozen_modules_off():
173173
system_jupyter_dir = tempfile.mkdtemp()
174174

@@ -182,13 +182,9 @@ def test_install_frozen_modules_off():
182182
assert spec["argv"][1] == "-Xfrozen_modules=off"
183183

184184

185-
@pytest.mark.skipif(
186-
sys.version_info >= (3, 11) or is_cpython,
187-
reason="checks versions older than 3.11 and other Python implementations",
188-
)
185+
@pytest.mark.skipif(is_cpython, reason="checks non-CPython implementations")
189186
def test_install_frozen_modules_no_op():
190-
# ensure we do not add add Xfrozen_modules on older Python versions
191-
# (although cPython does not error out on unknown X options as of 3.8)
187+
# ensure we do not add -Xfrozen_modules on non-CPython implementations
192188
system_jupyter_dir = tempfile.mkdtemp()
193189

194190
with mock.patch("jupyter_client.kernelspec.SYSTEM_JUPYTER_PATH", [system_jupyter_dir]):

0 commit comments

Comments
 (0)