Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ jobs:
- uses: actions/checkout@v6

- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Check mypy deps are in sync with project deps
run: hatch run typing:check

- name: Run Linters
run: |
hatch run typing:test
Expand Down
40 changes: 31 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ repos:
- id: trailing-whitespace

- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.37.0
rev: 0.37.2
hooks:
- id: check-github-workflows

Expand All @@ -39,28 +39,50 @@ repos:
types_or: [yaml, html, json]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.19.1"
rev: "v2.1.0"
hooks:
- id: mypy
files: ipykernel
stages: [manual]
args: ["--install-types", "--non-interactive"]
additional_dependencies:
[
"traitlets>=5.13",
"ipython>=8.16.1",
"jupyter_client>=8.5",
"appnope",
"appnope>=0.1.2",
"comm>=0.1.1",
"debugpy>=1.6.5",
"ipython>=7.23.1",
"jupyter_client>=8.9.0",
"jupyter_core>=5.1",
"matplotlib-inline>=0.1",
"nest_asyncio2>=1.7.0",
"packaging>=22",
"psutil>=5.7",
"pyzmq>=25",
"tornado>=6.4.1",
"traitlets>=5.4.0",
]

- repo: local
hooks:
- id: check-mypy-deps
name: mypy deps in sync with project deps
entry: python scripts/check_mypy_deps.py
language: python
pass_filenames: false
always_run: true
additional_dependencies:
- "pyyaml"
- "packaging"
- "tomli; python_version < '3.11'"

- repo: https://github.com/adamchainz/blacken-docs
rev: "1.20.0"
hooks:
- id: blacken-docs
additional_dependencies: [black==23.7.0]

- repo: https://github.com/codespell-project/codespell
rev: "v2.4.1"
rev: "v2.4.2"
hooks:
- id: codespell
args: ["-L", "sur,nd"]
Expand All @@ -73,7 +95,7 @@ repos:
- id: rst-inline-touching-normal

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.4
rev: v0.15.16
hooks:
- id: ruff-check
types_or: [python, jupyter]
Expand All @@ -82,7 +104,7 @@ repos:
types_or: [python, jupyter]

- repo: https://github.com/scientific-python/cookie
rev: "2026.03.02"
rev: "2026.04.04"
hooks:
- id: sp-repo-review
additional_dependencies: ["repo-review[cli]"]
4 changes: 2 additions & 2 deletions ipykernel/comm/comm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


# this is the class that will be created if we do comm.create_comm
class BaseComm(comm.base_comm.BaseComm): # type:ignore[misc]
class BaseComm(comm.base_comm.BaseComm):
"""The base class for comms."""

kernel: Optional["Kernel"] = None
Expand Down Expand Up @@ -90,7 +90,7 @@ def __init__(
kernel = kwargs.pop("kernel", None)
if target_name:
kwargs["target_name"] = target_name
BaseComm.__init__(self, data=data, metadata=metadata, buffers=buffers, **kwargs) # type:ignore[call-arg]
BaseComm.__init__(self, data=data, metadata=metadata, buffers=buffers, **kwargs)
# only re-add kernel if explicitly provided
if had_kernel:
kwargs["kernel"] = kernel
Expand Down
2 changes: 1 addition & 1 deletion ipykernel/comm/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
logger = logging.getLogger("ipykernel.comm")


class CommManager(comm.base_comm.CommManager, traitlets.config.LoggingConfigurable): # type:ignore[misc]
class CommManager(comm.base_comm.CommManager, traitlets.config.LoggingConfigurable):
"""A comm manager."""

kernel = traitlets.Instance("ipykernel.kernelbase.Kernel")
Expand Down
2 changes: 1 addition & 1 deletion ipykernel/eventloops.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ def _schedule_exit(delay):
else:
import asyncio

import nest_asyncio2
import nest_asyncio2 # type: ignore[import-untyped]

nest_asyncio2.apply()

Expand Down
2 changes: 1 addition & 1 deletion ipykernel/kernelbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ async def dispatch_shell(self, msg, /, subshell_id: str | None = None):
# Only abort execute requests
if msg_type == "execute_request":
if subshell_id is None:
aborting = self._aborting # type:ignore[unreachable]
aborting = self._aborting
else:
aborting = self.shell_channel_thread.manager.get_subshell_aborting(subshell_id)
if aborting:
Expand Down
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,16 @@ dependencies = ["pre-commit"]
detached = true
[tool.hatch.envs.typing.scripts]
test = "pre-commit run --all-files --hook-stage manual mypy"
check = "pre-commit run --all-files check-mypy-deps"

[tool.hatch.envs.lint]
dependencies = ["pre-commit"]
detached = true
[tool.hatch.envs.lint.scripts]
build = [
"pre-commit run --all-files ruff-check",
"pre-commit run --all-files ruff-format"
"pre-commit run --all-files ruff-format",
"pre-commit run --all-files check-mypy-deps",
]

[tool.mypy]
Expand Down
66 changes: 66 additions & 0 deletions scripts/check_mypy_deps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python
"""Verify that the mypy hook's additional_dependencies in .pre-commit-config.yaml
includes all runtime dependencies declared in pyproject.toml.

Run directly or via pre-commit (check-mypy-deps hook).
"""

from __future__ import annotations

import sys

try:
import tomllib
except ImportError:
import tomli as tomllib # type: ignore[no-reuse-def]

import yaml
from packaging.requirements import Requirement


def normalize(name: str) -> str:
return name.lower().replace("-", "_").replace(".", "_")


def main() -> int:
with open("pyproject.toml", "rb") as f:
pyproject = tomllib.load(f)

with open(".pre-commit-config.yaml") as f:
pre_commit = yaml.safe_load(f)

project_deps: list[str] = pyproject["project"]["dependencies"]
project_packages = {normalize(Requirement(dep).name) for dep in project_deps}

mypy_additional: list[str] | None = None
for repo in pre_commit["repos"]:
for hook in repo.get("hooks", []):
if hook["id"] == "mypy":
mypy_additional = hook.get("additional_dependencies", [])
break
if mypy_additional is not None:
break

if mypy_additional is None:
print("ERROR: mypy hook not found in .pre-commit-config.yaml")
return 1

mypy_packages = {normalize(Requirement(dep).name) for dep in mypy_additional}

missing = project_packages - mypy_packages
if missing:
print(
"ERROR: The following project dependencies are missing from the mypy\n"
"hook's additional_dependencies in .pre-commit-config.yaml:\n"
)
for pkg in sorted(missing):
print(f" {pkg}")
print("\nAdd them to the `additional_dependencies` list of the mypy hook.")
return 1

print("OK: mypy additional_dependencies covers all project runtime dependencies.")
return 0


if __name__ == "__main__":
sys.exit(main())
Loading