diff --git a/continuous_integration/recipes/distributed/meta.yaml b/continuous_integration/recipes/distributed/meta.yaml index 7fa5a531caa..ad36ae83364 100644 --- a/continuous_integration/recipes/distributed/meta.yaml +++ b/continuous_integration/recipes/distributed/meta.yaml @@ -16,11 +16,6 @@ build: string: py_{{ GIT_DESCRIBE_HASH }}_{{ GIT_DESCRIBE_NUMBER }} noarch: python script: {{ PYTHON }} -m pip install . -vv --no-deps - entry_points: - # Old style CLI - - dask-scheduler = distributed.cli.dask_scheduler:main - - dask-ssh = distributed.cli.dask_ssh:main - - dask-worker = distributed.cli.dask_worker:main requirements: host: @@ -61,9 +56,6 @@ test: - distributed.protocol commands: - pip check - - dask-scheduler --help - - dask-ssh --help - - dask-worker --help - dask scheduler --help - dask ssh --help - dask worker --help diff --git a/distributed/cli/dask_scheduler.py b/distributed/cli/dask_scheduler.py index b2b846ee46f..5038d48b22d 100755 --- a/distributed/cli/dask_scheduler.py +++ b/distributed/cli/dask_scheduler.py @@ -7,12 +7,12 @@ import os import re import sys -import warnings import click from distributed import Scheduler from distributed._signals import wait_for_signals +from distributed.cli.utils import deprecated_option from distributed.compatibility import asyncio_run from distributed.config import get_loop_factory from distributed.preloading import validate_preload_argv @@ -81,11 +81,13 @@ "it possible for anyone with access to your dashboard address to run" "Python code", ) -@click.option("--show/--no-show", default=False, help="Show web UI [default: --show]") +@deprecated_option( + "--show/--no-show", default=False, help="Show web UI [default: --show]" +) @click.option( "--dashboard-prefix", type=str, default="", help="Prefix for the dashboard app" ) -@click.option( +@deprecated_option( "--use-xheaders", type=bool, default=False, @@ -124,10 +126,10 @@ def main( port, protocol, interface, - show, + show, # deprecated dashboard, dashboard_prefix, - use_xheaders, + use_xheaders, # deprecated pid_file, tls_ca_file, tls_cert, @@ -137,14 +139,6 @@ def main( **kwargs, ): """Launch a Dask scheduler.""" - - if "dask-scheduler" in sys.argv[0]: - warnings.warn( - "dask-scheduler is deprecated and will be removed in a future release; use `dask scheduler` instead", - FutureWarning, - stacklevel=1, - ) - g0, g1, g2 = gc.get_threshold() # https://github.com/dask/distributed/issues/1653 gc.set_threshold(g0 * 3, g1 * 3, g2 * 3) diff --git a/distributed/cli/dask_ssh.py b/distributed/cli/dask_ssh.py index 919f1911b87..7bd5320f658 100755 --- a/distributed/cli/dask_ssh.py +++ b/distributed/cli/dask_ssh.py @@ -1,8 +1,6 @@ from __future__ import annotations import logging -import sys -import warnings from textwrap import dedent import click @@ -146,13 +144,6 @@ def main( remote_dask_worker, local_directory, ): - if "dask-ssh" in sys.argv[0]: - warnings.warn( - "dask-ssh is deprecated and will be removed in a future release; use `dask ssh` instead", - FutureWarning, - stacklevel=1, - ) - try: hostnames = list(hostnames) if hostfile: diff --git a/distributed/cli/dask_worker.py b/distributed/cli/dask_worker.py index 4ba62426242..053f0cea6b3 100755 --- a/distributed/cli/dask_worker.py +++ b/distributed/cli/dask_worker.py @@ -6,7 +6,6 @@ import logging import os import sys -import warnings from collections.abc import Iterator from contextlib import suppress from typing import Any @@ -20,6 +19,7 @@ from distributed import Nanny from distributed._signals import wait_for_signals +from distributed.cli.utils import deprecated_option from distributed.comm import get_address_host_port from distributed.compatibility import asyncio_run from distributed.config import get_loop_factory @@ -180,8 +180,11 @@ default=None, help="Seconds to wait for a scheduler before closing", ) -@click.option( - "--dashboard-prefix", type=str, default="", help="Prefix for the dashboard" +@deprecated_option( # type: ignore[untyped-decorator] + "--dashboard-prefix", + type=str, + default=None, + help="Prefix for the dashboard", ) @click.option( "--lifetime", @@ -251,7 +254,7 @@ def main( # type: ignore[no-untyped-def] resources, dashboard, scheduler_file, - dashboard_prefix, + dashboard_prefix, # deprecated tls_ca_file, tls_cert, tls_key, @@ -262,13 +265,6 @@ def main( # type: ignore[no-untyped-def] ): """Launch a Dask worker attached to an existing scheduler""" - if "dask-worker" in sys.argv[0]: - warnings.warn( - "dask-worker is deprecated and will be removed in a future release; use `dask worker` instead", - FutureWarning, - stacklevel=1, - ) - g0, g1, g2 = gc.get_threshold() # https://github.com/dask/distributed/issues/1653 gc.set_threshold(g0 * 3, g1 * 3, g2 * 3) diff --git a/distributed/cli/tests/test_dask_scheduler.py b/distributed/cli/tests/test_dask_scheduler.py index 6f35089c342..d593d50caad 100644 --- a/distributed/cli/tests/test_dask_scheduler.py +++ b/distributed/cli/tests/test_dask_scheduler.py @@ -51,6 +51,7 @@ async def f(): assert _get_dashboard_port(c) == 8787 +@pytest.mark.slow def test_hostport(loop): port = open_port() with popen( @@ -686,22 +687,3 @@ def test_signal_handling(loop, sig): assert scheduler.returncode == 0 assert "scheduler closing" in logs assert "end scheduler" in logs - - -@pytest.mark.skipif(WINDOWS, reason="POSIX only") -def test_single_executable_deprecated(loop): - port = open_port() - with popen( - [ - "dask-scheduler", - "--no-dashboard", - f"--port={port}", - ], - capture_output=True, - ) as scheduler: - with Client(f"127.0.0.1:{port}", loop=loop) as c: - pass - scheduler.send_signal(signal.SIGTERM) - stdout, stderr = scheduler.communicate() - logs = stdout.decode() - assert "FutureWarning: dask-scheduler is deprecated" in logs diff --git a/distributed/cli/tests/test_dask_worker.py b/distributed/cli/tests/test_dask_worker.py index ac50ceeda8d..bd12f8fc453 100644 --- a/distributed/cli/tests/test_dask_worker.py +++ b/distributed/cli/tests/test_dask_worker.py @@ -21,7 +21,6 @@ from distributed.utils import get_ip, open_port from distributed.utils_test import ( gen_cluster, - inc, popen, requires_ipv6, wait_for_log_line, @@ -812,20 +811,3 @@ def test_error_during_startup(monkeypatch, nanny, loop): ], ) as worker: assert worker.wait(10) == 1 - - -def test_single_executable_deprecated(): - assert ( - b"FutureWarning: dask-worker is deprecated" - in subprocess.run(["dask-worker"], capture_output=True).stderr - ) - - -@pytest.mark.slow -@gen_cluster(nthreads=[], client=True) -async def test_single_executable_works(c, s): - with popen(["dask-worker", s.address]): - # make sure the worker still works - await c.wait_for_workers(1) - results = await c.submit(inc, 1).result() - assert results == 2 diff --git a/distributed/cli/tests/test_tls_cli.py b/distributed/cli/tests/test_tls_cli.py index bca053ba2cc..196e5baa506 100644 --- a/distributed/cli/tests/test_tls_cli.py +++ b/distributed/cli/tests/test_tls_cli.py @@ -3,6 +3,8 @@ import sys from time import sleep +import pytest + from distributed import Client from distributed.metrics import time from distributed.utils import open_port @@ -75,6 +77,7 @@ def test_sni(loop): wait_for_cores(c) +@pytest.mark.slow def test_nanny(loop): port = open_port() with popen( diff --git a/distributed/cli/utils.py b/distributed/cli/utils.py index 47a06e2571b..03169b70221 100644 --- a/distributed/cli/utils.py +++ b/distributed/cli/utils.py @@ -1,38 +1,17 @@ from __future__ import annotations -import warnings +import importlib.metadata +from functools import wraps +from typing import Any -from tornado.ioloop import IOLoop +import click -warnings.warn( - "the distributed.cli.utils module is deprecated", DeprecationWarning, stacklevel=2 -) +CLICK_VERSION = tuple(map(int, importlib.metadata.version("click").split(".")[:2])) -def install_signal_handlers(loop=None, cleanup=None): - """ - Install global signal handlers to halt the Tornado IOLoop in case of - a SIGINT or SIGTERM. *cleanup* is an optional callback called, - before the loop stops, with a single signal number argument. - """ - import signal - - loop = loop or IOLoop.current() - - old_handlers = {} - - def handle_signal(sig, frame): - async def cleanup_and_stop(): - try: - if cleanup is not None: - await cleanup(sig) - finally: - loop.stop() - - loop.add_callback_from_signal(cleanup_and_stop) - # Restore old signal handler to allow for a quicker exit - # if the user sends the signal again. - signal.signal(sig, old_handlers[sig]) - - for sig in [signal.SIGINT, signal.SIGTERM]: - old_handlers[sig] = signal.signal(sig, handle_signal) +@wraps(click.option) +def deprecated_option(*args: Any, **kwargs: Any) -> Any: + if CLICK_VERSION >= (8, 2): + return click.option(*args, **kwargs, deprecated=True) + help = kwargs.pop("help", "") + "(DEPRECATED)" + return click.option(*args, help=help, **kwargs) diff --git a/distributed/deploy/old_ssh.py b/distributed/deploy/old_ssh.py index c3527e4e80d..ec7c01fca9b 100644 --- a/distributed/deploy/old_ssh.py +++ b/distributed/deploy/old_ssh.py @@ -18,7 +18,7 @@ # These are handy for creating colorful terminal output to enhance readability -# of the output generated by dask-ssh. +# of the output generated by dask ssh. class bcolors: HEADER = "\033[95m" OKBLUE = "\033[94m" diff --git a/distributed/nanny.py b/distributed/nanny.py index 4d54666b63c..53d1dffe636 100644 --- a/distributed/nanny.py +++ b/distributed/nanny.py @@ -102,7 +102,7 @@ class Nanny(ServerNode): For the same reason, be warned that changing ``distributed.worker.multiprocessing-method`` from ``spawn`` to ``fork`` or ``forkserver`` may inhibit some environment variables; if you do, you should - set the variables yourself in the shell before you start ``dask-worker``. + set the variables yourself in the shell before you start ``dask worker``. See Also -------- diff --git a/distributed/utils_test.py b/distributed/utils_test.py index 581824b4621..2d2d828a492 100644 --- a/distributed/utils_test.py +++ b/distributed/utils_test.py @@ -1202,12 +1202,14 @@ def popen( if not os.path.isabs(executable_path): executable_path = os.path.join(sysconfig.get_path("scripts"), executable_path) - # On Windows, it's valid to start a process using only '{program-name}' and Windows will - # automatically find and execute '{program-name}.exe'. + # On Windows, it's valid to start a process using only '{program-name}' and Windows + # will automatically find and execute '{program-name}.exe'. # - # That allows e.g. `popen(["dask-worker"])` to work despite the installed file being called 'dask-worker.exe'. + # That allows e.g. `popen(["dask", "worker"])` to work despite the installed file + # being called 'dask.exe'. # - # docs: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw + # docs: + # https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw # if WINDOWS: executable_exists = os.path.isfile(executable_path) or os.path.isfile( diff --git a/pyproject.toml b/pyproject.toml index 280c04923cd..e3e8157ce9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,11 +55,6 @@ worker = "distributed.cli.dask_worker:main" ssh = "distributed.cli.dask_ssh:main" spec = "distributed.cli.dask_spec:main" -[project.scripts] -dask-ssh = "distributed.cli.dask_ssh:main" -dask-scheduler = "distributed.cli.dask_scheduler:main" -dask-worker = "distributed.cli.dask_worker:main" - [tool.setuptools.packages.find] exclude = ["*tests*"] namespaces = false