Skip to content

Commit

Permalink
Drop Python 3.6 and 3.7 and fix test-suite (#1077)
Browse files Browse the repository at this point in the history
Co-authored-by: Simon Høxbro Hansen <simon.hansen@me.com>
  • Loading branch information
maximlt and hoxbro committed Aug 29, 2023
1 parent e323153 commit 30999e8
Show file tree
Hide file tree
Showing 15 changed files with 42 additions and 126 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yaml
Expand Up @@ -20,8 +20,8 @@ jobs:
shell: bash -l {0}
env:
CHANS_DEV: "-c pyviz/label/dev -c bokeh"
PKG_TEST_PYTHON: "--test-python=py37"
PYTHON_VERSION: "3.7"
PKG_TEST_PYTHON: "--test-python=py38"
PYTHON_VERSION: "3.8"
CHANS: "-c pyviz"
MPLBACKEND: "Agg"
CONDA_UPLOAD_TOKEN: ${{ secrets.CONDA_UPLOAD_TOKEN }}
Expand Down Expand Up @@ -64,8 +64,8 @@ jobs:
shell: bash -l {0}
env:
CHANS_DEV: "-c pyviz/label/dev -c bokeh"
PKG_TEST_PYTHON: "--test-python=py37"
PYTHON_VERSION: "3.7"
PKG_TEST_PYTHON: "--test-python=py38"
PYTHON_VERSION: "3.8"
CHANS: "-c pyviz"
MPLBACKEND: "Agg"
PPU: ${{ secrets.PPU }}
Expand Down
61 changes: 3 additions & 58 deletions .github/workflows/test.yaml
Expand Up @@ -39,35 +39,27 @@ jobs:
matrix:
os: ['ubuntu-latest', 'macos-latest', 'windows-latest']
# Run on the full set on schedule, workflow_dispatch and push&tags events, otherwise on a subset.
python-version: ${{ ( github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || ( github.event_name == 'push' && github.ref_type == 'tag' ) ) && fromJSON('["3.7", "3.8", "3.9", "3.10", "3.11"]') || fromJSON('["3.7", "3.9", "3.11"]') }}
python-version: ${{ ( github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || ( github.event_name == 'push' && github.ref_type == 'tag' ) ) && fromJSON('["3.8", "3.9", "3.10", "3.11"]') || fromJSON('["3.8", "3.11"]') }}
timeout-minutes: 90
defaults:
run:
shell: bash -el {0}
steps:
- uses: holoviz-dev/holoviz_tasks/install@v0.1a12
- uses: holoviz-dev/holoviz_tasks/install@v0.1a15
with:
name: unit_test_suite
python-version: ${{ matrix.python-version }}
channel-priority: strict
channels: pyviz/label/dev,conda-forge,nodefaults
envs: "-o examples_tests -o tests"
envs: "-o examples_tests -o tests -o examples_conda"
cache: true
conda-update: true
conda-mamba: mamba
id: install
- name: patch fiona/geostack on Python 3.7 / Macos
if: steps.install.outputs.cache-hit != 'true' && contains(matrix.os, 'macos') && matrix.python-version == '3.7'
run: |
conda activate test-environment
mamba install "fiona=1.8" "gdal=3.3"
- name: doit test_unit
run: |
conda activate test-environment
doit test_unit
- name: test examples
# Should be removed when numba support python 3.11
if: matrix.python-version != '3.11'
run: |
conda activate test-environment
bokeh sampledata
Expand All @@ -76,50 +68,3 @@ jobs:
run: |
conda activate test-environment
codecov
test_suite_36:
name: Pytest on ${{ matrix.os }} with Python ${{ matrix.python-version }}
needs: [pre_commit]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: ['macos-latest', 'windows-latest']
python-version: ['3.6']
timeout-minutes: 90
defaults:
run:
shell: bash -l {0}
steps:
- uses: holoviz-dev/holoviz_tasks/install@v0.1a12
with:
name: unit_test_suite_36
python-version: ${{ matrix.python-version }}
channel-priority: strict
channels: pyviz/label/dev,conda-forge,nodefaults
envs: "-o tests"
cache: true
conda-update: true
conda-mamba: mamba
id: install
- name: doit develop_install py
if: steps.install.outputs.cache-hit != 'true'
run: |
conda activate test-environment
# - Pin panel on Python 3.6 because one or more dev releases on the 0.13.* series
# can be installed on Python 3.6 but are actually not compatible with Python 3.6
# Panel 0.13 will support Python >= 3.7 only so the pin here can stay indefinitely.
# - Install importlib_resources to fix tqdm that missed adding it as a dependency
# for 3.6 (https://github.com/conda-forge/tqdm-feedstock/pull/114)
conda install "panel=0.12" "importlib_resources" --no-update-deps
- name: doit env_capture
run: |
conda activate test-environment
doit env_capture
- name: doit test_unit
run: |
conda activate test-environment
doit test_unit
- name: codecov
run: |
conda activate test-environment
codecov
2 changes: 1 addition & 1 deletion doc/getting_started/installation.md
Expand Up @@ -5,7 +5,7 @@
| Latest release | [![Github release](https://img.shields.io/github/release/holoviz/hvplot.svg?label=tag&colorB=11ccbb)](https://github.com/holoviz/hvplot/releases) [![PyPI version](https://img.shields.io/pypi/v/hvplot.svg?colorB=cc77dd)](https://pypi.python.org/pypi/hvplot) [![hvplot version](https://img.shields.io/conda/v/pyviz/hvplot.svg?colorB=4488ff&style=flat)](https://anaconda.org/pyviz/hvplot) [![conda-forge version](https://img.shields.io/conda/v/conda-forge/hvplot.svg?label=conda%7Cconda-forge&colorB=4488ff)](https://anaconda.org/conda-forge/hvplot) [![defaults version](https://img.shields.io/conda/v/anaconda/hvplot.svg?label=conda%7Cdefaults&style=flat&colorB=4488ff)](https://anaconda.org/anaconda/hvplot) |
| Python | [![Python support](https://img.shields.io/pypi/pyversions/hvplot.svg)](https://pypi.org/project/hvplot/) |

hvPlot supports Python 3.6, 3.7, 3.8, 3.9 and 3.10 on Linux, Windows, or Mac. The recommended way to install hvPlot is using the [conda](https://conda.io/en/latest/) command provided by [Anaconda](https://docs.anaconda.com/anaconda/install/index.html) or [Miniconda](https://docs.conda.io/en/latest/miniconda.html):
hvPlot supports Python 3.8, 3.9, 3.10 and 3.11 on Linux, Windows, or Mac. The recommended way to install hvPlot is using the [conda](https://conda.io/en/latest/) command provided by [Anaconda](https://docs.anaconda.com/anaconda/install/index.html) or [Miniconda](https://docs.conda.io/en/latest/miniconda.html):

conda install -c pyviz hvplot

Expand Down
27 changes: 13 additions & 14 deletions hvplot/converter.py
Expand Up @@ -417,9 +417,9 @@ def __init__(
if self.geo:
if self.kind not in self._geo_types:
param.main.param.warning(
"geo option cannot be used with kind=%r plot "
f"geo option cannot be used with kind={self.kind!r} plot "
"type. Geographic plots are only supported for "
"following plot types: %r" % (self.kind, self._geo_types))
f"following plot types: {self._geo_types!r}")
from cartopy import crs as ccrs
from geoviews.util import project_extents

Expand All @@ -436,7 +436,7 @@ def __init__(
else:
raise ValueError(
"Projection must be defined as cartopy CRS or "
"one of the following CRS string:\n {}".format(all_crs))
f"one of the following CRS string:\n {all_crs}")

projection = projection or (ccrs.GOOGLE_MERCATOR if tiles else self.crs)
if tiles and projection != ccrs.GOOGLE_MERCATOR:
Expand Down Expand Up @@ -664,8 +664,8 @@ def _process_crs(self, data, crs):
# only raise error if crs was specified in kwargs
if crs:
raise ValueError(
"'{}' must be either a valid crs or an reference to "
"a `data.attr` containing a valid crs.".format(crs))
f"'{crs}' must be either a valid crs or an reference to "
"a `data.attr` containing a valid crs.")

def _process_data(self, kind, data, x, y, by, groupby, row, col,
use_dask, persist, backlog, label, group_label,
Expand Down Expand Up @@ -851,14 +851,14 @@ def _process_data(self, kind, data, x, y, by, groupby, row, col,
groupby.append(data_dim)
self.variables = list(data.coords) + data_vars
if groupby and not_found:
raise ValueError('The supplied groupby dimension(s) %s '
raise ValueError(f'The supplied groupby dimension(s) {not_found} '
'could not be found, expected one or '
'more of: %s' % (not_found, list(data.coords)))
f'more of: {list(data.coords)}')
else:
if gridded and kind not in ('points', 'dataset'):
raise ValueError('%s plot type requires gridded data, '
raise ValueError(f'{kind} plot type requires gridded data, '
'e.g. a NumPy array or xarray Dataset, '
'found %s type' % (kind, type(self.data).__name__))
f'found {type(self.data).__name__} type')

if hasattr(data, 'columns') and hasattr(data.columns, 'name') and data.columns.name and not group_label:
group_label = data.columns.name
Expand Down Expand Up @@ -903,9 +903,9 @@ def _process_data(self, kind, data, x, y, by, groupby, row, col,
not_found = [g for g in groupby+by_cols if g not in list(self.data.columns)+indexes]
not_found, self.data = process_derived_datetime_pandas(self.data, not_found, indexes)
if groupby and not_found:
raise ValueError('The supplied groupby dimension(s) %s '
raise ValueError(f'The supplied groupby dimension(s) {not_found} '
'could not be found, expected one or '
'more of: %s' % (not_found, list(self.data.columns)))
f'more of: {list(self.data.columns)}')

if transforms:
self.data = Dataset(self.data, indexes).transform(**transforms).data
Expand Down Expand Up @@ -967,7 +967,7 @@ def _process_data(self, kind, data, x, y, by, groupby, row, col,
except Exception as e:
if attr_labels is True:
param.main.param.warning('Unable to auto label using xarray attrs '
'because {e}'.format(e=e))
f'because {e}')

def _process_plot(self):
kind = self.kind
Expand Down Expand Up @@ -1387,8 +1387,7 @@ def _apply_layers(self, obj):

if self.tiles:
tile_source = 'EsriImagery' if self.tiles == 'ESRI' else self.tiles
warning = ("%s tiles not recognized, must be one of: %s or a tile object" %
(tile_source, sorted(hv.element.tile_sources)))
warning = ("{} tiles not recognized, must be one of: {} or a tile object".format(tile_source, sorted(hv.element.tile_sources)))
if tile_source is True:
tiles = hv.element.tiles.OSM()
elif tile_source in hv.element.tile_sources.keys():
Expand Down
2 changes: 1 addition & 1 deletion hvplot/interactive.py
Expand Up @@ -227,7 +227,7 @@ def __new__(cls, obj, **kwargs):
for subcls in cls.__subclasses__():
if subcls.applies(obj):
clss = subcls
inst = super(Interactive, cls).__new__(clss)
inst = super().__new__(clss)
inst._shared_obj = kwargs.get('_shared_obj', [obj])
inst._fn = fn
return inst
Expand Down
6 changes: 3 additions & 3 deletions hvplot/plotting/core.py
Expand Up @@ -57,7 +57,7 @@ def __call__(self, x=None, y=None, kind=None, **kwds):

if isinstance(kind, str) and kind not in self.__all__:
raise NotImplementedError(
"kind='{kind}' for data of type {type}".format(kind=kind, type=type(self._data))
f"kind='{kind}' for data of type {type(self._data)}"
)

if panel_available:
Expand Down Expand Up @@ -115,8 +115,8 @@ def __getattribute__(self, name):
if "kind" in plot_opts and name in HoloViewsConverter._kind_mapping:
param.main.param.warning(
"Custom options for existing plot types should not "
"declare the 'kind' argument. The .%s plot method "
"was unexpectedly customized with kind=%r." % (plot_opts["kind"], name)
"declare the 'kind' argument. The .{} plot method "
"was unexpectedly customized with kind={!r}.".format(plot_opts["kind"], name)
)
plot_opts["kind"] = name
return hvPlotBase(self._data, **dict(self._metadata, **plot_opts))
Expand Down
6 changes: 2 additions & 4 deletions hvplot/plotting/scatter_matrix.py
Expand Up @@ -82,11 +82,9 @@ def scatter_matrix(data, c=None, chart='scatter', diagonal='hist',
data = _hv.Dataset(_convert_col_names_to_str(data))
supported = list(HoloViewsConverter._kind_mapping)
if diagonal not in supported:
raise ValueError('diagonal type must be one of: %s, found %s' %
(supported, diagonal))
raise ValueError(f'diagonal type must be one of: {supported}, found {diagonal}')
if chart not in supported:
raise ValueError('Chart type must be one of: %s, found %s' %
(supported, chart))
raise ValueError(f'Chart type must be one of: {supported}, found {chart}')
diagonal = HoloViewsConverter._kind_mapping[diagonal]
chart = HoloViewsConverter._kind_mapping[chart]

Expand Down
2 changes: 1 addition & 1 deletion hvplot/tests/test_links.py
Expand Up @@ -60,7 +60,7 @@ def _clean_url(url: str):

def _find_urls(text):
url = re.findall(URL_REGEX, text)
return set(_clean_url(x[0]) for x in url if not _skip_url(x[0]))
return {_clean_url(x[0]) for x in url if not _skip_url(x[0])}


def _request_a_response(url):
Expand Down
7 changes: 1 addition & 6 deletions hvplot/tests/testoptions.py
Expand Up @@ -7,7 +7,6 @@

from holoviews import Store
from holoviews.core.options import Options, OptionTree
from packaging.version import Version


@pytest.fixture(scope='class')
Expand Down Expand Up @@ -544,8 +543,4 @@ def test_dataset_scatter_with_title(self, ds2, backend):
ds_sel = ds2.sel(time=0, band=0, x=0, y=0)
plot = ds_sel.hvplot.scatter(x='foo', y='bar') # Image plot
opts = Store.lookup_options(backend, plot, 'plot')
# First assertion to remove when support for Python 3.7 is dropped.
if Version(xr.__version__) < Version('2022.6.0'):
assert opts.kwargs['title'] == 'y = 0, x = 0, time = 0, band = 0'
else:
assert opts.kwargs['title'] == 'time = 0, y = 0, x = 0, band = 0'
assert opts.kwargs['title'] == 'time = 0, y = 0, x = 0, band = 0'
14 changes: 2 additions & 12 deletions hvplot/tests/testui.py
@@ -1,20 +1,10 @@
import holoviews as hv
import hvplot.pandas
import pytest

try:
from bokeh.sampledata import penguins
except ImportError:
penguins = None

from bokeh.sampledata import penguins
from hvplot.ui import hvDataFrameExplorer

pytestmark = pytest.mark.skipif(
penguins is None,
reason='Penguins dataset not available on Python 3.6',
)

df = penguins.data if penguins is not None else None
df = penguins.data


def test_explorer_basic():
Expand Down
4 changes: 0 additions & 4 deletions hvplot/tests/testutil.py
Expand Up @@ -281,10 +281,6 @@ def test_check_crs():
assert p is None


@pytest.mark.skipif(
sys.version_info < (3, 8),
reason="PyProj is no longer releasing for Python 3.7",
)
@pytest.mark.parametrize("input", [
"+init=epsg:26911",
"4326",
Expand Down
2 changes: 1 addition & 1 deletion hvplot/ui.py
Expand Up @@ -577,7 +577,7 @@ def settings(self):
"""
settings = {}
for controller in self._controllers.values():
params = set(controller.param) - set(['name', 'explorer'])
params = set(controller.param) - {'name', 'explorer'}
for p in params:
value = getattr(controller, p)
if value != controller.param[p].default:
Expand Down
2 changes: 1 addition & 1 deletion hvplot/util.py
Expand Up @@ -69,7 +69,7 @@ def check_crs(crs):
try:
crs_type = pyproj.crs.CRS
except AttributeError:
class Dummy():
class Dummy:
pass
crs_type = Dummy

Expand Down
23 changes: 8 additions & 15 deletions setup.py
Expand Up @@ -86,23 +86,18 @@ def get_setup_version(reponame):
'pooch >=1.6.0',
'fiona',
'rioxarray',
# Extra dependency of cartopy on Python 3.6 only
'pyepsg',
'matplotlib',
'plotly',
'pygraphviz',
'ipykernel <6.18.0', # temporary
'numpy < 1.24', # temporary, for a numba error
'ipywidgets',
'numba >=0.51.0',
'datashader >=0.6.5',
'spatialpandas >=0.4.3',
]

# Packages not working on python 3.11 because of numba
if sys.version_info < (3, 11):
extras_require['examples'] += [
'numba >=0.51.0',
'datashader >=0.6.5',
'spatialpandas >=0.4.3',
]
extras_require['examples_conda'] = [
'hdf5 !=1.14.1', # Gives coredump in test suite on Linux and Mac
]

# Run the example tests by installing examples_tests together with tests
extras_require["examples_tests"] = extras_require["examples"] + extras_require['tests_nb']
Expand All @@ -128,7 +123,7 @@ def get_setup_version(reponame):
name='hvplot',
version=get_setup_version("hvplot"),
description='A high-level plotting API for the PyData ecosystem built on HoloViews.',
long_description=open("README.md", mode="r", encoding="utf-8").read(),
long_description=open("README.md", encoding="utf-8").read(),
long_description_content_type="text/markdown",
author= "Philipp Rudiger",
author_email= "developers@pyviz.org",
Expand All @@ -142,8 +137,6 @@ def get_setup_version(reponame):
classifiers = [
"License :: OSI Approved :: BSD License",
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand All @@ -154,7 +147,7 @@ def get_setup_version(reponame):
"Natural Language :: English",
"Topic :: Scientific/Engineering",
"Topic :: Software Development :: Libraries"],
python_requires=">=3.6",
python_requires=">=3.8",
install_requires=install_requires,
extras_require=extras_require,
tests_require=extras_require['tests'],
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Expand Up @@ -3,7 +3,7 @@

[tox]
# python version test group extra envs extra commands
envlist = {py36,py37,py38,py39,py310,py311}-{unit,examples,all}-{default}-{dev,pkg}
envlist = {py38,py39,py310,py311}-{unit,examples,all}-{default}-{dev,pkg}

[_unit]
description = Run unit tests with coverage
Expand Down

0 comments on commit 30999e8

Please sign in to comment.