diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2b903131f..e010c8b8a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,7 +36,7 @@ repos: - id: black - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.215 + rev: v0.0.236 hooks: - id: ruff args: ["--fix"] diff --git a/ipykernel/compiler.py b/ipykernel/compiler.py index fe5561594..7ba79472f 100644 --- a/ipykernel/compiler.py +++ b/ipykernel/compiler.py @@ -29,7 +29,7 @@ def murmur2_x86(data, seed): val = length & 0x03 k = 0 - if val == 3: + if val == 3: # noqa k = (ord(data[rounded_end + 2]) & 0xFF) << 16 if val in [2, 3]: k |= (ord(data[rounded_end + 1]) & 0xFF) << 8 diff --git a/ipykernel/connect.py b/ipykernel/connect.py index abc1a8211..b933179c5 100644 --- a/ipykernel/connect.py +++ b/ipykernel/connect.py @@ -117,7 +117,7 @@ def connect_qtconsole(connection_file=None, argv=None): kwargs["start_new_session"] = True return Popen( - [sys.executable, "-c", cmd, "--existing", cf] + argv, + [sys.executable, "-c", cmd, "--existing", cf, *argv], stdout=PIPE, stderr=PIPE, close_fds=(sys.platform != "win32"), diff --git a/ipykernel/eventloops.py b/ipykernel/eventloops.py index d7e2a04ee..b5c65dbc1 100644 --- a/ipykernel/eventloops.py +++ b/ipykernel/eventloops.py @@ -465,10 +465,9 @@ def set_qt_api_env_from_gui(gui): QT_API_PYSIDE6: 'qt6', QT_API_PYQT6: 'qt6', } - if loaded is not None and gui != 'qt': - if qt_env2gui[loaded] != gui: - print(f'Cannot switch Qt versions for this session; you must use {qt_env2gui[loaded]}.') - return + if loaded is not None and gui != 'qt' and qt_env2gui[loaded] != gui: + print(f'Cannot switch Qt versions for this session; you must use {qt_env2gui[loaded]}.') + return if qt_api is not None and gui != 'qt': if qt_env2gui[qt_api] != gui: @@ -504,7 +503,7 @@ def set_qt_api_env_from_gui(gui): os.environ["QT_API"] = "pyqt6" elif gui == 'qt': # Don't set QT_API; let IPython logic choose the version. - if 'QT_API' in os.environ.keys(): + if 'QT_API' in os.environ: del os.environ['QT_API'] else: print(f'Unrecognized Qt version: {gui}. Should be "qt5", "qt6", or "qt".') @@ -515,7 +514,7 @@ def set_qt_api_env_from_gui(gui): from IPython.external.qt_for_kernel import QtCore, QtGui # noqa except Exception as e: # Clear the environment variable for the next attempt. - if 'QT_API' in os.environ.keys(): + if 'QT_API' in os.environ: del os.environ["QT_API"] print(f"QT_API couldn't be set due to error {e}") return diff --git a/ipykernel/inprocess/client.py b/ipykernel/inprocess/client.py index 81bf2be5e..aaf2db8f5 100644 --- a/ipykernel/inprocess/client.py +++ b/ipykernel/inprocess/client.py @@ -161,10 +161,7 @@ def kernel_info(self): def comm_info(self, target_name=None): """Request a dictionary of valid comms and their targets.""" - if target_name is None: - content = {} - else: - content = dict(target_name=target_name) + content = {} if target_name is None else dict(target_name=target_name) msg = self.session.msg("comm_info_request", content) self._dispatch_to_kernel(msg) return msg["header"]["msg_id"] diff --git a/ipykernel/iostream.py b/ipykernel/iostream.py index 32829f6bd..ba5c3f390 100644 --- a/ipykernel/iostream.py +++ b/ipykernel/iostream.py @@ -234,7 +234,7 @@ def _really_send(self, msg, *args, **kwargs): # new context/socket for every pipe-out # since forks don't teardown politely, use ctx.term to ensure send has completed ctx, pipe_out = self._setup_pipe_out() - pipe_out.send_multipart([self._pipe_uuid] + msg, *args, **kwargs) + pipe_out.send_multipart([self._pipe_uuid, *msg], *args, **kwargs) pipe_out.close() ctx.term() diff --git a/ipykernel/ipkernel.py b/ipykernel/ipkernel.py index 6acc48725..bacb0ba78 100644 --- a/ipykernel/ipkernel.py +++ b/ipykernel/ipkernel.py @@ -431,10 +431,7 @@ async def run_cell(*args, **kwargs): finally: self._restore_input() - if res.error_before_exec is not None: - err = res.error_before_exec - else: - err = res.error_in_exec + err = res.error_before_exec if res.error_before_exec is not None else res.error_in_exec if res.success: reply_content["status"] = "ok" diff --git a/ipykernel/jsonutil.py b/ipykernel/jsonutil.py index 9d6da754f..73c95ca02 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") +datetime.strptime("1", "%d") # noqa # ----------------------------------------------------------------------------- # Classes and functions @@ -98,7 +98,7 @@ def json_clean(obj): # pragma: no cover it simply sanitizes it so that there will be no encoding errors later. """ - if int(JUPYTER_CLIENT_MAJOR_VERSION) >= 7: + if int(JUPYTER_CLIENT_MAJOR_VERSION) >= 7: # noqa return obj # types that are 'atomic' and ok in json as-is. @@ -156,7 +156,7 @@ def json_clean(obj): # pragma: no cover for k, v in obj.items(): out[str(k)] = json_clean(v) return out - if isinstance(obj, datetime) or isinstance(obj, date): + if isinstance(obj, (datetime, date)): return obj.strftime(ISO8601) # we don't understand it, it's probably an unserializable object diff --git a/ipykernel/kernelapp.py b/ipykernel/kernelapp.py index af580e496..8d7eea8c8 100644 --- a/ipykernel/kernelapp.py +++ b/ipykernel/kernelapp.py @@ -447,7 +447,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") + blackhole = open(os.devnull, "w") # noqa if self.no_stdout: sys.stdout = sys.__stdout__ = blackhole if self.no_stderr: @@ -473,7 +473,9 @@ def init_io(self): if hasattr(sys.stderr, "_original_stdstream_copy"): for handler in self.log.handlers: - if isinstance(handler, StreamHandler) and (handler.stream.buffer.fileno() == 2): + if isinstance(handler, StreamHandler) and ( + handler.stream.buffer.fileno() == 2 # noqa + ): self.log.debug("Seeing logger to stderr, rerouting to raw filedescriptor.") handler.stream = TextIOWrapper( diff --git a/ipykernel/kernelbase.py b/ipykernel/kernelbase.py index 110f834c1..a4ece0994 100644 --- a/ipykernel/kernelbase.py +++ b/ipykernel/kernelbase.py @@ -252,7 +252,8 @@ def _parent_header(self): "apply_request", ] # add deprecated ipyparallel control messages - control_msg_types = msg_types + [ + control_msg_types = [ + *msg_types, "clear_request", "abort_request", "debug_request", @@ -544,10 +545,7 @@ def start(self): self.control_stream.on_recv(self.dispatch_control, copy=False) - if self.control_thread: - control_loop = self.control_thread.io_loop - else: - control_loop = self.io_loop + control_loop = self.control_thread.io_loop if self.control_thread else self.io_loop asyncio.run_coroutine_threadsafe(self.poll_control_queue(), control_loop.asyncio_loop) @@ -844,10 +842,7 @@ def do_history( async def connect_request(self, stream, ident, parent): """Handle a connect request.""" - if self._recorded_ports is not None: - content = self._recorded_ports.copy() - else: - content = {} + content = self._recorded_ports.copy() if self._recorded_ports is not None else {} content["status"] = "ok" msg = self.session.send(stream, "connect_reply", content, parent, ident) self.log.debug("%s", msg) @@ -982,7 +977,7 @@ async def usage_request(self, stream, ident, parent): """Handle a usage request.""" reply_content = {"hostname": socket.gethostname(), "pid": os.getpid()} current_process = psutil.Process() - all_processes = [current_process] + current_process.children(recursive=True) + all_processes = [current_process, *current_process.children(recursive=True)] # Ensure 1) self.processes is updated to only current subprocesses # and 2) we reuse processes when possible (needed for accurate CPU) self.processes = { @@ -1004,7 +999,7 @@ async def usage_request(self, stream, ident, parent): cpu_percent = psutil.cpu_percent() # https://psutil.readthedocs.io/en/latest/index.html?highlight=cpu#psutil.cpu_percent # The first time cpu_percent is called it will return a meaningless 0.0 value which you are supposed to ignore. - if cpu_percent is not None and cpu_percent != 0.0: + if cpu_percent is not None and cpu_percent != 0.0: # noqa reply_content["host_cpu_percent"] = cpu_percent reply_content["cpu_count"] = psutil.cpu_count(logical=True) reply_content["host_virtual_memory"] = dict(psutil.virtual_memory()._asdict()) diff --git a/ipykernel/pickleutil.py b/ipykernel/pickleutil.py index 8e2dbe5f3..7a7e07ef6 100644 --- a/ipykernel/pickleutil.py +++ b/ipykernel/pickleutil.py @@ -236,14 +236,8 @@ def get_object(self, g=None): if g is None: g = {} - if self.defaults: - defaults = tuple(uncan(cfd, g) for cfd in self.defaults) - else: - defaults = None - if self.closure: - closure = tuple(uncan(cell, g) for cell in self.closure) - else: - closure = None + 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 @@ -260,10 +254,7 @@ def __init__(self, cls): for k, v in cls.__dict__.items(): if k not in ("__weakref__", "__dict__"): self._canned_dict[k] = can(v) - if self.old_style: - mro = [] - else: - mro = cls.mro() + mro = [] if self.old_style else cls.mro() self.parents = [can(c) for c in mro[1:]] self.buffers = [] @@ -376,10 +367,7 @@ def istype(obj, check): This won't catch subclasses. """ if isinstance(check, tuple): - for cls in check: - if type(obj) is cls: - return True - return False + return any(type(obj) is cls for cls in check) else: return type(obj) is check diff --git a/ipykernel/serialize.py b/ipykernel/serialize.py index 616410c81..50ffe8e85 100644 --- a/ipykernel/serialize.py +++ b/ipykernel/serialize.py @@ -181,7 +181,7 @@ def unpack_apply_message(bufs, g=None, copy=True): """unpack f,args,kwargs from buffers packed by pack_apply_message() Returns: original f,args,kwargs""" bufs = list(bufs) # allow us to pop - assert len(bufs) >= 2, "not enough buffers!" + assert len(bufs) >= 2, "not enough buffers!" # noqa pf = bufs.pop(0) f = uncan(pickle.loads(pf), g) pinfo = bufs.pop(0) diff --git a/ipykernel/tests/test_eventloop.py b/ipykernel/tests/test_eventloop.py index c8bd95407..a4d18d114 100644 --- a/ipykernel/tests/test_eventloop.py +++ b/ipykernel/tests/test_eventloop.py @@ -33,7 +33,7 @@ def _get_qt_vers(): try: __import__(gui_to_module[gui]) qt_guis_avail.append(gui) - if 'QT_API' in os.environ.keys(): + if 'QT_API' in os.environ: del os.environ['QT_API'] except ImportError: pass # that version of Qt isn't available. diff --git a/ipykernel/tests/test_jsonutil.py b/ipykernel/tests/test_jsonutil.py index 0189bc83b..faace16a7 100644 --- a/ipykernel/tests/test_jsonutil.py +++ b/ipykernel/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"), + (datetime(1991, 7, 3, 12, 00), "1991-07-03T12:00:00.000000"), # noqa (date(1991, 7, 3), "1991-07-03T00:00:00.000000"), (MyFloat(), 3.14), (MyInt(), 389), diff --git a/ipykernel/tests/test_parentpoller.py b/ipykernel/tests/test_parentpoller.py index a83cc392a..22df132e7 100644 --- a/ipykernel/tests/test_parentpoller.py +++ b/ipykernel/tests/test_parentpoller.py @@ -33,7 +33,7 @@ def test_parent_poller_windows(): def mock_wait(*args, **kwargs): return -1 - with mock.patch("ctypes.windll.kernel32.WaitForMultipleObjects", mock_wait): + with mock.patch("ctypes.windll.kernel32.WaitForMultipleObjects", mock_wait): # noqa with warnings.catch_warnings(): warnings.simplefilter("ignore") poller.run() diff --git a/pyproject.toml b/pyproject.toml index 64b858ff0..4e0ae62c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -114,7 +114,7 @@ dependencies = ["mypy>=0.990"] test = "mypy --install-types --non-interactive {args:.}" [tool.hatch.envs.lint] -dependencies = ["black==22.12.0", "mdformat>0.7", "ruff==0.0.215"] +dependencies = ["black==22.12.0", "mdformat>0.7", "ruff==0.0.236"] detached = true [tool.hatch.envs.lint.scripts] style = [ @@ -211,8 +211,31 @@ target-version = ["py37"] target-version = "py37" line-length = 100 select = [ - "A", "B", "C", "E", "EM", "F", "FBT", "I", "N", "Q", "RUF", "S", "T", - "UP", "W", "YTT", + "A", + "B", + "C", + "DTZ", + "E", + "EM", + "F", + "FBT", + "I", + "ICN", + "ISC", + "N", + "PLC", + "PLE", + "PLR", + "PLW", + "Q", + "RUF", + "S", + "SIM", + "T", + "TID", + "UP", + "W", + "YTT", ] ignore = [ # Allow non-abstract empty methods in abstract base classes @@ -247,6 +270,8 @@ ignore = [ "C408", # N801 Class name `directional_link` should use CapWords convention "N801", + # SIM105 Use `contextlib.suppress(ValueError)` instead of try-except-pass + "SIM105", ] unfixable = [ # Don't touch print statements @@ -265,7 +290,8 @@ unfixable = [ # 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 -"ipykernel/tests/*" = ["B011", "F841", "C408", "E402", "T201", "B007", "N802", "F841", "EM101", "EM102"] +# PLR2004 Magic value used in comparison +"ipykernel/tests/*" = ["B011", "F841", "C408", "E402", "T201", "B007", "N802", "F841", "EM101", "EM102", "EM103", "PLR2004"] [tool.interrogate] ignore-init-module=true