diff --git a/.github/workflows/check-release.yml b/.github/workflows/check-release.yml index f93ffec5b..1cc04883b 100644 --- a/.github/workflows/check-release.yml +++ b/.github/workflows/check-release.yml @@ -3,7 +3,6 @@ on: push: branches: ["main"] pull_request: - branches: ["*"] concurrency: group: check-release-${{ github.ref }} diff --git a/.github/workflows/downstream.yml b/.github/workflows/downstream.yml index da53a0316..97957f15a 100644 --- a/.github/workflows/downstream.yml +++ b/.github/workflows/downstream.yml @@ -2,9 +2,8 @@ name: Test downstream projects on: push: - branches: "*" + branches: ["main"] pull_request: - branches: "*" concurrency: group: downstream-${{ github.ref }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fe4aa8c78..b6371119a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,6 +2,7 @@ name: CI on: push: + branches: ["main"] pull_request: concurrency: @@ -51,7 +52,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [3.6, 3.7, 3.8, 3.9, "3.10"] + python-version: [3.7, 3.8, 3.9, "3.10"] env: OS: ${{ matrix.os }} @@ -65,7 +66,7 @@ jobs: - name: Install dependencies run: | - pip install --upgrade --upgrade-strategy eager --pre -e .[test] + pip install -e .[test] pip freeze - name: Check types @@ -82,3 +83,36 @@ jobs: - name: Code coverage run: codecov + + test_miniumum_verisons: + name: Test Minimum Versions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + with: + python_version: "3.7" + - name: Install miniumum versions + uses: jupyterlab/maintainer-tools/.github/actions/install-minimums@v1 + - name: Run the unit tests + run: pytest -vv jupyter_client || pytest -vv jupyter_client --lf + + test_prereleases: + name: Test Prereleases + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + - name: Install the Python dependencies + run: | + pip install --upgrade --upgrade-strategy eager --pre -e ".[test]" + - name: List installed packages + run: | + pip freeze + pip check + - name: Run the tests + run: | + pytest -vv jupyter_client || pytest -vv jupyter_client --lf diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 200c35923..cf55d0568 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,23 +1,23 @@ repos: - repo: https://github.com/asottile/reorder_python_imports - rev: v1.9.0 + rev: v2.7.1 hooks: - id: reorder-python-imports - repo: https://github.com/psf/black - rev: 20.8b1 + rev: 22.1.0 hooks: - id: black args: ["--line-length", "100"] - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.2.1 + rev: v2.5.1 hooks: - id: prettier - repo: https://gitlab.com/pycqa/flake8 - rev: "3.8.4" + rev: "3.9.2" hooks: - id: flake8 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v4.1.0 hooks: - id: end-of-file-fixer - id: check-case-conflict diff --git a/jupyter_client/channels.py b/jupyter_client/channels.py index 943b51208..348f51ae9 100644 --- a/jupyter_client/channels.py +++ b/jupyter_client/channels.py @@ -217,7 +217,7 @@ async def _recv(self, **kwargs) -> t.Dict[str, t.Any]: return self.session.deserialize(smsg) async def get_msg(self, timeout: t.Optional[float] = None) -> t.Dict[str, t.Any]: - """ Gets a message if there is one that is ready. """ + """Gets a message if there is one that is ready.""" assert self.socket is not None if timeout is not None: timeout *= 1000 # seconds to ms @@ -230,7 +230,7 @@ async def get_msg(self, timeout: t.Optional[float] = None) -> t.Dict[str, t.Any] raise Empty async def get_msgs(self) -> t.List[t.Dict[str, t.Any]]: - """ Get all messages that are currently ready. """ + """Get all messages that are currently ready.""" msgs = [] while True: try: @@ -240,7 +240,7 @@ async def get_msgs(self) -> t.List[t.Dict[str, t.Any]]: return msgs async def msg_ready(self) -> bool: - """ Is there a message that has been received? """ + """Is there a message that has been received?""" assert self.socket is not None return bool(await self.socket.poll(timeout=0)) diff --git a/jupyter_client/session.py b/jupyter_client/session.py index 44f0a799d..f21a34a84 100644 --- a/jupyter_client/session.py +++ b/jupyter_client/session.py @@ -465,7 +465,7 @@ def _new_auth(self) -> None: digest_history = Set() digest_history_size = Integer( - 2 ** 16, + 2**16, config=True, help="""The maximum number of digests to remember. @@ -504,7 +504,7 @@ def _unpack_changed(self, change): # thresholds: copy_threshold = Integer( - 2 ** 16, + 2**16, config=True, help="Threshold (in bytes) beyond which a buffer should be sent without copying.", ) diff --git a/jupyter_client/ssh/tunnel.py b/jupyter_client/ssh/tunnel.py index 02dfbbd49..88e10323f 100644 --- a/jupyter_client/ssh/tunnel.py +++ b/jupyter_client/ssh/tunnel.py @@ -28,7 +28,6 @@ class SSHException(Exception): # type: ignore pass - else: from .forward import forward_tunnel diff --git a/jupyter_client/tests/test_connect.py b/jupyter_client/tests/test_connect.py index 7ae6618c2..8fbe0f2a8 100644 --- a/jupyter_client/tests/test_connect.py +++ b/jupyter_client/tests/test_connect.py @@ -84,7 +84,7 @@ def test_write_connection_file(): def test_load_connection_file_session(): - """test load_connection_file() after """ + """test load_connection_file() after""" session = Session() app = DummyConsoleApp(session=Session()) app.initialize(argv=[]) @@ -101,7 +101,7 @@ def test_load_connection_file_session(): def test_load_connection_file_session_with_kn(): - """test load_connection_file() after """ + """test load_connection_file() after""" session = Session() app = DummyConsoleApp(session=Session()) app.initialize(argv=[]) diff --git a/jupyter_client/tests/test_kernelmanager.py b/jupyter_client/tests/test_kernelmanager.py index ed7f7cb51..983ca8095 100644 --- a/jupyter_client/tests/test_kernelmanager.py +++ b/jupyter_client/tests/test_kernelmanager.py @@ -164,15 +164,17 @@ def test_signal_kernel_subprocesses(self, name, install, expected): kc.stop_channels() km.shutdown_kernel() - assert km._shutdown_status == expected + if expected == _ShutdownStatus.ShutdownRequest: + expected = [expected, _ShutdownStatus.SigtermRequest] + else: + expected = [expected] + + assert km._shutdown_status in expected @pytest.mark.asyncio @pytest.mark.skipif(sys.platform == "win32", reason="Windows doesn't support signals") @pytest.mark.parametrize(*parameters) async def test_async_signal_kernel_subprocesses(self, name, install, expected): - # ipykernel doesn't support 3.6 and this test uses async shutdown_request - if expected == _ShutdownStatus.ShutdownRequest and sys.version_info < (3, 7): - pytest.skip() install() km, kc = await start_new_async_kernel(kernel_name=name) assert km._shutdown_status == _ShutdownStatus.Unset @@ -181,7 +183,12 @@ async def test_async_signal_kernel_subprocesses(self, name, install, expected): kc.stop_channels() await km.shutdown_kernel() - assert km._shutdown_status == expected + if expected == _ShutdownStatus.ShutdownRequest: + expected = [expected, _ShutdownStatus.SigtermRequest] + else: + expected = [expected] + + assert km._shutdown_status in expected class TestKernelManager: diff --git a/jupyter_client/tests/test_manager.py b/jupyter_client/tests/test_manager.py index 4f62ca17b..e3d6ea222 100644 --- a/jupyter_client/tests/test_manager.py +++ b/jupyter_client/tests/test_manager.py @@ -10,7 +10,7 @@ def test_connection_file_real_path(): - """ Verify realpath is used when formatting connection file """ + """Verify realpath is used when formatting connection file""" with mock.patch("os.path.realpath") as patched_realpath: patched_realpath.return_value = "foobar" km = KernelManager( diff --git a/jupyter_client/tests/test_provisioning.py b/jupyter_client/tests/test_provisioning.py index f6db54c01..f8063f272 100644 --- a/jupyter_client/tests/test_provisioning.py +++ b/jupyter_client/tests/test_provisioning.py @@ -261,7 +261,7 @@ def test_get_new(self, kpf): class TestRuntime: async def akm_test(self, kernel_mgr): - """Starts a kernel, validates the associated provisioner's config, shuts down kernel """ + """Starts a kernel, validates the associated provisioner's config, shuts down kernel""" assert kernel_mgr.provisioner is None if kernel_mgr.kernel_name == 'missing_provisioner': diff --git a/jupyter_client/tests/test_session.py b/jupyter_client/tests/test_session.py index 82ad9e666..edf7a2bcd 100644 --- a/jupyter_client/tests/test_session.py +++ b/jupyter_client/tests/test_session.py @@ -185,7 +185,7 @@ def test_tracking(self): def test_unique_msg_ids(self): """test that messages receive unique ids""" ids = set() - for i in range(2 ** 12): + for i in range(2**12): h = self.session.msg_header("test") msg_id = h["msg_id"] self.assertTrue(msg_id not in ids) diff --git a/jupyter_client/tests/utils.py b/jupyter_client/tests/utils.py index ead0e2cdf..5ca313469 100644 --- a/jupyter_client/tests/utils.py +++ b/jupyter_client/tests/utils.py @@ -132,51 +132,51 @@ def wrapped(self, *args, **kwargs): class KMSubclass(RecordCallMixin): @subclass_recorder def start_kernel(self, **kw): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def shutdown_kernel(self, now=False, restart=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def restart_kernel(self, now=False, **kw): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def interrupt_kernel(self): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def request_shutdown(self, restart=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def finish_shutdown(self, waittime=None, pollinterval=0.1, restart=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def _launch_kernel(self, kernel_cmd, **kw): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def _kill_kernel(self): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def cleanup_resources(self, restart=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def signal_kernel(self, signum: int): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def is_alive(self): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def _send_kernel_sigterm(self, restart: bool = False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" class SyncKMSubclass(KMSubclass, KernelManager): @@ -197,43 +197,43 @@ def _kernel_manager_class_default(self): @subclass_recorder def get_kernel(self, kernel_id): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def remove_kernel(self, kernel_id): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def start_kernel(self, kernel_name=None, **kwargs): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def shutdown_kernel(self, kernel_id, now=False, restart=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def restart_kernel(self, kernel_id, now=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def interrupt_kernel(self, kernel_id): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def request_shutdown(self, kernel_id, restart=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def finish_shutdown(self, kernel_id, waittime=None, pollinterval=0.1, restart=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def cleanup_resources(self, kernel_id, restart=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" @subclass_recorder def shutdown_all(self, now=False): - """ Record call and defer to superclass """ + """Record call and defer to superclass""" class SyncMKMSubclass(MKMSubclass, MultiKernelManager): diff --git a/pyproject.toml b/pyproject.toml index d25777c06..2336b4ddd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,9 +2,10 @@ line-length = 100 skip-string-normalization = true target_version = [ - "py36", "py37", "py38", + "py39", + "py310", ] [tool.jupyter-releaser] diff --git a/requirements-test.txt b/requirements-test.txt index ae0f98712..f3d81fe98 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,6 +1,6 @@ codecov coverage -ipykernel +ipykernel>=5.5.6 ipython jedi<0.18; python_version<="3.6" mock diff --git a/requirements.txt b/requirements.txt index 9219c73b6..7c48249e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ entrypoints -jupyter_core>=4.6.0 -nest-asyncio>=1.5 +jupyter_core>=4.9.2 +nest-asyncio>=1.5.1 python-dateutil>=2.1 -pyzmq>=13 -tornado>=4.1 +pyzmq>=17 +tornado>=5.0 traitlets diff --git a/setup.py b/setup.py index f302e77b2..b14bf9a8c 100644 --- a/setup.py +++ b/setup.py @@ -48,12 +48,12 @@ 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', ], - python_requires='>=3.6.1', + python_requires='>=3.7', install_requires=requirements, extras_require={ 'test': requirements_test,