From 5c81270a5254c7cdcebf5d06434dedc5abe4200a Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 22 Jan 2024 11:06:18 -0600 Subject: [PATCH 1/3] Add formatting and lint config --- .git-blame-ignore-revs | 2 + .github/dependabot.yml | 16 ++++ .github/workflows/tests.yml | 1 + .pre-commit-config.yaml | 69 ++++++++++++++++- .readthedocs.yaml | 19 +++++ CHANGELOG.md | 2 +- conftest.py | 10 ++- docs/source/conf.py | 5 +- docs/source/summary-changes.md | 2 +- .../setting_response_metadata.ipynb | 5 +- kernel_gateway/__init__.py | 5 +- kernel_gateway/__main__.py | 1 - kernel_gateway/auth/identity.py | 5 +- kernel_gateway/base/handlers.py | 7 +- kernel_gateway/gatewayapp.py | 56 ++++++-------- kernel_gateway/jupyter_websocket/__init__.py | 10 ++- kernel_gateway/jupyter_websocket/handlers.py | 9 ++- kernel_gateway/mixins.py | 11 +-- kernel_gateway/notebook_http/__init__.py | 22 +++--- kernel_gateway/notebook_http/cell/parser.py | 1 + kernel_gateway/notebook_http/errors.py | 4 - kernel_gateway/notebook_http/handlers.py | 30 ++++---- kernel_gateway/notebook_http/request_utils.py | 5 +- .../notebook_http/swagger/builders.py | 2 +- .../notebook_http/swagger/handlers.py | 6 +- .../notebook_http/swagger/parser.py | 15 ++-- kernel_gateway/services/kernels/handlers.py | 10 +-- kernel_gateway/services/kernels/manager.py | 14 ++-- kernel_gateway/services/kernels/pool.py | 13 ++-- .../services/kernelspecs/handlers.py | 4 +- kernel_gateway/services/sessions/handlers.py | 9 ++- .../services/sessions/sessionmanager.py | 5 +- .../tests/notebook_http/cell/test_parser.py | 7 +- .../notebook_http/swagger/test_builders.py | 2 +- .../notebook_http/swagger/test_parser.py | 6 +- .../tests/notebook_http/test_request_utils.py | 13 ++-- .../tests/resources/kernel_api.ipynb | 2 +- kernel_gateway/tests/test_gatewayapp.py | 4 +- .../tests/test_jupyter_websocket.py | 9 ++- kernel_gateway/tests/test_mixins.py | 19 ++--- kernel_gateway/tests/test_notebook_http.py | 6 +- pyproject.toml | 74 +++++++++++++++++++ readthedocs.yml | 4 - 43 files changed, 352 insertions(+), 169 deletions(-) create mode 100644 .git-blame-ignore-revs create mode 100644 .github/dependabot.yml mode change 100755 => 100644 .github/workflows/tests.yml create mode 100644 .readthedocs.yaml delete mode 100644 readthedocs.yml diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..4c5b659 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Initial pre-commit reformat +92edb7756e411f7e8295013b5da6a4255e89ac75 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5bf500b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + groups: + actions: + patterns: + - "*" + # Python + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml old mode 100755 new mode 100644 index c8209b4..902ce52 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,7 @@ name: Tests on: + workflow_dispatch: push: pull_request: branches: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d25248c..32991c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,77 @@ +ci: + autoupdate_schedule: monthly + autoupdate_commit_msg: "chore: update pre-commit hooks" + repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: + - id: check-case-conflict + - id: check-ast + - id: check-docstring-first + - id: check-executables-have-shebangs + - id: check-added-large-files + - id: check-case-conflict + - id: check-merge-conflict + - id: check-json + - id: check-toml + - id: check-yaml + - id: debug-statements - id: end-of-file-fixer + - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema rev: 0.27.3 hooks: - id: check-github-workflows + + - repo: https://github.com/executablebooks/mdformat + rev: 0.7.17 + hooks: + - id: mdformat + additional_dependencies: + [mdformat-gfm, mdformat-frontmatter, mdformat-footnote] + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v4.0.0-alpha.8" + hooks: + - id: prettier + types_or: [yaml, html, json] + + - repo: https://github.com/codespell-project/codespell + rev: "v2.2.6" + hooks: + - id: codespell + args: ["-L", "sur,nd"] + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: "v1.10.0" + hooks: + - id: rst-backticks + - id: rst-directive-colons + - id: rst-inline-touching-normal + + - repo: https://github.com/pre-commit/mirrors-mypy + rev: "v1.8.0" + hooks: + - id: mypy + files: kernel_gateway + stages: [manual] + additional_dependencies: [] + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.9 + hooks: + - id: ruff + types_or: [python, jupyter] + args: ["--fix", "--show-fixes"] + exclude: ^kernel_gateway/tests/resources/ + - id: ruff-format + types_or: [python, jupyter] + exclude: ^kernel_gateway/tests/resources/ + + - repo: https://github.com/scientific-python/cookie + rev: "2023.12.21" + hooks: + - id: sp-repo-review + additional_dependencies: ["repo-review[cli]"] diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..2ce0728 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,19 @@ +version: 2 +build: + os: ubuntu-22.04 + tools: + python: "3.9" +sphinx: + configuration: docs/source/conf.py +python: + install: + # install itself with pip install . + - method: pip + path: . + extra_requirements: + - docs +formats: + - epub + - htmlzip + # TODO: evaluate, see https://github.com/jupyter-server/jupyter_server/issues/1378 + # - pdf diff --git a/CHANGELOG.md b/CHANGELOG.md index a66b04b..803b36d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -117,7 +117,7 @@ - Add support for specifying notebook-http APIs using full Swagger specs - Add option to serve static web assets from Tornado in notebook-http mode - Add command line aliases for common options (e.g., `--ip`) -- Fix Tornado 4.4 compatbility: sending an empty body string with a 204 response +- Fix Tornado 4.4 compatibility: sending an empty body string with a 204 response ## 1.0.0 (2016-07-15) diff --git a/conftest.py b/conftest.py index 5ea6748..7efdf97 100644 --- a/conftest.py +++ b/conftest.py @@ -1,11 +1,13 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -import os import logging -import pytest +import os from binascii import hexlify + +import pytest from traitlets.config import Config + from kernel_gateway.gatewayapp import KernelGatewayApp pytest_plugins = ["pytest_jupyter.jupyter_core", "pytest_jupyter.jupyter_server"] @@ -92,13 +94,13 @@ def jp_server_cleanup(jp_asyncio_loop): try: jp_asyncio_loop.run_until_complete(app.async_shutdown()) except (RuntimeError, SystemExit) as e: - print("ignoring cleanup error", e) + print("ignoring cleanup error", e) # noqa: T201 if hasattr(app, "kernel_manager"): app.kernel_manager.context.destroy() KernelGatewayApp.clear_instance() -@pytest.fixture +@pytest.fixture() def jp_auth_header(jp_serverapp): """Configures an authorization header using the token from the serverapp fixture.""" return {"Authorization": f"token {jp_serverapp.identity_provider.token}"} diff --git a/docs/source/conf.py b/docs/source/conf.py index ae8d95e..1dbe9b8 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # This file is execfile()d with the current directory set to its # containing dir. @@ -60,7 +59,7 @@ # _version_py = "../../kernel_gateway/_version.py" version_ns = {} -exec(compile(open(_version_py).read(), _version_py, "exec"), version_ns) +exec(compile(open(_version_py).read(), _version_py, "exec"), version_ns) # noqa: S102 # The short X.Y version. version = "%i.%i" % version_ns["version_info"][:2] # The full version, including alpha/beta/rc tags. @@ -337,7 +336,7 @@ # The format is a list of tuples containing the path and title. # epub_pre_files = [] -# HTML files shat should be inserted after the pages created by sphinx. +# HTML files that should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. # epub_post_files = [] diff --git a/docs/source/summary-changes.md b/docs/source/summary-changes.md index e3c46f8..9739cdd 100644 --- a/docs/source/summary-changes.md +++ b/docs/source/summary-changes.md @@ -97,7 +97,7 @@ See `git log` for a more detailed summary of changes. - Add support for specifying notebook-http APIs using full Swagger specs - Add option to serve static web assets from Tornado in notebook-http mode - Add command line aliases for common options (e.g., `--ip`) -- Fix Tornado 4.4 compatbility: sending an empty body string with a 204 response +- Fix Tornado 4.4 compatibility: sending an empty body string with a 204 response ## 1.0 diff --git a/etc/api_examples/setting_response_metadata.ipynb b/etc/api_examples/setting_response_metadata.ipynb index 6a1931b..f6a4261 100644 --- a/etc/api_examples/setting_response_metadata.ipynb +++ b/etc/api_examples/setting_response_metadata.ipynb @@ -46,9 +46,10 @@ }, "outputs": [], "source": [ + "import hashlib\n", "import json\n", - "from dicttoxml import dicttoxml\n", - "import hashlib" + "\n", + "from dicttoxml import dicttoxml" ] }, { diff --git a/kernel_gateway/__init__.py b/kernel_gateway/__init__.py index 52d501a..120fcc8 100644 --- a/kernel_gateway/__init__.py +++ b/kernel_gateway/__init__.py @@ -1,6 +1,5 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. """Entrypoint for the kernel gateway package.""" -from .gatewayapp import launch_instance - -from ._version import version_info, __version__ +from ._version import __version__, version_info # noqa: F401 +from .gatewayapp import launch_instance # noqa: F401 diff --git a/kernel_gateway/__main__.py b/kernel_gateway/__main__.py index 9298bb4..95b8c56 100644 --- a/kernel_gateway/__main__.py +++ b/kernel_gateway/__main__.py @@ -1,7 +1,6 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. """CLI entrypoint for the kernel gateway package.""" -from __future__ import absolute_import if __name__ == "__main__": import kernel_gateway.gatewayapp as app diff --git a/kernel_gateway/auth/identity.py b/kernel_gateway/auth/identity.py index 0d60e63..3309c30 100644 --- a/kernel_gateway/auth/identity.py +++ b/kernel_gateway/auth/identity.py @@ -5,11 +5,10 @@ This defines the _authentication_ layer of Jupyter Server, to be used in combination with Authorizer for _authorization_. """ -from traitlets import default -from tornado import web - from jupyter_server.auth.identity import IdentityProvider, User from jupyter_server.base.handlers import JupyterHandler +from tornado import web +from traitlets import default class GatewayIdentityProvider(IdentityProvider): diff --git a/kernel_gateway/base/handlers.py b/kernel_gateway/base/handlers.py index 0212a7d..c2dc7e1 100644 --- a/kernel_gateway/base/handlers.py +++ b/kernel_gateway/base/handlers.py @@ -2,9 +2,10 @@ # Distributed under the terms of the Modified BSD License. """Tornado handlers for the base of the API.""" -from tornado import web import jupyter_server.base.handlers as server_handlers -from ..mixins import TokenAuthorizationMixin, CORSMixin, JSONErrorsMixin +from tornado import web + +from ..mixins import CORSMixin, JSONErrorsMixin, TokenAuthorizationMixin class APIVersionHandler( @@ -14,8 +15,6 @@ class APIVersionHandler( JSON errors. """ - pass - class NotFoundHandler(JSONErrorsMixin, web.RequestHandler): """Catches all requests and responds with 404 JSON messages. diff --git a/kernel_gateway/gatewayapp.py b/kernel_gateway/gatewayapp.py index 4c70526..ce47931 100644 --- a/kernel_gateway/gatewayapp.py +++ b/kernel_gateway/gatewayapp.py @@ -4,48 +4,40 @@ import asyncio import errno -import importlib -import logging import hashlib import hmac +import importlib +import logging import os -import sys -import signal import select -import socket +import signal import ssl +import sys import threading from base64 import encodebytes - -import nbformat -from jupyter_server.services.kernels.kernelmanager import MappingKernelManager - from urllib.parse import urlparse -from traitlets import Unicode, Integer, Bytes, default, observe, Type, Instance, List, CBool -from jupyter_core.application import JupyterApp, base_aliases +import nbformat from jupyter_client.kernelspec import KernelSpecManager - -from tornado import httpserver -from tornado import web, ioloop -from tornado.log import enable_pretty_logging, LogFormatter - +from jupyter_core.application import JupyterApp, base_aliases from jupyter_core.paths import secure_write +from jupyter_server.auth.authorizer import AllowAllAuthorizer, Authorizer from jupyter_server.serverapp import random_ports -from ._version import __version__ -from .services.sessions.sessionmanager import SessionManager -from .services.kernels.manager import SeedingMappingKernelManager +from jupyter_server.services.kernels.connection.base import BaseKernelWebsocketConnection +from jupyter_server.services.kernels.connection.channels import ZMQChannelsWebsocketConnection +from jupyter_server.services.kernels.kernelmanager import MappingKernelManager +from tornado import httpserver, ioloop, web +from tornado.log import LogFormatter, enable_pretty_logging +from traitlets import Bytes, CBool, Instance, Integer, List, Type, Unicode, default, observe +from ._version import __version__ from .auth.identity import GatewayIdentityProvider +from .jupyter_websocket import JupyterWebsocketPersonality # Only present for generating help documentation from .notebook_http import NotebookHTTPPersonality -from .jupyter_websocket import JupyterWebsocketPersonality - -from jupyter_server.auth.authorizer import AllowAllAuthorizer, Authorizer -from jupyter_server.services.kernels.connection.base import BaseKernelWebsocketConnection -from jupyter_server.services.kernels.connection.channels import ZMQChannelsWebsocketConnection - +from .services.kernels.manager import SeedingMappingKernelManager +from .services.sessions.sessionmanager import SessionManager # Add additional command line aliases aliases = dict(base_aliases) @@ -135,7 +127,7 @@ def base_url_default(self): return os.getenv(self.base_url_env, self.base_url_default_value) # Token authorization - auth_token_env = "KG_AUTH_TOKEN" + auth_token_env = "KG_AUTH_TOKEN" # noqa: S105 auth_token = Unicode( config=True, help="Authorization token required for all requests (KG_AUTH_TOKEN env var)" ) @@ -196,7 +188,7 @@ def expose_headers_default(self): trust_xheaders = CBool( False, config=True, - help="Use x-* header values for overriding the remote-ip, useful when application is behing a proxy. (KG_TRUST_XHEADERS env var)", + help="Use x-* header values for overriding the remote-ip, useful when application is behind a proxy. (KG_TRUST_XHEADERS env var)", ) @default("trust_xheaders") @@ -303,7 +295,7 @@ def api_changed(self, event): self._load_api_module(event["new"]) except ImportError: # re-raise with more sensible message to help the user - raise ImportError("API module {} not found".format(event["new"])) + raise ImportError("API module {} not found".format(event["new"])) from None certfile_env = "KG_CERTFILE" certfile = Unicode( @@ -506,7 +498,7 @@ def _load_notebook(self, uri): # Remote file import requests - resp = requests.get(uri) + resp = requests.get(uri, timeout=200) resp.raise_for_status() notebook = nbformat.reads(resp.text, 4) @@ -594,7 +586,7 @@ def init_configurables(self): raise RuntimeError(msg) api_module = self._load_api_module(self.api) - func = getattr(api_module, "create_personality") + func = api_module.create_personality self.personality = func(parent=self, log=self.log) self.io_loop.call_later( @@ -701,7 +693,7 @@ def init_http_server(self): for port in random_ports(self.port, self.port_retries + 1): try: self.http_server.listen(port, self.ip) - except socket.error as e: + except OSError as e: if e.errno == errno.EADDRINUSE: self.log.info("The port %i is already in use, trying another port." % port) continue @@ -764,7 +756,7 @@ def _confirm_exit(self): return yes = "y" no = "n" - sys.stdout.write("Shutdown this Jupyter server (%s/[%s])? " % (yes, no)) + sys.stdout.write("Shutdown this Jupyter server (%s/[%s])? " % (yes, no)) # noqa: UP031 sys.stdout.flush() r, w, x = select.select([sys.stdin], [], [], 5) if r: diff --git a/kernel_gateway/jupyter_websocket/__init__.py b/kernel_gateway/jupyter_websocket/__init__.py index 9ff8d8b..8640c7e 100644 --- a/kernel_gateway/jupyter_websocket/__init__.py +++ b/kernel_gateway/jupyter_websocket/__init__.py @@ -3,15 +3,17 @@ """Jupyter websocket personality for the Kernel Gateway""" import os + +from jupyter_server.utils import url_path_join +from traitlets import Bool, List, default +from traitlets.config.configurable import LoggingConfigurable + from ..base.handlers import default_handlers as default_base_handlers -from ..services.kernels.pool import KernelPool from ..services.kernels.handlers import default_handlers as default_kernel_handlers +from ..services.kernels.pool import KernelPool from ..services.kernelspecs.handlers import default_handlers as default_kernelspec_handlers from ..services.sessions.handlers import default_handlers as default_session_handlers from .handlers import default_handlers as default_api_handlers -from jupyter_server.utils import url_path_join -from traitlets import Bool, List, default -from traitlets.config.configurable import LoggingConfigurable class JupyterWebsocketPersonality(LoggingConfigurable): diff --git a/kernel_gateway/jupyter_websocket/handlers.py b/kernel_gateway/jupyter_websocket/handlers.py index bce9787..eaa74e4 100644 --- a/kernel_gateway/jupyter_websocket/handlers.py +++ b/kernel_gateway/jupyter_websocket/handlers.py @@ -2,9 +2,11 @@ # Distributed under the terms of the Modified BSD License. """Tornado handlers for kernel specs.""" +import os + from tornado import web + from ..mixins import CORSMixin -import os class BaseSpecHandler(CORSMixin, web.StaticFileHandler): @@ -13,7 +15,6 @@ class BaseSpecHandler(CORSMixin, web.StaticFileHandler): @staticmethod def get_resource_metadata(): """Returns the (resource, mime-type) for the handlers spec.""" - pass def initialize(self): """Initializes the instance of this class to serve files. @@ -52,6 +53,6 @@ def get_resource_metadata(): default_handlers = [ - ("/api/{}".format(SpecJsonHandler.get_resource_metadata()[0]), SpecJsonHandler), - ("/api/{}".format(APIYamlHandler.get_resource_metadata()[0]), APIYamlHandler), + (f"/api/{SpecJsonHandler.get_resource_metadata()[0]}", SpecJsonHandler), + (f"/api/{APIYamlHandler.get_resource_metadata()[0]}", APIYamlHandler), ] diff --git a/kernel_gateway/mixins.py b/kernel_gateway/mixins.py index 2c2d4b0..783fdfb 100644 --- a/kernel_gateway/mixins.py +++ b/kernel_gateway/mixins.py @@ -2,13 +2,14 @@ # Distributed under the terms of the Modified BSD License. """Mixins for Tornado handlers.""" -from http.client import responses import json import traceback +from http.client import responses + from tornado import web -class CORSMixin(object): +class CORSMixin: """Mixes CORS headers into tornado.web.RequestHandlers.""" SETTINGS_TO_HEADERS = { @@ -52,7 +53,7 @@ def options(self, *args, **kwargs): self.finish() -class TokenAuthorizationMixin(object): +class TokenAuthorizationMixin: """Mixes token auth into tornado.web.RequestHandlers and tornado.websocket.WebsocketHandlers. """ @@ -75,7 +76,7 @@ def prepare(self): package. """ server_token = self.settings.get("kg_auth_token") - if server_token and not self.request.method == "OPTIONS": + if server_token and self.request.method != "OPTIONS": client_token = self.get_argument("token", None) if client_token is None: client_token = self.request.headers.get("Authorization") @@ -88,7 +89,7 @@ def prepare(self): return super().prepare() -class JSONErrorsMixin(object): +class JSONErrorsMixin: """Mixes `write_error` into tornado.web.RequestHandlers to respond with JSON format errors. """ diff --git a/kernel_gateway/notebook_http/__init__.py b/kernel_gateway/notebook_http/__init__.py index 06129f0..514ff0d 100644 --- a/kernel_gateway/notebook_http/__init__.py +++ b/kernel_gateway/notebook_http/__init__.py @@ -2,17 +2,19 @@ # Distributed under the terms of the Modified BSD License. """Notebook HTTP personality for the Kernel Gateway""" +import importlib import os + import tornado -import importlib +from jupyter_server.utils import url_path_join +from traitlets import Bool, Dict, Unicode, default +from traitlets.config.configurable import LoggingConfigurable + from ..base.handlers import default_handlers as default_base_handlers from ..services.kernels.pool import ManagedKernelPool -from .cell.parser import APICellParser +from .cell.parser import APICellParser # noqa: F401 +from .handlers import NotebookAPIHandler, NotebookDownloadHandler, parameterize_path from .swagger.handlers import SwaggerSpecHandler -from .handlers import NotebookAPIHandler, parameterize_path, NotebookDownloadHandler -from jupyter_server.utils import url_path_join -from traitlets import Bool, Unicode, Dict, default -from traitlets.config.configurable import LoggingConfigurable class NotebookHTTPPersonality(LoggingConfigurable): @@ -68,7 +70,7 @@ def __init__(self, *args, **kwargs): # Import the module to use for cell endpoint parsing cell_parser_module = importlib.import_module(self.cell_parser) # Build the parser using the comment syntax for the notebook language - func = getattr(cell_parser_module, "create_parser") + func = cell_parser_module.create_parser try: kernel_language = self.parent.seed_notebook["metadata"]["language_info"]["name"] except (AttributeError, KeyError): @@ -95,13 +97,13 @@ def create_request_handlers(self): # Register the NotebookDownloadHandler if configuration allows if self.allow_notebook_download: path = url_path_join("/", self.parent.base_url, r"/_api/source") - self.log.info("Registering resource: {}, methods: (GET)".format(path)) + self.log.info(f"Registering resource: {path}, methods: (GET)") handlers.append((path, NotebookDownloadHandler, {"path": self.parent.seed_uri})) # Register a static path handler if configuration allows if self.static_path is not None: path = url_path_join("/", self.parent.base_url, r"/public/(.*)") - self.log.info("Registering resource: {}, methods: (GET)".format(path)) + self.log.info(f"Registering resource: {path}, methods: (GET)") handlers.append((path, tornado.web.StaticFileHandler, {"path": self.static_path})) # Discover the notebook endpoints and their implementations @@ -148,7 +150,7 @@ def create_request_handlers(self): }, ) ) - self.log.info("Registering resource: {}, methods: (GET)".format(path)) + self.log.info(f"Registering resource: {path}, methods: (GET)") # Add the 404 catch-all last handlers.append(default_base_handlers[-1]) diff --git a/kernel_gateway/notebook_http/cell/parser.py b/kernel_gateway/notebook_http/cell/parser.py index 3df1a57..2f0208d 100644 --- a/kernel_gateway/notebook_http/cell/parser.py +++ b/kernel_gateway/notebook_http/cell/parser.py @@ -4,6 +4,7 @@ import re import sys + from traitlets import Unicode from traitlets.config.configurable import LoggingConfigurable diff --git a/kernel_gateway/notebook_http/errors.py b/kernel_gateway/notebook_http/errors.py index c075c76..251ef9c 100644 --- a/kernel_gateway/notebook_http/errors.py +++ b/kernel_gateway/notebook_http/errors.py @@ -8,12 +8,8 @@ class CodeExecutionError(Exception): request. """ - pass - class UnsupportedMethodError(Exception): """Raised when a notebook-defined API does not support the requested HTTP method. """ - - pass diff --git a/kernel_gateway/notebook_http/handlers.py b/kernel_gateway/notebook_http/handlers.py index 507ad95..a87c0eb 100644 --- a/kernel_gateway/notebook_http/handlers.py +++ b/kernel_gateway/notebook_http/handlers.py @@ -2,22 +2,24 @@ # Distributed under the terms of the Modified BSD License. """Tornado handlers for invoking notebook cells as web APIs.""" -import os import json +import os +from functools import partial +from typing import Optional + import tornado.web +from tornado.concurrent import Future from tornado.log import access_log -from typing import Optional + +from ..mixins import CORSMixin, JSONErrorsMixin, TokenAuthorizationMixin +from .errors import CodeExecutionError, UnsupportedMethodError from .request_utils import ( - parse_body, - parse_args, format_request, headers_to_dict, - parameterize_path, + parameterize_path, # noqa: F401 + parse_args, + parse_body, ) -from tornado.concurrent import Future -from ..mixins import TokenAuthorizationMixin, CORSMixin, JSONErrorsMixin -from functools import partial -from .errors import UnsupportedMethodError, CodeExecutionError class NotebookAPIHandler( @@ -126,12 +128,12 @@ def on_recv(self, result_accumulator, future, parent_header, msg): # Only take stream output if it is on stdout or if the kernel # is non-confirming and does not name the stream if "name" not in msg["content"] or msg["content"]["name"] == "stdout": - result_accumulator["stream"].append((msg["content"]["text"])) + result_accumulator["stream"].append(msg["content"]["text"]) # Store the error message elif msg["header"]["msg_type"] == "error": error_name = msg["content"]["ename"] error_value = msg["content"]["evalue"] - result_accumulator["error"] = "Error {}: {} \n".format(error_name, error_value) + result_accumulator["error"] = f"Error {error_name}: {error_value} \n" def execute_code(self, kernel_client, kernel_id, source_code): """Executes `source_code` on the kernel specified. @@ -147,7 +149,7 @@ def execute_code(self, kernel_client, kernel_id, source_code): kernel_id : str ID of the kernel from the pool that will execute the request source_code : str - Source code to execut + Source code to execute Returns ------- @@ -199,7 +201,7 @@ async def _handle_request(self): request_code = format_request(request, self.kernel_language) # Run the request and source code and yield until there's a result - access_log.debug("Request code for notebook cell is: {}".format(request_code)) + access_log.debug(f"Request code for notebook cell is: {request_code}") await self.execute_code(kernel_client, kernel_id, request_code) source_result = await self.execute_code(kernel_client, kernel_id, source_code) @@ -264,7 +266,7 @@ class NotebookDownloadHandler( def initialize(self, path: str, default_filename: Optional[str] = None): self.dirname, self.filename = os.path.split(path) - super(NotebookDownloadHandler, self).initialize(self.dirname) + super().initialize(self.dirname) async def get(self, include_body: bool = True): res = await super().get(path=self.filename, include_body=include_body) diff --git a/kernel_gateway/notebook_http/request_utils.py b/kernel_gateway/notebook_http/request_utils.py index 1b0ae49..6e1b5a7 100644 --- a/kernel_gateway/notebook_http/request_utils.py +++ b/kernel_gateway/notebook_http/request_utils.py @@ -5,6 +5,7 @@ import json import re from typing import List, Union + from tornado.httputil import HTTPHeaders, HTTPServerRequest _named_param_regex = re.compile(r"(:([^/\s]*))") @@ -50,7 +51,7 @@ def parameterize_path(path: str) -> str: """ matches = re.findall(_named_param_regex, path) for match in matches: - path = path.replace(match[0], r"(?P<{}>[^\/]+)".format(match[1])) + path = path.replace(match[0], rf"(?P<{match[1]}>[^\/]+)") return path.strip() @@ -84,7 +85,7 @@ def parse_body(request: HTTPServerRequest) -> Union[str, dict]: # will treat the body as text try: return_body = json.loads(body) - except Exception: + except Exception: # noqa: S110 pass return return_body diff --git a/kernel_gateway/notebook_http/swagger/builders.py b/kernel_gateway/notebook_http/swagger/builders.py index daedfa8..bdde0a9 100644 --- a/kernel_gateway/notebook_http/swagger/builders.py +++ b/kernel_gateway/notebook_http/swagger/builders.py @@ -5,7 +5,7 @@ import os -class SwaggerSpecBuilder(object): +class SwaggerSpecBuilder: """Builds a Swagger specification. Parameters diff --git a/kernel_gateway/notebook_http/swagger/handlers.py b/kernel_gateway/notebook_http/swagger/handlers.py index 5c7f7a7..7cea53d 100644 --- a/kernel_gateway/notebook_http/swagger/handlers.py +++ b/kernel_gateway/notebook_http/swagger/handlers.py @@ -4,10 +4,12 @@ notebook-http mode, notebook-defined API. """ -import tornado.web import json + +import tornado.web + +from ...mixins import CORSMixin, JSONErrorsMixin, TokenAuthorizationMixin from .builders import SwaggerSpecBuilder -from ...mixins import TokenAuthorizationMixin, CORSMixin, JSONErrorsMixin class SwaggerSpecHandler( diff --git a/kernel_gateway/notebook_http/swagger/parser.py b/kernel_gateway/notebook_http/swagger/parser.py index e475612..6e7acef 100644 --- a/kernel_gateway/notebook_http/swagger/parser.py +++ b/kernel_gateway/notebook_http/swagger/parser.py @@ -4,10 +4,15 @@ import json import re -from kernel_gateway.notebook_http.cell.parser import first_path_param_index, APICellParser + from traitlets import List, Unicode from traitlets.config.configurable import LoggingConfigurable +from kernel_gateway.notebook_http.cell.parser import ( # noqa: F401 + APICellParser, + first_path_param_index, +) + def _swaggerlet_from_markdown(cell_source): """Pulls apart the first block comment of a cell's source, @@ -17,11 +22,11 @@ def _swaggerlet_from_markdown(cell_source): lines = cell_source.splitlines() # pull out the first block comment if len(lines) > 2: - for i in range(0, len(lines)): + for i in range(len(lines)): if lines[i].startswith("```"): lines = lines[i + 1 :] break - for i in range(0, len(lines)): + for i in range(len(lines)): if lines[i].startswith("```"): lines = lines[:i] break @@ -70,7 +75,7 @@ class SwaggerCellParser(LoggingConfigurable): notebook_cells = List() def __init__(self, comment_prefix, notebook_cells, **kwargs): - super(SwaggerCellParser, self).__init__(**kwargs) + super().__init__(**kwargs) self.notebook_cells = notebook_cells self.kernelspec_operation_indicator = re.compile( self.operation_indicator.format(comment_prefix) @@ -78,7 +83,7 @@ def __init__(self, comment_prefix, notebook_cells, **kwargs): self.kernelspec_operation_response_indicator = re.compile( self.operation_response_indicator.format(comment_prefix) ) - self.swagger = dict() + self.swagger = {} operationIdsFound = [] operationIdsDeclared = [] for cell in self.notebook_cells: diff --git a/kernel_gateway/services/kernels/handlers.py b/kernel_gateway/services/kernels/handlers.py index c883b46..528c70c 100644 --- a/kernel_gateway/services/kernels/handlers.py +++ b/kernel_gateway/services/kernels/handlers.py @@ -3,12 +3,12 @@ """Tornado handlers for kernel CRUD and communication.""" import os +from functools import partial -import tornado import jupyter_server.services.kernels.handlers as server_handlers -from tornado import gen -from functools import partial -from ...mixins import TokenAuthorizationMixin, CORSMixin, JSONErrorsMixin +import tornado + +from ...mixins import CORSMixin, JSONErrorsMixin, TokenAuthorizationMixin class MainKernelHandler( @@ -96,7 +96,7 @@ async def get(self): if not self.settings.get("kg_list_kernels"): raise tornado.web.HTTPError(403, "Forbidden") else: - await super(MainKernelHandler, self).get() + await super().get() def options(self, **kwargs): """Method for properly handling CORS pre-flight""" diff --git a/kernel_gateway/services/kernels/manager.py b/kernel_gateway/services/kernels/manager.py index b35deab..9fe4cb2 100644 --- a/kernel_gateway/services/kernels/manager.py +++ b/kernel_gateway/services/kernels/manager.py @@ -3,9 +3,10 @@ """Kernel manager that optionally seeds kernel memory.""" import os from typing import List, Optional -from traitlets import default -from jupyter_server.services.kernels.kernelmanager import AsyncMappingKernelManager + from jupyter_client.ioloop import AsyncIOLoopKernelManager +from jupyter_server.services.kernels.kernelmanager import AsyncMappingKernelManager +from traitlets import default class SeedingMappingKernelManager(AsyncMappingKernelManager): @@ -77,7 +78,8 @@ async def start_seeded_kernel(self, *args, **kwargs): Run synchronously so that any exceptions thrown while seed rise up to the caller. """ - await self.start_kernel(kernel_name=self.seed_kernelspec, *args, **kwargs) + kwargs["kernel_name"] = self.seed_kernelspec + await self.start_kernel(*args, **kwargs) async def start_kernel(self, *args, **kwargs): """Starts a kernel and then executes a list of code cells on it if a @@ -85,7 +87,7 @@ async def start_kernel(self, *args, **kwargs): """ if self.parent.force_kernel_name: kwargs["kernel_name"] = self.parent.force_kernel_name - kernel_id = await super(SeedingMappingKernelManager, self).start_kernel(*args, **kwargs) + kernel_id = await super().start_kernel(*args, **kwargs) if kernel_id and self.seed_source is not None: # Only run source if the kernel spec matches the notebook kernel spec @@ -137,6 +139,4 @@ async def _async_launch_kernel(self, kernel_cmd, **kw): env["KERNEL_GATEWAY"] = "1" if "KG_AUTH_TOKEN" in env: del env["KG_AUTH_TOKEN"] - return await super(KernelGatewayIOLoopKernelManager, self)._async_launch_kernel( - kernel_cmd, **kw - ) + return await super()._async_launch_kernel(kernel_cmd, **kw) diff --git a/kernel_gateway/services/kernels/pool.py b/kernel_gateway/services/kernels/pool.py index 8a3ad1d..9071e95 100644 --- a/kernel_gateway/services/kernels/pool.py +++ b/kernel_gateway/services/kernels/pool.py @@ -3,14 +3,13 @@ """Kernel pools that track and delegate to kernels.""" import asyncio -import tornado.gen -from tornado.locks import Semaphore -from tornado.concurrent import Future -from traitlets.config.configurable import LoggingConfigurable from typing import Awaitable, List, Optional from jupyter_client.session import Session from jupyter_server.services.kernels.kernelmanager import MappingKernelManager +from tornado.concurrent import Future +from tornado.locks import Semaphore +from traitlets.config.configurable import LoggingConfigurable class KernelPool(LoggingConfigurable): @@ -104,7 +103,7 @@ async def initialize(self, prespawn_count, kernel_manager, **kwargs): self.kernel_semaphore = Semaphore(prespawn_count) - await super(ManagedKernelPool, self).initialize(prespawn_count, kernel_manager) + await super().initialize(prespawn_count, kernel_manager) kernel_ids = self.kernel_manager.list_kernel_ids() @@ -157,7 +156,7 @@ def _on_reply(self, kernel_id, session, msg_list): List of 0mq messages """ if kernel_id not in self.on_recv_funcs: - self.log.warning("Could not find callback for kernel_id: {}".format(kernel_id)) + self.log.warning(f"Could not find callback for kernel_id: {kernel_id}") return idents, msg_list = session.feed_identities(msg_list) msg = session.deserialize(msg_list) @@ -207,4 +206,4 @@ async def shutdown(self): await self.kernel_manager.shutdown_kernel(kid, now=True) # Any remaining kernels that were not created for our pool should be shutdown - await super(ManagedKernelPool, self).shutdown() + await super().shutdown() diff --git a/kernel_gateway/services/kernelspecs/handlers.py b/kernel_gateway/services/kernelspecs/handlers.py index 131941d..4c706fd 100644 --- a/kernel_gateway/services/kernelspecs/handlers.py +++ b/kernel_gateway/services/kernelspecs/handlers.py @@ -2,10 +2,10 @@ # Distributed under the terms of the Modified BSD License. """Tornado handlers for kernel specs.""" -import jupyter_server.services.kernelspecs.handlers as server_handlers import jupyter_server.kernelspecs.handlers as server_kernelspecs_resources_handlers +import jupyter_server.services.kernelspecs.handlers as server_handlers -from ...mixins import TokenAuthorizationMixin, CORSMixin, JSONErrorsMixin +from ...mixins import CORSMixin, JSONErrorsMixin, TokenAuthorizationMixin # Extends the default handlers from the jupyter_server package with token auth, CORS # and JSON errors. diff --git a/kernel_gateway/services/sessions/handlers.py b/kernel_gateway/services/sessions/handlers.py index 855b71c..bab382d 100644 --- a/kernel_gateway/services/sessions/handlers.py +++ b/kernel_gateway/services/sessions/handlers.py @@ -2,9 +2,10 @@ # Distributed under the terms of the Modified BSD License. """Tornado handlers for session CRUD.""" -import tornado import jupyter_server.services.sessions.handlers as server_handlers -from ...mixins import TokenAuthorizationMixin, CORSMixin, JSONErrorsMixin +import tornado + +from ...mixins import CORSMixin, JSONErrorsMixin, TokenAuthorizationMixin class SessionRootHandler( @@ -23,10 +24,10 @@ async def get(self): tornado.web.HTTPError If kg_list_kernels is False, respond with 403 Forbidden """ - if "kg_list_kernels" not in self.settings or self.settings["kg_list_kernels"] != True: + if "kg_list_kernels" not in self.settings or self.settings["kg_list_kernels"] is not True: raise tornado.web.HTTPError(403, "Forbidden") else: - await super(SessionRootHandler, self).get() + await super().get() default_handlers = [] diff --git a/kernel_gateway/services/sessions/sessionmanager.py b/kernel_gateway/services/sessions/sessionmanager.py index 03a0a61..2e9b460 100644 --- a/kernel_gateway/services/sessions/sessionmanager.py +++ b/kernel_gateway/services/sessions/sessionmanager.py @@ -3,9 +3,10 @@ """Session manager that keeps all its metadata in memory.""" import uuid +from typing import List, Optional + from tornado import web from traitlets.config.configurable import LoggingConfigurable -from typing import List, Optional class SessionManager(LoggingConfigurable): @@ -28,7 +29,7 @@ class SessionManager(LoggingConfigurable): """ def __init__(self, kernel_manager, **kwargs): - super(SessionManager, self).__init__(**kwargs) + super().__init__(**kwargs) self.kernel_manager = kernel_manager self._sessions = [] self._columns = ["session_id", "path", "kernel_id"] diff --git a/kernel_gateway/tests/notebook_http/cell/test_parser.py b/kernel_gateway/tests/notebook_http/cell/test_parser.py index df79714..e509f6f 100644 --- a/kernel_gateway/tests/notebook_http/cell/test_parser.py +++ b/kernel_gateway/tests/notebook_http/cell/test_parser.py @@ -3,6 +3,7 @@ """Tests for notebook cell parsing.""" import sys + from kernel_gateway.notebook_http.cell.parser import APICellParser @@ -27,7 +28,7 @@ def test_endpoint_sort_default_strategy(self): endpoints = parser.endpoints(source_cells) expected_values = ["/hello/world", "/hello/:foo", "/:foo"] - for index in range(0, len(expected_values)): + for index in range(len(expected_values)): endpoint, _ = endpoints[index] assert expected_values[index] == endpoint, "Endpoint was not found in expected order" @@ -38,7 +39,7 @@ def test_endpoint_sort_custom_strategy(self): source_cells = ["# POST /1", "# POST /+", "# GET /a"] def custom_sort_fun(endpoint): - index = sys.maxsize + _ = sys.maxsize if endpoint.find("1") >= 0: return 0 elif endpoint.find("a") >= 0: @@ -50,7 +51,7 @@ def custom_sort_fun(endpoint): endpoints = parser.endpoints(source_cells, custom_sort_fun) expected_values = ["/+", "/a", "/1"] - for index in range(0, len(expected_values)): + for index in range(len(expected_values)): endpoint, _ = endpoints[index] assert expected_values[index] == endpoint, "Endpoint was not found in expected order" diff --git a/kernel_gateway/tests/notebook_http/swagger/test_builders.py b/kernel_gateway/tests/notebook_http/swagger/test_builders.py index 693f1f2..8a650b5 100644 --- a/kernel_gateway/tests/notebook_http/swagger/test_builders.py +++ b/kernel_gateway/tests/notebook_http/swagger/test_builders.py @@ -4,8 +4,8 @@ import json -from kernel_gateway.notebook_http.swagger.builders import SwaggerSpecBuilder from kernel_gateway.notebook_http.cell.parser import APICellParser +from kernel_gateway.notebook_http.swagger.builders import SwaggerSpecBuilder from kernel_gateway.notebook_http.swagger.parser import SwaggerCellParser diff --git a/kernel_gateway/tests/notebook_http/swagger/test_parser.py b/kernel_gateway/tests/notebook_http/swagger/test_parser.py index 523bbbe..87003e2 100644 --- a/kernel_gateway/tests/notebook_http/swagger/test_parser.py +++ b/kernel_gateway/tests/notebook_http/swagger/test_parser.py @@ -90,13 +90,13 @@ def test_endpoint_sort_default_strategy(self): expected_values = ["/hello/world", "/hello/:foo", "/:foo"] try: - for index in range(0, len(expected_values)): + for index in range(len(expected_values)): endpoint, _ = endpoints[index] assert ( expected_values[index] == endpoint ), "Endpoint was not found in expected order" except IndexError: - raise RuntimeError(endpoints) + raise RuntimeError(endpoints) from None def test_endpoint_sort_custom_strategy(self): """Parser should sort duplicate endpoint paths using a custom sort strategy.""" @@ -122,7 +122,7 @@ def custom_sort_fun(endpoint): print(str(endpoints)) expected_values = ["/+", "/a", "/1"] - for index in range(0, len(expected_values)): + for index in range(len(expected_values)): endpoint, _ = endpoints[index] assert expected_values[index] == endpoint, "Endpoint was not found in expected order" diff --git a/kernel_gateway/tests/notebook_http/test_request_utils.py b/kernel_gateway/tests/notebook_http/test_request_utils.py index e3b4ab1..5c61ed7 100644 --- a/kernel_gateway/tests/notebook_http/test_request_utils.py +++ b/kernel_gateway/tests/notebook_http/test_request_utils.py @@ -2,24 +2,25 @@ # Distributed under the terms of the Modified BSD License. """Tests for notebook request utilities.""" -import unittest import json +import unittest + from kernel_gateway.notebook_http.request_utils import ( format_request, - parse_body, - parameterize_path, headers_to_dict, + parameterize_path, parse_args, + parse_body, ) class MockRequest(dict): def __init__(self, *args, **kwargs): - super(MockRequest, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.__dict__ = self -class MockHeaders(object): +class MockHeaders: def __init__(self, headers, **kwargs): self.headers = headers @@ -151,7 +152,7 @@ def test_format_request_code_not_escaped(self): ) def test_format_request_code_escaped(self): - """Should handle backslash escaped characeters in headers.""" + """Should handle backslash escaped characters in headers.""" test_request = """{"body": "", "headers": {"Accept-Language": "en-US,en;q=0.8", "If-None-Match": "\"\"9a28a9262f954494a8de7442c63d6d0715ce0998\"\"", "Accept-Encoding": "gzip, deflate, sdch"}, "args": {}, "path": {}}""" diff --git a/kernel_gateway/tests/resources/kernel_api.ipynb b/kernel_gateway/tests/resources/kernel_api.ipynb index 88f9a4f..da7a01b 100644 --- a/kernel_gateway/tests/resources/kernel_api.ipynb +++ b/kernel_gateway/tests/resources/kernel_api.ipynb @@ -313,7 +313,7 @@ "outputs": [], "source": [ "# GET /error\n", - "this cell should print an error in the reponse" + "this cell should print an error in the response" ] }, { diff --git a/kernel_gateway/tests/test_gatewayapp.py b/kernel_gateway/tests/test_gatewayapp.py index 4e1bb10..cf7522f 100644 --- a/kernel_gateway/tests/test_gatewayapp.py +++ b/kernel_gateway/tests/test_gatewayapp.py @@ -1,13 +1,13 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. """Tests for basic gateway app behavior.""" +import os import ssl import nbformat -import os -from kernel_gateway.gatewayapp import KernelGatewayApp from kernel_gateway import __version__ +from kernel_gateway.gatewayapp import KernelGatewayApp RESOURCES = os.path.join(os.path.dirname(__file__), "resources") diff --git a/kernel_gateway/tests/test_jupyter_websocket.py b/kernel_gateway/tests/test_jupyter_websocket.py index 1cc2f34..4cce7e9 100644 --- a/kernel_gateway/tests/test_jupyter_websocket.py +++ b/kernel_gateway/tests/test_jupyter_websocket.py @@ -4,23 +4,24 @@ import json import os -import pytest import uuid +import pytest from jupyter_client.kernelspec import NoSuchKernel +from tornado.escape import json_decode, json_encode, url_escape from tornado.gen import sleep from tornado.httpclient import HTTPClientError -from tornado.escape import json_encode, json_decode, url_escape from tornado.web import HTTPError from traitlets.config import Config from kernel_gateway.gatewayapp import KernelGatewayApp from kernel_gateway.services.kernels.manager import AsyncMappingKernelManager from kernel_gateway.services.sessions.sessionmanager import SessionManager + from .test_gatewayapp import RESOURCES -@pytest.fixture +@pytest.fixture() def jp_server_config(): """Allows tests to setup their specific configuration values.""" config = { @@ -31,7 +32,7 @@ def jp_server_config(): return Config(config) -@pytest.fixture +@pytest.fixture() def spawn_kernel(jp_fetch, jp_http_port, jp_base_url, jp_ws_fetch): """Spawns a kernel where request.param contains the request body and returns the websocket.""" diff --git a/kernel_gateway/tests/test_mixins.py b/kernel_gateway/tests/test_mixins.py index 455ac48..e519ba8 100644 --- a/kernel_gateway/tests/test_mixins.py +++ b/kernel_gateway/tests/test_mixins.py @@ -3,14 +3,15 @@ """Tests for handler mixins.""" import json -import pytest from unittest.mock import Mock + +import pytest from tornado import web -from kernel_gateway.mixins import TokenAuthorizationMixin, JSONErrorsMixin +from kernel_gateway.mixins import JSONErrorsMixin, TokenAuthorizationMixin -class SuperTokenAuthHandler(object): +class SuperTokenAuthHandler: """Super class for the handler using TokenAuthorizationMixin.""" is_prepared = False @@ -36,10 +37,10 @@ def get_argument(self, name, default=""): return self.arguments.get(name, default) -@pytest.fixture +@pytest.fixture() def auth_mixin(): auth_mixin_instance = CustomTokenAuthHandler("YouKnowMe") - yield auth_mixin_instance + return auth_mixin_instance class TestTokenAuthMixin: @@ -146,10 +147,10 @@ def set_header(self, name, value): self.headers[name] = value -@pytest.fixture +@pytest.fixture() def errors_mixin(): errors_mixin_instance = CustomJSONErrorsHandler() - yield errors_mixin_instance + return errors_mixin_instance class TestJSONErrorsMixin: @@ -164,7 +165,7 @@ def test_status(self, errors_mixin): assert response["message"] == "" def test_custom_status(self, errors_mixin): - """Custom reason from exeception should be set in the response.""" + """Custom reason from exception should be set in the response.""" exc = web.HTTPError(500, reason="fake-reason") errors_mixin.write_error(500, exc_info=[None, exc]) @@ -174,7 +175,7 @@ def test_custom_status(self, errors_mixin): assert response["message"] == "" def test_log_message(self, errors_mixin): - """Custom message from exeception should be set in the response.""" + """Custom message from exception should be set in the response.""" exc = web.HTTPError(410, log_message="fake-message") errors_mixin.write_error(410, exc_info=[None, exc]) diff --git a/kernel_gateway/tests/test_notebook_http.py b/kernel_gateway/tests/test_notebook_http.py index 15334dd..1393ff1 100644 --- a/kernel_gateway/tests/test_notebook_http.py +++ b/kernel_gateway/tests/test_notebook_http.py @@ -3,10 +3,10 @@ """Tests for notebook-http mode.""" import asyncio -import os import json -import pytest +import os +import pytest from tornado.httpclient import HTTPClientError from traitlets.config import Config @@ -14,7 +14,7 @@ from .test_gatewayapp import RESOURCES -@pytest.fixture +@pytest.fixture() def jp_server_config(): """Allows tests to setup their specific configuration values.""" config = { diff --git a/pyproject.toml b/pyproject.toml index 61694c3..d66691d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,3 +88,77 @@ features = ["test"] dependencies = ["coverage[toml]", "pytest-cov"] [tool.hatch.envs.cov.scripts] test = "python -m pytest -vv --cov kernel_gateway --cov-branch --cov-report term-missing:skip-covered {args}" + +[tool.ruff.lint] +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 = [ + "PLR", # Design related pylint codes + "S101", # Use of `assert` detected +] +unfixable = [ + # Don't touch print statements + "T201", + # Don't touch unused imports + "F401", + "F403", + # Don't touch noqa lines + "RUF100", +] + +[tool.ruff] +line-length = 100 + +[tool.ruff.format] +docstring-code-format = true + +[tool.mypy] +python_version = "3.8" +explicit_package_bases = true +strict = true +pretty = true +warn_unreachable = true +disable_error_code = ["no-untyped-def", "no-untyped-call"] +enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] + +[tool.ruff.lint.per-file-ignores] +"kernel_gateway/tests/*" = ["T201", "S", "RET", "EM"] +"etc/*" = ["T201", "S", "RET"] + +[tool.pytest.ini_options] +minversion = "6.0" +xfail_strict = true +log_cli_level = "info" +addopts = [ + "-ra", "--durations=10", "--color=yes", "--doctest-modules", + "--showlocals", "--strict-markers", "--strict-config" +] +testpaths = [ + "kernel_gateway/tests/" +] +filterwarnings = [ + "error", +] + +[tool.repo-review] +ignore = ["GH102", "PC111"] diff --git a/readthedocs.yml b/readthedocs.yml deleted file mode 100644 index db58ec3..0000000 --- a/readthedocs.yml +++ /dev/null @@ -1,4 +0,0 @@ -conda: - file: docs/environment.yml -python: - version: 3 From a1a09170f6eaa09dc4135e46e3a6bb8ea5aef5f9 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 22 Jan 2024 11:06:58 -0600 Subject: [PATCH 2/3] update rtd config --- .readthedocs.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 2ce0728..92985dc 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -15,5 +15,3 @@ python: formats: - epub - htmlzip - # TODO: evaluate, see https://github.com/jupyter-server/jupyter_server/issues/1378 - # - pdf From 782fece9de1e14fdcced02de2476dc7aac70f293 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 22 Jan 2024 11:16:49 -0600 Subject: [PATCH 3/3] address deprecation warnings --- conftest.py | 11 ++++++++--- pyproject.toml | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/conftest.py b/conftest.py index 7efdf97..94f8f08 100644 --- a/conftest.py +++ b/conftest.py @@ -5,10 +5,15 @@ import os from binascii import hexlify -import pytest -from traitlets.config import Config +# isort: off +# This must come before any Jupyter imports. +os.environ["JUPYTER_PLATFORM_DIRS"] = "1" +# isort: on -from kernel_gateway.gatewayapp import KernelGatewayApp +import pytest # noqa: E402 +from traitlets.config import Config # noqa: E402 + +from kernel_gateway.gatewayapp import KernelGatewayApp # noqa: E402 pytest_plugins = ["pytest_jupyter.jupyter_core", "pytest_jupyter.jupyter_server"] diff --git a/pyproject.toml b/pyproject.toml index d66691d..dda23ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -158,6 +158,7 @@ testpaths = [ ] filterwarnings = [ "error", + "module:datetime.datetime.utc:DeprecationWarning", ] [tool.repo-review]