From 00eb4ee20b8d5838e44de7a756823e4cf02949fa Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 10 Dec 2023 21:24:15 -0600 Subject: [PATCH] Update ruff config (#101) --- .pre-commit-config.yaml | 8 ++-- docs/source/conf.py | 6 +-- jupyter_server_terminals/__init__.py | 2 +- jupyter_server_terminals/api_handlers.py | 8 ++-- jupyter_server_terminals/app.py | 6 +-- jupyter_server_terminals/terminalmanager.py | 14 +++--- pyproject.toml | 51 ++++++++++++--------- tests/test_auth.py | 12 ++--- tests/test_terminal.py | 13 +++--- 9 files changed, 64 insertions(+), 56 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e3e1f93..9166897 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.27.1 + rev: 0.27.3 hooks: - id: check-github-workflows @@ -56,7 +56,7 @@ repos: - id: rst-inline-touching-normal - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.7.0" + rev: "v1.7.1" hooks: - id: mypy files: "^jupyter_server_terminals" @@ -66,7 +66,7 @@ repos: ["traitlets>=5.13", "jupyter_server>=2.10.1", "terminado>=0.18"] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.5 + rev: v0.1.7 hooks: - id: ruff types_or: [python, jupyter] @@ -75,7 +75,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/source/conf.py b/docs/source/conf.py index 48e8b37..39aa633 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # Jupyter Server documentation build configuration file, created by # sphinx-quickstart on Mon Apr 13 09:51:11 2015. # @@ -68,7 +66,7 @@ ] try: - import enchant # type:ignore # noqa + import enchant # type:ignore[import] # noqa: F401 extensions += ["sphinxcontrib.spelling"] except ImportError: @@ -92,7 +90,7 @@ # General information about the project. project = "Jupyter Server Terminals" -copyright = "2021, Jupyter Team, https://jupyter.org" # noqa +copyright = "2021, Jupyter Team, https://jupyter.org" author = "The Jupyter Server Team" # ghissue config diff --git a/jupyter_server_terminals/__init__.py b/jupyter_server_terminals/__init__.py index 6f1a49a..bd9bcaf 100644 --- a/jupyter_server_terminals/__init__.py +++ b/jupyter_server_terminals/__init__.py @@ -8,7 +8,7 @@ msg = "Jupyter Server must be installed to use this extension." raise ModuleNotFoundError(msg) from None -if int(version_info[0]) < 2: # type:ignore[call-overload] # noqa +if int(version_info[0]) < 2: # type:ignore[call-overload] msg = "Jupyter Server Terminals requires Jupyter Server 2.0+" raise RuntimeError(msg) diff --git a/jupyter_server_terminals/api_handlers.py b/jupyter_server_terminals/api_handlers.py index 7957331..7822e03 100644 --- a/jupyter_server_terminals/api_handlers.py +++ b/jupyter_server_terminals/api_handlers.py @@ -50,12 +50,14 @@ def post(self) -> None: if cwd is None: server_root_dir = self.settings["server_root_dir"] self.log.debug( - f"Failed to find requested terminal cwd: {data.get('cwd')}\n" - f" It was not found within the server root neither: {server_root_dir}." + "Failed to find requested terminal cwd: %s\n" + " It was not found within the server root neither: %s.", + data.get("cwd"), + server_root_dir, ) del data["cwd"] else: - self.log.debug(f"Opening terminal in: {cwd.resolve()!s}") + self.log.debug("Opening terminal in: %s", cwd.resolve()) data["cwd"] = str(cwd.resolve()) model = self.terminal_manager.create(**data) diff --git a/jupyter_server_terminals/app.py b/jupyter_server_terminals/app.py index 4c33981..8ccbc4f 100644 --- a/jupyter_server_terminals/app.py +++ b/jupyter_server_terminals/app.py @@ -36,7 +36,7 @@ class TerminalsExtensionApp(ExtensionApp): def initialize_settings(self) -> None: """Initialize settings.""" - if not self.serverapp.terminals_enabled: + if not self.serverapp or not self.serverapp.terminals_enabled: return self.initialize_configurables() self.settings.update( @@ -73,7 +73,7 @@ def initialize_configurables(self) -> None: def initialize_handlers(self) -> None: """Initialize handlers.""" - if not self.serverapp.terminals_enabled: + if not self.serverapp or not self.serverapp.terminals_enabled: # Checking self.terminals_available instead breaks enabling terminals return self.handlers.append( @@ -112,7 +112,7 @@ async def cleanup_terminals(self) -> None: terminal_msg = trans.ngettext( "Shutting down %d terminal", "Shutting down %d terminals", n_terminals ) - self.log.info(terminal_msg % n_terminals) + self.log.info("%s %% %s", terminal_msg, n_terminals) await ensure_async(terminal_manager.terminate_all()) # type:ignore[arg-type] async def stop_extension(self) -> None: diff --git a/jupyter_server_terminals/terminalmanager.py b/jupyter_server_terminals/terminalmanager.py index ffd75a6..b21eb60 100644 --- a/jupyter_server_terminals/terminalmanager.py +++ b/jupyter_server_terminals/terminalmanager.py @@ -62,10 +62,9 @@ def create(self, **kwargs: t.Any) -> MODEL: def get(self, name: str) -> MODEL: """Get terminal 'name'.""" - model = self.get_terminal_model(name) - return model + return self.get_terminal_model(name) - def list(self) -> list[MODEL]: # noqa + def list(self) -> list[MODEL]: """Get a list of all running terminals.""" models = [self.get_terminal_model(name) for name in self.terminals] @@ -94,11 +93,10 @@ def get_terminal_model(self, name: str) -> MODEL: """ self._check_terminal(name) term = self.terminals[name] - model = { + return { "name": name, "last_activity": isoformat(term.last_activity), # type:ignore[attr-defined] } - return model def _check_terminal(self, name: str) -> None: """Check a that terminal 'name' exists and raise 404 if not.""" @@ -109,7 +107,7 @@ def _initialize_culler(self) -> None: """Start culler if 'cull_inactive_timeout' is greater than zero. Regardless of that value, set flag that we've been here. """ - if not self._initialized_culler and self.cull_inactive_timeout > 0: # noqa + if not self._initialized_culler and self.cull_inactive_timeout > 0: # noqa: SIM102 if self._culler_callback is None: _ = IOLoop.current() if self.cull_interval <= 0: # handle case where user set invalid value @@ -144,7 +142,9 @@ async def _cull_terminals(self) -> None: except Exception as e: self.log.exception( "The following exception was encountered while checking the " - f"activity of terminal {name}: {e}" + "activity of terminal %s: %s", + name, + e, ) async def _cull_inactive_terminal(self, name: str) -> None: diff --git a/pyproject.toml b/pyproject.toml index 3b3a2f9..b7c9c1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,7 +125,6 @@ source = ["jupyter_server_terminals"] files = "jupyter_server_terminals" python_version = "3.8" strict = true -show_error_codes = true enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] warn_unreachable = true @@ -134,26 +133,34 @@ warn_unreachable = true line-length = 100 [tool.ruff.lint] -select = [ - "A", "B", "C", "DTZ", "E", "EM", "F", "FBT", "I", "ICN", "N", - "PLC", "PLE", "PLR", "PLW", "Q", "RUF", "S", "SIM", "T", "TID", "UP", - "W", "YTT", +extend-select = [ + "B", # flake8-bugbear + "I", # isort + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PTH", # flake8-use-pathlib + "PT", # flake8-pytest-style + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "T20", # flake8-print + "UP", # pyupgrade + "YTT", # flake8-2020 + "EXE", # flake8-executable + "PYI", # flake8-pyi + "S", # flake8-bandit ] ignore = [ - # Q000 Single quotes found but double quotes preferred - "Q000", - # FBT001 Boolean positional arg in function definition - "FBT001", "FBT002", "FBT003", - # E501 Line too long (158 > 100 characters) - "E501", - # SIM105 Use `contextlib.suppress(...)` - "SIM105", - # T201 `print` found - "T201", - # N802 Function name `CreateWellKnownSid` should be lowercase - "N802", "N803", - # S101 Use of `assert` detected - "S101", + "PLR", # Design related pylint codes + "E501", # Line too long (158 > 100 characters) + "SIM105", # Use `contextlib.suppress(...)` + "T201", # `print` found + "S101", # Use of `assert` detected ] unfixable = [ # Don't touch print statements @@ -166,8 +173,8 @@ unfixable = [ # B011: Do not call assert False since python -O removes these calls # F841 local variable 'foo' is assigned to but never used # S101 Use of `assert` detected -# PLR2004 Magic value used in comparison -"tests/*" = ["B011", "F841", "S101", "PLR2004"] +"tests/*" = ["B011", "F841"] +"docs/*" = ["PTH"] [tool.interrogate] ignore-init-module=true @@ -180,4 +187,4 @@ fail-under=100 exclude = ["tests", "docs"] [tool.repo-review] -ignore = ["PY007", "GH102"] +ignore = ["GH102"] diff --git a/tests/test_auth.py b/tests/test_auth.py index 30ebd60..6f8b8d5 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -14,7 +14,7 @@ class AuthorizerforTesting(Authorizer): # Set these class attributes from within a test # to verify that they match the arguments passed # by the REST API. - permissions: Dict[str, str] = {} # noqa + permissions: Dict[str, str] = {} # noqa: RUF012 def normalize_url(self, path): """Drop the base URL and make sure path leads with a /""" @@ -50,7 +50,7 @@ def is_authorized(self, handler, user, action, resource): ) -@pytest.fixture +@pytest.fixture() def jp_server_config(): return Config( { @@ -62,7 +62,7 @@ def jp_server_config(): ) -@pytest.fixture +@pytest.fixture() def send_request(jp_fetch, jp_ws_fetch): """Send to Jupyter Server and return response code.""" @@ -109,9 +109,9 @@ async def _(url, **fetch_kwargs): # -------- Test scenarios ----------- -@pytest.mark.parametrize("method, url, body", HTTP_REQUESTS_PARAMETRIZED) -@pytest.mark.parametrize("allowed", (True, False)) -async def test_authorized_requests( # noqa +@pytest.mark.parametrize("method, url, body", HTTP_REQUESTS_PARAMETRIZED) # noqa: PT006 +@pytest.mark.parametrize("allowed", (True, False)) # noqa: PT007 +async def test_authorized_requests( request, io_loop, send_request, diff --git a/tests/test_terminal.py b/tests/test_terminal.py index 686df4c..6516eb7 100644 --- a/tests/test_terminal.py +++ b/tests/test_terminal.py @@ -3,13 +3,14 @@ import os import shutil import sys +from pathlib import Path import pytest from tornado.httpclient import HTTPClientError from traitlets.config.loader import Config -@pytest.fixture +@pytest.fixture() def terminal_path(tmp_path): subdir = tmp_path.joinpath("terminal_path") subdir.mkdir() @@ -19,7 +20,7 @@ def terminal_path(tmp_path): shutil.rmtree(str(subdir), ignore_errors=True) -@pytest.fixture +@pytest.fixture() def terminal_root_dir(jp_root_dir): subdir = jp_root_dir.joinpath("terminal_path") subdir.mkdir() @@ -33,7 +34,7 @@ def terminal_root_dir(jp_root_dir): CULL_INTERVAL = 3 -@pytest.fixture +@pytest.fixture() def jp_server_config(): return Config( { @@ -148,7 +149,7 @@ async def test_terminal_create_with_cwd(jp_fetch, jp_ws_fetch, terminal_path): ws.close() - assert os.path.basename(terminal_path) in message_stdout + assert Path(terminal_path).name in message_stdout async def test_terminal_create_with_relative_cwd( @@ -195,7 +196,7 @@ async def test_terminal_create_with_relative_cwd( async def test_terminal_create_with_bad_cwd(jp_fetch, jp_ws_fetch): - non_existing_path = "/tmp/path/to/nowhere" # noqa + non_existing_path = "/tmp/path/to/nowhere" # noqa: S108 resp = await jp_fetch( "api", "terminals", @@ -268,7 +269,7 @@ async def test_culling(jp_fetch): allow_nonstandard_methods=True, ) except HTTPClientError as e: - assert e.code == 404 + assert e.code == 404 # noqa: PT017 culled = True break else: