From 227d09b588ab45c5579047b1779315838c532859 Mon Sep 17 00:00:00 2001 From: philippe Date: Tue, 20 Oct 2026 11:59:12 -0400 Subject: [PATCH 1/2] Move plotly-cloud back to the optional cloud extra plotly-cloud is not on conda-forge, so as a hard dependency the dash conda-forge package can't be built for 4.5.0. It stays installable with dash[cloud], and Dash already handles it being absent. Reverts #3947. --- CHANGELOG.md | 1 - dash/_plotly_cli.py | 3 +-- requirements/install.txt | 1 - .../devtools/test_callback_validation.py | 2 +- tests/unit/test_plotly_cli.py | 24 +++++++++++++++++++ 5 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 tests/unit/test_plotly_cli.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed4634415..ec2d3eba34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). - [#4026](https://github.com/plotly/dash/pull/4026) Add `DASH_SHARED_STORAGE` to pick the shared-storage backend when the app does not pass `shared_storage=`: `local`, `none`, `diskcache:///abs/path`, or a `redis://` / `rediss://` URL. - [#4024](https://github.com/plotly/dash/pull/4024) Add support for social media meta tags in regular Dash apps using `app.title`, `app.description`, and `app.image`. - [#3976](https://github.com/plotly/dash/pull/3976) Add a new `scrollToTop` prop to `dcc.Link` to control whether the page scrolls to the top after client-side navigation. It defaults to `True` to preserve the existing behavior. Fixes [#3974](https://github.com/plotly/dash/issues/3974). -- [#3947](https://github.com/plotly/dash/pull/3947) Make `plotly-cloud` a default install dependency of Dash instead of an optional extra, so the `plotly` CLI and Dash's cloud integration work out of the box. The `dash[cloud]` extra is kept for backward compatibility. - [#3930](https://github.com/plotly/dash/pull/3930) Add shared storage: a backend-agnostic cross-process state manager (key/value with optional TTL, plus ordered replayable pub/sub) on every app via `dash.ctx.shared_storage`, started lazily and disabled with `shared_storage=None`. Ships `LocalSharedStorage` (default, in-memory with optional disk persistence), `DiskcacheSharedStorage`, and `RedisSharedStorage` for horizontally-scaled deployments; see `.ai/ARCHITECTURE.md`. - [#3931](https://github.com/plotly/dash/pull/3931) Add streaming callbacks: an `async def` generator callback streams its yields to the browser as they are produced (`dash.Patch` yields apply incrementally). A browser's streams share one SharedWorker-hosted connection so they do not count against the per-host connection limit; closing a tab cancels its streams. - [#3977](https://github.com/plotly/dash/pull/3977) Add partial WebSocket prop reads with `get_prop(..., path=...)`. Closes [#3975](https://github.com/plotly/dash/issues/3975). diff --git a/dash/_plotly_cli.py b/dash/_plotly_cli.py index 4456962746..9974cd23b9 100644 --- a/dash/_plotly_cli.py +++ b/dash/_plotly_cli.py @@ -9,8 +9,7 @@ def cli(): except ImportError: print( "Plotly cloud is not installed," - " install it with `pip install plotly-cloud` (or reinstall dash)" - " to use the plotly command", + " install it with `pip install dash[cloud]` to use the plotly command", file=sys.stderr, ) sys.exit(-1) diff --git a/requirements/install.txt b/requirements/install.txt index 71e0dafb32..795f0c85c8 100644 --- a/requirements/install.txt +++ b/requirements/install.txt @@ -1,7 +1,6 @@ Flask>=1.0.4,<3.2 Werkzeug<3.2 plotly>=5.0.0 -plotly-cloud importlib-metadata typing_extensions>=4.1.1 requests diff --git a/tests/integration/devtools/test_callback_validation.py b/tests/integration/devtools/test_callback_validation.py index e4f89432d5..33a5ad485d 100644 --- a/tests/integration/devtools/test_callback_validation.py +++ b/tests/integration/devtools/test_callback_validation.py @@ -33,7 +33,7 @@ def check_errors(dash_duo, specs): found = [] for i in range(cnt): msg = dash_duo.find_elements(".dash-fe-error__title")[i].text - # plotly-cloud (a default install dep) injects a `_plotly-cloud-*` + # plotly-cloud (installed with dash[cloud]) injects a `_plotly-cloud-*` # component into every layout via a dash_hooks entry point, so it # shows up in the "string ids in the current layout" list. Strip it # so these assertions hold whether or not plotly-cloud is installed. diff --git a/tests/unit/test_plotly_cli.py b/tests/unit/test_plotly_cli.py new file mode 100644 index 0000000000..9cbe34021e --- /dev/null +++ b/tests/unit/test_plotly_cli.py @@ -0,0 +1,24 @@ +import sys +from pathlib import Path + +import pytest + +from dash._plotly_cli import cli + + +def test_plotly_cli_hints_cloud_extra_when_missing(monkeypatch, capsys): + # A None entry in sys.modules makes the import raise ImportError. + monkeypatch.setitem(sys.modules, "plotly_cloud", None) + monkeypatch.setitem(sys.modules, "plotly_cloud.cli", None) + + with pytest.raises(SystemExit) as exc: + cli() + + assert exc.value.code == -1 + assert "pip install dash[cloud]" in capsys.readouterr().err + + +def test_plotly_cloud_is_not_an_install_requirement(): + install = Path(__file__).parents[2] / "requirements" / "install.txt" + required = install.read_text(encoding="utf-8").lower().split() + assert "plotly-cloud" not in required From 970c4fdeafd48096529fb4018de875fec8841b4c Mon Sep 17 00:00:00 2001 From: philippe Date: Tue, 20 Oct 2026 12:11:36 -0400 Subject: [PATCH 2/2] Keep the #3947 CHANGELOG entry and note the move back to dash[cloud] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec2d3eba34..5f53980dee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - [#4026](https://github.com/plotly/dash/pull/4026) Add `DASH_SHARED_STORAGE` to pick the shared-storage backend when the app does not pass `shared_storage=`: `local`, `none`, `diskcache:///abs/path`, or a `redis://` / `rediss://` URL. - [#4024](https://github.com/plotly/dash/pull/4024) Add support for social media meta tags in regular Dash apps using `app.title`, `app.description`, and `app.image`. - [#3976](https://github.com/plotly/dash/pull/3976) Add a new `scrollToTop` prop to `dcc.Link` to control whether the page scrolls to the top after client-side navigation. It defaults to `True` to preserve the existing behavior. Fixes [#3974](https://github.com/plotly/dash/issues/3974). +- [#3947](https://github.com/plotly/dash/pull/3947) Make `plotly-cloud` a default install dependency of Dash instead of an optional extra, so the `plotly` CLI and Dash's cloud integration work out of the box. The `dash[cloud]` extra is kept for backward compatibility. - [#3930](https://github.com/plotly/dash/pull/3930) Add shared storage: a backend-agnostic cross-process state manager (key/value with optional TTL, plus ordered replayable pub/sub) on every app via `dash.ctx.shared_storage`, started lazily and disabled with `shared_storage=None`. Ships `LocalSharedStorage` (default, in-memory with optional disk persistence), `DiskcacheSharedStorage`, and `RedisSharedStorage` for horizontally-scaled deployments; see `.ai/ARCHITECTURE.md`. - [#3931](https://github.com/plotly/dash/pull/3931) Add streaming callbacks: an `async def` generator callback streams its yields to the browser as they are produced (`dash.Patch` yields apply incrementally). A browser's streams share one SharedWorker-hosted connection so they do not count against the per-host connection limit; closing a tab cancels its streams. - [#3977](https://github.com/plotly/dash/pull/3977) Add partial WebSocket prop reads with `get_prop(..., path=...)`. Closes [#3975](https://github.com/plotly/dash/issues/3975). @@ -23,6 +24,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - [#3646](https://github.com/plotly/dash/pull/3646) Remove React 16 support (`16.14.0` is no longer an accepted value for `REACT_VERSION` / `_set_react_version`). ### Changed +- [#4073](https://github.com/plotly/dash/pull/4073) Move `plotly-cloud` back to the optional `dash[cloud]` extra (it was a default dependency in 4.5.0rc0/rc1), since it is not available on conda-forge. - [#4026](https://github.com/plotly/dash/pull/4026) Log a warning, once per process, when a streaming request is refused because its stream token failed verification, which on multi-worker deployments usually means the workers do not share a signing secret. - [#3987](https://github.com/plotly/dash/pull/3987) Forward FastAPI reload scope options (`reload_dirs`, `reload_excludes`, and `reload_includes`) to Uvicorn when reloading. - [#3986](https://github.com/plotly/dash/pull/3986) Adjust `_run_before_hooks` in the `fastapi` backend to honor a response returned by a `before_request` function, matching the `flask` backend's behavior.