diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c86e5cf4..70b3bf40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.9", "3.12"] + python-version: ["3.9", "3.13"] include: - os: ubuntu-latest python-version: "pypy-3.9" @@ -30,6 +30,8 @@ jobs: python-version: "3.10" - os: ubuntu-latest python-version: "3.11" + - os: ubuntu-latest + python-version: "3.12" steps: - name: Checkout uses: actions/checkout@v4 @@ -148,6 +150,7 @@ jobs: uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 with: dependency_type: minimum + python_version: "3.9" - name: List installed packages run: | diff --git a/docs/conf.py b/docs/conf.py index 4bb59932..38a724b5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,7 +13,7 @@ import os import shutil from pathlib import Path -from typing import Any, Dict, List +from typing import Any # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -70,7 +70,7 @@ # built documents. # -version_ns: Dict[str, Any] = {} +version_ns: dict[str, Any] = {} here = Path(__file__).parent.resolve() version_py = Path(here) / os.pardir / "ipykernel" / "_version.py" with open(version_py) as f: @@ -159,7 +159,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path: List[str] = [] +html_static_path: list[str] = [] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -226,7 +226,7 @@ # -- Options for LaTeX output --------------------------------------------- -latex_elements: Dict[str, object] = {} +latex_elements: dict[str, object] = {} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, diff --git a/ipykernel/_version.py b/ipykernel/_version.py index d9a9f534..5907d150 100644 --- a/ipykernel/_version.py +++ b/ipykernel/_version.py @@ -2,7 +2,6 @@ store the current version info of the server. """ import re -from typing import List # Version string must appear intact for hatch versioning __version__ = "7.0.0a0" @@ -11,7 +10,7 @@ pattern = r"(?P\d+).(?P\d+).(?P\d+)(?P.*)" match = re.match(pattern, __version__) assert match is not None -parts: List[object] = [int(match[part]) for part in ["major", "minor", "patch"]] +parts: list[object] = [int(match[part]) for part in ["major", "minor", "patch"]] if match["rest"]: parts.append(match["rest"]) version_info = tuple(parts) diff --git a/ipykernel/debugger.py b/ipykernel/debugger.py index 8680793f..780d1801 100644 --- a/ipykernel/debugger.py +++ b/ipykernel/debugger.py @@ -130,7 +130,7 @@ def _reset_tcp_pos(self): def _put_message(self, raw_msg): self.log.debug("QUEUE - _put_message:") - msg = t.cast(t.Dict[str, t.Any], jsonapi.loads(raw_msg)) + msg = t.cast(dict[str, t.Any], jsonapi.loads(raw_msg)) if msg["type"] == "event": self.log.debug("QUEUE - received event:") self.log.debug(msg) diff --git a/ipykernel/inprocess/channels.py b/ipykernel/inprocess/channels.py index 378416dc..4c01c5bc 100644 --- a/ipykernel/inprocess/channels.py +++ b/ipykernel/inprocess/channels.py @@ -3,8 +3,6 @@ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. -from typing import List - from jupyter_client.channelsabc import HBChannelABC # ----------------------------------------------------------------------------- @@ -15,7 +13,7 @@ class InProcessChannel: """Base class for in-process channels.""" - proxy_methods: List[object] = [] + proxy_methods: list[object] = [] def __init__(self, client=None): """Initialize the channel.""" diff --git a/ipykernel/iostream.py b/ipykernel/iostream.py index beca44b1..81170b97 100644 --- a/ipykernel/iostream.py +++ b/ipykernel/iostream.py @@ -15,7 +15,7 @@ from collections import defaultdict, deque from io import StringIO, TextIOBase from threading import Event, Thread, local -from typing import Any, Callable, Deque, Dict, Optional +from typing import Any, Callable, Optional import zmq from anyio import create_task_group, run, sleep, to_thread @@ -94,8 +94,8 @@ def __init__(self, socket, pipe=False): if pipe: self._setup_pipe_in() self._local = threading.local() - self._events: Deque[Callable[..., Any]] = deque() - self._event_pipes: Dict[threading.Thread, Any] = {} + self._events: deque[Callable[..., Any]] = deque() + self._event_pipes: dict[threading.Thread, Any] = {} self._event_pipe_gc_lock: threading.Lock = threading.Lock() self._event_pipe_gc_seconds: float = 10 self._setup_event_pipe() @@ -470,7 +470,7 @@ def __init__( self.pub_thread = pub_thread self.name = name self.topic = b"stream." + name.encode() - self._parent_header: contextvars.ContextVar[Dict[str, Any]] = contextvars.ContextVar( + self._parent_header: contextvars.ContextVar[dict[str, Any]] = contextvars.ContextVar( "parent_header" ) self._parent_header.set({}) diff --git a/ipykernel/ipkernel.py b/ipykernel/ipkernel.py index db83d986..48efa6cd 100644 --- a/ipykernel/ipkernel.py +++ b/ipykernel/ipkernel.py @@ -1,5 +1,7 @@ """The IPython kernel implementation""" +from __future__ import annotations + import builtins import gc import getpass @@ -16,7 +18,7 @@ from IPython.core import release from IPython.utils.tokenutil import line_at_cursor, token_at_cursor from jupyter_client.session import extract_header -from traitlets import Any, Bool, HasTraits, Instance, List, Type, observe, observe_compat +from traitlets import Any, Bool, HasTraits, Instance, List, Type, default, observe, observe_compat from .comm.comm import BaseComm from .comm.manager import CommManager @@ -46,7 +48,7 @@ def _create_comm(*args, **kwargs): # there can only be one comm manager in a ipykernel process _comm_lock = threading.Lock() -_comm_manager: t.Optional[CommManager] = None +_comm_manager: CommManager | None = None def _get_comm_manager(*args, **kwargs): @@ -84,7 +86,11 @@ def _user_module_changed(self, change): if self.shell is not None: self.shell.user_module = change["new"] - user_ns = Instance(dict, args=None, allow_none=True) + user_ns = Instance("collections.abc.Mapping", allow_none=True) + + @default("user_ns") + def _default_user_ns(self): + return dict() @observe("user_ns") @observe_compat @@ -353,7 +359,7 @@ async def do_execute( self._forward_input(allow_stdin) - reply_content: t.Dict[str, t.Any] = {} + reply_content: dict[str, t.Any] = {} if hasattr(shell, "run_cell_async") and hasattr(shell, "should_run_async"): run_cell = shell.run_cell_async should_run_async = shell.should_run_async @@ -559,7 +565,7 @@ def do_inspect(self, code, cursor_pos, detail_level=0, omit_sections=()): """Handle code inspection.""" name = token_at_cursor(code, cursor_pos) - reply_content: t.Dict[str, t.Any] = {"status": "ok"} + reply_content: dict[str, t.Any] = {"status": "ok"} reply_content["data"] = {} reply_content["metadata"] = {} assert self.shell is not None @@ -755,7 +761,7 @@ def init_closure(self: threading.Thread, *args, **kwargs): threading.Thread.run = run_closure # type:ignore[method-assign] def _clean_thread_parent_frames( - self, phase: t.Literal["start", "stop"], info: t.Dict[str, t.Any] + self, phase: t.Literal["start", "stop"], info: dict[str, t.Any] ): """Clean parent frames of threads which are no longer running. This is meant to be invoked by garbage collector callback hook. diff --git a/ipykernel/pickleutil.py b/ipykernel/pickleutil.py index 6f156594..4ffa5262 100644 --- a/ipykernel/pickleutil.py +++ b/ipykernel/pickleutil.py @@ -209,7 +209,7 @@ def __init__(self, f): """Initialize the can""" self._check_type(f) self.code = f.__code__ - self.defaults: typing.Optional[typing.List[typing.Any]] + self.defaults: typing.Optional[list[typing.Any]] if f.__defaults__: self.defaults = [can(fd) for fd in f.__defaults__] else: @@ -475,7 +475,7 @@ def uncan_sequence(obj, g=None): if buffer is not memoryview: can_map[buffer] = CannedBuffer -uncan_map: typing.Dict[type, typing.Any] = { +uncan_map: dict[type, typing.Any] = { CannedObject: lambda obj, g: obj.get_object(g), dict: uncan_dict, } diff --git a/ipykernel/thread.py b/ipykernel/thread.py index a63011de..40509ece 100644 --- a/ipykernel/thread.py +++ b/ipykernel/thread.py @@ -17,7 +17,7 @@ def __init__(self, **kwargs): self.pydev_do_not_trace = True self.is_pydev_daemon_thread = True self.__stop = Event() - self._tasks_and_args: t.List[t.Tuple[t.Any, t.Any]] = [] + self._tasks_and_args: list[tuple[t.Any, t.Any]] = [] def add_task(self, task: t.Any, *args: t.Any) -> None: # May only add tasks before the thread is started. diff --git a/pyproject.toml b/pyproject.toml index 1e9e543c..e1d7b1d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -187,6 +187,9 @@ filterwarnings= [ # https://github.com/python-trio/trio/issues/3053 "ignore:The `hash` argument is deprecated in favor of `unsafe_hash` and will be removed in or after August 2025.", + + # ignore unclosed sqlite in traits + "ignore:unclosed database in