From f2ec33e17d9ec20255b127e2ea494997cff93514 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 31 Oct 2022 05:32:16 -0500 Subject: [PATCH 1/3] support python 3.8-3.11 --- .github/workflows/main.yml | 6 +++--- .readthedocs.yaml | 2 +- pyproject.toml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7ea63e53d..59fb8215a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,14 +41,14 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.7", "3.10"] + python-version: ["3.8", "3.11"] include: - os: windows-latest python-version: "3.9" - os: ubuntu-latest python-version: "pypy-3.8" - os: ubuntu-latest - python-version: "3.11-dev" + python-version: "3.10" - os: macos-latest python-version: "3.8" steps: @@ -86,7 +86,7 @@ jobs: - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 with: - python_version: "3.7" + python_version: "3.8" - name: Install miniumum versions uses: jupyterlab/maintainer-tools/.github/actions/install-minimums@v1 - name: Run the unit tests diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 856ac9b4d..5e5abeddb 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -2,7 +2,7 @@ version: 2 sphinx: configuration: docs/conf.py python: - version: 3.7 + version: 3.8 install: # install jupyter-client itself - method: pip diff --git a/pyproject.toml b/pyproject.toml index 240179ff0..416fad7aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,12 +17,12 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ] -requires-python = ">=3.7" +requires-python = ">=3.8" dependencies = [ "entrypoints", "jupyter_core>=4.9.2", From 58e4b1103936aaf2bfe1a2129d6a956ffa4f212f Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 31 Oct 2022 16:57:32 -0500 Subject: [PATCH 2/3] run pyupgrade --- .pre-commit-config.yaml | 6 ++++++ jupyter_client/adapter.py | 2 +- jupyter_client/channels.py | 2 +- jupyter_client/channelsabc.py | 2 +- jupyter_client/clientabc.py | 2 +- jupyter_client/connect.py | 8 ++++---- jupyter_client/consoleapp.py | 4 ++-- jupyter_client/kernelspec.py | 10 ++++------ jupyter_client/kernelspecapp.py | 4 ++-- jupyter_client/localinterfaces.py | 6 +++--- jupyter_client/managerabc.py | 2 +- jupyter_client/multikernelmanager.py | 2 +- jupyter_client/session.py | 2 +- jupyter_client/ssh/tunnel.py | 4 ++-- jupyter_client/threaded.py | 2 +- jupyter_client/utils.py | 4 +--- tests/test_connect.py | 4 ++-- tests/test_jsonutil.py | 6 +++--- tests/test_kernelapp.py | 4 ++-- tests/utils.py | 2 +- 20 files changed, 40 insertions(+), 38 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1ff5215a7..a89198435 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,6 +37,12 @@ repos: hooks: - id: mdformat + - repo: https://github.com/asottile/pyupgrade + rev: v3.1.0 + hooks: + - id: pyupgrade + args: [--py38-plus] + - repo: https://github.com/PyCQA/doc8 rev: v1.0.0 hooks: diff --git a/jupyter_client/adapter.py b/jupyter_client/adapter.py index 6ae357953..3c229e8c7 100644 --- a/jupyter_client/adapter.py +++ b/jupyter_client/adapter.py @@ -56,7 +56,7 @@ def extract_oname_v4(code: str, cursor_pos: int) -> str: return "" -class Adapter(object): +class Adapter: """Base class for adapting messages Override message_type(msg) methods to create adapters. diff --git a/jupyter_client/channels.py b/jupyter_client/channels.py index 978cf6824..1daf322e8 100644 --- a/jupyter_client/channels.py +++ b/jupyter_client/channels.py @@ -191,7 +191,7 @@ def call_handlers(self, since_last_heartbeat: float) -> None: HBChannelABC.register(HBChannel) -class ZMQSocketChannel(object): +class ZMQSocketChannel: """A ZMQ socket wrapper""" def __init__(self, socket: zmq.Socket, session: Session, loop: t.Any = None) -> None: diff --git a/jupyter_client/channelsabc.py b/jupyter_client/channelsabc.py index aee5d9d60..ce502a39c 100644 --- a/jupyter_client/channelsabc.py +++ b/jupyter_client/channelsabc.py @@ -4,7 +4,7 @@ import abc -class ChannelABC(object, metaclass=abc.ABCMeta): +class ChannelABC(metaclass=abc.ABCMeta): """A base class for all channel ABCs.""" @abc.abstractmethod diff --git a/jupyter_client/clientabc.py b/jupyter_client/clientabc.py index 8227cb377..88d5e7d9b 100644 --- a/jupyter_client/clientabc.py +++ b/jupyter_client/clientabc.py @@ -15,7 +15,7 @@ # ----------------------------------------------------------------------------- -class KernelClientABC(object, metaclass=abc.ABCMeta): +class KernelClientABC(metaclass=abc.ABCMeta): """KernelManager ABC. The docstrings for this class can be found in the base implementation: diff --git a/jupyter_client/connect.py b/jupyter_client/connect.py index f9c98bbd1..8ce3fe03b 100644 --- a/jupyter_client/connect.py +++ b/jupyter_client/connect.py @@ -130,7 +130,7 @@ def write_connection_file( else: N = 1 for _ in range(ports_needed): - while os.path.exists("%s-%s" % (ip, str(N))): + while os.path.exists(f"{ip}-{str(N)}"): N += 1 ports.append(N) N += 1 @@ -229,7 +229,7 @@ def find_connection_file( try: # first, try explicit name return _filefind(filename, path) - except IOError: + except OSError: pass # not found by full name @@ -247,7 +247,7 @@ def find_connection_file( matches = [os.path.abspath(m) for m in matches] if not matches: - raise IOError("Could not find %r in %r" % (filename, path)) + raise OSError(f"Could not find {filename!r} in {path!r}") elif len(matches) == 1: return matches[0] else: @@ -605,7 +605,7 @@ def _make_url(self, channel: str) -> str: if transport == "tcp": return "tcp://%s:%i" % (ip, port) else: - return "%s://%s-%s" % (transport, ip, port) + return f"{transport}://{ip}-{port}" def _create_connected_socket( self, channel: str, identity: Optional[bytes] = None diff --git a/jupyter_client/consoleapp.py b/jupyter_client/consoleapp.py index 3e9b37561..c8b0cc13b 100644 --- a/jupyter_client/consoleapp.py +++ b/jupyter_client/consoleapp.py @@ -202,7 +202,7 @@ def init_connection_file(self) -> None: self.connection_file = cf try: self.connection_file = _filefind(self.connection_file, [".", self.runtime_dir]) - except IOError: + except OSError: self.log.debug("Connection File not found: %s", self.connection_file) return @@ -247,7 +247,7 @@ def init_ssh(self) -> None: control_port=self.control_port, ) - self.log.info("Forwarding connections to %s via %s" % (ip, self.sshserver)) + self.log.info(f"Forwarding connections to {ip} via {self.sshserver}") # tunnels return a new set of ports, which will be on localhost: self.ip = localhost() diff --git a/jupyter_client/kernelspec.py b/jupyter_client/kernelspec.py index 3ab07937e..7bc615d3d 100644 --- a/jupyter_client/kernelspec.py +++ b/jupyter_client/kernelspec.py @@ -47,7 +47,7 @@ def from_resource_dir(cls, resource_dir): Pass the path to the *directory* containing kernel.json. """ kernel_file = pjoin(resource_dir, "kernel.json") - with io.open(kernel_file, "r", encoding="utf-8") as f: + with open(kernel_file, encoding="utf-8") as f: kernel_dict = json.load(f) return cls(resource_dir=resource_dir, **kernel_dict) @@ -106,7 +106,7 @@ def _list_kernels_in(dir): key = f.lower() if not _is_valid_kernel_name(key): warnings.warn( - "Invalid kernelspec directory name (%s): %s" % (_kernel_name_description, path), + f"Invalid kernelspec directory name ({_kernel_name_description}): {path}", stacklevel=3, ) kernels[key] = path @@ -118,7 +118,7 @@ def __init__(self, name): self.name = name def __str__(self): - return "No such kernel named {}".format(self.name) + return f"No such kernel named {self.name}" class KernelSpecManager(LoggingConfigurable): @@ -375,9 +375,7 @@ def install_kernel_spec( kernel_name = os.path.basename(source_dir) kernel_name = kernel_name.lower() if not _is_valid_kernel_name(kernel_name): - raise ValueError( - "Invalid kernel name %r. %s" % (kernel_name, _kernel_name_description) - ) + raise ValueError(f"Invalid kernel name {kernel_name!r}. {_kernel_name_description}") if user and prefix: raise ValueError("Can't specify both user and prefix. Please choose one or the other.") diff --git a/jupyter_client/kernelspecapp.py b/jupyter_client/kernelspecapp.py index 2e58ed280..e7430d172 100644 --- a/jupyter_client/kernelspecapp.py +++ b/jupyter_client/kernelspecapp.py @@ -63,7 +63,7 @@ def path_key(item): print("Available kernels:") for kernelname, path in sorted(paths.items(), key=path_key): - print(" %s %s" % (kernelname.ljust(name_len), path)) + print(f" {kernelname.ljust(name_len)} {path}") else: print(json.dumps({"kernelspecs": specs}, indent=2)) @@ -205,7 +205,7 @@ def start(self): if not (self.force or self.answer_yes): print("Kernel specs to remove:") for name in self.spec_names: - print(" %s\t%s" % (name.ljust(20), spec_paths[name])) + print(f" {name.ljust(20)}\t{spec_paths[name]}") answer = input("Remove %i kernel specs [y/N]: " % len(self.spec_names)) if not answer.lower().startswith("y"): return diff --git a/jupyter_client/localinterfaces.py b/jupyter_client/localinterfaces.py index ba06de3d2..a173e912e 100644 --- a/jupyter_client/localinterfaces.py +++ b/jupyter_client/localinterfaces.py @@ -41,7 +41,7 @@ def _get_output(cmd): p = Popen(cmd, stdout=PIPE, stderr=PIPE, startupinfo=startupinfo) stdout, stderr = p.communicate() if p.returncode: - raise IOError("Failed to run %s: %s" % (cmd, stderr.decode("utf8", "replace"))) + raise OSError("Failed to run {}: {}".format(cmd, stderr.decode("utf8", "replace"))) return stdout.decode("utf8", "replace") @@ -188,7 +188,7 @@ def _load_ips_gethostbyname(): global LOCALHOST try: LOCAL_IPS[:] = socket.gethostbyname_ex("localhost")[2] - except socket.error: + except OSError: # assume common default LOCAL_IPS[:] = ["127.0.0.1"] @@ -198,7 +198,7 @@ def _load_ips_gethostbyname(): # try hostname.local, in case hostname has been short-circuited to loopback if not hostname.endswith(".local") and all(ip.startswith("127") for ip in PUBLIC_IPS): PUBLIC_IPS[:] = socket.gethostbyname_ex(socket.gethostname() + ".local")[2] - except socket.error: + except OSError: pass finally: PUBLIC_IPS[:] = _uniq_stable(PUBLIC_IPS) diff --git a/jupyter_client/managerabc.py b/jupyter_client/managerabc.py index 138485e2c..8a6ea1d34 100644 --- a/jupyter_client/managerabc.py +++ b/jupyter_client/managerabc.py @@ -4,7 +4,7 @@ import abc -class KernelManagerABC(object, metaclass=abc.ABCMeta): +class KernelManagerABC(metaclass=abc.ABCMeta): """KernelManager ABC. The docstrings for this class can be found in the base implementation: diff --git a/jupyter_client/multikernelmanager.py b/jupyter_client/multikernelmanager.py index 5a2ffb5f3..738de5652 100644 --- a/jupyter_client/multikernelmanager.py +++ b/jupyter_client/multikernelmanager.py @@ -353,7 +353,7 @@ def signal_kernel(self, kernel_id: str, signum: int) -> None: signum : int Signal number to send kernel. """ - self.log.info("Signaled Kernel %s with %s" % (kernel_id, signum)) + self.log.info(f"Signaled Kernel {kernel_id} with {signum}") async def _async_restart_kernel(self, kernel_id: str, now: bool = False) -> None: """Restart a kernel by its uuid, keeping the same ports. diff --git a/jupyter_client/session.py b/jupyter_client/session.py index 4a2ebda77..d499a7a8c 100644 --- a/jupyter_client/session.py +++ b/jupyter_client/session.py @@ -240,7 +240,7 @@ def __init__(self, **kwargs): self.session = Session(**kwargs) -class Message(object): +class Message: """A simple message object that maps dict keys to attributes. A Message can be created from a dict and a dict from a Message instance diff --git a/jupyter_client/ssh/tunnel.py b/jupyter_client/ssh/tunnel.py index a465d16cd..84053e2d0 100644 --- a/jupyter_client/ssh/tunnel.py +++ b/jupyter_client/ssh/tunnel.py @@ -54,7 +54,7 @@ def select_random_ports(n): # ----------------------------------------------------------------------------- # Check for passwordless login # ----------------------------------------------------------------------------- -_password_pat = re.compile((r"pass(word|phrase):".encode("utf8")), re.IGNORECASE) +_password_pat = re.compile((br"pass(word|phrase):"), re.IGNORECASE) def try_passwordless_ssh(server, keyfile, paramiko=None): @@ -227,7 +227,7 @@ def openssh_tunnel( server, port = server.split(":") ssh += " -p %s" % port - cmd = "%s -O check %s" % (ssh, server) + cmd = f"{ssh} -O check {server}" (output, exitstatus) = pexpect.run(cmd, withexitstatus=True) if not exitstatus: pid = int(output[output.find(b"(pid=") + 5 : output.find(b")")]) # noqa diff --git a/jupyter_client/threaded.py b/jupyter_client/threaded.py index ca61ff781..29bcc7c9b 100644 --- a/jupyter_client/threaded.py +++ b/jupyter_client/threaded.py @@ -26,7 +26,7 @@ # during garbage collection of threads at exit -class ThreadedZMQSocketChannel(object): +class ThreadedZMQSocketChannel: """A ZMQ socket invoking a callback in the ioloop""" session = None diff --git a/jupyter_client/utils.py b/jupyter_client/utils.py index d94654d88..84a19616c 100644 --- a/jupyter_client/utils.py +++ b/jupyter_client/utils.py @@ -134,9 +134,7 @@ def _filefind(filename, path_dirs=None): if os.path.isfile(testname): return os.path.abspath(testname) - raise IOError( - "File {!r} does not exist in any of the search paths: {!r}".format(filename, path_dirs) - ) + raise OSError(f"File {filename!r} does not exist in any of the search paths: {path_dirs!r}") def _expand_path(s): diff --git a/tests/test_connect.py b/tests/test_connect.py index 7075c9d91..8a237de76 100644 --- a/tests/test_connect.py +++ b/tests/test_connect.py @@ -77,7 +77,7 @@ def test_write_connection_file(): cf = os.path.join(d, "kernel.json") connect.write_connection_file(cf, **sample_info) assert os.path.exists(cf) - with open(cf, "r") as f: + with open(cf) as f: info = json.load(f) info["key"] = info["key"].encode() assert info == sample_info @@ -129,7 +129,7 @@ def test_app_load_connection_file(): if attr in ("key", "signature_scheme"): continue value = getattr(app, attr) - assert value == expected, "app.%s = %s != %s" % (attr, value, expected) + assert value == expected, f"app.{attr} = {value} != {expected}" def test_load_connection_info(): diff --git a/tests/test_jsonutil.py b/tests/test_jsonutil.py index ef739b936..52f735dde 100644 --- a/tests/test_jsonutil.py +++ b/tests/test_jsonutil.py @@ -17,7 +17,7 @@ REFERENCE_DATETIME = datetime.datetime(2013, 7, 3, 16, 34, 52, 249482, tzlocal()) -class MyInt(object): +class MyInt: def __int__(self): return 389 @@ -25,7 +25,7 @@ def __int__(self): numbers.Integral.register(MyInt) -class MyFloat(object): +class MyFloat: def __float__(self): return 3.14 @@ -113,7 +113,7 @@ def test_json_default(): # Containers ([1, 2], None), ((1, 2), [1, 2]), - (set([1, 2]), [1, 2]), + ({1, 2}, [1, 2]), (dict(x=1), None), ({'x': 1, 'y': [1, 2, 3], '1': 'int'}, None), # More exotic objects diff --git a/tests/test_kernelapp.py b/tests/test_kernelapp.py index 702e2b375..b214ef545 100644 --- a/tests/test_kernelapp.py +++ b/tests/test_kernelapp.py @@ -39,7 +39,7 @@ def test_kernelapp_lifecycle(): break time.sleep(1 / POLL_FREQ) else: - raise AssertionError("No started file created in {} seconds".format(WAIT_TIME)) + raise AssertionError(f"No started file created in {WAIT_TIME} seconds") # Connection file should be there by now for _ in range(WAIT_TIME * POLL_FREQ): @@ -48,7 +48,7 @@ def test_kernelapp_lifecycle(): break time.sleep(1 / POLL_FREQ) else: - raise AssertionError("No connection file created in {} seconds".format(WAIT_TIME)) + raise AssertionError(f"No connection file created in {WAIT_TIME} seconds") assert len(files) == 1 cf = files[0] assert cf.startswith("kernel") diff --git a/tests/utils.py b/tests/utils.py index 317fdce7f..6591a5558 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -40,7 +40,7 @@ def install_kernel(kernels_dir, argv=None, name="test", display_name=None): return kernel_dir -class test_env(object): +class test_env: """Set Jupyter path variables to a temporary directory Useful as a context manager or with explicit start/stop From 269602b68fa678dea93be46ff08989e526ad4e4b Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 31 Oct 2022 17:16:56 -0500 Subject: [PATCH 3/3] lint --- jupyter_client/kernelspec.py | 1 - 1 file changed, 1 deletion(-) diff --git a/jupyter_client/kernelspec.py b/jupyter_client/kernelspec.py index 7bc615d3d..d4b79f33e 100644 --- a/jupyter_client/kernelspec.py +++ b/jupyter_client/kernelspec.py @@ -1,7 +1,6 @@ """Tools for managing kernel specs""" # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -import io import json import os import re