diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f10a5bc1f..cbd920f6b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,10 @@ version: 2 updates: - # Set update schedule for GitHub Actions - package-ecosystem: "github-actions" directory: "/" schedule: - # Check for updates to GitHub Actions every weekday + interval: "weekly" + - package-ecosystem: "pip" + directory: "/" + schedule: interval: "weekly" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b5241b140..865182559 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,13 +16,6 @@ defaults: jobs: - pre_commit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - - uses: jupyterlab/maintainer-tools/.github/actions/pre-commit@v1 - check_release: runs-on: ubuntu-latest steps: @@ -84,6 +77,19 @@ jobs: - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - run: hatch run docs:build + lint: + name: Test Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + - name: Run Linters + run: | + hatch run typing:test + hatch run lint:style + pipx run 'validate-pyproject[all]' pyproject.toml + pipx run doc8 --max-line-length=200 --ignore-path=docs/source/other/full-config.rst + test_minimum_verisons: name: Test Minimum Versions runs-on: ubuntu-latest @@ -135,9 +141,9 @@ jobs: needs: - test - docs + - lint - check_links - test_minimum_verisons - - pre_commit - test_prereleases - test_sdist runs-on: ubuntu-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d2468e091..ff708b297 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,6 @@ +ci: + autoupdate_schedule: monthly + repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 @@ -15,71 +18,23 @@ repos: - id: check-builtin-literals - id: trailing-whitespace - - repo: https://github.com/asottile/reorder_python_imports - rev: v3.9.0 - hooks: - - id: reorder-python-imports - - - repo: https://github.com/psf/black - rev: 22.10.0 - hooks: - - id: black - args: ["--line-length", "100"] - - - repo: https://github.com/abravalheri/validate-pyproject - rev: v0.10.1 + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.19.2 hooks: - - id: validate-pyproject - stages: [manual] + - id: check-github-workflows - repo: https://github.com/executablebooks/mdformat rev: 0.7.16 hooks: - id: mdformat - - repo: https://github.com/asottile/pyupgrade - rev: v3.3.0 - hooks: - - id: pyupgrade - args: [--py38-plus] - - - repo: https://github.com/PyCQA/doc8 - rev: v1.0.0 - hooks: - - id: doc8 - args: [--max-line-length=200] - stages: [manual] - - - repo: https://github.com/john-hen/Flake8-pyproject - rev: 1.2.2 - hooks: - - id: Flake8-pyproject - alias: flake8 - additional_dependencies: - ["flake8-bugbear==22.6.22", "flake8-implicit-str-concat==0.2.0"] - stages: [manual] - - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.991 - hooks: - - id: mypy - exclude: tests - args: ["--config-file", "pyproject.toml"] - additional_dependencies: [pyzmq, tornado, types-paramiko, traitlets, "jupyter_core>=5.0", ipykernel] - stages: [manual] - - - repo: https://github.com/PyCQA/doc8 - rev: v1.0.0 + - repo: https://github.com/psf/black + rev: 22.10.0 hooks: - - id: doc8 - args: [--max-line-length=100] + - id: black - - repo: https://github.com/sirosen/check-jsonschema - rev: 0.19.2 + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.165 hooks: - - id: check-jsonschema - name: "Check GitHub Workflows" - files: ^\.github/workflows/ - types: [yaml] - args: ["--schemafile", "https://json.schemastore.org/github-workflow"] - stages: [manual] + - id: ruff + args: ["--fix"] diff --git a/docs/conf.py b/docs/conf.py index 531c7207a..639018ed7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -67,7 +67,7 @@ here = os.path.dirname(__file__) version_py = os.path.join(here, os.pardir, 'jupyter_client', '_version.py') with open(version_py) as f: - exec(compile(f.read(), version_py, 'exec'), version_ns) + exec(compile(f.read(), version_py, 'exec'), version_ns) # noqa # The short X.Y version. version = '%i.%i' % version_ns['version_info'][:2] diff --git a/jupyter_client/_version.py b/jupyter_client/_version.py index 546b2b7f2..852244b3e 100644 --- a/jupyter_client/_version.py +++ b/jupyter_client/_version.py @@ -1,6 +1,5 @@ import re -from typing import List -from typing import Union +from typing import List, Union __version__ = "8.0.0b1" diff --git a/jupyter_client/adapter.py b/jupyter_client/adapter.py index 3c229e8c7..ff48b6235 100644 --- a/jupyter_client/adapter.py +++ b/jupyter_client/adapter.py @@ -3,10 +3,7 @@ # Distributed under the terms of the Modified BSD License. import json import re -from typing import Any -from typing import Dict -from typing import List -from typing import Tuple +from typing import Any, Dict, List, Tuple from jupyter_client import protocol_version_info diff --git a/jupyter_client/asynchronous/client.py b/jupyter_client/asynchronous/client.py index fa613909b..04510e809 100644 --- a/jupyter_client/asynchronous/client.py +++ b/jupyter_client/asynchronous/client.py @@ -4,13 +4,10 @@ import asyncio import zmq.asyncio -from traitlets import Instance -from traitlets import Type +from traitlets import Instance, Type -from jupyter_client.channels import AsyncZMQSocketChannel -from jupyter_client.channels import HBChannel -from jupyter_client.client import KernelClient -from jupyter_client.client import reqrep +from jupyter_client.channels import AsyncZMQSocketChannel, HBChannel +from jupyter_client.client import KernelClient, reqrep def wrapped(meth, channel): diff --git a/jupyter_client/blocking/client.py b/jupyter_client/blocking/client.py index 2303519fa..672f3a854 100644 --- a/jupyter_client/blocking/client.py +++ b/jupyter_client/blocking/client.py @@ -6,11 +6,10 @@ # Distributed under the terms of the Modified BSD License. from traitlets import Type +from jupyter_client.channels import HBChannel, ZMQSocketChannel +from jupyter_client.client import KernelClient, reqrep + from ..utils import run_sync -from jupyter_client.channels import HBChannel -from jupyter_client.channels import ZMQSocketChannel -from jupyter_client.client import KernelClient -from jupyter_client.client import reqrep def wrapped(meth, channel): diff --git a/jupyter_client/channels.py b/jupyter_client/channels.py index 1daf322e8..1020ff6f7 100644 --- a/jupyter_client/channels.py +++ b/jupyter_client/channels.py @@ -6,16 +6,16 @@ import time import typing as t from queue import Empty -from threading import Event -from threading import Thread +from threading import Event, Thread import zmq.asyncio -from .channelsabc import HBChannelABC -from .session import Session from jupyter_client import protocol_version_info from jupyter_client.utils import ensure_async +from .channelsabc import HBChannelABC +from .session import Session + # import ZMQError in top-level namespace, to avoid ugly attribute-error messages # during garbage collection of threads at exit @@ -26,7 +26,7 @@ major_protocol_version = protocol_version_info[0] -class InvalidPortNumber(Exception): +class InvalidPortNumber(Exception): # noqa pass diff --git a/jupyter_client/client.py b/jupyter_client/client.py index afe1dc21d..c1ce3a974 100644 --- a/jupyter_client/client.py +++ b/jupyter_client/client.py @@ -11,18 +11,16 @@ from queue import Empty import zmq.asyncio -from traitlets import Any -from traitlets import Bool -from traitlets import Instance -from traitlets import Type +from traitlets import Any, Bool, Instance, Type -from .channelsabc import ChannelABC -from .channelsabc import HBChannelABC +from jupyter_client.channels import major_protocol_version +from jupyter_client.utils import ensure_async + +from .channelsabc import ChannelABC, HBChannelABC from .clientabc import KernelClientABC from .connect import ConnectionFileMixin from .session import Session -from jupyter_client.channels import major_protocol_version -from jupyter_client.utils import ensure_async + # some utilities to validate message structure, these might get moved elsewhere # if they prove to have more generic utility @@ -265,7 +263,7 @@ def _output_hook_default(self, msg: t.Dict[str, t.Any]) -> None: elif msg_type in ("display_data", "execute_result"): sys.stdout.write(content["data"].get("text/plain", "")) elif msg_type == "error": - print("\n".join(content["traceback"]), file=sys.stderr) + sys.stderr.write("\n".join(content["traceback"])) def _output_hook_kernel( self, @@ -621,14 +619,14 @@ def execute( # Create class for content/msg creation. Related to, but possibly # not in Session. - content = dict( - code=code, - silent=silent, - store_history=store_history, - user_expressions=user_expressions, - allow_stdin=allow_stdin, - stop_on_error=stop_on_error, - ) + content = { + "code": code, + "silent": silent, + "store_history": store_history, + "user_expressions": user_expressions, + "allow_stdin": allow_stdin, + "stop_on_error": stop_on_error, + } msg = self.session.msg("execute_request", content) self.shell_channel.send(msg) return msg["header"]["msg_id"] @@ -651,7 +649,7 @@ def complete(self, code: str, cursor_pos: t.Optional[int] = None) -> str: """ if cursor_pos is None: cursor_pos = len(code) - content = dict(code=code, cursor_pos=cursor_pos) + content = {"code": code, "cursor_pos": cursor_pos} msg = self.session.msg("complete_request", content) self.shell_channel.send(msg) return msg["header"]["msg_id"] @@ -678,11 +676,11 @@ def inspect(self, code: str, cursor_pos: t.Optional[int] = None, detail_level: i """ if cursor_pos is None: cursor_pos = len(code) - content = dict( - code=code, - cursor_pos=cursor_pos, - detail_level=detail_level, - ) + content = { + "code": code, + "cursor_pos": cursor_pos, + "detail_level": detail_level, + } msg = self.session.msg("inspect_request", content) self.shell_channel.send(msg) return msg["header"]["msg_id"] @@ -754,7 +752,7 @@ def comm_info(self, target_name: t.Optional[str] = None) -> str: if target_name is None: content = {} else: - content = dict(target_name=target_name) + content = {"target_name": target_name} msg = self.session.msg("comm_info_request", content) self.shell_channel.send(msg) return msg["header"]["msg_id"] @@ -790,7 +788,7 @@ def input(self, string: str) -> None: ------- The ID of the message sent. """ - content = dict(value=string) + content = {"value": string} msg = self.session.msg("input_reply", content) self.stdin_channel.send(msg) diff --git a/jupyter_client/clientabc.py b/jupyter_client/clientabc.py index 88d5e7d9b..de22b7c59 100644 --- a/jupyter_client/clientabc.py +++ b/jupyter_client/clientabc.py @@ -10,6 +10,7 @@ # ----------------------------------------------------------------------------- import abc + # ----------------------------------------------------------------------------- # Main kernel client class # ----------------------------------------------------------------------------- diff --git a/jupyter_client/connect.py b/jupyter_client/connect.py index 8ebe96c60..e03c364b8 100644 --- a/jupyter_client/connect.py +++ b/jupyter_client/connect.py @@ -14,28 +14,12 @@ import tempfile import warnings from getpass import getpass -from typing import Any -from typing import cast -from typing import Dict -from typing import List -from typing import Optional -from typing import Set -from typing import Tuple -from typing import Union +from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast import zmq -from jupyter_core.paths import jupyter_data_dir -from jupyter_core.paths import jupyter_runtime_dir -from jupyter_core.paths import secure_write -from traitlets import Bool -from traitlets import CaselessStrEnum -from traitlets import Instance -from traitlets import Integer -from traitlets import observe -from traitlets import Type -from traitlets import Unicode -from traitlets.config import LoggingConfigurable -from traitlets.config import SingletonConfigurable +from jupyter_core.paths import jupyter_data_dir, jupyter_runtime_dir, secure_write +from traitlets import Bool, CaselessStrEnum, Instance, Integer, Type, Unicode, observe +from traitlets.config import LoggingConfigurable, SingletonConfigurable from .localinterfaces import localhost from .utils import _filefind @@ -144,13 +128,13 @@ def write_connection_file( if hb_port <= 0: hb_port = ports.pop(0) - cfg: KernelConnectionInfo = dict( - shell_port=shell_port, - iopub_port=iopub_port, - stdin_port=stdin_port, - control_port=control_port, - hb_port=hb_port, - ) + cfg: KernelConnectionInfo = { + "shell_port": shell_port, + "iopub_port": iopub_port, + "stdin_port": stdin_port, + "control_port": control_port, + "hb_port": hb_port, + } cfg["ip"] = ip cfg["key"] = key.decode() cfg["transport"] = transport @@ -364,7 +348,7 @@ def _ip_default(self): @observe("ip") def _ip_changed(self, change): if change["new"] == "*": - self.ip = "0.0.0.0" + self.ip = "0.0.0.0" # noqa # protected traits @@ -408,15 +392,15 @@ def get_connection_info(self, session: bool = False) -> KernelConnectionInfo: connect_info : dict dictionary of connection information. """ - info = dict( - transport=self.transport, - ip=self.ip, - shell_port=self.shell_port, - iopub_port=self.iopub_port, - stdin_port=self.stdin_port, - hb_port=self.hb_port, - control_port=self.control_port, - ) + info = { + "transport": self.transport, + "ip": self.ip, + "shell_port": self.shell_port, + "iopub_port": self.iopub_port, + "stdin_port": self.stdin_port, + "hb_port": self.hb_port, + "control_port": self.control_port, + } if session: # add *clone* of my session, # so that state such as digest_history is not shared. @@ -424,10 +408,10 @@ def get_connection_info(self, session: bool = False) -> KernelConnectionInfo: else: # add session info info.update( - dict( - signature_scheme=self.session.signature_scheme, - key=self.session.key, - ) + { + "signature_scheme": self.session.signature_scheme, + "key": self.session.key, + } ) return info diff --git a/jupyter_client/consoleapp.py b/jupyter_client/consoleapp.py index a8885bf68..526f79fd2 100644 --- a/jupyter_client/consoleapp.py +++ b/jupyter_client/consoleapp.py @@ -14,20 +14,11 @@ import uuid import warnings -from jupyter_core.application import base_aliases -from jupyter_core.application import base_flags -from traitlets import CBool -from traitlets import CUnicode -from traitlets import Dict -from traitlets import List -from traitlets import Type -from traitlets import Unicode +from jupyter_core.application import base_aliases, base_flags +from traitlets import CBool, CUnicode, Dict, List, Type, Unicode from traitlets.config.application import boolean_flag -from . import connect -from . import find_connection_file -from . import KernelManager -from . import tunnel_to_kernel +from . import KernelManager, connect, find_connection_file, tunnel_to_kernel from .blocking import BlockingKernelClient from .kernelspec import NoSuchKernel from .localinterfaces import localhost @@ -74,20 +65,20 @@ aliases.update(base_aliases) # also scrub aliases from the frontend -app_aliases = dict( - ip="JupyterConsoleApp.ip", - transport="JupyterConsoleApp.transport", - hb="JupyterConsoleApp.hb_port", - shell="JupyterConsoleApp.shell_port", - iopub="JupyterConsoleApp.iopub_port", - stdin="JupyterConsoleApp.stdin_port", - control="JupyterConsoleApp.control_port", - existing="JupyterConsoleApp.existing", - f="JupyterConsoleApp.connection_file", - kernel="JupyterConsoleApp.kernel_name", - ssh="JupyterConsoleApp.sshserver", - sshkey="JupyterConsoleApp.sshkey", -) +app_aliases = { + "ip": "JupyterConsoleApp.ip", + "transport": "JupyterConsoleApp.transport", + "hb": "JupyterConsoleApp.hb_port", + "shell": "JupyterConsoleApp.shell_port", + "iopub": "JupyterConsoleApp.iopub_port", + "stdin": "JupyterConsoleApp.stdin_port", + "control": "JupyterConsoleApp.control_port", + "existing": "JupyterConsoleApp.existing", + "f": "JupyterConsoleApp.connection_file", + "kernel": "JupyterConsoleApp.kernel_name", + "ssh": "JupyterConsoleApp.sshserver", + "sshkey": "JupyterConsoleApp.sshkey", +} aliases.update(app_aliases) # ----------------------------------------------------------------------------- @@ -98,9 +89,11 @@ class JupyterConsoleApp(ConnectionFileMixin): - name = "jupyter-console-mixin" + name: t.Union[str, Unicode] = "jupyter-console-mixin" - description = """ + description: t.Union[ + str, Unicode + ] = """ The Jupyter Console Mixin. This class contains the common portions of console client (QtConsole, @@ -239,14 +232,14 @@ def init_ssh(self) -> None: ip = localhost() # build connection dict for tunnels: - info = dict( - ip=ip, - shell_port=self.shell_port, - iopub_port=self.iopub_port, - stdin_port=self.stdin_port, - hb_port=self.hb_port, - control_port=self.control_port, - ) + info = { + "ip": ip, + "shell_port": self.shell_port, + "iopub_port": self.iopub_port, + "stdin_port": self.stdin_port, + "hb_port": self.hb_port, + "control_port": self.control_port, + } self.log.info(f"Forwarding connections to {ip} via {self.sshserver}") diff --git a/jupyter_client/ioloop/manager.py b/jupyter_client/ioloop/manager.py index f6d0f65c3..1e9ef4ef0 100644 --- a/jupyter_client/ioloop/manager.py +++ b/jupyter_client/ioloop/manager.py @@ -5,14 +5,12 @@ import zmq from tornado import ioloop -from traitlets import Instance -from traitlets import Type +from traitlets import Instance, Type from zmq.eventloop.zmqstream import ZMQStream -from .restarter import AsyncIOLoopKernelRestarter -from .restarter import IOLoopKernelRestarter -from jupyter_client.manager import AsyncKernelManager -from jupyter_client.manager import KernelManager +from jupyter_client.manager import AsyncKernelManager, KernelManager + +from .restarter import AsyncIOLoopKernelRestarter, IOLoopKernelRestarter def as_zmqstream(f): diff --git a/jupyter_client/jsonutil.py b/jupyter_client/jsonutil.py index 9903f70ec..e2bc3bccc 100644 --- a/jupyter_client/jsonutil.py +++ b/jupyter_client/jsonutil.py @@ -9,11 +9,10 @@ from binascii import b2a_base64 from collections.abc import Iterable from datetime import datetime -from typing import Optional -from typing import Union +from typing import Optional, Union -from dateutil.parser import parse as _dateutil_parse # type: ignore -from dateutil.tz import tzlocal # type: ignore +from dateutil.parser import parse as _dateutil_parse +from dateutil.tz import tzlocal next_attr_name = "__next__" # Not sure what downstream library uses this, but left it to be safe diff --git a/jupyter_client/kernelapp.py b/jupyter_client/kernelapp.py index a0112c785..b637aa71a 100644 --- a/jupyter_client/kernelapp.py +++ b/jupyter_client/kernelapp.py @@ -2,14 +2,12 @@ import signal import uuid -from jupyter_core.application import base_flags -from jupyter_core.application import JupyterApp +from jupyter_core.application import JupyterApp, base_flags from tornado.ioloop import IOLoop from traitlets import Unicode from . import __version__ -from .kernelspec import KernelSpecManager -from .kernelspec import NATIVE_KERNEL_NAME +from .kernelspec import NATIVE_KERNEL_NAME, KernelSpecManager from .manager import KernelManager diff --git a/jupyter_client/kernelspec.py b/jupyter_client/kernelspec.py index aedc55264..0167cbb39 100644 --- a/jupyter_client/kernelspec.py +++ b/jupyter_client/kernelspec.py @@ -7,21 +7,11 @@ import shutil import warnings -from jupyter_core.paths import jupyter_data_dir -from jupyter_core.paths import jupyter_path -from jupyter_core.paths import SYSTEM_JUPYTER_PATH -from traitlets import Bool -from traitlets import CaselessStrEnum -from traitlets import Dict -from traitlets import HasTraits -from traitlets import List -from traitlets import observe -from traitlets import Set -from traitlets import Type -from traitlets import Unicode +from jupyter_core.paths import SYSTEM_JUPYTER_PATH, jupyter_data_dir, jupyter_path +from traitlets import Bool, CaselessStrEnum, Dict, HasTraits, List, Set, Type, Unicode, observe from traitlets.config import LoggingConfigurable -from .provisioning import KernelProvisionerFactory as KPF +from .provisioning import KernelProvisionerFactory as KPF # noqa pjoin = os.path.join @@ -51,14 +41,14 @@ def from_resource_dir(cls, resource_dir): return cls(resource_dir=resource_dir, **kernel_dict) def to_dict(self): - d = dict( - argv=self.argv, - env=self.env, - display_name=self.display_name, - language=self.language, - interrupt_mode=self.interrupt_mode, - metadata=self.metadata, - ) + d = { + "argv": self.argv, + "env": self.env, + "display_name": self.display_name, + "language": self.language, + "interrupt_mode": self.interrupt_mode, + "metadata": self.metadata, + } return d @@ -112,7 +102,7 @@ def _list_kernels_in(dir): return kernels -class NoSuchKernel(KeyError): +class NoSuchKernel(KeyError): # noqa def __init__(self, name): self.name = name diff --git a/jupyter_client/kernelspecapp.py b/jupyter_client/kernelspecapp.py index db240af21..1ee076c0b 100644 --- a/jupyter_client/kernelspecapp.py +++ b/jupyter_client/kernelspecapp.py @@ -6,14 +6,8 @@ import sys import typing as t -from jupyter_core.application import base_aliases -from jupyter_core.application import base_flags -from jupyter_core.application import JupyterApp -from traitlets import Bool -from traitlets import Dict -from traitlets import Instance -from traitlets import List -from traitlets import Unicode +from jupyter_core.application import JupyterApp, base_aliases, base_flags +from traitlets import Bool, Dict, Instance, List, Unicode from traitlets.config.application import Application from . import __version__ @@ -47,7 +41,7 @@ def start(self): specs = self.kernel_spec_manager.get_all_specs() if not self.json_output: if not specs: - print("No kernels available") + self.log.info("No kernels available") return # pad to width of longest kernel name name_len = len(sorted(paths, key=lambda name: len(name))[-1]) @@ -61,11 +55,11 @@ def path_key(item): # not in jupyter path, artificially added to the front return (-1, path) - print("Available kernels:") + self.log.info("Available kernels:") for kernelname, path in sorted(paths.items(), key=path_key): - print(f" {kernelname.ljust(name_len)} {path}") + self.log.info(f" {kernelname.ljust(name_len)} {path}") else: - print(json.dumps({"kernelspecs": specs}, indent=2)) + self.log.info(json.dumps({"kernelspecs": specs}, indent=2)) return specs @@ -138,7 +132,7 @@ def parse_command_line(self, argv): if self.extra_args: self.sourcedir = self.extra_args[0] else: - print("No source directory specified.") + self.log.info("No source directory specified.") self.exit(1) def start(self): @@ -154,18 +148,14 @@ def start(self): ) except OSError as e: if e.errno == errno.EACCES: - print(e, file=sys.stderr) + self.log.exception(e) if not self.user: - print( + self.log.warn( "Perhaps you want to install with `sudo` or `--user`?", - file=sys.stderr, ) self.exit(1) elif e.errno == errno.EEXIST: - print( - "A kernel spec is already present at %s" % e.filename, - file=sys.stderr, - ) + self.log.warn("A kernel spec is already present at %s" % e.filename) self.exit(1) raise @@ -204,9 +194,9 @@ def start(self): self.exit("Couldn't find kernel spec(s): %s" % ", ".join(missing)) if not (self.force or self.answer_yes): - print("Kernel specs to remove:") + self.log.info("Kernel specs to remove:") for name in self.spec_names: - print(f" {name.ljust(20)}\t{spec_paths[name]}") + self.log.info(f" {name.ljust(20)}\t{spec_paths[name]}") answer = input("Remove %i kernel specs [y/N]: " % len(self.spec_names)) if not answer.lower().startswith("y"): return @@ -216,8 +206,8 @@ def start(self): path = self.kernel_spec_manager.remove_kernel_spec(kernel_name) except OSError as e: if e.errno == errno.EACCES: - print(e, file=sys.stderr) - print("Perhaps you want sudo?", file=sys.stderr) + self.log.info(e, file=sys.stderr) + self.log.info("Perhaps you want sudo?", file=sys.stderr) self.exit(1) else: raise @@ -257,15 +247,15 @@ def start(self): # pragma: no cover try: from ipykernel import kernelspec except ImportError: - print("ipykernel not available, can't install its spec.", file=sys.stderr) + self.log.info("ipykernel not available, can't install its spec.", file=sys.stderr) self.exit(1) try: kernelspec.install(self.kernel_spec_manager, user=self.user) except OSError as e: if e.errno == errno.EACCES: - print(e, file=sys.stderr) + self.log.info(e, file=sys.stderr) if not self.user: - print( + self.log.info( "Perhaps you want to install with `sudo` or `--user`?", file=sys.stderr, ) @@ -279,14 +269,14 @@ class ListProvisioners(JupyterApp): def start(self): kfp = KernelProvisionerFactory.instance(parent=self) - print("Available kernel provisioners:") + self.log.info("Available kernel provisioners:") provisioners = kfp.get_provisioner_entries() # pad to width of longest kernel name name_len = len(sorted(provisioners, key=lambda name: len(name))[-1]) for name in sorted(provisioners): - print(f" {name.ljust(name_len)} {provisioners[name]}") + self.log.info(f" {name.ljust(name_len)} {provisioners[name]}") class KernelSpecApp(Application): @@ -316,8 +306,10 @@ class KernelSpecApp(Application): def start(self): if self.subapp is None: - print("No subcommand specified. Must specify one of: %s" % list(self.subcommands)) - print() + self.log.info( + "No subcommand specified. Must specify one of: %s" % list(self.subcommands) + ) + self.log.info() self.print_description() self.print_subcommands() self.exit(1) diff --git a/jupyter_client/launcher.py b/jupyter_client/launcher.py index 667c7f773..76b4b0666 100644 --- a/jupyter_client/launcher.py +++ b/jupyter_client/launcher.py @@ -3,12 +3,9 @@ # Distributed under the terms of the Modified BSD License. import os import sys -from subprocess import PIPE -from subprocess import Popen -from typing import Any -from typing import Dict -from typing import List -from typing import Optional +import warnings +from subprocess import PIPE, Popen +from typing import Any, Dict, List, Optional from traitlets.log import get_logger @@ -78,13 +75,13 @@ def launch_kernel( env = env if (env is not None) else os.environ.copy() kwargs = kw.copy() - main_args = dict( - stdin=_stdin, - stdout=_stdout, - stderr=_stderr, - cwd=cwd, - env=env, - ) + main_args = { + "stdin": _stdin, + "stdout": _stdout, + "stderr": _stderr, + "cwd": cwd, + "env": env, + } kwargs.update(main_args) # Spawn a kernel. @@ -110,10 +107,10 @@ def launch_kernel( ) except: # noqa from _subprocess import ( - GetCurrentProcess, CREATE_NEW_PROCESS_GROUP, DUPLICATE_SAME_ACCESS, DuplicateHandle, + GetCurrentProcess, ) # create a handle on the parent to be inherited @@ -165,8 +162,8 @@ def launch_kernel( msg = msg.format(cmd, env.get("PATH", os.defpath), without_env) get_logger().error(msg) except Exception as ex2: # Don't let a formatting/logger issue lead to the wrong exception - print(f"Failed to run command: '{cmd}' due to exception: {ex}") - print(f"The following exception occurred handling the previous failure: {ex2}") + warnings.warn(f"Failed to run command: '{cmd}' due to exception: {ex}") + warnings.warn(f"The following exception occurred handling the previous failure: {ex2}") raise ex if sys.platform == "win32": diff --git a/jupyter_client/localinterfaces.py b/jupyter_client/localinterfaces.py index a173e912e..6ba7e838d 100644 --- a/jupyter_client/localinterfaces.py +++ b/jupyter_client/localinterfaces.py @@ -5,10 +5,8 @@ import re import socket import subprocess -from subprocess import PIPE -from subprocess import Popen -from typing import Iterable -from typing import List +from subprocess import PIPE, Popen +from typing import Iterable, List from warnings import warn LOCAL_IPS: List = [] @@ -70,7 +68,7 @@ def ips_loaded(*args, **kwargs): # subprocess-parsing ip finders -class NoIPAddresses(Exception): +class NoIPAddresses(Exception): # noqa pass @@ -94,7 +92,7 @@ def _populate_from_list(addrs): LOCALHOST = "127.0.0.1" local_ips.insert(0, LOCALHOST) - local_ips.extend(["0.0.0.0", ""]) + local_ips.extend(["0.0.0.0", ""]) # noqa LOCAL_IPS[:] = _uniq_stable(local_ips) PUBLIC_IPS[:] = _uniq_stable(public_ips) @@ -175,7 +173,7 @@ def _load_ips_netifaces(): # we never found a loopback interface (can this ever happen?), assume common default LOCALHOST = "127.0.0.1" local_ips.insert(0, LOCALHOST) - local_ips.extend(["0.0.0.0", ""]) + local_ips.extend(["0.0.0.0", ""]) # noqa LOCAL_IPS[:] = _uniq_stable(local_ips) PUBLIC_IPS[:] = _uniq_stable(public_ips) @@ -205,7 +203,7 @@ def _load_ips_gethostbyname(): LOCAL_IPS.extend(PUBLIC_IPS) # include all-interface aliases: 0.0.0.0 and '' - LOCAL_IPS.extend(["0.0.0.0", ""]) + LOCAL_IPS.extend(["0.0.0.0", ""]) # noqa LOCAL_IPS[:] = _uniq_stable(LOCAL_IPS) @@ -216,7 +214,7 @@ def _load_ips_dumb(): """Fallback in case of unexpected failure""" global LOCALHOST LOCALHOST = "127.0.0.1" - LOCAL_IPS[:] = [LOCALHOST, "0.0.0.0", ""] + LOCAL_IPS[:] = [LOCALHOST, "0.0.0.0", ""] # noqa PUBLIC_IPS[:] = [] diff --git a/jupyter_client/manager.py b/jupyter_client/manager.py index 5fa3d2e9b..1271b692a 100644 --- a/jupyter_client/manager.py +++ b/jupyter_client/manager.py @@ -15,25 +15,29 @@ from enum import Enum import zmq -from traitlets import Any -from traitlets import Bool -from traitlets import default -from traitlets import DottedObjectName -from traitlets import Float -from traitlets import Instance -from traitlets import observe -from traitlets import observe_compat -from traitlets import Type -from traitlets import Unicode +from traitlets import ( + Any, + Bool, + DottedObjectName, + Float, + Instance, + Type, + Unicode, + default, + observe, + observe_compat, +) from traitlets.utils.importstring import import_item +from jupyter_client import KernelClient, kernelspec +from jupyter_client.asynchronous import AsyncKernelClient +from jupyter_client.blocking import BlockingKernelClient + from .connect import ConnectionFileMixin from .managerabc import KernelManagerABC from .provisioning import KernelProvisionerBase -from .provisioning import KernelProvisionerFactory as KPF +from .provisioning import KernelProvisionerFactory as KPF # noqa from .utils import run_sync -from jupyter_client import KernelClient -from jupyter_client import kernelspec class _ShutdownStatus(Enum): @@ -119,7 +123,7 @@ def _context_default(self) -> zmq.Context: client_class: DottedObjectName = DottedObjectName( "jupyter_client.blocking.BlockingKernelClient" ) - client_factory: Type = Type(klass="jupyter_client.KernelClient") + client_factory: Type = Type(klass=KernelClient) @default("client_factory") # type:ignore[misc] def _client_factory_default(self) -> Type: @@ -238,15 +242,15 @@ def remove_restart_callback(self, callback: t.Callable, event: str = "restart") # create a Client connected to our Kernel # -------------------------------------------------------------------------- - def client(self, **kwargs: t.Any) -> KernelClient: + def client(self, **kwargs: t.Any) -> BlockingKernelClient: """Create a client configured to connect to our kernel""" kw: dict = {} kw.update(self.get_connection_info(session=True)) kw.update( - dict( - connection_file=self.connection_file, - parent=self, - ) + { + "connection_file": self.connection_file, + "parent": self, + } ) # add kwargs last, for manual overrides @@ -281,10 +285,10 @@ def format_kernel_cmd(self, extra_arguments: t.Optional[t.List[str]] = None) -> # is not usable by non python kernels because the path is being rerouted when # inside of a store app. # See this bug here: https://bugs.python.org/issue41196 - ns = dict( - connection_file=os.path.realpath(self.connection_file), - prefix=sys.prefix, - ) + ns = { + "connection_file": os.path.realpath(self.connection_file), + "prefix": sys.prefix, + } if self.kernel_spec: ns["resource_dir"] = self.kernel_spec.resource_dir @@ -398,7 +402,7 @@ async def _async_start_kernel(self, **kw: t.Any) -> None: async def _async_request_shutdown(self, restart: bool = False) -> None: """Send a shutdown request via control channel""" - content = dict(restart=restart) + content = {"restart": restart} msg = self.session.msg("shutdown_request", content=content) # ensure control socket is connected self._connect_control_socket() @@ -657,20 +661,45 @@ def _context_default(self) -> zmq.asyncio.Context: self._created_context = True return zmq.asyncio.Context() + def client(self, **kwargs: t.Any) -> AsyncKernelClient: # type:ignore + return super().client(**kwargs) # type:ignore + _launch_kernel = KernelManager._async_launch_kernel # type:ignore[assignment] - start_kernel = KernelManager._async_start_kernel # type:ignore[assignment] - pre_start_kernel = KernelManager._async_pre_start_kernel # type:ignore[assignment] - post_start_kernel = KernelManager._async_post_start_kernel # type:ignore[assignment] - request_shutdown = KernelManager._async_request_shutdown # type:ignore[assignment] - finish_shutdown = KernelManager._async_finish_shutdown # type:ignore[assignment] - cleanup_resources = KernelManager._async_cleanup_resources # type:ignore[assignment] - shutdown_kernel = KernelManager._async_shutdown_kernel # type:ignore[assignment] - restart_kernel = KernelManager._async_restart_kernel # type:ignore[assignment] + start_kernel: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_start_kernel # type:ignore[assignment] + pre_start_kernel: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_pre_start_kernel # type:ignore[assignment] + post_start_kernel: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_post_start_kernel # type:ignore[assignment] + request_shutdown: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_request_shutdown # type:ignore[assignment] + finish_shutdown: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_finish_shutdown # type:ignore[assignment] + cleanup_resources: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_cleanup_resources # type:ignore[assignment] + shutdown_kernel: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_shutdown_kernel # type:ignore[assignment] + restart_kernel: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_restart_kernel # type:ignore[assignment] _send_kernel_sigterm = KernelManager._async_send_kernel_sigterm # type:ignore[assignment] _kill_kernel = KernelManager._async_kill_kernel # type:ignore[assignment] - interrupt_kernel = KernelManager._async_interrupt_kernel # type:ignore[assignment] - signal_kernel = KernelManager._async_signal_kernel # type:ignore[assignment] - is_alive = KernelManager._async_is_alive # type:ignore[assignment] + interrupt_kernel: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_interrupt_kernel # type:ignore[assignment] + signal_kernel: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_signal_kernel # type:ignore[assignment] + is_alive: t.Callable[ + ..., t.Awaitable + ] = KernelManager._async_is_alive # type:ignore[assignment] KernelManagerABC.register(KernelManager) @@ -678,14 +707,14 @@ def _context_default(self) -> zmq.asyncio.Context: def start_new_kernel( startup_timeout: float = 60, kernel_name: str = "python", **kwargs: t.Any -) -> t.Tuple[KernelManager, KernelClient]: +) -> t.Tuple[KernelManager, BlockingKernelClient]: """Start a new kernel, and return its Manager and Client""" km = KernelManager(kernel_name=kernel_name) km.start_kernel(**kwargs) kc = km.client() kc.start_channels() try: - kc.wait_for_ready(timeout=startup_timeout) # type:ignore[attr-defined] + kc.wait_for_ready(timeout=startup_timeout) except RuntimeError: kc.stop_channels() km.shutdown_kernel() @@ -696,17 +725,17 @@ def start_new_kernel( async def start_new_async_kernel( startup_timeout: float = 60, kernel_name: str = "python", **kwargs: t.Any -) -> t.Tuple[AsyncKernelManager, KernelClient]: +) -> t.Tuple[AsyncKernelManager, AsyncKernelClient]: """Start a new kernel, and return its Manager and Client""" km = AsyncKernelManager(kernel_name=kernel_name) - await km.start_kernel(**kwargs) # type:ignore[has-type] + await km.start_kernel(**kwargs) kc = km.client() kc.start_channels() try: - await kc.wait_for_ready(timeout=startup_timeout) # type:ignore[attr-defined] + await kc.wait_for_ready(timeout=startup_timeout) except RuntimeError: kc.stop_channels() - await km.shutdown_kernel() # type:ignore[has-type] + await km.shutdown_kernel() raise return (km, kc) diff --git a/jupyter_client/multikernelmanager.py b/jupyter_client/multikernelmanager.py index 287582f0d..e707c8cc4 100644 --- a/jupyter_client/multikernelmanager.py +++ b/jupyter_client/multikernelmanager.py @@ -8,22 +8,13 @@ import uuid import zmq -from traitlets import Any -from traitlets import Bool -from traitlets import default -from traitlets import Dict -from traitlets import DottedObjectName -from traitlets import Instance -from traitlets import observe -from traitlets import Unicode +from traitlets import Any, Bool, Dict, DottedObjectName, Instance, Unicode, default, observe from traitlets.config.configurable import LoggingConfigurable from traitlets.utils.importstring import import_item -from .kernelspec import KernelSpecManager -from .kernelspec import NATIVE_KERNEL_NAME +from .kernelspec import NATIVE_KERNEL_NAME, KernelSpecManager from .manager import KernelManager -from .utils import ensure_async -from .utils import run_sync +from .utils import ensure_async, run_sync class DuplicateKernelError(Exception): @@ -562,7 +553,15 @@ def _context_default(self) -> zmq.asyncio.Context: self._created_context = True return zmq.asyncio.Context() - start_kernel = MultiKernelManager._async_start_kernel # type:ignore[assignment] - restart_kernel = MultiKernelManager._async_restart_kernel # type:ignore[assignment] - shutdown_kernel = MultiKernelManager._async_shutdown_kernel # type:ignore[assignment] - shutdown_all = MultiKernelManager._async_shutdown_all # type:ignore[assignment] + start_kernel: t.Callable[ + ..., t.Awaitable + ] = MultiKernelManager._async_start_kernel # type:ignore[assignment] + restart_kernel: t.Callable[ + ..., t.Awaitable + ] = MultiKernelManager._async_restart_kernel # type:ignore[assignment] + shutdown_kernel: t.Callable[ + ..., t.Awaitable + ] = MultiKernelManager._async_shutdown_kernel # type:ignore[assignment] + shutdown_all: t.Callable[ + ..., t.Awaitable + ] = MultiKernelManager._async_shutdown_all # type:ignore[assignment] diff --git a/jupyter_client/provisioning/factory.py b/jupyter_client/provisioning/factory.py index 1efa52798..e3491ec82 100644 --- a/jupyter_client/provisioning/factory.py +++ b/jupyter_client/provisioning/factory.py @@ -3,22 +3,16 @@ # Distributed under the terms of the Modified BSD License. import glob import sys -from os import getenv -from os import path -from typing import Any -from typing import Dict -from typing import List - +from os import getenv, path +from typing import Any, Dict, List # See compatibility note on `group` keyword in https://docs.python.org/3/library/importlib.metadata.html#entry-points if sys.version_info < (3, 10): # pragma: no cover - from importlib_metadata import entry_points, EntryPoint + from importlib_metadata import EntryPoint, entry_points else: # pragma: no cover - from importlib.metadata import entry_points, EntryPoint + from importlib.metadata import EntryPoint, entry_points -from traitlets.config import default -from traitlets.config import SingletonConfigurable -from traitlets.config import Unicode +from traitlets.config import SingletonConfigurable, Unicode, default from .provisioner_base import KernelProvisionerBase diff --git a/jupyter_client/provisioning/local_provisioner.py b/jupyter_client/provisioning/local_provisioner.py index 8d66f03a8..df80cdf94 100644 --- a/jupyter_client/provisioning/local_provisioner.py +++ b/jupyter_client/provisioning/local_provisioner.py @@ -5,16 +5,11 @@ import os import signal import sys -from typing import Any -from typing import Dict -from typing import List -from typing import Optional +from typing import Any, Dict, List, Optional -from ..connect import KernelConnectionInfo -from ..connect import LocalPortCache +from ..connect import KernelConnectionInfo, LocalPortCache from ..launcher import launch_kernel -from ..localinterfaces import is_local_ip -from ..localinterfaces import local_ips +from ..localinterfaces import is_local_ip, local_ips from .provisioner_base import KernelProvisionerBase diff --git a/jupyter_client/provisioning/provisioner_base.py b/jupyter_client/provisioning/provisioner_base.py index 3fe729346..7ab2a9b97 100644 --- a/jupyter_client/provisioning/provisioner_base.py +++ b/jupyter_client/provisioning/provisioner_base.py @@ -2,18 +2,10 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import os -from abc import ABC -from abc import ABCMeta -from abc import abstractmethod -from typing import Any -from typing import Dict -from typing import List -from typing import Optional -from typing import Union - -from traitlets.config import Instance -from traitlets.config import LoggingConfigurable -from traitlets.config import Unicode +from abc import ABC, ABCMeta, abstractmethod +from typing import Any, Dict, List, Optional, Union + +from traitlets.config import Instance, LoggingConfigurable, Unicode from ..connect import KernelConnectionInfo diff --git a/jupyter_client/restarter.py b/jupyter_client/restarter.py index be9760103..a31b3caca 100644 --- a/jupyter_client/restarter.py +++ b/jupyter_client/restarter.py @@ -9,12 +9,7 @@ # Distributed under the terms of the Modified BSD License. import time -from traitlets import Bool -from traitlets import default -from traitlets import Dict -from traitlets import Float -from traitlets import Instance -from traitlets import Integer +from traitlets import Bool, Dict, Float, Instance, Integer, default from traitlets.config.configurable import LoggingConfigurable @@ -63,7 +58,7 @@ def _default_last_dead(self): callbacks = Dict() def _callbacks_default(self): - return dict(restart=[], dead=[]) + return {"restart": [], "dead": []} def start(self): """Start the polling of the kernel.""" diff --git a/jupyter_client/runapp.py b/jupyter_client/runapp.py index 3784586b1..950f42d07 100644 --- a/jupyter_client/runapp.py +++ b/jupyter_client/runapp.py @@ -5,18 +5,12 @@ import sys import time -from jupyter_core.application import base_aliases -from jupyter_core.application import base_flags -from jupyter_core.application import JupyterApp -from traitlets import Any -from traitlets import Dict -from traitlets import Float +from jupyter_core.application import JupyterApp, base_aliases, base_flags +from traitlets import Any, Dict, Float from traitlets.config import catch_config_error from . import __version__ -from .consoleapp import app_aliases -from .consoleapp import app_flags -from .consoleapp import JupyterConsoleApp +from .consoleapp import JupyterConsoleApp, app_aliases, app_flags OUTPUT_TIMEOUT = 10 diff --git a/jupyter_client/session.py b/jupyter_client/session.py index 8674f31a7..b17e052b3 100644 --- a/jupyter_client/session.py +++ b/jupyter_client/session.py @@ -21,29 +21,28 @@ import typing as t import warnings from binascii import b2a_hex -from datetime import datetime -from datetime import timezone -from hmac import ( - compare_digest, -) # We are using compare_digest to limit the surface of timing attacks -from typing import Optional -from typing import Union +from datetime import datetime, timezone +from hmac import compare_digest + +# We are using compare_digest to limit the surface of timing attacks +from typing import Optional, Union import zmq.asyncio -from traitlets import Any -from traitlets import Bool -from traitlets import CBytes -from traitlets import CUnicode -from traitlets import Dict -from traitlets import DottedObjectName -from traitlets import Instance -from traitlets import Integer -from traitlets import observe -from traitlets import Set -from traitlets import TraitError -from traitlets import Unicode -from traitlets.config.configurable import Configurable -from traitlets.config.configurable import LoggingConfigurable +from traitlets import ( + Any, + Bool, + CBytes, + CUnicode, + Dict, + DottedObjectName, + Instance, + Integer, + Set, + TraitError, + Unicode, + observe, +) +from traitlets.config.configurable import Configurable, LoggingConfigurable from traitlets.log import get_logger from traitlets.utils.importstring import import_item from zmq.eventloop.ioloop import IOLoop @@ -51,11 +50,7 @@ from jupyter_client import protocol_version from jupyter_client.adapter import adapt -from jupyter_client.jsonutil import extract_dates -from jupyter_client.jsonutil import json_clean -from jupyter_client.jsonutil import json_default -from jupyter_client.jsonutil import squash_dates - +from jupyter_client.jsonutil import extract_dates, json_clean, json_default, squash_dates PICKLE_PROTOCOL = pickle.DEFAULT_PROTOCOL @@ -164,11 +159,11 @@ def new_id_bytes() -> bytes: return new_id().encode("ascii") -session_aliases = dict( - ident="Session.session", - user="Session.username", - keyfile="Session.keyfile", -) +session_aliases = { + "ident": "Session.session", + "user": "Session.username", + "keyfile": "Session.keyfile", +} session_flags = { "secure": ( @@ -608,7 +603,7 @@ def _check_packers(self) -> None: unpack = self.unpack # check simple serialization - msg_list = dict(a=[1, "hi"]) + msg_list = {"a": [1, "hi"]} try: packed = pack(msg_list) except Exception as e: @@ -631,7 +626,7 @@ def _check_packers(self) -> None: ) from e # check datetime support - msg_datetime = dict(t=utcnow()) + msg_datetime = {"t": utcnow()} try: unpacked = unpack(pack(msg_datetime)) if isinstance(unpacked["t"], datetime): @@ -859,9 +854,9 @@ def send( stream.send_multipart(to_send, copy=copy) if self.debug: - pprint.pprint(msg) - pprint.pprint(to_send) - pprint.pprint(buffers) + pprint.pprint(msg) # noqa + pprint.pprint(to_send) # noqa + pprint.pprint(buffers) # noqa msg["tracker"] = tracker @@ -975,7 +970,7 @@ def feed_identities( if copy: msg_list = t.cast(t.List[bytes], msg_list) idx = msg_list.index(DELIM) - return msg_list[:idx], msg_list[idx + 1 :] # noqa + return msg_list[:idx], msg_list[idx + 1 :] else: msg_list = t.cast(t.List[zmq.Message], msg_list) failed = True @@ -985,7 +980,7 @@ def feed_identities( break if failed: raise ValueError("DELIM not in msg_list") - idents, msg_list = msg_list[:idx], msg_list[idx + 1 :] # noqa + idents, msg_list = msg_list[:idx], msg_list[idx + 1 :] return [bytes(m.bytes) for m in idents], msg_list def _add_digest(self, signature: bytes) -> None: @@ -1082,7 +1077,7 @@ def deserialize( buffers = [memoryview(bytes(b.bytes)) for b in msg_list[5:]] message["buffers"] = buffers if self.debug: - pprint.pprint(message) + pprint.pprint(message) # noqa # adapt to the current version return adapt(message) diff --git a/jupyter_client/ssh/tunnel.py b/jupyter_client/ssh/tunnel.py index ce9fe7097..b7e217bf5 100644 --- a/jupyter_client/ssh/tunnel.py +++ b/jupyter_client/ssh/tunnel.py @@ -12,8 +12,7 @@ import socket import sys import warnings -from getpass import getpass -from getpass import getuser +from getpass import getpass, getuser from multiprocessing import Process try: @@ -25,7 +24,7 @@ except ImportError: paramiko = None # type:ignore[assignment] - class SSHException(Exception): # type: ignore + class SSHException(Exception): # type: ignore # noqa pass else: @@ -230,7 +229,7 @@ def openssh_tunnel( cmd = f"{ssh} -O check {server}" (output, exitstatus) = pexpect.run(cmd, withexitstatus=True) if not exitstatus: - pid = int(output[output.find(b"(pid=") + 5 : output.find(b")")]) # noqa + pid = int(output[output.find(b"(pid=") + 5 : output.find(b")")]) cmd = "%s -O forward -L 127.0.0.1:%i:%s:%i %s" % ( ssh, lport, @@ -268,15 +267,12 @@ def openssh_tunnel( except pexpect.EOF as e: tunnel.wait() if tunnel.exitstatus: - print(tunnel.exitstatus) - print(tunnel.before) - print(tunnel.after) raise RuntimeError("tunnel '%s' failed to start" % (cmd)) from e else: return tunnel.pid else: if failed: - print("Password rejected, try again") + warnings.warn("Password rejected, try again") password = None if password is None: password = getpass("%s's password: " % (server)) @@ -353,7 +349,7 @@ def paramiko_tunnel( p = Process( target=_paramiko_tunnel, args=(lport, rport, server, remoteip), - kwargs=dict(keyfile=keyfile, password=password), + kwargs={"keyfile": keyfile, "password": password}, ) p.daemon = True p.start() @@ -385,7 +381,7 @@ def _paramiko_tunnel(lport, rport, server, remoteip, keyfile=None, password=None # else: # raise except Exception as e: - print("*** Failed to connect to %s:%d: %r" % (server, port, e)) + warnings.warn("*** Failed to connect to %s:%d: %r" % (server, port, e)) sys.exit(1) # Don't let SIGINT kill the tunnel subprocess @@ -394,10 +390,10 @@ def _paramiko_tunnel(lport, rport, server, remoteip, keyfile=None, password=None try: forward_tunnel(lport, remoteip, rport, client.get_transport()) except KeyboardInterrupt: - print("SIGINT: Port forwarding stopped cleanly") + warnings.warn("SIGINT: Port forwarding stopped cleanly") sys.exit(0) except Exception as e: - print("Port forwarding stopped uncleanly: %s" % e) + warnings.warn("Port forwarding stopped uncleanly: %s" % e) sys.exit(255) diff --git a/jupyter_client/threaded.py b/jupyter_client/threaded.py index 29bcc7c9b..e5393bc36 100644 --- a/jupyter_client/threaded.py +++ b/jupyter_client/threaded.py @@ -4,23 +4,20 @@ import asyncio import atexit import time -from threading import Event -from threading import Thread -from typing import Any -from typing import Dict -from typing import List -from typing import Optional +from threading import Event, Thread +from typing import Any, Dict, List, Optional import zmq from tornado.ioloop import IOLoop -from traitlets import Instance -from traitlets import Type +from traitlets import Instance, Type from zmq.eventloop import zmqstream -from .session import Session from jupyter_client import KernelClient from jupyter_client.channels import HBChannel +from .session import Session + + # Local imports # import ZMQError in top-level namespace, to avoid ugly attribute-error messages # during garbage collection of threads at exit diff --git a/jupyter_client/utils.py b/jupyter_client/utils.py index f9448841d..e43d89d10 100644 --- a/jupyter_client/utils.py +++ b/jupyter_client/utils.py @@ -5,8 +5,7 @@ """ import os -from jupyter_core.utils import ensure_async # noqa: F401 -from jupyter_core.utils import run_sync # noqa: F401 +from jupyter_core.utils import ensure_async, run_sync # noqa: F401 # noqa: F401 def _filefind(filename, path_dirs=None): diff --git a/jupyter_client/win_interrupt.py b/jupyter_client/win_interrupt.py index 2da10f414..e782222e4 100644 --- a/jupyter_client/win_interrupt.py +++ b/jupyter_client/win_interrupt.py @@ -19,7 +19,7 @@ def create_interrupt_event(): # Create a security attributes struct that permits inheritance of the # handle by new processes. # FIXME: We can clean up this mess by requiring pywin32 for IPython. - class SECURITY_ATTRIBUTES(ctypes.Structure): + class SECURITY_ATTRIBUTES(ctypes.Structure): # noqa _fields_ = [ ("nLength", ctypes.c_int), ("lpSecurityDescriptor", ctypes.c_void_p), diff --git a/pyproject.toml b/pyproject.toml index 8365c880f..f40e0a816 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,14 @@ docs = [ "pydata_sphinx_theme", "sphinxcontrib_github_alt", ] +lint = [ + "black>=22.6.0", + "mdformat>0.7", + "ruff>=0.0.156", +] +typing = [ + "mypy>=0.990" +] [project.scripts] jupyter-kernelspec = "jupyter_client.kernelspecapp:KernelSpecApp.launch_instance" @@ -97,14 +105,24 @@ dependencies = ["coverage[toml]", "pytest-cov"] test = "python -m pytest -vv --cov jupyter_client --cov-branch --cov-report term-missing:skip-covered {args}" nowarn = "test -W default {args}" -[tool.black] -line-length = 100 -skip-string-normalization = true -target_version = [ - "py38", - "py39", - "py310", - "py311", +[tool.hatch.envs.typing] +features = ["test", "typing"] +dependencies = ["mypy>=0.990"] +[tool.hatch.envs.typing.scripts] +test = "mypy --install-types --non-interactive {args:.}" + +[tool.hatch.envs.lint] +features = ["lint"] +[tool.hatch.envs.lint.scripts] +style = [ + "ruff {args:.}", + "black --check --diff {args:.}", + "mdformat --check {args:docs *.md}" +] +fmt = [ + "black {args:.}", + "ruff --fix {args:.}", + "mdformat {args:docs *.md}" ] [tool.pytest.ini_options] @@ -155,24 +173,62 @@ warn_redundant_casts = true warn_return_any = false warn_unused_ignores = true -[tool.flake8] -ignore = "E501, W503, E402" -builtins = "c, get_config" -exclude = [ - ".cache", - ".github", - "docs", - "setup.py", + +[tool.black] +line-length = 100 +skip-string-normalization = true +target-version = ["py38"] + +[tool.ruff] +target-version = "py38" +line-length = 100 +select = [ + "A", "B", "C", "E", "F", "FBT", "I", "N", "Q", "RUF", "S", "T", + "UP", "W", "YTT", ] -enable-extensions = "G" -extend-ignore = [ - "G001", "G002", "G004", "G200", "G201", "G202", - # black adds spaces around ':' - "E203", +ignore = [ + # Allow non-abstract empty methods in abstract base classes + "B027", + # Ignore McCabe complexity + "C901", + # Allow boolean positional values in function calls, like `dict.get(... True)` + "FBT003", + # Use of `assert` detected + "S101", + # Line too long + "E501", + # Relative imports are banned + "I252", + # Boolean ... in function definition + "FBT001", + "FBT002", + # Module level import not at top of file + "E402", + # A001/A002/A003 .. is shadowing a python builtin + "A001", + "A002", + "A003", + # Possible hardcoded password + "S105", + "S106", + # Q000 Single quotes found but double quotes preferred + "Q000", + # N806 Variable `B` in function should be lowercase + "N806", ] -per-file-ignores = [ - # B011: Do not call assert False since python -O removes these calls - # F841 local variable 'foo' is assigned to but never used - # B007 Loop control variable - "tests/*: B011", "F841", "B007", +unfixable = [ + # Don't touch print statements + "T201", + # Don't touch noqa lines + "RUF100", ] + +[tool.ruff.per-file-ignores] +# B011 Do not call assert False since python -O removes these calls +# F841 local variable 'foo' is assigned to but never used +# C408 Unnecessary `dict` call +# E402 Module level import not at top of file +# T201 `print` found +# B007 Loop control variable `i` not used within the loop body. +# N802 Function name `assertIn` should be lowercase +"tests/*" = ["B011", "F841", "C408", "E402", "T201", "B007", "N802"] diff --git a/tests/conftest.py b/tests/conftest.py index 07c0b032b..4352bf04a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,7 @@ import os if os.name == "nt": - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # type:ignore import pytest diff --git a/tests/signalkernel.py b/tests/signalkernel.py index 52679f6d5..31e561efa 100644 --- a/tests/signalkernel.py +++ b/tests/signalkernel.py @@ -4,8 +4,7 @@ import os import signal import time -from subprocess import PIPE -from subprocess import Popen +from subprocess import PIPE, Popen from ipykernel.displayhook import ZMQDisplayHook from ipykernel.kernelapp import IPKernelApp @@ -35,7 +34,7 @@ def do_execute( self, code, silent, store_history=True, user_expressions=None, allow_stdin=False ): code = code.strip() - reply = { + reply: dict = { "status": "ok", "user_expressions": {}, } diff --git a/tests/test_adapter.py b/tests/test_adapter.py index 9f45c0267..807e46ca3 100644 --- a/tests/test_adapter.py +++ b/tests/test_adapter.py @@ -5,9 +5,7 @@ import json from unittest import TestCase -from jupyter_client.adapter import adapt -from jupyter_client.adapter import code_to_line -from jupyter_client.adapter import V4toV5 +from jupyter_client.adapter import V4toV5, adapt, code_to_line from jupyter_client.session import Session @@ -32,7 +30,7 @@ def setUp(self): def adapt(self, msg, version=None): original = copy.deepcopy(msg) - adapted = adapt(msg, version or self.to_version) + adapted = adapt(msg, version or self.to_version) # type:ignore return original, adapted def check_header(self, msg): diff --git a/tests/test_client.py b/tests/test_client.py index 87a6a9e7d..346777da9 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -5,22 +5,16 @@ import platform import sys from threading import Event -from unittest import mock -from unittest import TestCase +from unittest import TestCase, mock import pytest -from IPython.utils.capture import capture_output -from traitlets import DottedObjectName -from traitlets import Type +from IPython.utils.capture import capture_output # type:ignore +from traitlets import DottedObjectName, Type from jupyter_client.client import validate_string_dict -from jupyter_client.kernelspec import KernelSpecManager -from jupyter_client.kernelspec import NoSuchKernel -from jupyter_client.manager import KernelManager -from jupyter_client.manager import start_new_async_kernel -from jupyter_client.manager import start_new_kernel -from jupyter_client.threaded import ThreadedKernelClient -from jupyter_client.threaded import ThreadedZMQSocketChannel +from jupyter_client.kernelspec import KernelSpecManager, NoSuchKernel +from jupyter_client.manager import KernelManager, start_new_async_kernel, start_new_kernel +from jupyter_client.threaded import ThreadedKernelClient, ThreadedZMQSocketChannel TIMEOUT = 30 @@ -302,6 +296,6 @@ def test_shutdown_id(self): def test_validate_string_dict(): with pytest.raises(ValueError): - validate_string_dict(dict(a=1)) + validate_string_dict(dict(a=1)) # type:ignore with pytest.raises(ValueError): - validate_string_dict({1: 'a'}) + validate_string_dict({1: 'a'}) # type:ignore diff --git a/tests/test_connect.py b/tests/test_connect.py index 4449b9091..34253666b 100644 --- a/tests/test_connect.py +++ b/tests/test_connect.py @@ -9,9 +9,7 @@ from jupyter_core.application import JupyterApp from jupyter_core.paths import jupyter_runtime_dir -from jupyter_client import connect -from jupyter_client import KernelClient -from jupyter_client import KernelManager +from jupyter_client import KernelClient, KernelManager, connect from jupyter_client.consoleapp import JupyterConsoleApp from jupyter_client.session import Session @@ -36,7 +34,7 @@ def __exit__(self, exc, value, tb): return super().__exit__(exc, value, tb) -class DummyConsoleApp(JupyterApp, JupyterConsoleApp): +class DummyConsoleApp(JupyterApp, JupyterConsoleApp): # type:ignore def initialize(self, argv=None): JupyterApp.initialize(self, argv=argv or []) self.init_connection_file() @@ -47,7 +45,7 @@ def initialize(self): pass -sample_info = dict( +sample_info: dict = dict( ip="1.2.3.4", transport="ipc", shell_port=1, @@ -60,7 +58,7 @@ def initialize(self): kernel_name="python", ) -sample_info_kn = dict( +sample_info_kn: dict = dict( ip="1.2.3.4", transport="ipc", shell_port=1, @@ -136,11 +134,11 @@ def test_app_load_connection_file(): def test_load_connection_info(): client = KernelClient() - info = { + info: dict = { "control_port": 53702, "hb_port": 53705, "iopub_port": 53703, - "ip": "0.0.0.0", + "ip": "0.0.0.0", # noqa "key": "secret", "shell_port": 53700, "signature_scheme": "hmac-sha256", @@ -235,7 +233,7 @@ def test_mixin_cleanup_random_ports(): dc.cleanup_random_ports() assert not os.path.exists(filename) - for name in dc._random_port_names: + for name in dc._random_port_names: # type:ignore assert getattr(dc, name) == 0 @@ -264,7 +262,8 @@ def test_reconcile_connection_info(file_exists, km_matches): if file_exists: _, info = connect.write_connection_file(cf, **expected_info) - info["key"] = info["key"].encode() # set 'key' back to bytes + # set 'key' back to bytes + info["key"] = info["key"].encode() # type:ignore if km_matches: # Let this be the case where the connection file exists, and the KM has matching diff --git a/tests/test_consoleapp.py b/tests/test_consoleapp.py index 8fe4edbae..753ce9b1a 100644 --- a/tests/test_consoleapp.py +++ b/tests/test_consoleapp.py @@ -10,7 +10,7 @@ from jupyter_client.manager import start_new_kernel -class MockConsoleApp(JupyterConsoleApp, JupyterApp): +class MockConsoleApp(JupyterConsoleApp, JupyterApp): # type:ignore pass diff --git a/tests/test_jsonutil.py b/tests/test_jsonutil.py index 52f735dde..6d32f8864 100644 --- a/tests/test_jsonutil.py +++ b/tests/test_jsonutil.py @@ -8,8 +8,7 @@ from unittest import mock import pytest -from dateutil.tz import tzlocal -from dateutil.tz import tzoffset +from dateutil.tz import tzlocal, tzoffset from jupyter_client import jsonutil from jupyter_client.session import utcnow @@ -101,7 +100,7 @@ def test_json_default_date(): def test_json_default(): # list of input/expected output. Use None for the expected output if it # can be the same as the input. - pairs = [ + pairs: list = [ (1, None), # start with scalars (1.123, None), (1.0, None), diff --git a/tests/test_kernelapp.py b/tests/test_kernelapp.py index b214ef545..355b406fe 100644 --- a/tests/test_kernelapp.py +++ b/tests/test_kernelapp.py @@ -2,8 +2,7 @@ import shutil import sys import time -from subprocess import PIPE -from subprocess import Popen +from subprocess import PIPE, Popen from tempfile import mkdtemp diff --git a/tests/test_kernelmanager.py b/tests/test_kernelmanager.py index 0dc1dee31..cfce5b532 100644 --- a/tests/test_kernelmanager.py +++ b/tests/test_kernelmanager.py @@ -14,13 +14,10 @@ from jupyter_core import paths from traitlets.config.loader import Config -from .utils import AsyncKMSubclass -from .utils import SyncKMSubclass -from jupyter_client import AsyncKernelManager -from jupyter_client import KernelManager -from jupyter_client.manager import _ShutdownStatus -from jupyter_client.manager import start_new_async_kernel -from jupyter_client.manager import start_new_kernel +from jupyter_client import AsyncKernelManager, KernelManager +from jupyter_client.manager import _ShutdownStatus, start_new_async_kernel, start_new_kernel + +from .utils import AsyncKMSubclass, SyncKMSubclass pjoin = os.path.join @@ -279,7 +276,7 @@ def test_no_cleanup_shared_context(self, jp_zmq_context): assert km.context.closed is False assert jp_zmq_context.closed is False - def test_subclass_callables(self, km_subclass): + def test_subclass_callables(self, km_subclass: SyncKMSubclass) -> None: km_subclass.reset_counts() km_subclass.start_kernel(stdout=PIPE, stderr=PIPE) @@ -503,7 +500,7 @@ async def test_start_new_async_kernel(self, install_kernel, jp_start_kernel): is_alive = await kc.is_alive() assert is_alive - async def test_subclass_callables(self, async_km_subclass): + async def test_subclass_callables(self, async_km_subclass: AsyncKMSubclass) -> None: async_km_subclass.reset_counts() await async_km_subclass.start_kernel(stdout=PIPE, stderr=PIPE) diff --git a/tests/test_kernelspec.py b/tests/test_kernelspec.py index 99e725098..115d9a298 100644 --- a/tests/test_kernelspec.py +++ b/tests/test_kernelspec.py @@ -10,18 +10,16 @@ from io import StringIO from logging import StreamHandler from os.path import join as pjoin -from subprocess import PIPE -from subprocess import Popen -from subprocess import STDOUT +from subprocess import PIPE, STDOUT, Popen from tempfile import TemporaryDirectory import pytest from jupyter_core import paths -from .utils import install_kernel -from .utils import sample_kernel_json from jupyter_client import kernelspec +from .utils import install_kernel, sample_kernel_json + class KernelSpecTests(unittest.TestCase): def setUp(self): diff --git a/tests/test_kernelspecapp.py b/tests/test_kernelspecapp.py index 40ca590de..7fa161eed 100644 --- a/tests/test_kernelspecapp.py +++ b/tests/test_kernelspecapp.py @@ -4,11 +4,13 @@ import os import warnings -from jupyter_client.kernelspecapp import InstallKernelSpec -from jupyter_client.kernelspecapp import KernelSpecApp -from jupyter_client.kernelspecapp import ListKernelSpecs -from jupyter_client.kernelspecapp import ListProvisioners -from jupyter_client.kernelspecapp import RemoveKernelSpec +from jupyter_client.kernelspecapp import ( + InstallKernelSpec, + KernelSpecApp, + ListKernelSpecs, + ListProvisioners, + RemoveKernelSpec, +) def test_kernelspec_sub_apps(jp_kernel_dir): @@ -22,18 +24,18 @@ def test_kernelspec_sub_apps(jp_kernel_dir): warnings.simplefilter("ignore") app.start() - app = ListKernelSpecs() - app.kernel_spec_manager.kernel_dirs.append(kernel_dir) - specs = app.start() + app1 = ListKernelSpecs() + app1.kernel_spec_manager.kernel_dirs.append(kernel_dir) + specs = app1.start() assert 'echo' in specs - app = RemoveKernelSpec(spec_names=['echo'], force=True) - app.kernel_spec_manager.kernel_dirs.append(kernel_dir) - app.start() + app2 = RemoveKernelSpec(spec_names=['echo'], force=True) + app2.kernel_spec_manager.kernel_dirs.append(kernel_dir) + app2.start() - app = ListKernelSpecs() - app.kernel_spec_manager.kernel_dirs.append(kernel_dir) - specs = app.start() + app3 = ListKernelSpecs() + app3.kernel_spec_manager.kernel_dirs.append(kernel_dir) + specs = app3.start() assert 'echo' not in specs diff --git a/tests/test_multikernelmanager.py b/tests/test_multikernelmanager.py index e887c5c32..e6e6576a0 100644 --- a/tests/test_multikernelmanager.py +++ b/tests/test_multikernelmanager.py @@ -10,21 +10,21 @@ import pytest from jupyter_core import paths -from tornado.testing import AsyncTestCase -from tornado.testing import gen_test +from tornado.testing import AsyncTestCase, gen_test from traitlets.config.loader import Config -from .utils import AsyncKMSubclass -from .utils import AsyncMKMSubclass -from .utils import install_kernel -from .utils import skip_win32 -from .utils import SyncKMSubclass -from .utils import SyncMKMSubclass -from jupyter_client import AsyncKernelManager -from jupyter_client import KernelManager +from jupyter_client import AsyncKernelManager, KernelManager from jupyter_client.localinterfaces import localhost -from jupyter_client.multikernelmanager import AsyncMultiKernelManager -from jupyter_client.multikernelmanager import MultiKernelManager +from jupyter_client.multikernelmanager import AsyncMultiKernelManager, MultiKernelManager + +from .utils import ( + AsyncKMSubclass, + AsyncMKMSubclass, + SyncKMSubclass, + SyncMKMSubclass, + install_kernel, + skip_win32, +) TIMEOUT = 30 diff --git a/tests/test_provisioning.py b/tests/test_provisioning.py index 5e6ab21ef..58ba6a0c6 100644 --- a/tests/test_provisioning.py +++ b/tests/test_provisioning.py @@ -7,45 +7,42 @@ import signal import sys from subprocess import PIPE -from typing import Any -from typing import Dict -from typing import List -from typing import Optional +from typing import Any, Dict, List, Optional import pytest from jupyter_core import paths -from traitlets import Int -from traitlets import Unicode +from traitlets import Int, Unicode from jupyter_client.connect import KernelConnectionInfo -from jupyter_client.kernelspec import KernelSpecManager -from jupyter_client.kernelspec import NoSuchKernel +from jupyter_client.kernelspec import KernelSpecManager, NoSuchKernel from jupyter_client.launcher import launch_kernel from jupyter_client.manager import AsyncKernelManager -from jupyter_client.provisioning import KernelProvisionerBase -from jupyter_client.provisioning import KernelProvisionerFactory -from jupyter_client.provisioning import LocalProvisioner +from jupyter_client.provisioning import ( + KernelProvisionerBase, + KernelProvisionerFactory, + LocalProvisioner, +) from jupyter_client.provisioning.factory import EntryPoint pjoin = os.path.join -class SubclassedTestProvisioner(LocalProvisioner): +class SubclassedTestProvisioner(LocalProvisioner): # type:ignore - config_var_1: int = Int(config=True) - config_var_2: str = Unicode(config=True) + config_var_1: int = Int(config=True) # type:ignore + config_var_2: str = Unicode(config=True) # type:ignore pass -class CustomTestProvisioner(KernelProvisionerBase): +class CustomTestProvisioner(KernelProvisionerBase): # type:ignore process = None pid = None pgid = None - config_var_1: int = Int(config=True) - config_var_2: str = Unicode(config=True) + config_var_1: int = Int(config=True) # type:ignore + config_var_2: str = Unicode(config=True) # type:ignore @property def has_process(self) -> bool: @@ -90,11 +87,11 @@ async def send_signal(self, signum: int) -> None: pass return self.process.send_signal(signum) - async def kill(self, restart=False) -> None: + async def kill(self, restart: bool = False) -> None: if self.process: self.process.kill() - async def terminate(self, restart=False) -> None: + async def terminate(self, restart: bool = False) -> None: if self.process: self.process.terminate() @@ -115,6 +112,7 @@ async def pre_launch(self, **kwargs: Any) -> Dict[str, Any]: ) # This needs to remain here for b/c return await super().pre_launch(cmd=kernel_cmd, **kwargs) + return {} async def launch_kernel(self, cmd: List[str], **kwargs: Any) -> KernelConnectionInfo: scrubbed_kwargs = kwargs @@ -130,16 +128,16 @@ async def launch_kernel(self, cmd: List[str], **kwargs: Any) -> KernelConnection self.pgid = pgid return self.connection_info - async def cleanup(self, restart=False) -> None: + async def cleanup(self, restart: bool = False) -> None: pass -class NewTestProvisioner(CustomTestProvisioner): +class NewTestProvisioner(CustomTestProvisioner): # type:ignore pass def build_kernelspec(name: str, provisioner: Optional[str] = None) -> None: - spec = { + spec: dict = { 'argv': [ sys.executable, '-m', @@ -211,7 +209,7 @@ def mock_get_all_provisioners() -> List[EntryPoint]: return result -def mock_get_provisioner(factory, name) -> EntryPoint: +def mock_get_provisioner(_: str, name: str) -> EntryPoint: if name == 'new-test-provisioner': return EntryPoint( 'new-test-provisioner', @@ -276,6 +274,7 @@ async def akm_test(self, kernel_mgr): TestRuntime.validate_provisioner(kernel_mgr) await kernel_mgr.shutdown_kernel() + assert kernel_mgr.provisioner is not None assert kernel_mgr.provisioner.has_process is False async def test_existing(self, kpf, akm): @@ -318,7 +317,7 @@ async def test_default_provisioner_config(self, kpf, all_provisioners): assert async_km.context.closed @staticmethod - def validate_provisioner(akm: AsyncKernelManager): + def validate_provisioner(akm: AsyncKernelManager) -> None: # Ensure the provisioner is managing a process at this point assert akm.provisioner is not None and akm.provisioner.has_process @@ -327,8 +326,8 @@ def validate_provisioner(akm: AsyncKernelManager): assert not hasattr(akm.provisioner, 'config_var_1') assert not hasattr(akm.provisioner, 'config_var_2') else: - assert akm.provisioner.config_var_1 == 42 - assert akm.provisioner.config_var_2 == akm.kernel_name + assert akm.provisioner.config_var_1 == 42 # type:ignore + assert akm.provisioner.config_var_2 == akm.kernel_name # type:ignore # Validate provisioner class if akm.kernel_name in ['no_provisioner', 'default_provisioner', 'subclassed_provisioner']: diff --git a/tests/test_public_api.py b/tests/test_public_api.py index 6b3fdc671..327957c37 100644 --- a/tests/test_public_api.py +++ b/tests/test_public_api.py @@ -3,8 +3,7 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import jupyter_client -from jupyter_client import connect -from jupyter_client import launcher +from jupyter_client import connect, launcher def test_kms(): diff --git a/tests/test_restarter.py b/tests/test_restarter.py index 636afa153..4ce2c7e9d 100644 --- a/tests/test_restarter.py +++ b/tests/test_restarter.py @@ -12,8 +12,7 @@ from traitlets.config.loader import Config from traitlets.log import get_logger -from jupyter_client.ioloop import AsyncIOLoopKernelManager -from jupyter_client.ioloop import IOLoopKernelManager +from jupyter_client.ioloop import AsyncIOLoopKernelManager, IOLoopKernelManager pjoin = os.path.join @@ -96,7 +95,7 @@ async def test_restart_check(config, install_kernel, debug_logging): km = IOLoopKernelManager(kernel_name=install_kernel, config=config) cbs = 0 - restarts = [Future() for i in range(N_restarts)] + restarts: list = [Future() for i in range(N_restarts)] def cb(): nonlocal cbs @@ -121,6 +120,7 @@ def cb(): kc.stop_channels() if i < N_restarts: # Kill without cleanup to simulate crash: + assert km.provisioner is not None await km.provisioner.kill() restarts[i].result() # Wait for kill + restart @@ -152,7 +152,7 @@ async def test_restarter_gives_up(config, install_fail_kernel, debug_logging): km = IOLoopKernelManager(kernel_name=install_fail_kernel, config=config) cbs = 0 - restarts = [Future() for i in range(N_restarts)] + restarts: list = [Future() for i in range(N_restarts)] def cb(): nonlocal cbs @@ -161,7 +161,7 @@ def cb(): restarts[cbs].set_result(True) cbs += 1 - died = Future() + died: Future = Future() def on_death(): died.set_result(True) @@ -197,7 +197,7 @@ async def test_async_restart_check(config, install_kernel, debug_logging): km = AsyncIOLoopKernelManager(kernel_name=install_kernel, config=config) cbs = 0 - restarts = [asyncio.Future() for i in range(N_restarts)] + restarts: list = [asyncio.Future() for i in range(N_restarts)] def cb(): nonlocal cbs @@ -222,6 +222,7 @@ def cb(): kc.stop_channels() if i < N_restarts: # Kill without cleanup to simulate crash: + assert km.provisioner is not None await km.provisioner.kill() await restarts[i] # Wait for kill + restart @@ -253,7 +254,7 @@ async def test_async_restarter_gives_up(config, install_slow_fail_kernel, debug_ km = AsyncIOLoopKernelManager(kernel_name=install_slow_fail_kernel, config=config) cbs = 0 - restarts = [asyncio.Future() for i in range(N_restarts)] + restarts: list = [asyncio.Future() for i in range(N_restarts)] def cb(): nonlocal cbs @@ -262,7 +263,7 @@ def cb(): restarts[cbs].set_result(True) cbs += 1 - died = asyncio.Future() + died: asyncio.Future = asyncio.Future() def on_death(): died.set_result(True) diff --git a/tests/test_session.py b/tests/test_session.py index 90b4a41f4..b7a843709 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -478,7 +478,7 @@ async def test_send_raw(self, session): ] session.send_raw(A, msg_list, ident=b"foo") - ident, new_msg_list = session.feed_identities(B.recv_multipart().result()) + ident, new_msg_list = session.feed_identities(B.recv_multipart().result()) # type:ignore new_msg = session.deserialize(new_msg_list) self.assertEqual(ident[0], b"foo") self.assertEqual(new_msg["msg_type"], msg["msg_type"]) @@ -527,7 +527,7 @@ def test_json_packer(): def test_message_cls(): m = ss.Message(dict(a=1)) - foo = dict(m) + foo = dict(m) # type:ignore assert foo['a'] == 1 assert m['a'] == 1, m['a'] assert 'a' in m diff --git a/tests/test_ssh.py b/tests/test_ssh.py index 3b41211f9..095bcc485 100644 --- a/tests/test_ssh.py +++ b/tests/test_ssh.py @@ -2,8 +2,7 @@ import pytest -from jupyter_client.ssh.tunnel import open_tunnel -from jupyter_client.ssh.tunnel import select_random_ports +from jupyter_client.ssh.tunnel import open_tunnel, select_random_ports def test_random_ports(): diff --git a/tests/utils.py b/tests/utils.py index a730d9e56..0c617d3a7 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -8,10 +8,12 @@ import pytest -from jupyter_client import AsyncKernelManager -from jupyter_client import AsyncMultiKernelManager -from jupyter_client import KernelManager -from jupyter_client import MultiKernelManager +from jupyter_client import ( + AsyncKernelManager, + AsyncMultiKernelManager, + KernelManager, + MultiKernelManager, +) pjoin = os.path.join @@ -124,11 +126,11 @@ def _async_cleanup_resources(self, restart=False): """Record call and defer to superclass""" @subclass_recorder - def signal_kernel(self, signum: int): + def signal_kernel(self, signum): """Record call and defer to superclass""" @subclass_recorder - def _async_signal_kernel(self, signum: int): + def _async_signal_kernel(self, signum): """Record call and defer to superclass""" @subclass_recorder @@ -140,7 +142,7 @@ def _async_is_alive(self): """Record call and defer to superclass""" @subclass_recorder - def _async_send_kernel_sigterm(self, restart: bool = False): + def _async_send_kernel_sigterm(self, restart=False): """Record call and defer to superclass"""