From b7881b2abacd738e63b166aa58da63f6fe049b67 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 19 Nov 2023 07:50:54 -0600 Subject: [PATCH 1/5] Update ruff and typings --- .pre-commit-config.yaml | 8 +-- docs/conf.py | 14 ++-- hatch_build.py | 9 +-- ipykernel/__init__.py | 12 ++-- ipykernel/_eventloop_macos.py | 2 +- ipykernel/comm/comm.py | 1 + ipykernel/comm/manager.py | 4 +- ipykernel/compiler.py | 5 +- ipykernel/connect.py | 5 +- ipykernel/debugger.py | 66 +++++++++--------- ipykernel/eventloops.py | 14 ++-- ipykernel/gui/gtk3embed.py | 1 - ipykernel/gui/gtkembed.py | 1 - ipykernel/heartbeat.py | 11 ++- ipykernel/inprocess/__init__.py | 8 +-- ipykernel/inprocess/channels.py | 1 - ipykernel/inprocess/ipkernel.py | 2 - ipykernel/inprocess/socket.py | 1 - ipykernel/iostream.py | 43 ++++++------ ipykernel/ipkernel.py | 9 ++- ipykernel/jsonutil.py | 2 +- ipykernel/kernelapp.py | 29 ++++---- ipykernel/kernelbase.py | 34 +++++----- ipykernel/kernelspec.py | 13 ++-- ipykernel/log.py | 3 +- ipykernel/pickleutil.py | 40 +++++------ ipykernel/pylab/backend_inline.py | 2 +- ipykernel/pylab/config.py | 2 +- ipykernel/serialize.py | 6 +- ipykernel/trio_runner.py | 1 + ipykernel/zmqshell.py | 9 ++- pyproject.toml | 97 ++++++++++----------------- tests/conftest.py | 4 +- tests/inprocess/test_kernel.py | 2 +- tests/inprocess/test_kernelmanager.py | 14 ++-- tests/test_debugger.py | 6 +- tests/test_io.py | 4 +- tests/test_jsonutil.py | 6 +- tests/test_message_spec.py | 2 +- tests/test_parentpoller.py | 4 +- tests/test_pickleutil.py | 2 +- tests/test_zmq_shell.py | 4 +- 42 files changed, 232 insertions(+), 271 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3fefcf03c..5418e5337 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,13 +34,13 @@ repos: [mdformat-gfm, mdformat-frontmatter, mdformat-footnote] - repo: https://github.com/pre-commit/mirrors-prettier - rev: "v3.0.3" + rev: "v3.1.0" hooks: - id: prettier types_or: [yaml, html, json] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.6.1" + rev: "v1.7.0" hooks: - id: mypy files: ipykernel @@ -74,7 +74,7 @@ repos: - id: rst-inline-touching-normal - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.5 + rev: v0.1.6 hooks: - id: ruff types_or: [python, jupyter] @@ -83,7 +83,7 @@ repos: types_or: [python, jupyter] - repo: https://github.com/scientific-python/cookie - rev: "2023.10.27" + rev: "2023.11.17" hooks: - id: sp-repo-review additional_dependencies: ["repo-review[cli]"] diff --git a/docs/conf.py b/docs/conf.py index f3bb74bf5..643740ec0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # IPython Kernel documentation build configuration file, created by # sphinx-quickstart on Mon Oct 5 11:32:44 2015. # @@ -14,6 +12,7 @@ import os import shutil +from pathlib import Path from typing import Any, Dict, List # If extensions (or modules to document with autodoc) are in another directory, @@ -38,7 +37,7 @@ ] try: - import enchant # noqa + import enchant extensions += ["sphinxcontrib.spelling"] except ImportError: @@ -72,10 +71,10 @@ # version_ns: Dict[str, Any] = {} -here = os.path.dirname(__file__) -version_py = os.path.join(here, os.pardir, "ipykernel", "_version.py") +here = Path(__file__).parent.resolve() +version_py = Path(here) / os.pardir / "ipykernel" / "_version.py" with open(version_py) as f: - exec(compile(f.read(), version_py, "exec"), version_ns) # noqa + exec(compile(f.read(), version_py, "exec"), version_ns) # The short X.Y version. version = "%i.%i" % version_ns["version_info"][:2] @@ -312,5 +311,4 @@ def setup(app): - here = os.path.dirname(os.path.abspath(__file__)) - shutil.copy(os.path.join(here, "..", "CHANGELOG.md"), "changelog.md") + shutil.copy(Path(here) / ".." / "CHANGELOG.md", "changelog.md") diff --git a/hatch_build.py b/hatch_build.py index 71dc49be3..410b4603e 100644 --- a/hatch_build.py +++ b/hatch_build.py @@ -2,6 +2,7 @@ import os import shutil import sys +from pathlib import Path from hatchling.builders.hooks.plugin.interface import BuildHookInterface @@ -11,8 +12,8 @@ class CustomHook(BuildHookInterface): def initialize(self, version, build_data): """Initialize the hook.""" - here = os.path.abspath(os.path.dirname(__file__)) - sys.path.insert(0, here) + here = Path(__file__).parent.resolve() + sys.path.insert(0, str(here)) from ipykernel.kernelspec import make_ipkernel_cmd, write_kernel_spec overrides = {} @@ -28,8 +29,8 @@ def initialize(self, version, build_data): overrides["argv"] = argv - dest = os.path.join(here, "data_kernelspec") - if os.path.exists(dest): + dest = Path(here) / "data_kernelspec" + if Path(dest).exists(): shutil.rmtree(dest) write_kernel_spec(dest, overrides=overrides) diff --git a/ipykernel/__init__.py b/ipykernel/__init__.py index a6c1666d6..bc5fbb726 100644 --- a/ipykernel/__init__.py +++ b/ipykernel/__init__.py @@ -1,5 +1,7 @@ -from ._version import __version__ # noqa -from ._version import kernel_protocol_version # noqa -from ._version import kernel_protocol_version_info # noqa -from ._version import version_info # noqa -from .connect import * # noqa +from ._version import ( + __version__, + kernel_protocol_version, + kernel_protocol_version_info, + version_info, +) +from .connect import * diff --git a/ipykernel/_eventloop_macos.py b/ipykernel/_eventloop_macos.py index f07ce6ffc..3a6692fce 100644 --- a/ipykernel/_eventloop_macos.py +++ b/ipykernel/_eventloop_macos.py @@ -75,7 +75,7 @@ def C(classname): CFRunLoopAddTimer.restype = None CFRunLoopAddTimer.argtypes = [void_p, void_p, void_p] -kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, "kCFRunLoopCommonModes") # noqa +kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, "kCFRunLoopCommonModes") def _NSApp(): diff --git a/ipykernel/comm/comm.py b/ipykernel/comm/comm.py index bb9b077d5..1747d4ce7 100644 --- a/ipykernel/comm/comm.py +++ b/ipykernel/comm/comm.py @@ -67,6 +67,7 @@ class Comm(BaseComm, traitlets.config.LoggingConfigurable): def _default_kernel(self): if Kernel.initialized(): return Kernel.instance() + return None @default("comm_id") def _default_comm_id(self): diff --git a/ipykernel/comm/manager.py b/ipykernel/comm/manager.py index 7e4850630..aaef027ce 100644 --- a/ipykernel/comm/manager.py +++ b/ipykernel/comm/manager.py @@ -49,13 +49,13 @@ def comm_open(self, stream, ident, msg): f(comm, msg) return except Exception: - logger.error("Exception opening comm with target: %s", target_name, exc_info=True) + logger.error("Exception opening comm with target: %s", target_name, exc_info=True) # noqa: G201 # Failure. try: comm.close() except Exception: - logger.error( + logger.error( # noqa: G201 """Could not close comm during `comm_open` failure clean-up. The comm may not have been opened yet.""", exc_info=True, diff --git a/ipykernel/compiler.py b/ipykernel/compiler.py index fe5561594..0657f5693 100644 --- a/ipykernel/compiler.py +++ b/ipykernel/compiler.py @@ -45,7 +45,7 @@ def murmur2_x86(data, seed): return h -convert_to_long_pathname = lambda filename: filename # noqa +convert_to_long_pathname = lambda filename: filename if sys.platform == "win32": try: @@ -80,8 +80,7 @@ def get_tmp_directory(): def get_tmp_hash_seed(): """Get a temp hash seed.""" - hash_seed = 0xC70F6907 - return hash_seed + return 0xC70F6907 def get_file_name(code): diff --git a/ipykernel/connect.py b/ipykernel/connect.py index 9f851caab..59d36452d 100644 --- a/ipykernel/connect.py +++ b/ipykernel/connect.py @@ -46,8 +46,7 @@ def _find_connection_file(connection_file): if connection_file is None: # get connection file from current kernel return get_connection_file() - else: - return jupyter_client.find_connection_file(connection_file) + return jupyter_client.find_connection_file(connection_file) def get_connection_info( @@ -125,7 +124,7 @@ def connect_qtconsole( kwargs["start_new_session"] = True return Popen( - [sys.executable, "-c", cmd, "--existing", cf, *argv], # noqa: S603 + [sys.executable, "-c", cmd, "--existing", cf, *argv], stdout=PIPE, stderr=PIPE, close_fds=(sys.platform != "win32"), diff --git a/ipykernel/debugger.py b/ipykernel/debugger.py index 90e4f8885..e236a7c2a 100644 --- a/ipykernel/debugger.py +++ b/ipykernel/debugger.py @@ -3,6 +3,7 @@ import re import sys import typing as t +from pathlib import Path import zmq from IPython.core.getipython import get_ipython @@ -20,7 +21,7 @@ try: # This import is required to have the next ones working... - from debugpy.server import api # noqa + from debugpy.server import api from _pydevd_bundle import pydevd_frame_utils # isort: skip from _pydevd_bundle.pydevd_suspended_frames import ( # isort: skip @@ -179,10 +180,10 @@ def put_tcp_frame(self, frame): self.tcp_buffer = "" self._reset_tcp_pos() return - else: - self.tcp_buffer = self.tcp_buffer[self.message_pos + self.message_size :] - self.log.debug("QUEUE - slicing tcp_buffer: %s", self.tcp_buffer) - self._reset_tcp_pos() + + self.tcp_buffer = self.tcp_buffer[self.message_pos + self.message_size :] + self.log.debug("QUEUE - slicing tcp_buffer: %s", self.tcp_buffer) + self._reset_tcp_pos() async def get_message(self): """Get a message from the queue.""" @@ -256,8 +257,7 @@ async def _handle_init_sequence(self): await self._wait_for_response() # 4] Waits for attachResponse and returns it - attach_rep = await self._wait_for_response() - return attach_rep + return await self._wait_for_response() def get_host_port(self): """Get the host debugpy port.""" @@ -294,11 +294,11 @@ async def send_dap_request(self, msg): rep = await self._handle_init_sequence() self.wait_for_attach = False return rep - else: - rep = await self._wait_for_response() - self.log.debug("DEBUGPYCLIENT - returning:") - self.log.debug(rep) - return rep + + rep = await self._wait_for_response() + self.log.debug("DEBUGPYCLIENT - returning:") + self.log.debug(rep) + return rep class Debugger: @@ -363,9 +363,8 @@ def _handle_event(self, msg): self.stopped_queue.put_nowait(msg) # Do not forward the event now, will be done in the handle_stopped_event return - else: - self.stopped_threads.add(msg["body"]["threadId"]) - self.event_callback(msg) + self.stopped_threads.add(msg["body"]["threadId"]) + self.event_callback(msg) elif msg["event"] == "continued": if msg["body"]["allThreadsContinued"]: self.stopped_threads = set() @@ -380,7 +379,7 @@ async def _forward_message(self, msg): def _build_variables_response(self, request, variables): var_list = [var for var in variables if self.accept_variable(var["name"])] - reply = { + return { "seq": request["seq"], "type": "response", "request_seq": request["seq"], @@ -388,7 +387,6 @@ def _build_variables_response(self, request, variables): "command": request["command"], "body": {"variables": var_list}, } - return reply def _accept_stopped_thread(self, thread_name): # TODO: identify Thread-2, Thread-3 and Thread-4. These are NOT @@ -416,8 +414,8 @@ def start(self): """Start the debugger.""" if not self.debugpy_initialized: tmp_dir = get_tmp_directory() - if not os.path.exists(tmp_dir): - os.makedirs(tmp_dir) + if not Path(tmp_dir).exists(): + Path(tmp_dir).mkdir(parents=True) host, port = self.debugpy_client.get_host_port() code = "import debugpy;" code += 'debugpy.listen(("' + host + '",' + port + "))" @@ -460,14 +458,13 @@ async def dumpCell(self, message): with open(file_name, "w", encoding="utf-8") as f: f.write(code) - reply = { + return { "type": "response", "request_seq": message["seq"], "success": True, "command": message["command"], "body": {"sourcePath": file_name}, } - return reply async def setBreakpoints(self, message): """Handle a set breakpoints message.""" @@ -487,7 +484,7 @@ async def source(self, message): """Handle a source message.""" reply = {"type": "response", "request_seq": message["seq"], "command": message["command"]} source_path = message["arguments"]["source"]["path"] - if os.path.isfile(source_path): + if Path(source_path).is_file(): with open(source_path, encoding="utf-8") as f: reply["success"] = True reply["body"] = {"content": f.read()} @@ -547,7 +544,7 @@ def accept_variable(self, variable_name): cond = variable_name not in forbid_list cond = cond and not bool(re.search(r"^_\d", variable_name)) cond = cond and variable_name[0:2] != "_i" - return cond + return cond # noqa: RET504 async def variables(self, message): """Handle a variables message.""" @@ -557,12 +554,12 @@ async def variables(self, message): message["arguments"]["variablesReference"] ) return self._build_variables_response(message, variables) - else: - reply = await self._forward_message(message) - # TODO : check start and count arguments work as expected in debugpy - reply["body"]["variables"] = [ - var for var in reply["body"]["variables"] if self.accept_variable(var["name"]) - ] + + reply = await self._forward_message(message) + # TODO : check start and count arguments work as expected in debugpy + reply["body"]["variables"] = [ + var for var in reply["body"]["variables"] if self.accept_variable(var["name"]) + ] return reply async def attach(self, message): @@ -580,21 +577,20 @@ async def attach(self, message): async def configurationDone(self, message): """Handle a configuration done message.""" - reply = { + return { "seq": message["seq"], "type": "response", "request_seq": message["seq"], "success": True, "command": message["command"], } - return reply async def debugInfo(self, message): """Handle a debug info message.""" breakpoint_list = [] for key, value in self.breakpoint_list.items(): breakpoint_list.append({"source": key, "breakpoints": value}) - reply = { + return { "type": "response", "request_seq": message["seq"], "success": True, @@ -611,7 +607,6 @@ async def debugInfo(self, message): "exceptionPaths": ["Python Exceptions"], }, } - return reply async def inspectVariables(self, message): """Handle an insepct variables message.""" @@ -665,7 +660,7 @@ async def richInspectVariables(self, message): } ) if reply["success"]: - repr_data, repr_metadata = eval(reply["body"]["result"], {}, {}) # noqa: S307 + repr_data, repr_metadata = eval(reply["body"]["result"], {}, {}) # noqa: PGH001 body = { "data": repr_data, @@ -708,8 +703,7 @@ async def modules(self, message): if filename and filename.endswith(".py"): mods.append({"id": i, "name": module.__name__, "path": filename}) - reply = {"body": {"modules": mods, "totalModules": len(modules)}} - return reply + return {"body": {"modules": mods, "totalModules": len(modules)}} async def process_request(self, message): """Process a request.""" diff --git a/ipykernel/eventloops.py b/ipykernel/eventloops.py index bf1e3d0d6..401aebd3e 100644 --- a/ipykernel/eventloops.py +++ b/ipykernel/eventloops.py @@ -9,7 +9,7 @@ from functools import partial import zmq -from packaging.version import Version as V # noqa +from packaging.version import Version as V from traitlets.config.application import Application @@ -52,7 +52,7 @@ def decorator(func): for name in toolkitnames: loop_map[name] = func - func.exit_hook = lambda kernel: None + func.exit_hook = lambda kernel: None # noqa: ARG005 def exit_decorator(exit_func): """@func.exit is now a decorator @@ -484,24 +484,24 @@ def set_qt_api_env_from_gui(gui): else: if gui == "qt5": try: - import PyQt5 # noqa + import PyQt5 os.environ["QT_API"] = "pyqt5" except ImportError: try: - import PySide2 # noqa + import PySide2 os.environ["QT_API"] = "pyside2" except ImportError: os.environ["QT_API"] = "pyqt5" elif gui == "qt6": try: - import PyQt6 # noqa + import PyQt6 os.environ["QT_API"] = "pyqt6" except ImportError: try: - import PySide6 # noqa + import PySide6 os.environ["QT_API"] = "pyside6" except ImportError: @@ -516,7 +516,7 @@ def set_qt_api_env_from_gui(gui): # Do the actual import now that the environment variable is set to make sure it works. try: - from IPython.external.qt_for_kernel import QtCore, QtGui # noqa + from IPython.external.qt_for_kernel import QtCore, QtGui except Exception as e: # Clear the environment variable for the next attempt. if "QT_API" in os.environ: diff --git a/ipykernel/gui/gtk3embed.py b/ipykernel/gui/gtk3embed.py index baf8c5ee9..f270b5dd0 100644 --- a/ipykernel/gui/gtk3embed.py +++ b/ipykernel/gui/gtk3embed.py @@ -91,7 +91,6 @@ def _hijack_gtk(self): def dummy(*args, **kw): """No-op.""" - pass # save and trap main and main_quit from gtk orig_main, Gtk.main = Gtk.main, dummy diff --git a/ipykernel/gui/gtkembed.py b/ipykernel/gui/gtkembed.py index ac23afc71..f6b8bf5bb 100644 --- a/ipykernel/gui/gtkembed.py +++ b/ipykernel/gui/gtkembed.py @@ -88,7 +88,6 @@ def _hijack_gtk(self): def dummy(*args, **kw): """No-op.""" - pass # save and trap main and main_quit from gtk orig_main, gtk.main = gtk.main, dummy diff --git a/ipykernel/heartbeat.py b/ipykernel/heartbeat.py index 33beaad66..d2890f672 100644 --- a/ipykernel/heartbeat.py +++ b/ipykernel/heartbeat.py @@ -13,8 +13,8 @@ # ----------------------------------------------------------------------------- import errno -import os import socket +from pathlib import Path from threading import Thread import zmq @@ -54,7 +54,7 @@ def pick_port(self): s.close() elif self.transport == "ipc": self.port = 1 - while os.path.exists(f"{self.ip}-{self.port}"): + while Path(f"{self.ip}-{self.port}").exists(): self.port = self.port + 1 else: raise ValueError("Unrecognized zmq transport: %s" % self.transport) @@ -108,7 +108,7 @@ def run(self): if e.errno == errno.EINTR: # signal interrupt, resume heartbeat continue - elif e.errno == zmq.ETERM: + if e.errno == zmq.ETERM: # context terminated, close socket and exit try: self.socket.close() @@ -117,10 +117,9 @@ def run(self): # this shouldn't happen, though pass break - elif e.errno == zmq.ENOTSOCK: + if e.errno == zmq.ENOTSOCK: # socket closed elsewhere, exit break - else: - raise + raise else: break diff --git a/ipykernel/inprocess/__init__.py b/ipykernel/inprocess/__init__.py index 5d5147172..b10698910 100644 --- a/ipykernel/inprocess/__init__.py +++ b/ipykernel/inprocess/__init__.py @@ -1,4 +1,4 @@ -from .blocking import BlockingInProcessKernelClient # noqa -from .channels import InProcessChannel, InProcessHBChannel # noqa -from .client import InProcessKernelClient # noqa -from .manager import InProcessKernelManager # noqa +from .blocking import BlockingInProcessKernelClient +from .channels import InProcessChannel, InProcessHBChannel +from .client import InProcessKernelClient +from .manager import InProcessKernelManager diff --git a/ipykernel/inprocess/channels.py b/ipykernel/inprocess/channels.py index d3f03fcfd..378416dcc 100644 --- a/ipykernel/inprocess/channels.py +++ b/ipykernel/inprocess/channels.py @@ -45,7 +45,6 @@ def call_handlers(self, msg): def flush(self, timeout=1.0): """Flush the channel.""" - pass def call_handlers_later(self, *args, **kwds): """Call the message handlers later. diff --git a/ipykernel/inprocess/ipkernel.py b/ipykernel/inprocess/ipkernel.py index cbbe85278..873b96d20 100644 --- a/ipykernel/inprocess/ipkernel.py +++ b/ipykernel/inprocess/ipkernel.py @@ -87,11 +87,9 @@ def start(self): def _abort_queues(self): """The in-process kernel doesn't abort requests.""" - pass async def _flush_control_queue(self): """No need to flush control queues for in-process""" - pass def _input_request(self, prompt, ident, parent, password=False): # Flush output before making the request. diff --git a/ipykernel/inprocess/socket.py b/ipykernel/inprocess/socket.py index 7e48789e9..2df72b5e1 100644 --- a/ipykernel/inprocess/socket.py +++ b/ipykernel/inprocess/socket.py @@ -39,4 +39,3 @@ def send_multipart(self, msg_parts, flags=0, copy=True, track=False): def flush(self, timeout=1.0): """no-op to comply with stream API""" - pass diff --git a/ipykernel/iostream.py b/ipykernel/iostream.py index 3588e5884..0bbdbe275 100644 --- a/ipykernel/iostream.py +++ b/ipykernel/iostream.py @@ -216,8 +216,7 @@ def _check_mp_mode(self): """check for forks, and switch to zmq pipeline if necessary""" if not self._pipe_flag or self._is_master_process(): return MASTER - else: - return CHILD + return CHILD def start(self): """Start the IOPub thread""" @@ -319,7 +318,7 @@ def __getattr__(self, attr): stacklevel=2, ) return getattr(self.io_thread.socket, attr) - super().__getattr__(attr) # type:ignore[misc] + return super().__getattr__(attr) # type:ignore[misc] def __setattr__(self, attr, value): """Set an attribute on the socket.""" @@ -367,9 +366,8 @@ def fileno(self): """ if getattr(self, "_original_stdstream_copy", None) is not None: return self._original_stdstream_copy - else: - msg = "fileno" - raise io.UnsupportedOperation(msg) + msg = "fileno" + raise io.UnsupportedOperation(msg) def _watch_pipe_fd(self): """ @@ -647,21 +645,21 @@ def write(self, string: str) -> Optional[int]: # type:ignore[override] if self.pub_thread is None: msg = "I/O operation on closed file" raise ValueError(msg) + + is_child = not self._is_master_process() + # only touch the buffer in the IO thread to avoid races + with self._buffer_lock: + self._buffer.write(string) + if is_child: + # mp.Pool cannot be trusted to flush promptly (or ever), + # and this helps. + if self._subprocess_flush_pending: + return None + self._subprocess_flush_pending = True + # We can not rely on self._io_loop.call_later from a subprocess + self.pub_thread.schedule(self._flush) else: - is_child = not self._is_master_process() - # only touch the buffer in the IO thread to avoid races - with self._buffer_lock: - self._buffer.write(string) - if is_child: - # mp.Pool cannot be trusted to flush promptly (or ever), - # and this helps. - if self._subprocess_flush_pending: - return None - self._subprocess_flush_pending = True - # We can not rely on self._io_loop.call_later from a subprocess - self.pub_thread.schedule(self._flush) - else: - self._schedule_flush() + self._schedule_flush() return len(string) @@ -670,9 +668,8 @@ def writelines(self, sequence): if self.pub_thread is None: msg = "I/O operation on closed file" raise ValueError(msg) - else: - for string in sequence: - self.write(string) + for string in sequence: + self.write(string) def writable(self): """Test whether the stream is writable.""" diff --git a/ipykernel/ipkernel.py b/ipykernel/ipkernel.py index 6e358c7d1..e32f06e1f 100644 --- a/ipykernel/ipkernel.py +++ b/ipykernel/ipkernel.py @@ -55,7 +55,7 @@ def _create_comm(*args, **kwargs): def _get_comm_manager(*args, **kwargs): """Create a new CommManager.""" - global _comm_manager # noqa + global _comm_manager # noqa: PLW0603 if _comm_manager is None: with _comm_lock: if _comm_manager is None: @@ -208,6 +208,7 @@ def dispatch_debugpy(self, msg): def banner(self): if self.shell: return self.shell.banner + return None async def poll_stopped_queue(self): """Poll the stopped queue.""" @@ -288,6 +289,7 @@ def _restore_input(self): def execution_count(self): if self.shell: return self.shell.execution_count + return None @execution_count.setter def execution_count(self, value): @@ -361,7 +363,7 @@ async def do_execute( should_run_async = shell.should_run_async with_cell_id = _accepts_cell_id(run_cell) else: - should_run_async = lambda cell: False # noqa + should_run_async = lambda cell: False # noqa: ARG005 # older IPython, # use blocking run_cell and wrap it in coroutine @@ -506,6 +508,7 @@ async def do_debug_request(self, msg): """Handle a debug request.""" if _is_debugpy_available: return await self.debugger.process_request(msg) + return None def _experimental_do_complete(self, code, cursor_pos): """ @@ -657,7 +660,7 @@ def do_apply(self, content, bufs, msg_id, reply_metadata): working.update(ns) code = f"{resultname} = {fname}(*{argname},**{kwargname})" try: - exec(code, shell.user_global_ns, shell.user_ns) # noqa + exec(code, shell.user_global_ns, shell.user_ns) result = working.get(resultname) finally: for key in ns: diff --git a/ipykernel/jsonutil.py b/ipykernel/jsonutil.py index 629dfc045..6a463cf1b 100644 --- a/ipykernel/jsonutil.py +++ b/ipykernel/jsonutil.py @@ -26,7 +26,7 @@ # holy crap, strptime is not threadsafe. # Calling it once at import seems to help. -datetime.strptime("1", "%d") # noqa +datetime.strptime("1", "%d") # ----------------------------------------------------------------------------- # Classes and functions diff --git a/ipykernel/kernelapp.py b/ipykernel/kernelapp.py index 5bfcccbf5..69dfa8565 100644 --- a/ipykernel/kernelapp.py +++ b/ipykernel/kernelapp.py @@ -15,6 +15,7 @@ from functools import partial from io import FileIO, TextIOWrapper from logging import StreamHandler +from pathlib import Path import zmq from IPython.core.application import ( # type:ignore[attr-defined] @@ -161,10 +162,9 @@ def _default_connection_dir(self): @property def abs_connection_file(self): - if os.path.basename(self.connection_file) == self.connection_file: - return os.path.join(self.connection_dir, self.connection_file) - else: - return self.connection_file + if Path(self.connection_file).name == self.connection_file and self.connection_dir: + return str(Path(str(self.connection_dir)) / self.connection_file) + return self.connection_file # streams, etc. no_stdout = Bool(False, help="redirect stdout to the null device").tag(config=True) @@ -231,7 +231,7 @@ def _try_bind_socket(self, s, port): if port <= 0: port = 1 path = "%s-%i" % (self.ip, port) - while os.path.exists(path): + while Path(path).exists(): port = port + 1 path = "%s-%i" % (self.ip, port) else: @@ -257,6 +257,7 @@ def _bind_socket(self, s, port): raise if attempt == max_attempts - 1: raise + return None def write_connection_file(self): """write connection info to JSON file""" @@ -271,7 +272,7 @@ def write_connection_file(self): iopub_port=self.iopub_port, control_port=self.control_port, ) - if os.path.exists(cf): + if Path(cf).exists(): # If the file exists, merge our info into it. For example, if the # original file had port number 0, we update with the actual port # used. @@ -291,7 +292,7 @@ def cleanup_connection_file(self): cf = self.abs_connection_file self.log.debug("Cleaning up connection file: %s", cf) try: - os.remove(cf) + Path(cf).unlink() except OSError: pass @@ -306,14 +307,14 @@ def init_connection_file(self): except OSError: self.log.debug("Connection file not found: %s", self.connection_file) # This means I own it, and I'll create it in this directory: - os.makedirs(os.path.dirname(self.abs_connection_file), mode=0o700, exist_ok=True) + Path(self.abs_connection_file).parent.mkdir(mode=0o700, exist_ok=True, parents=True) # Also, I will clean it up: atexit.register(self.cleanup_connection_file) return try: self.load_connection_file() except Exception: - self.log.error( + self.log.error( # noqa: G201 "Failed to load connection file: %r", self.connection_file, exc_info=True ) self.exit(1) @@ -423,10 +424,10 @@ def close(self): def log_connection_info(self): """display connection info, and store ports""" - basename = os.path.basename(self.connection_file) + basename = Path(self.connection_file).name if ( basename == self.connection_file - or os.path.dirname(self.connection_file) == self.connection_dir + or Path(self.connection_file).parent == self.connection_dir ): # use shortname tail = basename @@ -460,7 +461,7 @@ def log_connection_info(self): def init_blackhole(self): """redirects stdout/stderr to devnull if necessary""" if self.no_stdout or self.no_stderr: - blackhole = open(os.devnull, "w") # noqa + blackhole = open(os.devnull, "w") # noqa: SIM115 if self.no_stdout: sys.stdout = sys.__stdout__ = blackhole # type:ignore[misc] if self.no_stderr: @@ -666,7 +667,7 @@ def init_pdb(self): With the non-interruptible version, stopping pdb() locks up the kernel in a non-recoverable state. """ - import pdb # noqa + import pdb from IPython.core import debugger @@ -702,7 +703,7 @@ def initialize(self, argv=None): # Catch exception when initializing signal fails, eg when running the # kernel on a separate thread if int(self.log_level) < logging.CRITICAL: # type:ignore[call-overload] - self.log.error("Unable to initialize signal:", exc_info=True) + self.log.error("Unable to initialize signal:", exc_info=True) # noqa: G201 self.init_kernel() # shell init steps self.init_path() diff --git a/ipykernel/kernelbase.py b/ipykernel/kernelbase.py index 79ecddb3f..319c69939 100644 --- a/ipykernel/kernelbase.py +++ b/ipykernel/kernelbase.py @@ -115,8 +115,7 @@ def _shell_streams_default(self): # pragma: no cover ) if self.shell_stream is not None: return [self.shell_stream] - else: - return [] + return [] @observe("shell_streams") def _shell_streams_changed(self, change): # pragma: no cover @@ -322,7 +321,7 @@ async def process_control(self, msg): try: msg = self.session.deserialize(msg, content=True, copy=False) except Exception: - self.log.error("Invalid Control Message", exc_info=True) + self.log.error("Invalid Control Message", exc_info=True) # noqa: G201 return self.log.debug("Control received: %s", msg) @@ -343,7 +342,7 @@ async def process_control(self, msg): if inspect.isawaitable(result): await result except Exception: - self.log.error("Exception in control handler:", exc_info=True) + self.log.error("Exception in control handler:", exc_info=True) # noqa: G201 sys.stdout.flush() sys.stderr.flush() @@ -376,7 +375,7 @@ async def dispatch_shell(self, msg): try: msg = self.session.deserialize(msg, content=True, copy=False) except Exception: - self.log.error("Invalid Message", exc_info=True) + self.log.error("Invalid Message", exc_info=True) # noqa: G201 return # Set the parent message for side effects. @@ -418,7 +417,7 @@ async def dispatch_shell(self, msg): if inspect.isawaitable(result): await result except Exception: - self.log.error("Exception in message handler:", exc_info=True) + self.log.error("Exception in message handler:", exc_info=True) # noqa: G201 except KeyboardInterrupt: # Ctrl-c shouldn't crash the kernel here. self.log.error("KeyboardInterrupt caught in kernel.") @@ -470,7 +469,6 @@ def advance_eventloop(): except KeyboardInterrupt: # Ctrl-C shouldn't crash the kernel self.log.error("KeyboardInterrupt caught in kernel") - pass if self.eventloop is eventloop: # schedule advance again schedule_next() @@ -510,7 +508,7 @@ async def process_one(self, wait=True): try: t, dispatch, args = self.msg_queue.get_nowait() except (asyncio.QueueEmpty, QueueEmpty): - return None + return await dispatch(*args) async def dispatch_queue(self): @@ -678,7 +676,7 @@ def send_response( message. """ if not self.session: - return + return None return self.session.send( stream, msg_or_type, @@ -1027,8 +1025,8 @@ def get_process_metric_value(self, process, name, attribute=None): metric_value = getattr(process, name)() if attribute is not None: # ... a named tuple return getattr(metric_value, attribute) - else: # ... or a number - return metric_value + # ... or a number + return metric_value # Avoid littering logs with stack traces # complaining about dead processes except BaseException: @@ -1085,7 +1083,7 @@ async def apply_request(self, stream, ident, parent): # pragma: no cover bufs = parent["buffers"] msg_id = parent["header"]["msg_id"] except Exception: - self.log.error("Got bad msg: %s", parent, exc_info=True) + self.log.error("Got bad msg: %s", parent, exc_info=True) # noqa: G201 return md = self.init_metadata(parent) @@ -1193,7 +1191,7 @@ def _send_abort_reply(self, stream, msg, idents): """Send a reply to an aborted request""" if not self.session: return - self.log.info(f"Aborting {msg['header']['msg_id']}: {msg['header']['msg_type']}") + self.log.info("Aborting %s: %s", msg["header"]["msg_id"], msg["header"]["msg_type"]) reply_type = msg["header"]["msg_type"].rsplit("_", 1)[0] + "_reply" status = {"status": "aborted"} md = self.init_metadata(msg) @@ -1269,8 +1267,7 @@ def _input_request(self, prompt, ident, parent, password=False): except zmq.ZMQError as e: if e.errno == zmq.EAGAIN: break - else: - raise + raise # Send the input request. assert self.session is not None @@ -1315,8 +1312,9 @@ def _signal_children(self, signum): Like `killpg`, but does not include the current process (or possible parents). """ + sig_rep = f"{Signals(signum)!r}" for p in self._process_children(): - self.log.debug(f"Sending {Signals(signum)!r} to subprocess {p}") + self.log.debug("Sending %s to subprocess %s", sig_rep, p) try: if signum == SIGTERM: p.terminate() @@ -1365,7 +1363,9 @@ async def _progressively_terminate_all_children(self): # signals only children, not current process self._signal_children(signum) self.log.debug( - f"Will sleep {delay}s before checking for children and retrying. {children}" + "Will sleep %s sec before checking for children and retrying. %s", + delay, + children, ) await asyncio.sleep(delay) diff --git a/ipykernel/kernelspec.py b/ipykernel/kernelspec.py index 414b1d951..70253c15c 100644 --- a/ipykernel/kernelspec.py +++ b/ipykernel/kernelspec.py @@ -12,6 +12,7 @@ import stat import sys import tempfile +from pathlib import Path from typing import Any from jupyter_client.kernelspec import KernelSpecManager @@ -27,7 +28,7 @@ KERNEL_NAME = "python%i" % sys.version_info[0] # path to kernelspec resources -RESOURCES = pjoin(os.path.dirname(__file__), "resources") +RESOURCES = pjoin(Path(__file__).parent, "resources") def make_ipkernel_cmd( @@ -70,7 +71,7 @@ def get_kernel_dict(extra_arguments: list[str] | None = None) -> dict[str, Any]: def write_kernel_spec( - path: str | None = None, + path: Path | str | None = None, overrides: dict[str, Any] | None = None, extra_arguments: list[str] | None = None, ) -> str: @@ -82,15 +83,15 @@ def write_kernel_spec( The path to the kernelspec is always returned. """ if path is None: - path = os.path.join(tempfile.mkdtemp(suffix="_kernels"), KERNEL_NAME) + path = Path(tempfile.mkdtemp(suffix="_kernels")) / KERNEL_NAME # stage resources shutil.copytree(RESOURCES, path) # ensure path is writable - mask = os.stat(path).st_mode + mask = Path(path).stat().st_mode if not mask & stat.S_IWUSR: - os.chmod(path, mask | stat.S_IWUSR) + Path(path).chmod(mask | stat.S_IWUSR) # write kernel.json kernel_dict = get_kernel_dict(extra_arguments) @@ -100,7 +101,7 @@ def write_kernel_spec( with open(pjoin(path, "kernel.json"), "w") as f: json.dump(kernel_dict, f, indent=1) - return path + return str(path) def install( diff --git a/ipykernel/log.py b/ipykernel/log.py index d55c21d04..bbd4c445b 100644 --- a/ipykernel/log.py +++ b/ipykernel/log.py @@ -26,5 +26,4 @@ def root_topic(self): before the engine gets registered with an id""" if isinstance(getattr(self.engine, "id", None), int): return "engine.%i" % self.engine.id # type:ignore[union-attr] - else: - return "engine" + return "engine" diff --git a/ipykernel/pickleutil.py b/ipykernel/pickleutil.py index c6b71096e..3cfb74a50 100644 --- a/ipykernel/pickleutil.py +++ b/ipykernel/pickleutil.py @@ -17,7 +17,7 @@ from types import FunctionType # This registers a hook when it's imported -from ipyparallel.serialize import codeutil # noqa F401 +from ipyparallel.serialize import codeutil from traitlets.log import get_logger from traitlets.utils.importstring import import_item @@ -77,7 +77,7 @@ def use_dill(): # dill doesn't work with cPickle, # tell the two relevant modules to use plain pickle - global pickle # noqa + global pickle # noqa: PLW0603 pickle = dill try: @@ -98,7 +98,7 @@ def use_cloudpickle(): """ import cloudpickle - global pickle # noqa + global pickle # noqa: PLW0603 pickle = cloudpickle try: @@ -179,7 +179,7 @@ def get_object(self, g=None): if g is None: g = {} - return eval(self.name, g) # noqa: S307 + return eval(self.name, g) # noqa: PGH001 class CannedCell(CannedObject): @@ -238,8 +238,7 @@ def get_object(self, g=None): g = {} defaults = tuple(uncan(cfd, g) for cfd in self.defaults) if self.defaults else None closure = tuple(uncan(cell, g) for cell in self.closure) if self.closure else None - newFunc = FunctionType(self.code, g, self.__name__, defaults, closure) - return newFunc + return FunctionType(self.code, g, self.__name__, defaults, closure) class CannedClass(CannedObject): @@ -300,9 +299,8 @@ def get_object(self, g=None): data = self.buffers[0] if self.pickled: # we just pickled it - return pickle.loads(data) # noqa - else: - return frombuffer(data, dtype=self.dtype).reshape(self.shape) + return pickle.loads(data) + return frombuffer(data, dtype=self.dtype).reshape(self.shape) class CannedBytes(CannedObject): @@ -355,7 +353,7 @@ def _import_mapping(mapping, original=None): except Exception: if original and key not in original: # only message on user-added classes - log.error("canning class not importable: %r", key, exc_info=True) + log.error("canning class not importable: %r", key, exc_info=True) # noqa: G201 mapping.pop(key) else: mapping[cls] = mapping.pop(key) @@ -368,8 +366,7 @@ def istype(obj, check): """ if isinstance(check, tuple): return any(type(obj) is cls for cls in check) - else: - return type(obj) is check + return type(obj) is check def can(obj): @@ -381,7 +378,7 @@ def can(obj): if isinstance(cls, str): import_needed = True break - elif istype(obj, cls): + if istype(obj, cls): return canner(obj) if import_needed: @@ -397,8 +394,7 @@ def can_class(obj): """Can a class object.""" if isinstance(obj, class_type) and obj.__module__ == "__main__": return CannedClass(obj) - else: - return obj + return obj def can_dict(obj): @@ -408,8 +404,7 @@ def can_dict(obj): for k, v in obj.items(): newobj[k] = can(v) return newobj - else: - return obj + return obj sequence_types = (list, tuple, set) @@ -420,8 +415,7 @@ def can_sequence(obj): if istype(obj, sequence_types): t = type(obj) return t([can(i) for i in obj]) - else: - return obj + return obj def uncan(obj, g=None): @@ -432,7 +426,7 @@ def uncan(obj, g=None): if isinstance(cls, str): import_needed = True break - elif isinstance(obj, cls): + if isinstance(obj, cls): return uncanner(obj, g) if import_needed: @@ -451,8 +445,7 @@ def uncan_dict(obj, g=None): for k, v in obj.items(): newobj[k] = uncan(v, g) return newobj - else: - return obj + return obj def uncan_sequence(obj, g=None): @@ -460,8 +453,7 @@ def uncan_sequence(obj, g=None): if istype(obj, sequence_types): t = type(obj) return t([uncan(i, g) for i in obj]) - else: - return obj + return obj # ------------------------------------------------------------------------------- diff --git a/ipykernel/pylab/backend_inline.py b/ipykernel/pylab/backend_inline.py index cc389ccae..cbc253064 100644 --- a/ipykernel/pylab/backend_inline.py +++ b/ipykernel/pylab/backend_inline.py @@ -5,7 +5,7 @@ import warnings -from matplotlib_inline.backend_inline import * # type:ignore[import-untyped] # analysis: ignore # noqa F401 +from matplotlib_inline.backend_inline import * # type:ignore[import-untyped] # analysis: ignore warnings.warn( "`ipykernel.pylab.backend_inline` is deprecated, directly " diff --git a/ipykernel/pylab/config.py b/ipykernel/pylab/config.py index afd44d19d..f32787283 100644 --- a/ipykernel/pylab/config.py +++ b/ipykernel/pylab/config.py @@ -5,7 +5,7 @@ import warnings -from matplotlib_inline.config import * # type:ignore[import-untyped] # analysis: ignore # noqa F401 +from matplotlib_inline.config import * # type:ignore[import-untyped] # analysis: ignore warnings.warn( "`ipykernel.pylab.config` is deprecated, directly use `matplotlib_inline.config`", diff --git a/ipykernel/serialize.py b/ipykernel/serialize.py index 12e5b9a99..616410c81 100644 --- a/ipykernel/serialize.py +++ b/ipykernel/serialize.py @@ -122,7 +122,7 @@ def deserialize_object(buffers, g=None): """ bufs = list(buffers) pobj = bufs.pop(0) - canned = pickle.loads(pobj) # noqa + canned = pickle.loads(pobj) if istype(canned, sequence_types) and len(canned) < MAX_ITEMS: for c in canned: _restore_buffers(c, bufs) @@ -183,9 +183,9 @@ def unpack_apply_message(bufs, g=None, copy=True): bufs = list(bufs) # allow us to pop assert len(bufs) >= 2, "not enough buffers!" pf = bufs.pop(0) - f = uncan(pickle.loads(pf), g) # noqa + f = uncan(pickle.loads(pf), g) pinfo = bufs.pop(0) - info = pickle.loads(pinfo) # noqa + info = pickle.loads(pinfo) arg_bufs, kwarg_bufs = bufs[: info["narg_bufs"]], bufs[info["narg_bufs"] :] args_list = [] diff --git a/ipykernel/trio_runner.py b/ipykernel/trio_runner.py index 977302a8a..45f738acb 100644 --- a/ipykernel/trio_runner.py +++ b/ipykernel/trio_runner.py @@ -66,5 +66,6 @@ async def loc(coro): with self._cell_cancel_scope: return await coro self._cell_cancel_scope = None # type:ignore[unreachable] + return None return trio.from_thread.run(loc, async_fn, trio_token=self._trio_token) diff --git a/ipykernel/zmqshell.py b/ipykernel/zmqshell.py index d381a5c98..44df9c342 100644 --- a/ipykernel/zmqshell.py +++ b/ipykernel/zmqshell.py @@ -17,6 +17,7 @@ import os import sys import warnings +from pathlib import Path from threading import local from IPython.core import page, payloadpage @@ -301,7 +302,7 @@ def edit(self, parameter_s="", last_call=None): # Make sure we send to the client an absolute path, in case the working # directory of client and kernel don't match - filename = os.path.abspath(filename) + filename = Path(filename).resolve() payload = {"source": "edit_magic", "filename": filename, "line_number": lineno} assert self.shell is not None @@ -375,8 +376,8 @@ def connect_info(self, arg_s): return # if it's in the default dir, truncate to basename - if jupyter_runtime_dir() == os.path.dirname(connection_file): - connection_file = os.path.basename(connection_file) + if jupyter_runtime_dir() == Path(connection_file).parent: + connection_file = Path(connection_file).name assert isinstance(info, str) print(info + "\n") @@ -514,7 +515,6 @@ def init_hooks(self): def init_data_pub(self): """Delay datapub init until request, for deprecation warnings""" - pass @property def data_pub(self): @@ -620,7 +620,6 @@ def init_virtualenv(self): # not appropriate in a kernel. To use a kernel in a virtualenv, install # it inside the virtualenv. # https://ipython.readthedocs.io/en/latest/install/kernel_install.html - pass def system_piped(self, cmd): """Call the given cmd in a subprocess, piping stdout/err diff --git a/pyproject.toml b/pyproject.toml index 1e5c71a88..dec3ae13a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -132,7 +132,6 @@ disable_error_code = ["no-untyped-def", "no-untyped-call", "import-not-found"] enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] follow_imports = "normal" pretty = true -show_error_codes = true warn_unreachable = true [tool.pytest.ini_options] @@ -212,69 +211,55 @@ line-length = 100 [tool.ruff.lint] select = [ - "A", - "B", - "C", - "DTZ", - "E", - "EM", - "F", - "FBT", - "I", - "ICN", - "N", - "PLC", - "PLE", - "PLW", - "Q", - "RUF", - "S", - "SIM", - "T", - "TID", - "UP", - "W", - "YTT", + "B", # flake8-bugbear + "I", # isort + "ARG", # flake8-unused-arguments + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "T20", # flake8-print + "UP", # pyupgrade + "YTT", # flake8-2020 + "EXE", # flake8-executable + "NPY", # NumPy specific rules + "PD", # pandas-vet + "PYI", # flake8-pyi ] ignore = [ + "PLR", # Design related pylint codes # 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 - "TID252", - # 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", - # T201 `print` found + # `print` found "T201", - # N802 Function name `CreateWellKnownSid` should be lowercase - "N802", "N803", - # C408 Unnecessary `dict` call (rewrite as a literal) + # Unnecessary `dict` call (rewrite as a literal) "C408", - # N801 Class name `directional_link` should use CapWords convention - "N801", - # SIM105 Use `contextlib.suppress(ValueError)` instead of try-except-pass + # Use `contextlib.suppress(ValueError)` instead of try-except-pass "SIM105", - # S110 `try`-`except`-`pass` detected + # `try`-`except`-`pass` detected "S110", - # RUF012 Mutable class attributes should be annotated with `typing.ClassVar` + # Mutable class attributes should be annotated with `typing.ClassVar` "RUF012", + # Unused function argument: + "ARG001", + # Unused method argument: + "ARG002", + # Logging statement uses `%` + "G002", + # `open()` should be replaced by `Path.open()` + "PTH123", ] unfixable = [ # Don't touch print statements @@ -285,22 +270,14 @@ unfixable = [ [tool.ruff.lint.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 -# F841 Local variable `t` is assigned to but never used -# EM101 Exception must not use a string literal, assign to variable first -# PLR2004 Magic value used in comparison # PLW0603 Using the global statement to update ... -# PLW2901 `for` loop variable ... # PLC1901 `stderr == ""` can be simplified to `not stderr` as an empty string is falsey # B018 Found useless expression. Either assign it to a variable or remove it. # S603 `subprocess` call: check for execution of untrusted input -"tests/*" = ["B011", "F841", "C408", "E402", "T201", "B007", "N802", "F841", "EM101", - "EM102", "EM103", "PLR2004", "PLW0603", "PLW2901", "PLC1901", "B018", "S603"] +"tests/*" = ["B011", "C408", "T201", "B007", "EM", "PTH", "PLW", "PLC1901", "B018", "S603", "ARG", "RET", "PGH"] [tool.interrogate] ignore-init-module=true diff --git a/tests/conftest.py b/tests/conftest.py index 00f8394f6..5c2d364f5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -143,7 +143,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) -@pytest.fixture +@pytest.fixture() async def kernel(): kernel = MockKernel() kernel.io_loop = IOLoop.current() @@ -151,7 +151,7 @@ async def kernel(): kernel.destroy() -@pytest.fixture +@pytest.fixture() async def ipkernel(): kernel = MockIPyKernel() kernel.io_loop = IOLoop.current() diff --git a/tests/inprocess/test_kernel.py b/tests/inprocess/test_kernel.py index 793485d95..33692e85f 100644 --- a/tests/inprocess/test_kernel.py +++ b/tests/inprocess/test_kernel.py @@ -45,7 +45,7 @@ def kc(): kc = km.client() kc.start_channels() kc.wait_for_ready() - yield kc + return kc def test_with_cell_id(kc): diff --git a/tests/inprocess/test_kernelmanager.py b/tests/inprocess/test_kernelmanager.py index 2b6d5faa0..c3bb5be2a 100644 --- a/tests/inprocess/test_kernelmanager.py +++ b/tests/inprocess/test_kernelmanager.py @@ -3,6 +3,7 @@ import unittest +import pytest from flaky import flaky from ipykernel.inprocess.manager import InProcessKernelManager @@ -38,14 +39,17 @@ def test_interface(self): old_kernel = km.kernel km.restart_kernel() - self.assertIsNotNone(km.kernel) + assert km.kernel is None assert km.kernel != old_kernel km.shutdown_kernel() assert not km.has_kernel - self.assertRaises(NotImplementedError, km.interrupt_kernel) - self.assertRaises(NotImplementedError, km.signal_kernel, 9) + with pytest.raises(NotImplementedError): + km.interrupt_kernel() + + with pytest.raises(NotImplementedError): + km.signal_kernel(9) kc.stop_channels() assert not kc.channels_running @@ -71,7 +75,7 @@ def test_complete(self): kc.complete("my_ba", 5) msg = kc.get_shell_msg() assert msg["header"]["msg_type"] == "complete_reply" - self.assertEqual(sorted(msg["content"]["matches"]), ["my_bar", "my_baz"]) + assert sorted(msg["content"]["matches"]) == ["my_bar", "my_baz"] def test_inspect(self): """Does requesting object information from an in-process kernel work?""" @@ -87,7 +91,7 @@ def test_inspect(self): content = msg["content"] assert content["found"] text = content["data"]["text/plain"] - self.assertIn("int", text) + assert "int" in text def test_history(self): """Does requesting history from an in-process kernel work?""" diff --git a/tests/test_debugger.py b/tests/test_debugger.py index 48fafb42e..262f102de 100644 --- a/tests/test_debugger.py +++ b/tests/test_debugger.py @@ -32,13 +32,13 @@ def wait_for_debug_request(kernel, command, arguments=None, full_reply=False): return reply if full_reply else reply["content"] -@pytest.fixture +@pytest.fixture() def kernel(): with new_kernel() as kc: yield kc -@pytest.fixture +@pytest.fixture() def kernel_with_debug(kernel): # Initialize wait_for_debug_request( @@ -386,4 +386,4 @@ def my_test(): assert global_var is not None # Compare local and global variable - assert global_var["value"] == local_var["value"] and global_var["type"] == local_var["type"] + assert global_var["value"] == local_var["value"] and global_var["type"] == local_var["type"] # noqa: PT018 diff --git a/tests/test_io.py b/tests/test_io.py index a7691ee5c..0e23b4b14 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -17,14 +17,14 @@ from ipykernel.iostream import MASTER, BackgroundSocket, IOPubThread, OutStream -@pytest.fixture +@pytest.fixture() def ctx(): ctx = zmq.Context() yield ctx ctx.destroy() -@pytest.fixture +@pytest.fixture() def iopub_thread(ctx): with ctx.socket(zmq.PUB) as pub: thread = IOPubThread(pub) diff --git a/tests/test_jsonutil.py b/tests/test_jsonutil.py index 2f7e5dbcd..2c6b95372 100644 --- a/tests/test_jsonutil.py +++ b/tests/test_jsonutil.py @@ -53,7 +53,7 @@ def test(): # More exotic objects ((x for x in range(3)), [0, 1, 2]), (iter([1, 2]), [1, 2]), - (datetime(1991, 7, 3, 12, 00), "1991-07-03T12:00:00.000000"), # noqa + (datetime(1991, 7, 3, 12, 00), "1991-07-03T12:00:00.000000"), (date(1991, 7, 3), "1991-07-03T00:00:00.000000"), (MyFloat(), 3.14), (MyInt(), 389), @@ -98,7 +98,7 @@ def test_encode_images(): @pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op") def test_lambda(): - with pytest.raises(ValueError): + with pytest.raises(ValueError): # noqa: PT011 json_clean(lambda: 1) @@ -109,7 +109,7 @@ def test_exception(): {True: "bool", "True": "string"}, ] for d in bad_dicts: - with pytest.raises(ValueError): + with pytest.raises(ValueError): # noqa: PT011 json_clean(d) diff --git a/tests/test_message_spec.py b/tests/test_message_spec.py index 0c9e777cd..db6ea7d7f 100644 --- a/tests/test_message_spec.py +++ b/tests/test_message_spec.py @@ -10,7 +10,7 @@ import pytest from jupyter_client._version import version_info from jupyter_client.blocking.client import BlockingKernelClient -from packaging.version import Version as V # noqa +from packaging.version import Version as V from traitlets import Bool, Dict, Enum, HasTraits, Integer, List, TraitError, Unicode, observe from .utils import TIMEOUT, execute, flush_channels, get_reply, start_global_kernel diff --git a/tests/test_parentpoller.py b/tests/test_parentpoller.py index c40a47204..97cd80440 100644 --- a/tests/test_parentpoller.py +++ b/tests/test_parentpoller.py @@ -11,7 +11,7 @@ @pytest.mark.skipif(os.name == "nt", reason="only works on posix") def test_parent_poller_unix(): poller = ParentPollerUnix() - with mock.patch("os.getppid", lambda: 1): + with mock.patch("os.getppid", lambda: 1): # noqa: PT008 def exit_mock(*args): sys.exit(1) @@ -23,7 +23,7 @@ def mock_getppid(): msg = "hi" raise ValueError(msg) - with mock.patch("os.getppid", mock_getppid), pytest.raises(ValueError): + with mock.patch("os.getppid", mock_getppid), pytest.raises(ValueError): # noqa: PT011 poller.run() diff --git a/tests/test_pickleutil.py b/tests/test_pickleutil.py index 3351d7882..c48eadf77 100644 --- a/tests/test_pickleutil.py +++ b/tests/test_pickleutil.py @@ -16,7 +16,7 @@ def dumps(obj): def loads(obj): - return uncan(pickle.loads(obj)) # noqa + return uncan(pickle.loads(obj)) def test_no_closure(): diff --git a/tests/test_zmq_shell.py b/tests/test_zmq_shell.py index 665139271..57a70f304 100644 --- a/tests/test_zmq_shell.py +++ b/tests/test_zmq_shell.py @@ -198,7 +198,7 @@ def test_unregister_hook(self): first = self.disp_pub.unregister_hook(hook) self.disp_pub.publish(data) - self.assertTrue(first) + assert bool(first) assert hook.call_count == 1 assert self.session.send_count == 1 @@ -207,7 +207,7 @@ def test_unregister_hook(self): # should return false. # second = self.disp_pub.unregister_hook(hook) - self.assertFalse(second) + assert not bool(second) def test_magics(tmp_path): From f5d56eea4284826694af4c696cb3185de043c3c8 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 19 Nov 2023 07:51:57 -0600 Subject: [PATCH 2/5] fix types --- ipykernel/kernelapp.py | 2 +- ipykernel/zmqshell.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ipykernel/kernelapp.py b/ipykernel/kernelapp.py index 69dfa8565..9cfb55a54 100644 --- a/ipykernel/kernelapp.py +++ b/ipykernel/kernelapp.py @@ -427,7 +427,7 @@ def log_connection_info(self): basename = Path(self.connection_file).name if ( basename == self.connection_file - or Path(self.connection_file).parent == self.connection_dir + or str(Path(self.connection_file).parent) == self.connection_dir ): # use shortname tail = basename diff --git a/ipykernel/zmqshell.py b/ipykernel/zmqshell.py index 44df9c342..21983b504 100644 --- a/ipykernel/zmqshell.py +++ b/ipykernel/zmqshell.py @@ -376,7 +376,7 @@ def connect_info(self, arg_s): return # if it's in the default dir, truncate to basename - if jupyter_runtime_dir() == Path(connection_file).parent: + if jupyter_runtime_dir() == str(Path(connection_file).parent): connection_file = Path(connection_file).name assert isinstance(info, str) From 3c1d2fe73945802f0b3ec4edc6e3af7fbf466b37 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 19 Nov 2023 07:57:21 -0600 Subject: [PATCH 3/5] fix test --- tests/inprocess/test_kernelmanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/inprocess/test_kernelmanager.py b/tests/inprocess/test_kernelmanager.py index c3bb5be2a..d3ee99913 100644 --- a/tests/inprocess/test_kernelmanager.py +++ b/tests/inprocess/test_kernelmanager.py @@ -39,7 +39,7 @@ def test_interface(self): old_kernel = km.kernel km.restart_kernel() - assert km.kernel is None + assert km.kernel is not None assert km.kernel != old_kernel km.shutdown_kernel() From 14a2372ba9a2ad7167bfdd5684287fa631d1231d Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 19 Nov 2023 09:19:40 -0600 Subject: [PATCH 4/5] try removing pytest_asyncio --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index dec3ae13a..ed966da3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,6 @@ test = [ "flaky", "ipyparallel", "pre-commit", - "pytest-asyncio", "pytest-timeout" ] cov = [ From 906851571bba200b3831c6ee6ecb2454f1b5d51d Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 19 Nov 2023 10:06:44 -0600 Subject: [PATCH 5/5] reinstate pytest-asyncio --- pyproject.toml | 1 + tests/conftest.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ed966da3f..dec3ae13a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,7 @@ test = [ "flaky", "ipyparallel", "pre-commit", + "pytest-asyncio", "pytest-timeout" ] cov = [ diff --git a/tests/conftest.py b/tests/conftest.py index 5c2d364f5..7fe026a03 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -144,7 +144,7 @@ def __init__(self, *args, **kwargs): @pytest.fixture() -async def kernel(): +def kernel(): kernel = MockKernel() kernel.io_loop = IOLoop.current() yield kernel @@ -152,7 +152,7 @@ async def kernel(): @pytest.fixture() -async def ipkernel(): +def ipkernel(): kernel = MockIPyKernel() kernel.io_loop = IOLoop.current() yield kernel