Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pytest-jupyter for openSUSE:Factory checked in at 2023-05-01 18:51:10 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pytest-jupyter (Old) and /work/SRC/openSUSE:Factory/.python-pytest-jupyter.new.1533 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pytest-jupyter" Mon May 1 18:51:10 2023 rev:3 rq:1083771 version:0.7.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pytest-jupyter/python-pytest-jupyter.changes 2023-02-03 22:16:55.463321927 +0100 +++ /work/SRC/openSUSE:Factory/.python-pytest-jupyter.new.1533/python-pytest-jupyter.changes 2023-05-01 18:51:10.629353768 +0200 @@ -1,0 +2,7 @@ +Sun Apr 23 17:24:28 UTC 2023 - Ben Greiner <c...@bnavigator.de> + +- Update to 0.7.0 + * Enable header overrides in jp_ws_fetch fixture by @kevin-bates + in #51 + +------------------------------------------------------------------- Old: ---- pytest_jupyter-0.6.2.tar.gz New: ---- pytest_jupyter-0.7.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pytest-jupyter.spec ++++++ --- /var/tmp/diff_new_pack.VLyeJa/_old 2023-05-01 18:51:11.069356380 +0200 +++ /var/tmp/diff_new_pack.VLyeJa/_new 2023-05-01 18:51:11.073356404 +0200 @@ -1,7 +1,7 @@ # -# spec file for package python-pytest-jupyter +# spec file # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -26,10 +26,10 @@ %endif Name: python-pytest-jupyter%{psuffix} -Version: 0.6.2 +Version: 0.7.0 Release: 0 Summary: A pytest plugin for testing Jupyter libraries and extensions -License: MIT AND BSD-3-Clause +License: BSD-3-Clause AND MIT URL: https://github.com/jupyter-server/pytest-jupyter Source: https://files.pythonhosted.org/packages/source/p/pytest_jupyter/pytest_jupyter-%{version}.tar.gz BuildRequires: %{python_module base >= 3.7} ++++++ pytest_jupyter-0.6.2.tar.gz -> pytest_jupyter-0.7.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/PKG-INFO new/pytest_jupyter-0.7.0/PKG-INFO --- old/pytest_jupyter-0.6.2/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytest-jupyter -Version: 0.6.2 +Version: 0.7.0 Summary: A pytest plugin for testing Jupyter libraries and extensions. Project-URL: Homepage, http://jupyter.org Project-URL: Funding, https://numfocus.org/donate @@ -111,18 +111,13 @@ Requires-Dist: myst-parser; extra == 'docs' Requires-Dist: pydata-sphinx-theme; extra == 'docs' Requires-Dist: sphinx; extra == 'docs' -Provides-Extra: lint -Requires-Dist: black>=22.6.0; extra == 'lint' -Requires-Dist: mdformat>0.7; extra == 'lint' -Requires-Dist: ruff>=0.0.156; extra == 'lint' +Requires-Dist: sphinxcontrib-spelling; extra == 'docs' Provides-Extra: server Requires-Dist: jupyter-server>=1.21; extra == 'server' Requires-Dist: nbformat>=5.3; extra == 'server' Requires-Dist: pytest-jupyter[client]; extra == 'server' Provides-Extra: test Requires-Dist: pytest-timeout; extra == 'test' -Provides-Extra: typing -Requires-Dist: mypy>=0.990; extra == 'typing' Description-Content-Type: text/markdown # pytest-jupyter diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/pyproject.toml new/pytest_jupyter-0.7.0/pyproject.toml --- old/pytest_jupyter-0.6.2/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 @@ -38,6 +38,7 @@ "myst_parser", "pydata_sphinx_theme", "Sphinx", + "sphinxcontrib-spelling" ] client = [ "jupyter_client>=7.4.0", @@ -51,14 +52,6 @@ test = [ "pytest-timeout" ] -lint = [ - "black>=22.6.0", - "mdformat>0.7", - "ruff>=0.0.156", -] -typing = [ - "mypy>=0.990" -] [project.urls] Homepage = "http://jupyter.org" @@ -95,13 +88,18 @@ nowarn = "test -W default {args}" [tool.hatch.envs.typing] -features = ["test", "typing", "server", "client"] +features = ["test", "server", "client"] dependencies = ["mypy>=0.990"] [tool.hatch.envs.typing.scripts] test = "mypy --install-types --non-interactive {args:.}" [tool.hatch.envs.lint] -features = ["lint"] +dependencies = [ + "black[jupyter]==23.1.0", + "mdformat>0.7", + "ruff==0.0.254", +] +detached = true [tool.hatch.envs.lint.scripts] style = [ "ruff {args:.}", @@ -167,38 +165,21 @@ target-version = "py38" line-length = 100 select = [ - "A", "B", "C", "E", "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 - "B027", - # Ignore McCabe complexity - "C901", - # Allow boolean positional values in function calls, like `dict.get(... True)` - "FBT003", - # Use of `assert` detected - "S101", - # Line too long - "E501", - # Relative imports are banned - "I252", - # Boolean ... in function definition - "FBT001", - "FBT002", - # Module level import not at top of file - "E402", - # A001/A002/A003 .. is shadowing a python builtin - "A001", - "A002", - "A003", - # Possible hardcoded password - "S105", - "S106", - # Q000 Single quotes found but double quotes preferred - "Q000", - # N806 Variable `B` in function should be lowercase - "N806", +# 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", +#PLR0913 Too many arguments to function call +"PLR0913", ] unfixable = [ # Don't touch print statements @@ -215,4 +196,15 @@ # T201 `print` found # B007 Loop control variable `i` not used within the loop body. # N802 Function name `assertIn` should be lowercase -"tests/*" = ["B011", "F841", "C408", "E402", "T201", "B007", "N802"] +# S101 Use of `assert` detected +"tests/*" = ["B011", "F841", "C408", "E402", "T201", "B007", "N802", "S101"] + +[tool.interrogate] +ignore-init-module=true +ignore-private=true +ignore-semiprivate=true +ignore-property-decorators=true +ignore-nested-functions=true +ignore-nested-classes=true +fail-under=100 +exclude = ["docs", "tests"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/pytest_jupyter/_version.py new/pytest_jupyter-0.7.0/pytest_jupyter/_version.py --- old/pytest_jupyter-0.6.2/pytest_jupyter/_version.py 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/pytest_jupyter/_version.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,4 +1,5 @@ +"""Version info for pytest_jupyter.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -__version__ = "0.6.2" +__version__ = "0.7.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/pytest_jupyter/echo_kernel.py new/pytest_jupyter-0.7.0/pytest_jupyter/echo_kernel.py --- old/pytest_jupyter-0.6.2/pytest_jupyter/echo_kernel.py 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/pytest_jupyter/echo_kernel.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,3 +1,4 @@ +"""A simple echo kernel.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. @@ -8,6 +9,8 @@ class EchoKernel(Kernel): + """An echo kernel.""" + implementation = "Echo" implementation_version = "1.0" language = "echo" @@ -22,6 +25,7 @@ def do_execute( self, code, silent, store_history=True, user_expressions=None, allow_stdin=False ): + """Execute code on the kernel.""" if not silent: stream_content = {"name": "stdout", "text": code} self.send_response(self.iopub_socket, "stream", stream_content) @@ -45,6 +49,8 @@ class EchoKernelApp(IPKernelApp): + """An app for the echo kernel.""" + kernel_class = EchoKernel diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/pytest_jupyter/jupyter_client.py new/pytest_jupyter-0.7.0/pytest_jupyter/jupyter_client.py --- old/pytest_jupyter-0.6.2/pytest_jupyter/jupyter_client.py 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/pytest_jupyter/jupyter_client.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,3 +1,4 @@ +"""Fixtures for use with jupyter_client and downstream.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. @@ -24,6 +25,7 @@ @pytest.fixture def jp_zmq_context(): + """Get a zmq context.""" import zmq ctx = zmq.asyncio.Context() @@ -33,10 +35,12 @@ @pytest.fixture def jp_start_kernel(jp_environ, jp_asyncio_loop): + """Get a function to a kernel and clean up resources when done.""" kms = [] kcs = [] async def inner(kernel_name=NATIVE_KERNEL_NAME, **kwargs): + """A function used to start a kernel.""" km, kc = await start_new_async_kernel(kernel_name=kernel_name, **kwargs) kms.append(km) kcs.append(kc) @@ -49,4 +53,5 @@ for km in kms: jp_asyncio_loop.run_until_complete(km.shutdown_kernel(now=True)) - assert km.context.closed + if not km.context.closed: + raise AssertionError diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/pytest_jupyter/jupyter_core.py new/pytest_jupyter-0.7.0/pytest_jupyter/jupyter_core.py --- old/pytest_jupyter-0.6.2/pytest_jupyter/jupyter_core.py 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/pytest_jupyter/jupyter_core.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,3 +1,4 @@ +"""Fixtures for use with jupyter core and downstream.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import asyncio @@ -35,6 +36,7 @@ @pytest.fixture def jp_asyncio_loop(): + """Get an asyncio loop.""" if os.name == "nt": asyncio.set_event_loop_policy( asyncio.WindowsSelectorEventLoopPolicy() # type:ignore[attr-defined] @@ -51,6 +53,7 @@ if tornado is not installed.""" async def get_tornado_loop(): + """Asynchronously get a tornado loop.""" try: from tornado.ioloop import IOLoop @@ -111,11 +114,13 @@ @pytest.fixture() def jp_kernel_dir(jp_data_dir): + """Get the directory for kernel specs.""" return mkdir(jp_data_dir, "kernels") @pytest.fixture def echo_kernel_spec(jp_kernel_dir): + """Install a kernel spec for the echo kernel.""" test_dir = Path(jp_kernel_dir) / "echo" test_dir.mkdir(parents=True, exist_ok=True) argv = [sys.executable, "-m", "pytest_jupyter.echo_kernel", "-f", "{connection_file}"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/pytest_jupyter/jupyter_server.py new/pytest_jupyter-0.7.0/pytest_jupyter/jupyter_server.py --- old/pytest_jupyter-0.6.2/pytest_jupyter/jupyter_server.py 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/pytest_jupyter/jupyter_server.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,3 +1,4 @@ +"""Fixtures for use with jupyter server and downstream.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. @@ -30,7 +31,7 @@ from tornado.websocket import WebSocketHandler from traitlets.config import Config - is_v2 = version_info[0] == 2 + is_v2 = version_info[0] == 2 # noqa except ImportError: Authorizer = object # type:ignore @@ -59,6 +60,7 @@ """Start a tornado HTTP server that listens on all available interfaces.""" async def get_server(): + """Get a server asynchronously.""" server = tornado.httpserver.HTTPServer(jp_web_app) server.add_socket(http_server_port[0]) return server @@ -156,7 +158,7 @@ output = logging_stream.getvalue() # If output exists, print it. if output: - print(output) # noqa + print(output) return output @@ -353,8 +355,9 @@ urlparts = urllib.parse.urlparse(f"ws://localhost:{jp_http_port}") urlparts = urlparts._replace(path=base_path_url, query=urllib.parse.urlencode(params)) url = urlparts.geturl() - # Add auth keys to header - headers.update(jp_auth_header) + # Add auth keys to header, if not overridden + for key, value in jp_auth_header.items(): + headers.setdefault(key, value) # Make request. req = tornado.httpclient.HTTPRequest(url, headers=headers, connect_timeout=120) return tornado.websocket.websocket_connect(req) @@ -370,7 +373,8 @@ nbpath = jp_root_dir.joinpath(nbpath) # Check that the notebook has the correct file extension. if nbpath.suffix != ".ipynb": - raise Exception("File extension for notebook must be .ipynb") + msg = "File extension for notebook must be .ipynb" + raise Exception(msg) # If the notebook path has a parent directory, make sure it's created. parent = nbpath.parent parent.mkdir(parents=True, exist_ok=True) @@ -385,12 +389,13 @@ @pytest.fixture(autouse=True) def jp_server_cleanup(jp_asyncio_loop): + """Automatically cleans up server resources.""" yield app: ServerApp = ServerApp.instance() try: jp_asyncio_loop.run_until_complete(app._cleanup()) except (RuntimeError, SystemExit) as e: - print("ignoring cleanup error", e) # noqa + print("ignoring cleanup error", e) if hasattr(app, "kernel_manager"): app.kernel_manager.context.destroy() ServerApp.clear_instance() @@ -401,10 +406,7 @@ """Send to Jupyter Server and return response code.""" async def _(url, **fetch_kwargs): - if url.endswith("channels") or "/websocket/" in url: - fetch = jp_ws_fetch - else: - fetch = jp_fetch + fetch = jp_ws_fetch if url.endswith("channels") or "/websocket/" in url else jp_fetch try: r = await fetch(url, **fetch_kwargs, allow_nonstandard_methods=True) @@ -422,6 +424,7 @@ @pytest.fixture def jp_server_auth_core_resources(): + """The core auth resources for use with a server.""" modules = [] for mod_name in JUPYTER_SERVICE_HANDLERS.values(): if mod_name: @@ -438,10 +441,13 @@ @pytest.fixture def jp_server_auth_resources(jp_server_auth_core_resources): + """The auth resources used by the server.""" return jp_server_auth_core_resources class _Authorizer(Authorizer): + """A custom authorizer class for testing.""" + # Set these class attributes from within a test # to verify that they match the arguments passed # by the REST API. @@ -484,11 +490,9 @@ return path def is_authorized(self, handler, user, action, resource): + """Test if a request is authorized.""" # Parse Request - if isinstance(handler, WebSocketHandler): - method = "WEBSOCKET" - else: - method = handler.request.method + method = "WEBSOCKET" if isinstance(handler, WebSocketHandler) else handler.request.method url = self.normalize_url(handler.request.path) # Map request parts to expected action and resource. @@ -497,8 +501,8 @@ # Assert that authorization layer returns the # correct action + resource. - assert action == expected_action - assert resource == expected_resource + if action != expected_action or resource != expected_resource: + raise AssertionError # Now, actually apply the authorization layer. return all( @@ -511,6 +515,7 @@ @pytest.fixture def jp_server_authorizer(jp_server_auth_resources): + """An authorizer for the server.""" auth_klass = _Authorizer auth_klass._default_regex_mapping = jp_server_auth_resources return auth_klass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/pytest_jupyter/pytest_tornasync.py new/pytest_jupyter-0.7.0/pytest_jupyter/pytest_tornasync.py --- old/pytest_jupyter-0.6.2/pytest_jupyter/pytest_tornasync.py 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/pytest_jupyter/pytest_tornasync.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ -# Vendored fork of pytest_tornasync from -# https://github.com/eukaryote/pytest-tornasync/blob/9f1bdeec3eb5816e0183f975ca65b5f6f29fbfbb/src/pytest_tornasync/plugin.py - +"""Vendored fork of pytest_tornasync from + https://github.com/eukaryote/pytest-tornasync/blob/9f1bdeec3eb5816e0183f975ca65b5f6f29fbfbb/src/pytest_tornasync/plugin.py +""" from contextlib import closing from inspect import iscoroutinefunction @@ -16,12 +16,14 @@ @pytest.hookimpl(tryfirst=True) def pytest_pycollect_makeitem(collector, name, obj): + """Custom pytest collection hook.""" if collector.funcnamefilter(name) and iscoroutinefunction(obj): return list(collector._genfunctions(name, obj)) @pytest.hookimpl(tryfirst=True) def pytest_pyfunc_call(pyfuncitem): + """Custom pytest function call hook.""" funcargs = pyfuncitem.funcargs testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} @@ -53,6 +55,7 @@ """ async def get_client(): + """Get a client.""" return AsyncHTTPServerClient(http_server=http_server) client = io_loop.run_sync(get_client) @@ -61,7 +64,10 @@ class AsyncHTTPServerClient(SimpleAsyncHTTPClient): + """An async http server client.""" + def initialize(self, *, http_server=None): + """Initialize the client.""" super().initialize() self._http_server = http_server @@ -73,11 +79,14 @@ return super().fetch(self.get_url(path), **kwargs) def get_protocol(self): + """Get the protocol for the client.""" return "http" def get_http_port(self): + """Get a port for the client.""" for sock in self._http_server._sockets.values(): return sock.getsockname()[1] def get_url(self, path): + """Get the url for the client.""" return f"{self.get_protocol()}://127.0.0.1:{self.get_http_port()}{path}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/pytest_jupyter/utils.py new/pytest_jupyter-0.7.0/pytest_jupyter/utils.py --- old/pytest_jupyter-0.6.2/pytest_jupyter/utils.py 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/pytest_jupyter/utils.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,8 +1,10 @@ +"""Utilities for pytest-jupyter.""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. def mkdir(tmp_path, *parts): + """Make a directory given extra path parts.""" path = tmp_path.joinpath(*parts) if not path.exists(): path.mkdir(parents=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest_jupyter-0.6.2/tests/test_jupyter_server.py new/pytest_jupyter-0.7.0/tests/test_jupyter_server.py --- old/pytest_jupyter-0.6.2/tests/test_jupyter_server.py 2020-02-02 01:00:00.000000000 +0100 +++ new/pytest_jupyter-0.7.0/tests/test_jupyter_server.py 2020-02-02 01:00:00.000000000 +0100 @@ -20,12 +20,12 @@ async def test_get_api_spec(jp_fetch): response = await jp_fetch("api", "spec.yaml", method="GET") - assert response.code == 200 + assert response.code == 200 # noqa async def test_send_request(send_request): code = await send_request("api/spec.yaml", method="GET") - assert code == 200 + assert code == 200 # noqa async def test_connection(jp_fetch, jp_ws_fetch, jp_http_port, jp_auth_header):