diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index cce07b85..88cf4ff8 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -19,11 +19,12 @@ jobs: run: shell: bash -l {0} env: - CHANS_DEV: "-c pyviz/label/dev -c conda-forge" + CHANS_DEV: "-c pyviz/label/dev -c bokeh -c conda-forge -c nodefaults" PKG_TEST_PYTHON: "--test-python=py38" PYTHON_VERSION: "3.8" MPLBACKEND: "Agg" CONDA_UPLOAD_TOKEN: ${{ secrets.CONDA_UPLOAD_TOKEN }} + SETUPTOOLS_ENABLE_FEATURES: "legacy-editable" steps: - name: remove nodejs run: | @@ -53,8 +54,8 @@ jobs: doit ecosystem_setup - name: conda build run: | - doit package_build --recipe=core $CHANS_DEV $PKG_TEST_PYTHON --test-group=unit - doit package_build --recipe=recommended $CHANS_DEV $PKG_TEST_PYTHON --test-group=unit + doit package_build --recipe=core $CHANS_DEV $PKG_TEST_PYTHON --test-group=simple + doit package_build --recipe=recommended $CHANS_DEV $PKG_TEST_PYTHON --test-group=simple - name: npm setup run: | echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_API_TOKEN }}" > $HOME/.npmrc @@ -104,6 +105,7 @@ jobs: PPU: ${{ secrets.PPU }} PPP: ${{ secrets.PPP }} PYPI: "https://upload.pypi.org/legacy/" + SETUPTOOLS_ENABLE_FEATURES: "legacy-editable" steps: - name: remove nodejs run: | diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 531dcf56..c058b334 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -50,7 +50,7 @@ jobs: run: | conda create -n test-environment conda activate test-environment - conda config --env --append channels pyviz/label/dev --append channels conda-forge + conda config --env --append channels pyviz/label/dev --append channels bokeh --append channels conda-forge conda config --env --remove channels defaults conda config --env --set channel_priority strict conda config --env --show-sources diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c6c198b9..57dab0f7 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -55,7 +55,7 @@ jobs: name: unit_test_suite python-version: ${{ matrix.python-version }} channel-priority: strict - channels: pyviz/label/dev,conda-forge,nodefaults + channels: pyviz/label/dev,bokeh,conda-forge,nodefaults envs: "-o tests -o examples -o recommended" cache: true conda-update: true diff --git a/examples/gallery/bokeh/airport_graph.ipynb b/examples/gallery/bokeh/airport_graph.ipynb index b7f3da83..5a8fbba4 100644 --- a/examples/gallery/bokeh/airport_graph.ipynb +++ b/examples/gallery/bokeh/airport_graph.ipynb @@ -39,7 +39,7 @@ "nodes = gv.Nodes(airport_points, ['Longitude', 'Latitude', 'AirportID'],\n", " ['Name', 'City', 'Connections'])\n", "graph = gv.Graph((routes, nodes), ['SourceID', 'DestinationID'], ['Source', 'Destination'])\n", - "tiles = gv.tile_sources.Wikipedia\n", + "tiles = gv.tile_sources.OSM\n", "\n", "# Select 50 busiest airports\n", "busiest = list(routes.groupby('SourceID').count().sort_values('Stops').iloc[-50:].index.values)\n", diff --git a/geoviews/__init__.py b/geoviews/__init__.py index f793b51f..427abffc 100644 --- a/geoviews/__init__.py +++ b/geoviews/__init__.py @@ -15,6 +15,7 @@ ) from .util import load_tiff, from_xarray # noqa (API import) from .operation import project # noqa (API import) +from ._warnings import GeoviewsDeprecationWarning, GeoviewsUserWarning # noqa: F401 from . import data # noqa (API import) from . import operation # noqa (API import) from . import plotting # noqa (API import) diff --git a/geoviews/_warnings.py b/geoviews/_warnings.py new file mode 100644 index 00000000..732c6e20 --- /dev/null +++ b/geoviews/_warnings.py @@ -0,0 +1,96 @@ +import inspect +import os +import warnings + +import holoviews as hv +import param + +from packaging.version import Version + +__all__ = ( + "deprecated", + "find_stack_level", + "GeoviewsDeprecationWarning", + "GeoviewsUserWarning", + "warn", +) + + +def warn(message, category=None, stacklevel=None): + if stacklevel is None: + stacklevel = find_stack_level() + + warnings.warn(message, category, stacklevel=stacklevel) + + +def find_stack_level(): + """ + Find the first place in the stack that is not inside + Geoviews, Holoviews, or Param. + + Inspired by: pandas.util._exceptions.find_stack_level + """ + import geoviews as gv + + pkg_dir = os.path.dirname(gv.__file__) + test_dir = os.path.join(pkg_dir, "tests") + param_dir = os.path.dirname(param.__file__) + hv_dir = os.path.dirname(hv.__file__) + + frame = inspect.currentframe() + stacklevel = 0 + while frame: + fname = inspect.getfile(frame) + if ( + fname.startswith(pkg_dir) + or fname.startswith(param_dir) + or fname.startswith(hv_dir) + ) and not fname.startswith(test_dir): + frame = frame.f_back + stacklevel += 1 + else: + break + + return stacklevel + + +def deprecated(remove_version, old, new=None, extra=None): + import geoviews as gv + + current_version = Version(Version(gv.__version__).base_version) + + if isinstance(remove_version, str): + remove_version = Version(remove_version) + + if remove_version < current_version: + # This error is mainly for developers to remove the deprecated. + raise ValueError( + f"{old!r} should have been removed in {remove_version}" + f", current version {current_version}." + ) + + message = f"{old!r} is deprecated and will be removed in version {remove_version}." + + if new: + message = f"{message[:-1]}, use {new!r} instead." + + if extra: + message += " " + extra.strip() + + warn(message, GeoviewsDeprecationWarning) + + +class GeoviewsDeprecationWarning(DeprecationWarning): + """A Geoviews-specific ``DeprecationWarning`` subclass. + Used to selectively filter Geoviews deprecations for unconditional display. + """ + + +class GeoviewsUserWarning(UserWarning): + """A Geoviews-specific ``UserWarning`` subclass. + Used to selectively filter Geoviews warnings for unconditional display. + """ + + +warnings.simplefilter("always", GeoviewsDeprecationWarning) +warnings.simplefilter("always", GeoviewsUserWarning) diff --git a/geoviews/element/geo.py b/geoviews/element/geo.py index a8cb51c5..07f6277d 100644 --- a/geoviews/element/geo.py +++ b/geoviews/element/geo.py @@ -27,7 +27,10 @@ try: from iris.cube import Cube -except ImportError: +except (ImportError, OSError): + # OSError because environment variable $UDUNITS2_XML_PATH + # is sometimes not set. Should be done automatically + # when installing the package. Cube = None diff --git a/geoviews/operation/__init__.py b/geoviews/operation/__init__.py index 9870e0c4..2ff2bb32 100644 --- a/geoviews/operation/__init__.py +++ b/geoviews/operation/__init__.py @@ -11,9 +11,9 @@ geo_ops = [contours, bivariate_kde] try: - from holoviews.operation.datashader import ( - ResamplingOperation, shade, stack, dynspread) - geo_ops += [ResamplingOperation, shade, stack, dynspread] + from holoviews.operation.datashader import shade, stack, dynspread + from holoviews.operation.resample import ResampleOperation2D + geo_ops += [ResampleOperation2D, shade, stack, dynspread] except ImportError: pass diff --git a/geoviews/tile_sources.py b/geoviews/tile_sources.py index d59dd04a..dbfec5a6 100644 --- a/geoviews/tile_sources.py +++ b/geoviews/tile_sources.py @@ -86,7 +86,13 @@ # Miscellaneous OSM = WMTS('https://c.tile.openstreetmap.org/{Z}/{X}/{Y}.png', name="OSM") OpenTopoMap = WMTS('https://a.tile.opentopomap.org/{Z}/{X}/{Y}.png', name="OpenTopoMap") -Wikipedia = WMTS('https://c.tile.openstreetmap.org/{Z}/{X}/{Y}.png', name="Wikipedia") + +def __getattr__(name): + if name == "Wikipedia": + from ._warnings import deprecated + deprecated("1.11", "Wikipedia", "OSM") + return WMTS('https://c.tile.openstreetmap.org/{Z}/{X}/{Y}.png', name="Wikipedia") + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") tile_sources = {k: v for k, v in locals().items() if isinstance(v, WMTS) and k != 'ESRI'} diff --git a/setup.py b/setup.py index 8d28f007..afd5ed5b 100644 --- a/setup.py +++ b/setup.py @@ -96,12 +96,12 @@ def run(self): _required = [ 'bokeh >=3.1.0,<3.2.0', 'cartopy >=0.18.0', - 'holoviews >=1.16.0a5', + 'holoviews >=1.16.0', 'packaging', 'numpy', 'shapely', 'param', - 'panel >=1.0.0rc1', + 'panel >=1.0.0rc7', 'pyproj', ] @@ -135,7 +135,7 @@ def run(self): 'recommended': _recommended, 'examples_extra': _examples_extra, 'doc': _examples_extra + [ - 'nbsite >=0.7.2rc10', + 'nbsite ==0.8.0rc15', # Broken for newer versions 'cartopy >=0.20.0', 'graphviz', 'lxml', diff --git a/tox.ini b/tox.ini index d140b3a1..8271e6d6 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ [tox] # python version test group extra envs extra commands -envlist = {py38,py39,py310,py311}-{flakes,unit,examples,all_recommended,examples_extra}-{default}-{dev,pkg} +envlist = {py38,py39,py310,py311}-{flakes,unit,examples,all_recommended,examples_extra,simple}-{default}-{dev,pkg} [_simple] description = Install geoviews without any optional dependencies @@ -81,6 +81,10 @@ filterwarnings = ignore:`.+?` is a deprecated alias for `.+?`.:DeprecationWarning:cupy ; 2023-01: https://github.com/SciTools/cartopy/issues/2113 ignore:The 'geom_factory' function is deprecated in Shapely 2:DeprecationWarning:cartopy.crs + error::holoviews.HoloviewsDeprecationWarning + error::holoviews.HoloviewsUserWarning + error::geoviews.GeoviewsDeprecationWarning + error::geoviews.GeoviewsUserWarning [flake8] include = *.py