From b0f4c04735949f1bb6598e2778554cac11b641bc Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Fri, 26 Sep 2025 11:25:17 +0100 Subject: [PATCH 01/23] replace direct download of nyc_data with hvsampledata --- datashader/__init__.py | 11 ++- examples/datasets.yml | 8 -- examples/getting_started/1_Introduction.ipynb | 15 +--- examples/taxi_preprocessing_example.py | 75 ------------------- pixi.toml | 2 + scripts/download_data.py | 7 +- 6 files changed, 11 insertions(+), 107 deletions(-) delete mode 100644 examples/datasets.yml delete mode 100644 examples/taxi_preprocessing_example.py diff --git a/datashader/__init__.py b/datashader/__init__.py index c06d5a30c..1c66ab6e7 100644 --- a/datashader/__init__.py +++ b/datashader/__init__.py @@ -17,19 +17,18 @@ if Version(pandas_version) >= Version('0.24.0'): from . import datatypes # noqa (API import) -# make pyct's example/data commands available if possible +# make pyct's example commands available if possible from functools import partial try: - from pyct.cmd import copy_examples as _copy, fetch_data as _fetch, examples as _examples + from pyct.cmd import copy_examples as _copy, examples as _examples copy_examples = partial(_copy,'datashader') - fetch_data = partial(_fetch,'datashader') examples = partial(_examples,'datashader') except ImportError: def _missing_cmd(*args,**kw): return("install pyct to enable this command (e.g. `conda install pyct or " "`pip install pyct[cmd]`)") - _copy = _fetch = _examples = _missing_cmd + _copy = _examples = _missing_cmd def err(): raise ValueError(_missing_cmd()) - fetch_data = copy_examples = examples = err -del partial, _examples, _copy, _fetch + copy_examples = examples = err +del partial, _examples, _copy diff --git a/examples/datasets.yml b/examples/datasets.yml deleted file mode 100644 index 2f7236e0d..000000000 --- a/examples/datasets.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- - -data: - - - url: http://s3.amazonaws.com/datashader-data/nyc_taxi.zip - title: 'NYC Taxi Data' - files: - - nyc_taxi.csv diff --git a/examples/getting_started/1_Introduction.ipynb b/examples/getting_started/1_Introduction.ipynb index d00c954a5..91751db57 100644 --- a/examples/getting_started/1_Introduction.ipynb +++ b/examples/getting_started/1_Introduction.ipynb @@ -24,22 +24,13 @@ "metadata": {}, "outputs": [], "source": [ - "import datashader as ds, pandas as pd, colorcet as cc\n", + "import datashader as ds, colorcet as cc\n", + "import hvsampledata as hvs\n", "\n", - "df = pd.read_csv('../data/nyc_taxi.csv', usecols=['dropoff_x', 'dropoff_y'])\n", + "df = hvs.nyc_taxi(\"pandas\", engine_kwargs={\"columns\": ['dropoff_x', 'dropoff_y']})\n", "df.head()" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{note}\n", - "The file `nyc_taxi.csv` used above is located at\n", - "[nyc_taxi.csv](https://github.com/holoviz/datashader/blob/main/examples/data/.data_stubs/nyc_taxi.csv) in the Datashader repository. When running this example, make sure the file is available locally and update the path accordingly.\n", - ":::\n" - ] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/examples/taxi_preprocessing_example.py b/examples/taxi_preprocessing_example.py deleted file mode 100644 index f16488f5e..000000000 --- a/examples/taxi_preprocessing_example.py +++ /dev/null @@ -1,75 +0,0 @@ -"""Download data needed for the examples""" - -from __future__ import annotations - -if __name__ == "__main__": - - from os import path, makedirs, remove - from download_sample_data import bar as progressbar - - import pandas as pd - import numpy as np - import sys - - try: - import requests - except ImportError: - print('Download script required requests package: conda install requests') - sys.exit(1) - - def _download_dataset(url): - r = requests.get(url, stream=True) - output_path = path.split(url)[1] - with open(output_path, 'wb') as f: - total_length = int(r.headers.get('content-length')) - for chunk in progressbar(r.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1): - if chunk: - f.write(chunk) - f.flush() - - examples_dir = path.dirname(path.realpath(__file__)) - data_dir = path.join(examples_dir, 'data') - if not path.exists(data_dir): - makedirs(data_dir) - - # Taxi data - def latlng_to_meters(df, lat_name, lng_name): - lat = df[lat_name] - lng = df[lng_name] - origin_shift = 2 * np.pi * 6378137 / 2.0 - mx = lng * origin_shift / 180.0 - my = np.log(np.tan((90 + lat) * np.pi / 360.0)) / (np.pi / 180.0) - my = my * origin_shift / 180.0 - df.loc[:, lng_name] = mx - df.loc[:, lat_name] = my - - taxi_path = path.join(data_dir, 'nyc_taxi.csv') - if not path.exists(taxi_path): - print("Downloading Taxi Data...") - url = ('https://storage.googleapis.com/tlc-trip-data/2015/' - 'yellow_tripdata_2015-01.csv') - - _download_dataset(url) - df = pd.read_csv('yellow_tripdata_2015-01.csv') - - print('Filtering Taxi Data') - df = df.loc[(df.pickup_longitude < -73.75) & - (df.pickup_longitude > -74.15) & - (df.dropoff_longitude < -73.75) & - (df.dropoff_longitude > -74.15) & - (df.pickup_latitude > 40.68) & - (df.pickup_latitude < 40.84) & - (df.dropoff_latitude > 40.68) & - (df.dropoff_latitude < 40.84)].copy() - - print('Reprojecting Taxi Data') - latlng_to_meters(df, 'pickup_latitude', 'pickup_longitude') - latlng_to_meters(df, 'dropoff_latitude', 'dropoff_longitude') - df.rename(columns={'pickup_longitude': 'pickup_x', 'dropoff_longitude': 'dropoff_x', - 'pickup_latitude': 'pickup_y', 'dropoff_latitude': 'dropoff_y'}, - inplace=True) - df.to_csv(taxi_path, index=False) - remove('yellow_tripdata_2015-01.csv') - - - print("\nAll data downloaded.") diff --git a/pixi.toml b/pixi.toml index e7a6ab71a..751b8a21d 100644 --- a/pixi.toml +++ b/pixi.toml @@ -38,6 +38,7 @@ scipy = "*" setuptools = "*" # distutils for pyct toolz = "*" xarray = "*" +fastparquet = "*" [feature.py310.dependencies] python = "3.10.*" @@ -80,6 +81,7 @@ scikit-image = "*" shapely = ">=2.0.0" spatialpandas = "*" streamz = "*" +hvsampledata = ">=0.1.4" # ============================================= # =================== TESTS =================== diff --git a/scripts/download_data.py b/scripts/download_data.py index 586548243..57783b96e 100644 --- a/scripts/download_data.py +++ b/scripts/download_data.py @@ -1,11 +1,6 @@ from contextlib import suppress - -import pyct.cmd from packaging.version import Version -pyct.cmd.fetch_data(name="data", path="examples", datasets="datasets.yml") - - with suppress(ImportError): import bokeh @@ -21,4 +16,4 @@ gds.get_path("geoda.natregimes") gds.get_path("nybb") - gds.get_path('geoda health') + gds.get_path("geoda health") From 015d39a7aa6f24d2ed6642f9f7379536d98021d5 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Fri, 26 Sep 2025 18:35:55 +0100 Subject: [PATCH 02/23] remove pyct completely --- benchmarks/asv.conf.json | 4 +--- datashader/__init__.py | 16 ---------------- datashader/__main__.py | 12 ------------ pixi.toml | 2 -- pyproject.toml | 4 ---- 5 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 datashader/__main__.py diff --git a/benchmarks/asv.conf.json b/benchmarks/asv.conf.json index ccea8c131..7e6cb4ade 100644 --- a/benchmarks/asv.conf.json +++ b/benchmarks/asv.conf.json @@ -83,9 +83,7 @@ // new environments. A value of ``null`` means that the variable // will not be set for the current combination. // - "matrix": { - "pyct": [], - }, + "matrix": {}, // Combinations of libraries/python versions can be excluded/included // from the set to test. Each entry is a dictionary containing additional diff --git a/datashader/__init__.py b/datashader/__init__.py index 1c66ab6e7..a86a3325a 100644 --- a/datashader/__init__.py +++ b/datashader/__init__.py @@ -16,19 +16,3 @@ from pandas import __version__ as pandas_version if Version(pandas_version) >= Version('0.24.0'): from . import datatypes # noqa (API import) - -# make pyct's example commands available if possible -from functools import partial -try: - from pyct.cmd import copy_examples as _copy, examples as _examples - copy_examples = partial(_copy,'datashader') - examples = partial(_examples,'datashader') -except ImportError: - def _missing_cmd(*args,**kw): - return("install pyct to enable this command (e.g. `conda install pyct or " - "`pip install pyct[cmd]`)") - _copy = _examples = _missing_cmd - def err(): - raise ValueError(_missing_cmd()) - copy_examples = examples = err -del partial, _examples, _copy diff --git a/datashader/__main__.py b/datashader/__main__.py deleted file mode 100644 index 9c685d604..000000000 --- a/datashader/__main__.py +++ /dev/null @@ -1,12 +0,0 @@ -def main(args=None): - try: - import pyct.cmd - except ImportError: - import sys - from . import _missing_cmd - print(_missing_cmd()) - sys.exit(1) - return pyct.cmd.substitute_main('datashader',args=args) - -if __name__ == "__main__": - main() diff --git a/pixi.toml b/pixi.toml index 751b8a21d..e4de133b6 100644 --- a/pixi.toml +++ b/pixi.toml @@ -32,10 +32,8 @@ multipledispatch = "*" numpy = "*" pandas = "*" param = "*" -pyct = "*" requests = "*" scipy = "*" -setuptools = "*" # distutils for pyct toolz = "*" xarray = "*" fastparquet = "*" diff --git a/pyproject.toml b/pyproject.toml index a61cff7a0..6ec17c3c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,6 @@ dependencies = [ 'numpy', 'pandas', 'param', - 'pyct', 'requests', 'scipy', 'toolz', @@ -50,9 +49,6 @@ HoloViz = "https://holoviz.org/" [project.optional-dependencies] tests = ["pytest", "hypothesis"] -[project.scripts] -datashader = "datashader.__main:main" - [tool.hatch.version] source = "vcs" raw-options = { version_scheme = "no-guess-dev" } From 39ec30e9ea6c60ba902901f702e6670b8465708c Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Fri, 26 Sep 2025 18:36:34 +0100 Subject: [PATCH 03/23] use pyarrow instead --- pixi.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pixi.toml b/pixi.toml index e4de133b6..8ae95d219 100644 --- a/pixi.toml +++ b/pixi.toml @@ -36,7 +36,7 @@ requests = "*" scipy = "*" toolz = "*" xarray = "*" -fastparquet = "*" +pyarrow = "*" [feature.py310.dependencies] python = "3.10.*" @@ -105,7 +105,6 @@ dask-geopandas = "*" geodatasets = "*" geopandas-base = "*" netcdf4 = "*" -pyarrow = "*" pillow = "*" pyogrio = "*" rasterio = "*" From c54c98d23b4f8de26bdba00ea78f81486beadf80 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Fri, 26 Sep 2025 18:37:14 +0100 Subject: [PATCH 04/23] download data in script and update example notebook --- examples/getting_started/1_Introduction.ipynb | 11 ++++++++++- scripts/download_data.py | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/getting_started/1_Introduction.ipynb b/examples/getting_started/1_Introduction.ipynb index 91751db57..1f03157bb 100644 --- a/examples/getting_started/1_Introduction.ipynb +++ b/examples/getting_started/1_Introduction.ipynb @@ -27,10 +27,19 @@ "import datashader as ds, colorcet as cc\n", "import hvsampledata as hvs\n", "\n", - "df = hvs.nyc_taxi(\"pandas\", engine_kwargs={\"columns\": ['dropoff_x', 'dropoff_y']})\n", + "df = hvs.nyc_taxi_remote(\"pandas\", engine_kwargs={\"columns\": ['dropoff_x', 'dropoff_y']})\n", "df.head()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{note}\n", + "The first time this cell is run, it may take some time for the NYC taxi dataset to be downloaded remotely (about 260MB).\n", + ":::" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/scripts/download_data.py b/scripts/download_data.py index 57783b96e..8a464464b 100644 --- a/scripts/download_data.py +++ b/scripts/download_data.py @@ -17,3 +17,9 @@ gds.get_path("geoda.natregimes") gds.get_path("nybb") gds.get_path("geoda health") + + +with suppress(ImportError): + import hvsampledata as hvs + + hvs.nyc_taxi_remote("pandas") From 17d6402b41d559cb93885afeff8209808012c601 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 15 Oct 2025 10:05:40 +0100 Subject: [PATCH 05/23] Revert "remove pyct completely" --- benchmarks/asv.conf.json | 4 +++- datashader/__init__.py | 16 ++++++++++++++++ datashader/__main__.py | 12 ++++++++++++ pixi.toml | 2 ++ pyproject.toml | 4 ++++ 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 datashader/__main__.py diff --git a/benchmarks/asv.conf.json b/benchmarks/asv.conf.json index 7e6cb4ade..ccea8c131 100644 --- a/benchmarks/asv.conf.json +++ b/benchmarks/asv.conf.json @@ -83,7 +83,9 @@ // new environments. A value of ``null`` means that the variable // will not be set for the current combination. // - "matrix": {}, + "matrix": { + "pyct": [], + }, // Combinations of libraries/python versions can be excluded/included // from the set to test. Each entry is a dictionary containing additional diff --git a/datashader/__init__.py b/datashader/__init__.py index a86a3325a..1c66ab6e7 100644 --- a/datashader/__init__.py +++ b/datashader/__init__.py @@ -16,3 +16,19 @@ from pandas import __version__ as pandas_version if Version(pandas_version) >= Version('0.24.0'): from . import datatypes # noqa (API import) + +# make pyct's example commands available if possible +from functools import partial +try: + from pyct.cmd import copy_examples as _copy, examples as _examples + copy_examples = partial(_copy,'datashader') + examples = partial(_examples,'datashader') +except ImportError: + def _missing_cmd(*args,**kw): + return("install pyct to enable this command (e.g. `conda install pyct or " + "`pip install pyct[cmd]`)") + _copy = _examples = _missing_cmd + def err(): + raise ValueError(_missing_cmd()) + copy_examples = examples = err +del partial, _examples, _copy diff --git a/datashader/__main__.py b/datashader/__main__.py new file mode 100644 index 000000000..9c685d604 --- /dev/null +++ b/datashader/__main__.py @@ -0,0 +1,12 @@ +def main(args=None): + try: + import pyct.cmd + except ImportError: + import sys + from . import _missing_cmd + print(_missing_cmd()) + sys.exit(1) + return pyct.cmd.substitute_main('datashader',args=args) + +if __name__ == "__main__": + main() diff --git a/pixi.toml b/pixi.toml index d1eb7d373..0b72a9063 100644 --- a/pixi.toml +++ b/pixi.toml @@ -32,8 +32,10 @@ multipledispatch = "*" numpy = "*" pandas = "*" param = "*" +pyct = "*" requests = "*" scipy = "*" +setuptools = "*" # distutils for pyct toolz = "*" xarray = "*" pyarrow = "*" diff --git a/pyproject.toml b/pyproject.toml index 6ec17c3c5..a61cff7a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ dependencies = [ 'numpy', 'pandas', 'param', + 'pyct', 'requests', 'scipy', 'toolz', @@ -49,6 +50,9 @@ HoloViz = "https://holoviz.org/" [project.optional-dependencies] tests = ["pytest", "hypothesis"] +[project.scripts] +datashader = "datashader.__main:main" + [tool.hatch.version] source = "vcs" raw-options = { version_scheme = "no-guess-dev" } From 83e277e0fd3c6bf980e9ab88b7f6cdcc738e775c Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 15 Oct 2025 10:52:44 +0100 Subject: [PATCH 06/23] add deprecation warning for pyct --- datashader/__init__.py | 14 ++++++++++++++ pyproject.toml | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/datashader/__init__.py b/datashader/__init__.py index 1c66ab6e7..b5a3c9b23 100644 --- a/datashader/__init__.py +++ b/datashader/__init__.py @@ -1,5 +1,7 @@ from __future__ import annotations +import warnings +from contextlib import suppress from packaging.version import Version from .__version import __version__ # noqa: F401 @@ -11,6 +13,18 @@ from . import transfer_functions as tf # noqa (API import) from . import data_libraries # noqa (API import) +with suppress(ImportError): + import pyct # noqa: F401 + + warnings.warn( + "The 'pyct' package bundled as a datashader dependency is deprecated since version 0.19 " + "and will be removed in version 0.20. For downloading sample datasets, " + "prefer using 'hvsampledata' (for example: " + "`hvsampledata.nyc_taxi_remote('pandas')`).", + category=FutureWarning, + stacklevel=2, + ) + # Make RaggedArray pandas extension array available for # pandas >= 0.24.0 is installed from pandas import __version__ as pandas_version diff --git a/pyproject.toml b/pyproject.toml index a61cff7a0..034b8403c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,6 @@ dependencies = [ 'numpy', 'pandas', 'param', - 'pyct', 'requests', 'scipy', 'toolz', @@ -49,6 +48,7 @@ HoloViz = "https://holoviz.org/" [project.optional-dependencies] tests = ["pytest", "hypothesis"] +pyct = ["pyct"] [project.scripts] datashader = "datashader.__main:main" @@ -119,4 +119,6 @@ filterwarnings = [ "ignore:The 'shapely.geos' module is deprecated, and will be removed in a future version:DeprecationWarning", # 2025-09 "ignore:Signature .* for .*:UserWarning", + # 2025-10 + "ignore:The 'pyct' package bundled as a datashader dependency is deprecated since version 0.19 and will be removed in version 0.20.*" # https://github.com/holoviz/datashader/pull/1462 ] From ecfbfabd1fefe0704c707a2eb71a3a33723eda2d Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 15 Oct 2025 12:04:38 +0100 Subject: [PATCH 07/23] temp workaround for CI --- scripts/download_data.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/scripts/download_data.py b/scripts/download_data.py index 8a464464b..04eaae861 100644 --- a/scripts/download_data.py +++ b/scripts/download_data.py @@ -22,4 +22,26 @@ with suppress(ImportError): import hvsampledata as hvs - hvs.nyc_taxi_remote("pandas") + # Temp workaround for CI until a new hvsampledata release is available. + import logging + import sys + + log = logging.getLogger("datashader.download_data") + if not log.handlers: + # Ensure at least one handler so warnings are visible in CI logs + handler = logging.StreamHandler(stream=sys.stderr) + formatter = logging.Formatter("%(levelname)s: %(message)s") + handler.setFormatter(formatter) + log.addHandler(handler) + + nyc_taxi = getattr(hvs, "nyc_taxi_remote", None) + if nyc_taxi is None: + log.warning( + "Skipping nyc_taxi download: installed hvsampledata version has no 'nyc_taxi_remote'. " + "Please upgrade hvsampledata when a new release is available." + ) + else: + try: + nyc_taxi("pandas") + except Exception as e: + log.warning(f"hvsampledata.nyc_taxi_remote() failed: {e}") From c48447c4d95e28362336287f6ee8d90cb51b84a7 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 15 Oct 2025 16:02:21 +0100 Subject: [PATCH 08/23] move deprecation warning to main.py --- datashader/__init__.py | 14 -------------- datashader/__main__.py | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/datashader/__init__.py b/datashader/__init__.py index b5a3c9b23..1c66ab6e7 100644 --- a/datashader/__init__.py +++ b/datashader/__init__.py @@ -1,7 +1,5 @@ from __future__ import annotations -import warnings -from contextlib import suppress from packaging.version import Version from .__version import __version__ # noqa: F401 @@ -13,18 +11,6 @@ from . import transfer_functions as tf # noqa (API import) from . import data_libraries # noqa (API import) -with suppress(ImportError): - import pyct # noqa: F401 - - warnings.warn( - "The 'pyct' package bundled as a datashader dependency is deprecated since version 0.19 " - "and will be removed in version 0.20. For downloading sample datasets, " - "prefer using 'hvsampledata' (for example: " - "`hvsampledata.nyc_taxi_remote('pandas')`).", - category=FutureWarning, - stacklevel=2, - ) - # Make RaggedArray pandas extension array available for # pandas >= 0.24.0 is installed from pandas import __version__ as pandas_version diff --git a/datashader/__main__.py b/datashader/__main__.py index 9c685d604..a697aa104 100644 --- a/datashader/__main__.py +++ b/datashader/__main__.py @@ -1,4 +1,19 @@ +import warnings +from contextlib import suppress + + def main(args=None): + with suppress(ImportError): + import pyct # noqa: F401 + + warnings.warn( + "The 'pyct' package is deprecated since version 0.19 " + "and will be removed in version 0.20. For downloading sample datasets, " + "prefer using 'hvsampledata' (for example: " + "`hvsampledata.nyc_taxi_remote('pandas')`).", + category=FutureWarning, + stacklevel=2, + ) try: import pyct.cmd except ImportError: From 0f657bdccd53700881f14ecd3008bf1154b57736 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 15 Oct 2025 16:03:19 +0100 Subject: [PATCH 09/23] second try --- scripts/download_data.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/scripts/download_data.py b/scripts/download_data.py index 04eaae861..f596219d3 100644 --- a/scripts/download_data.py +++ b/scripts/download_data.py @@ -36,10 +36,29 @@ nyc_taxi = getattr(hvs, "nyc_taxi_remote", None) if nyc_taxi is None: - log.warning( - "Skipping nyc_taxi download: installed hvsampledata version has no 'nyc_taxi_remote'. " - "Please upgrade hvsampledata when a new release is available." - ) + # Try a direct download of the parquet file as a temporary fallback. + URL = "https://datasets.holoviz.org/nyc_taxi/v2/nyc_taxi_wide.parq" + + from pathlib import Path + dest = Path(hvs._DATAPATH) / "nyc_taxi_wide.parq" + dest.parent.mkdir(parents=True, exist_ok=True) + try: + import requests + + tmp = dest.with_suffix(".part") + with requests.get(URL, stream=True, timeout=120) as r: + r.raise_for_status() + with open(tmp, "wb") as f: + for chunk in r.iter_content(chunk_size=10_485_760): + if chunk: + f.write(chunk) + tmp.replace(dest) + except Exception: + # Fallback if requests not available or streaming fails + import urllib.request + + urllib.request.urlretrieve(URL, dest) + log.info("nyc_taxi parquet downloaded to %s", dest) else: try: nyc_taxi("pandas") From 8ba61dafa2feb8fb05d910d27da66c9f23cd0b49 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 15 Oct 2025 17:10:00 +0100 Subject: [PATCH 10/23] third try for example notebook --- examples/getting_started/1_Introduction.ipynb | 13 ++++++++++++- pyproject.toml | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/getting_started/1_Introduction.ipynb b/examples/getting_started/1_Introduction.ipynb index 1f03157bb..e4a56443f 100644 --- a/examples/getting_started/1_Introduction.ipynb +++ b/examples/getting_started/1_Introduction.ipynb @@ -27,7 +27,18 @@ "import datashader as ds, colorcet as cc\n", "import hvsampledata as hvs\n", "\n", - "df = hvs.nyc_taxi_remote(\"pandas\", engine_kwargs={\"columns\": ['dropoff_x', 'dropoff_y']})\n", + "# Temp workaround for CI until a new hvsampledata release is available.\n", + "try:\n", + " df = hvs.nyc_taxi_remote(\"pandas\", engine_kwargs={\"columns\": ['dropoff_x', 'dropoff_y']})\n", + "except AttributeError:\n", + " import pandas as pd\n", + " from pathlib import Path\n", + " file = Path(hvs._DATAPATH) / \"nyc_taxi_wide.parq\"\n", + " if file.exists():\n", + " df = pd.read_parquet(file, columns=['dropoff_x', 'dropoff_y'])\n", + " else:\n", + " file = \"https://datasets.holoviz.org/nyc_taxi/v2/nyc_taxi_wide.parq\"\n", + " df = pd.read_parquet(file, columns=['dropoff_x', 'dropoff_y'])\n", "df.head()" ] }, diff --git a/pyproject.toml b/pyproject.toml index 034b8403c..1d108de1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ dependencies = [ 'numpy', 'pandas', 'param', + 'pyct', 'requests', 'scipy', 'toolz', @@ -48,7 +49,6 @@ HoloViz = "https://holoviz.org/" [project.optional-dependencies] tests = ["pytest", "hypothesis"] -pyct = ["pyct"] [project.scripts] datashader = "datashader.__main:main" From 192dd6273a5b3d3c13adcc2a02a857991023814a Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 15 Oct 2025 18:03:30 +0100 Subject: [PATCH 11/23] Try GH install of hvsampledata for CI instead --- .github/workflows/test.yaml | 3 +++ examples/getting_started/1_Introduction.ipynb | 13 +------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 0a74b3ceb..8181d94e0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -121,6 +121,9 @@ jobs: - uses: holoviz-dev/holoviz_tasks/pixi_install@v0 with: environments: ${{ matrix.environment }} + - name: PATCH # Temp hack: Don't merge into main + run: | + pixi run -e ${{ matrix.environment }} pip install 'git+https://github.com/holoviz/hvsampledata.git@1bac391' - name: Restore cached hypothesis directory uses: actions/cache/restore@v4 with: diff --git a/examples/getting_started/1_Introduction.ipynb b/examples/getting_started/1_Introduction.ipynb index e4a56443f..1f03157bb 100644 --- a/examples/getting_started/1_Introduction.ipynb +++ b/examples/getting_started/1_Introduction.ipynb @@ -27,18 +27,7 @@ "import datashader as ds, colorcet as cc\n", "import hvsampledata as hvs\n", "\n", - "# Temp workaround for CI until a new hvsampledata release is available.\n", - "try:\n", - " df = hvs.nyc_taxi_remote(\"pandas\", engine_kwargs={\"columns\": ['dropoff_x', 'dropoff_y']})\n", - "except AttributeError:\n", - " import pandas as pd\n", - " from pathlib import Path\n", - " file = Path(hvs._DATAPATH) / \"nyc_taxi_wide.parq\"\n", - " if file.exists():\n", - " df = pd.read_parquet(file, columns=['dropoff_x', 'dropoff_y'])\n", - " else:\n", - " file = \"https://datasets.holoviz.org/nyc_taxi/v2/nyc_taxi_wide.parq\"\n", - " df = pd.read_parquet(file, columns=['dropoff_x', 'dropoff_y'])\n", + "df = hvs.nyc_taxi_remote(\"pandas\", engine_kwargs={\"columns\": ['dropoff_x', 'dropoff_y']})\n", "df.head()" ] }, From a916499adc9cb5dcaa3f77a3063bce5e6a5cf07b Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Thu, 16 Oct 2025 14:53:03 +0100 Subject: [PATCH 12/23] remove filtering --- pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1d108de1e..a61cff7a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -119,6 +119,4 @@ filterwarnings = [ "ignore:The 'shapely.geos' module is deprecated, and will be removed in a future version:DeprecationWarning", # 2025-09 "ignore:Signature .* for .*:UserWarning", - # 2025-10 - "ignore:The 'pyct' package bundled as a datashader dependency is deprecated since version 0.19 and will be removed in version 0.20.*" # https://github.com/holoviz/datashader/pull/1462 ] From b94cb8623682487b9a84f300c2acafbb1f91e450 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Tue, 25 Nov 2025 17:58:22 +0100 Subject: [PATCH 13/23] replace ugly boilerplate code --- scripts/download_data.py | 43 +--------------------------------------- 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/scripts/download_data.py b/scripts/download_data.py index f596219d3..1940ab20d 100644 --- a/scripts/download_data.py +++ b/scripts/download_data.py @@ -22,45 +22,4 @@ with suppress(ImportError): import hvsampledata as hvs - # Temp workaround for CI until a new hvsampledata release is available. - import logging - import sys - - log = logging.getLogger("datashader.download_data") - if not log.handlers: - # Ensure at least one handler so warnings are visible in CI logs - handler = logging.StreamHandler(stream=sys.stderr) - formatter = logging.Formatter("%(levelname)s: %(message)s") - handler.setFormatter(formatter) - log.addHandler(handler) - - nyc_taxi = getattr(hvs, "nyc_taxi_remote", None) - if nyc_taxi is None: - # Try a direct download of the parquet file as a temporary fallback. - URL = "https://datasets.holoviz.org/nyc_taxi/v2/nyc_taxi_wide.parq" - - from pathlib import Path - dest = Path(hvs._DATAPATH) / "nyc_taxi_wide.parq" - dest.parent.mkdir(parents=True, exist_ok=True) - try: - import requests - - tmp = dest.with_suffix(".part") - with requests.get(URL, stream=True, timeout=120) as r: - r.raise_for_status() - with open(tmp, "wb") as f: - for chunk in r.iter_content(chunk_size=10_485_760): - if chunk: - f.write(chunk) - tmp.replace(dest) - except Exception: - # Fallback if requests not available or streaming fails - import urllib.request - - urllib.request.urlretrieve(URL, dest) - log.info("nyc_taxi parquet downloaded to %s", dest) - else: - try: - nyc_taxi("pandas") - except Exception as e: - log.warning(f"hvsampledata.nyc_taxi_remote() failed: {e}") + path = hvs.download("nyc_taxi_remote") From 49c3e2251b7443a8c42fa47e5e24c65a91b4a541 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Tue, 25 Nov 2025 18:03:17 +0100 Subject: [PATCH 14/23] update hvsampledata version --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8181d94e0..9e8a4bc21 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -123,7 +123,7 @@ jobs: environments: ${{ matrix.environment }} - name: PATCH # Temp hack: Don't merge into main run: | - pixi run -e ${{ matrix.environment }} pip install 'git+https://github.com/holoviz/hvsampledata.git@1bac391' + pixi run -e ${{ matrix.environment }} pip install 'git+https://github.com/holoviz/hvsampledata.git@7baf0f1' - name: Restore cached hypothesis directory uses: actions/cache/restore@v4 with: From 70ff1e835cbb839391998e079e87b98b311c749e Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Tue, 25 Nov 2025 18:06:23 +0100 Subject: [PATCH 15/23] update notebook --- examples/getting_started/1_Introduction.ipynb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/getting_started/1_Introduction.ipynb b/examples/getting_started/1_Introduction.ipynb index 1f03157bb..9959b2c41 100644 --- a/examples/getting_started/1_Introduction.ipynb +++ b/examples/getting_started/1_Introduction.ipynb @@ -25,9 +25,10 @@ "outputs": [], "source": [ "import datashader as ds, colorcet as cc\n", - "import hvsampledata as hvs\n", + "import hvsampledata as hvs, pandas as pd\n", "\n", - "df = hvs.nyc_taxi_remote(\"pandas\", engine_kwargs={\"columns\": ['dropoff_x', 'dropoff_y']})\n", + "file_path = hvs.download(\"nyc_taxi_remote\")\n", + "df = pd.read_parquet(file_path, columns=['dropoff_x', 'dropoff_y'])\n", "df.head()" ] }, From 1a8b640af69f194cc0adfe40370b1fffe33d5b81 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Tue, 25 Nov 2025 18:30:05 +0100 Subject: [PATCH 16/23] point to main --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 9e8a4bc21..6bc287b44 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -123,7 +123,7 @@ jobs: environments: ${{ matrix.environment }} - name: PATCH # Temp hack: Don't merge into main run: | - pixi run -e ${{ matrix.environment }} pip install 'git+https://github.com/holoviz/hvsampledata.git@7baf0f1' + pixi run -e ${{ matrix.environment }} pip install 'git+https://github.com/holoviz/hvsampledata.git@main' - name: Restore cached hypothesis directory uses: actions/cache/restore@v4 with: From f16f4dd9c3d4a6a34688b97913ca3a20919438dd Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Tue, 25 Nov 2025 18:31:59 +0100 Subject: [PATCH 17/23] Revert "update notebook" This reverts commit 70ff1e835cbb839391998e079e87b98b311c749e. --- examples/getting_started/1_Introduction.ipynb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/getting_started/1_Introduction.ipynb b/examples/getting_started/1_Introduction.ipynb index 9959b2c41..1f03157bb 100644 --- a/examples/getting_started/1_Introduction.ipynb +++ b/examples/getting_started/1_Introduction.ipynb @@ -25,10 +25,9 @@ "outputs": [], "source": [ "import datashader as ds, colorcet as cc\n", - "import hvsampledata as hvs, pandas as pd\n", + "import hvsampledata as hvs\n", "\n", - "file_path = hvs.download(\"nyc_taxi_remote\")\n", - "df = pd.read_parquet(file_path, columns=['dropoff_x', 'dropoff_y'])\n", + "df = hvs.nyc_taxi_remote(\"pandas\", engine_kwargs={\"columns\": ['dropoff_x', 'dropoff_y']})\n", "df.head()" ] }, From 3089271e40a402706f27adece2d0bd6377c95d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8xbro=20Hansen?= Date: Wed, 26 Nov 2025 09:30:38 +0100 Subject: [PATCH 18/23] update test.yaml --- .github/workflows/test.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6bc287b44..0a74b3ceb 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -121,9 +121,6 @@ jobs: - uses: holoviz-dev/holoviz_tasks/pixi_install@v0 with: environments: ${{ matrix.environment }} - - name: PATCH # Temp hack: Don't merge into main - run: | - pixi run -e ${{ matrix.environment }} pip install 'git+https://github.com/holoviz/hvsampledata.git@main' - name: Restore cached hypothesis directory uses: actions/cache/restore@v4 with: From 7b4586ecd4f8de7972b7e1946dee5573b38e49b1 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 26 Nov 2025 11:34:26 +0100 Subject: [PATCH 19/23] revert deletion of pyct usage --- datashader/__init__.py | 11 ++++++----- examples/datasets.yml | 8 ++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 examples/datasets.yml diff --git a/datashader/__init__.py b/datashader/__init__.py index 1c66ab6e7..c06d5a30c 100644 --- a/datashader/__init__.py +++ b/datashader/__init__.py @@ -17,18 +17,19 @@ if Version(pandas_version) >= Version('0.24.0'): from . import datatypes # noqa (API import) -# make pyct's example commands available if possible +# make pyct's example/data commands available if possible from functools import partial try: - from pyct.cmd import copy_examples as _copy, examples as _examples + from pyct.cmd import copy_examples as _copy, fetch_data as _fetch, examples as _examples copy_examples = partial(_copy,'datashader') + fetch_data = partial(_fetch,'datashader') examples = partial(_examples,'datashader') except ImportError: def _missing_cmd(*args,**kw): return("install pyct to enable this command (e.g. `conda install pyct or " "`pip install pyct[cmd]`)") - _copy = _examples = _missing_cmd + _copy = _fetch = _examples = _missing_cmd def err(): raise ValueError(_missing_cmd()) - copy_examples = examples = err -del partial, _examples, _copy + fetch_data = copy_examples = examples = err +del partial, _examples, _copy, _fetch diff --git a/examples/datasets.yml b/examples/datasets.yml new file mode 100644 index 000000000..2f7236e0d --- /dev/null +++ b/examples/datasets.yml @@ -0,0 +1,8 @@ +--- + +data: + + - url: http://s3.amazonaws.com/datashader-data/nyc_taxi.zip + title: 'NYC Taxi Data' + files: + - nyc_taxi.csv From db073d82e255dd834286ef8e7fd7a5616f263061 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 26 Nov 2025 12:11:15 +0100 Subject: [PATCH 20/23] add deprecation warning for all usage of pyct --- datashader/__init__.py | 31 +++++++++++++++++++++++++++---- datashader/__main__.py | 11 ++--------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/datashader/__init__.py b/datashader/__init__.py index c06d5a30c..7c274d2e1 100644 --- a/datashader/__init__.py +++ b/datashader/__init__.py @@ -18,12 +18,35 @@ from . import datatypes # noqa (API import) # make pyct's example/data commands available if possible -from functools import partial +import warnings +from functools import partial, wraps + + +def _warn_pyct_deprecated(stacklevel=2): + warnings.warn( + "The 'pyct' package is deprecated since version 0.19 " + "and will be removed in version 0.20. For downloading sample datasets, " + "prefer using 'hvsampledata' (for example: " + "`hvsampledata.nyc_taxi_remote('pandas')`).", + category=FutureWarning, + stacklevel=stacklevel, + ) + + +def _deprecated_pyct_wrapper(func): + """Wrapper to add deprecation warning to pyct functions.""" + @wraps(func) + def wrapper(*args, **kwargs): + _warn_pyct_deprecated(stacklevel=2) + return func(*args, **kwargs) + return wrapper + + try: from pyct.cmd import copy_examples as _copy, fetch_data as _fetch, examples as _examples - copy_examples = partial(_copy,'datashader') - fetch_data = partial(_fetch,'datashader') - examples = partial(_examples,'datashader') + copy_examples = _deprecated_pyct_wrapper(partial(_copy, 'datashader')) + fetch_data = _deprecated_pyct_wrapper(partial(_fetch, 'datashader')) + examples = _deprecated_pyct_wrapper(partial(_examples, 'datashader')) except ImportError: def _missing_cmd(*args,**kw): return("install pyct to enable this command (e.g. `conda install pyct or " diff --git a/datashader/__main__.py b/datashader/__main__.py index a697aa104..badc2389b 100644 --- a/datashader/__main__.py +++ b/datashader/__main__.py @@ -1,4 +1,3 @@ -import warnings from contextlib import suppress @@ -6,14 +5,8 @@ def main(args=None): with suppress(ImportError): import pyct # noqa: F401 - warnings.warn( - "The 'pyct' package is deprecated since version 0.19 " - "and will be removed in version 0.20. For downloading sample datasets, " - "prefer using 'hvsampledata' (for example: " - "`hvsampledata.nyc_taxi_remote('pandas')`).", - category=FutureWarning, - stacklevel=2, - ) + from . import _warn_pyct_deprecated + _warn_pyct_deprecated(stacklevel=2) try: import pyct.cmd except ImportError: From 0e7d3b533ecdf478a4e985cd61caad39c69ac31e Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Wed, 26 Nov 2025 12:33:29 +0100 Subject: [PATCH 21/23] add warning for old pyct download pattern --- scripts/download_data.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/download_data.py b/scripts/download_data.py index 1940ab20d..04c4a53b2 100644 --- a/scripts/download_data.py +++ b/scripts/download_data.py @@ -1,6 +1,14 @@ from contextlib import suppress from packaging.version import Version +with suppress(ImportError): + import pyct.cmd + from datashader import _warn_pyct_deprecated + + _warn_pyct_deprecated(stacklevel=1) + pyct.cmd.fetch_data(name="data", path="examples", datasets="datasets.yml") + + with suppress(ImportError): import bokeh From 78ac90fb80e83237f73f642be8a9511c1f1e6c3d Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Thu, 27 Nov 2025 17:28:52 +0100 Subject: [PATCH 22/23] post review --- datashader/__init__.py | 13 +++++++------ datashader/__main__.py | 2 +- pixi.toml | 2 +- scripts/download_data.py | 2 -- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/datashader/__init__.py b/datashader/__init__.py index 7c274d2e1..7ff4dba2b 100644 --- a/datashader/__init__.py +++ b/datashader/__init__.py @@ -18,16 +18,17 @@ from . import datatypes # noqa (API import) # make pyct's example/data commands available if possible -import warnings from functools import partial, wraps def _warn_pyct_deprecated(stacklevel=2): + import warnings + warnings.warn( - "The 'pyct' package is deprecated since version 0.19 " - "and will be removed in version 0.20. For downloading sample datasets, " - "prefer using 'hvsampledata' (for example: " - "`hvsampledata.nyc_taxi_remote('pandas')`).", + "The 'fetch_data()', 'copy_examples()', and 'examples()' functions are " + "deprecated since version 0.19 and will be removed in version 0.20. " + "For downloading sample datasets, use 'hvsampledata' instead. " + "For example: `hvsampledata.nyc_taxi_remote('pandas')`.", category=FutureWarning, stacklevel=stacklevel, ) @@ -37,7 +38,7 @@ def _deprecated_pyct_wrapper(func): """Wrapper to add deprecation warning to pyct functions.""" @wraps(func) def wrapper(*args, **kwargs): - _warn_pyct_deprecated(stacklevel=2) + _warn_pyct_deprecated(stacklevel=3) return func(*args, **kwargs) return wrapper diff --git a/datashader/__main__.py b/datashader/__main__.py index badc2389b..b7668cd3c 100644 --- a/datashader/__main__.py +++ b/datashader/__main__.py @@ -6,7 +6,7 @@ def main(args=None): import pyct # noqa: F401 from . import _warn_pyct_deprecated - _warn_pyct_deprecated(stacklevel=2) + _warn_pyct_deprecated(stacklevel=3) try: import pyct.cmd except ImportError: diff --git a/pixi.toml b/pixi.toml index 0b72a9063..51d50b2c8 100644 --- a/pixi.toml +++ b/pixi.toml @@ -38,7 +38,6 @@ scipy = "*" setuptools = "*" # distutils for pyct toolz = "*" xarray = "*" -pyarrow = "*" [feature.py310.dependencies] python = "3.10.*" @@ -107,6 +106,7 @@ dask-geopandas = "*" geodatasets = "*" geopandas-base = "*" netcdf4 = "*" +pyarrow = "*" pillow = "*" pyogrio = "*" rasterio = "*" diff --git a/scripts/download_data.py b/scripts/download_data.py index 04c4a53b2..dfa47b93b 100644 --- a/scripts/download_data.py +++ b/scripts/download_data.py @@ -3,9 +3,7 @@ with suppress(ImportError): import pyct.cmd - from datashader import _warn_pyct_deprecated - _warn_pyct_deprecated(stacklevel=1) pyct.cmd.fetch_data(name="data", path="examples", datasets="datasets.yml") From 22e7fc1dd705dd6704552dfede61081fd8978d85 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Fri, 28 Nov 2025 13:06:54 +0100 Subject: [PATCH 23/23] review again --- datashader/__init__.py | 4 ++-- datashader/__main__.py | 8 ++------ examples/getting_started/1_Introduction.ipynb | 2 +- pixi.toml | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/datashader/__init__.py b/datashader/__init__.py index 7ff4dba2b..067be40a5 100644 --- a/datashader/__init__.py +++ b/datashader/__init__.py @@ -36,7 +36,7 @@ def _warn_pyct_deprecated(stacklevel=2): def _deprecated_pyct_wrapper(func): """Wrapper to add deprecation warning to pyct functions.""" - @wraps(func) + @wraps(func) # noqa: F821 def wrapper(*args, **kwargs): _warn_pyct_deprecated(stacklevel=3) return func(*args, **kwargs) @@ -56,4 +56,4 @@ def _missing_cmd(*args,**kw): def err(): raise ValueError(_missing_cmd()) fetch_data = copy_examples = examples = err -del partial, _examples, _copy, _fetch +del partial, wraps, _examples, _copy, _fetch diff --git a/datashader/__main__.py b/datashader/__main__.py index b7668cd3c..49050c59e 100644 --- a/datashader/__main__.py +++ b/datashader/__main__.py @@ -1,14 +1,10 @@ -from contextlib import suppress def main(args=None): - with suppress(ImportError): - import pyct # noqa: F401 - - from . import _warn_pyct_deprecated - _warn_pyct_deprecated(stacklevel=3) try: import pyct.cmd + from . import _warn_pyct_deprecated + _warn_pyct_deprecated(stacklevel=3) except ImportError: import sys from . import _missing_cmd diff --git a/examples/getting_started/1_Introduction.ipynb b/examples/getting_started/1_Introduction.ipynb index 1f03157bb..203e21089 100644 --- a/examples/getting_started/1_Introduction.ipynb +++ b/examples/getting_started/1_Introduction.ipynb @@ -36,7 +36,7 @@ "metadata": {}, "source": [ ":::{note}\n", - "The first time this cell is run, it may take some time for the NYC taxi dataset to be downloaded remotely (about 260MB).\n", + "The first time this cell is run, it will download the NYC taxi dataset (about 260MB).\n", ":::" ] }, diff --git a/pixi.toml b/pixi.toml index 51d50b2c8..9cf6a69fc 100644 --- a/pixi.toml +++ b/pixi.toml @@ -80,7 +80,7 @@ scikit-image = "*" shapely = ">=2.0.0" spatialpandas = "*" streamz = "*" -hvsampledata = ">=0.1.4" +hvsampledata = ">=0.1.5a3" # ============================================= # =================== TESTS ===================