Skip to content

Commit

Permalink
refactor: Align version check (#6413)
Browse files Browse the repository at this point in the history
  • Loading branch information
hoxbro authored Oct 16, 2024
1 parent ee7a485 commit 31ee32d
Show file tree
Hide file tree
Showing 43 changed files with 170 additions and 190 deletions.
6 changes: 3 additions & 3 deletions examples/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

system = platform.system()
py_version = sys.version_info[:2]
PD2 = Version(pd.__version__) >= Version("2.0")
PANDAS_GE_2_0_0 = Version(pd.__version__).release >= (2, 0, 0)

# Having "OMP_NUM_THREADS"=1, set as an environment variable, can be needed
# to avoid crashing when running tests with pytest-xdist on Windows.
Expand All @@ -30,7 +30,7 @@

# 2023-07-14 with following error:
# ValueError: Buffer dtype mismatch, expected 'const int64_t' but got 'int'
if PD2 and system == "Windows":
if PANDAS_GE_2_0_0 and system == "Windows":
collect_ignore_glob += [
"gallery/demos/bokeh/point_draw_triangulate.ipynb",
"reference/elements/*/TriMesh.ipynb",
Expand All @@ -45,7 +45,7 @@
]

# First available in Bokeh 3.2.0
if Version(bokeh.__version__) < Version("3.2.0"):
if Version(bokeh.__version__).release < (3, 2, 0):
collect_ignore_glob += [
"reference/elements/bokeh/HLines.ipynb",
"reference/elements/bokeh/HSpans.ipynb",
Expand Down
2 changes: 1 addition & 1 deletion holoviews/core/data/dask.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def groupby(cls, dataset, dimensions, container_type, group_type, **kwargs):
for coord in indices:
if any(isinstance(c, float) and np.isnan(c) for c in coord):
continue
if len(coord) == 1 and not util.PANDAS_GE_220:
if len(coord) == 1 and not util.PANDAS_GE_2_2_0:
coord = coord[0]
group = group_type(groupby.get_group(coord), **group_kwargs)
data.append((coord, group))
Expand Down
53 changes: 18 additions & 35 deletions holoviews/core/data/ibis.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
import sys
from collections.abc import Iterable
from functools import lru_cache

import numpy as np
from packaging.version import Version

from .. import util
from ..element import Element
from ..ndmapping import NdMapping, item_check, sorted_context
from .interface import DataError, Interface
from .util import cached


@lru_cache
def ibis_version():
import ibis
return Version(ibis.__version__)


@lru_cache
def ibis4():
return ibis_version() >= Version("4.0")


@lru_cache
def ibis5():
return ibis_version() >= Version("5.0")

@lru_cache
def ibis9_5():
return ibis_version() >= Version("9.5")
IBIS_VERSION = util._no_import_version("ibis-framework")
IBIS_GE_4_0_0 = IBIS_VERSION >= (4, 0, 0)
IBIS_GE_5_0_0 = IBIS_VERSION >= (5, 0, 0)
IBIS_GE_9_5_0 = IBIS_VERSION >= (9, 5, 0)


class IbisInterface(Interface):
Expand Down Expand Up @@ -120,7 +103,7 @@ def persist(cls, dataset):
@cached
def length(self, dataset):
# Get the length by counting the length of an empty query.
if ibis4():
if IBIS_GE_4_0_0:
return dataset.data.count().execute()
else:
return dataset.data[[]].count().execute()
Expand All @@ -129,7 +112,7 @@ def length(self, dataset):
@cached
def nonzero(cls, dataset):
# Make an empty query to see if a row is returned.
if ibis4():
if IBIS_GE_4_0_0:
return bool(len(dataset.data.head(1).execute()))
else:
return bool(len(dataset.data[[]].head(1).execute()))
Expand Down Expand Up @@ -163,7 +146,7 @@ def values(
dimension = dataset.get_dimension(dimension, strict=True)
data = dataset.data[dimension.name]
if (
ibis_version() > Version("3")
IBIS_VERSION > (3, 0, 0)
and isinstance(data, ibis.expr.types.AnyColumn)
and not expanded
):
Expand All @@ -178,12 +161,12 @@ def histogram(cls, expr, bins, density=True, weights=None):
bins = [int(v) if bins.dtype.kind in 'iu' else float(v) for v in bins]
binned = expr.bucket(bins).name('bucket')
hist = np.zeros(len(bins)-1)
if ibis4():
if IBIS_GE_4_0_0:
hist_bins = binned.value_counts().order_by('bucket').execute()
else:
# sort_by will be removed in Ibis 5.0
hist_bins = binned.value_counts().sort_by('bucket').execute()
metric_name = 'bucket_count' if ibis5() else 'count'
metric_name = 'bucket_count' if IBIS_GE_5_0_0 else 'count'
for b, v in zip(hist_bins['bucket'], hist_bins[metric_name]):
if np.isnan(b):
continue
Expand Down Expand Up @@ -212,11 +195,11 @@ def dtype(cls, dataset, dimension):
def sort(cls, dataset, by=None, reverse=False):
if by is None:
by = []
if ibis_version() >= Version("6.0"):
if IBIS_VERSION >= (6, 0, 0):
import ibis
order = ibis.desc if reverse else ibis.asc
return dataset.data.order_by([order(dataset.get_dimension(x).name) for x in by])
elif ibis4():
elif IBIS_GE_4_0_0:
# Tuple syntax will be removed in Ibis 7.0:
# https://github.com/ibis-project/ibis/pull/6082
return dataset.data.order_by([(dataset.get_dimension(x).name, not reverse) for x in by])
Expand Down Expand Up @@ -245,7 +228,7 @@ def _index_ibis_table(cls, data):
if "hv_row_id__" in data.columns:
return data

if ibis4():
if IBIS_GE_4_0_0:
return data.mutate(hv_row_id__=ibis.row_number())
elif cls.is_rowid_zero_indexed(data):
return data.mutate(hv_row_id__=data.rowid())
Expand Down Expand Up @@ -290,7 +273,7 @@ def iloc(cls, dataset, index):
rows = [rows]
data = data.filter([data.hv_row_id__.isin(rows)])

if ibis4():
if IBIS_GE_4_0_0:
return data.drop("hv_row_id__")
else:
# Passing a sequence of fields to `drop` will be removed in Ibis 5.0
Expand All @@ -302,7 +285,7 @@ def unpack_scalar(cls, dataset, data):
Given a dataset object and data in the appropriate format for
the interface, return a simple scalar.
"""
if ibis4():
if IBIS_GE_4_0_0:
count = data.count().execute()
else:
count = data[[]].count().execute()
Expand All @@ -326,7 +309,7 @@ def groupby(cls, dataset, dimensions, container_type, group_type, **kwargs):
group_by = [d.name for d in index_dims]

# execute a query against the table to find the unique groups.
if ibis4():
if IBIS_GE_4_0_0:
groups = dataset.data.group_by(group_by).aggregate().execute()
else:
# groupby will be removed in Ibis 5.0
Expand Down Expand Up @@ -392,7 +375,7 @@ def select(cls, dataset, selection_mask=None, **selection):
data["hv_row_id__"].isin(list(map(int, selection_mask)))
)

if ibis4():
if IBIS_GE_4_0_0:
data = data.drop("hv_row_id__")
else:
# Passing a sequence of fields to `drop` will be removed in Ibis 5.0
Expand Down Expand Up @@ -462,7 +445,7 @@ def sample(cls, dataset, samples=None):
if all(util.isscalar(s) or len(s) == 1 for s in samples):
items = [s[0] if isinstance(s, tuple) else s for s in samples]
subset = data[dims[0].name].isin(items)
return data.filter(subset) if ibis9_5() else data[subset]
return data.filter(subset) if IBIS_GE_9_5_0 else data[subset]

predicates = None
for sample in samples:
Expand Down Expand Up @@ -508,7 +491,7 @@ def aggregate(cls, dataset, dimensions, function, **kwargs):
}.get(function, function)

if len(dimensions):
if ibis4():
if IBIS_GE_4_0_0:
selection = new.group_by(columns)
else:
# groupby will be removed in Ibis 5.0
Expand Down
9 changes: 4 additions & 5 deletions holoviews/core/data/pandas.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import numpy as np
import pandas as pd
from packaging.version import Version
from pandas.api.types import is_numeric_dtype

from .. import util
from ..dimension import Dimension, dimension_name
from ..element import Element
from ..ndmapping import NdMapping, item_check, sorted_context
from ..util import PANDAS_GE_210
from ..util import PANDAS_GE_2_1_0
from .interface import DataError, Interface
from .util import finite_range

Expand Down Expand Up @@ -251,14 +250,14 @@ def groupby(cls, dataset, dimensions, container_type, group_type, **kwargs):
group_kwargs['dataset'] = dataset.dataset

group_by = [d.name for d in index_dims]
if len(group_by) == 1 and util.pandas_version >= Version("1.5.0"):
if len(group_by) == 1 and util.PANDAS_VERSION >= (1, 5, 0):
# Because of this deprecation warning from pandas 1.5.0:
# In a future version of pandas, a length 1 tuple will be returned
# when iterating over a groupby with a grouper equal to a list of length 1.
# Don't supply a list with a single grouper to avoid this warning.
group_by = group_by[0]
groupby_kwargs = {"sort": False}
if PANDAS_GE_210:
if PANDAS_GE_2_1_0:
groupby_kwargs["observed"] = False
data = [(k, group_type(v, **group_kwargs)) for k, v in
dataset.data.groupby(group_by, **groupby_kwargs)]
Expand Down Expand Up @@ -296,7 +295,7 @@ def aggregate(cls, dataset, dimensions, function, **kwargs):
if is_numeric_dtype(d) and c not in cols
]
groupby_kwargs = {"sort": False}
if PANDAS_GE_210:
if PANDAS_GE_2_1_0:
groupby_kwargs["observed"] = False
grouped = reindexed.groupby(cols, **groupby_kwargs)
df = grouped[numeric_cols].aggregate(fn, **kwargs).reset_index()
Expand Down
21 changes: 15 additions & 6 deletions holoviews/core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from collections import defaultdict, namedtuple
from contextlib import contextmanager
from functools import partial
from importlib.metadata import PackageNotFoundError, version
from threading import Event, Thread
from types import FunctionType

Expand All @@ -38,13 +39,13 @@
get_keywords = operator.attrgetter('varkw')

# Versions
numpy_version = Version(Version(np.__version__).base_version)
param_version = Version(param.__version__)
pandas_version = Version(pd.__version__)
NUMPY_VERSION = Version(np.__version__).release
PARAM_VERSION = Version(param.__version__).release
PANDAS_VERSION = Version(pd.__version__).release

NUMPY_GE_200 = numpy_version >= Version("2")
PANDAS_GE_210 = pandas_version >= Version("2.1")
PANDAS_GE_220 = pandas_version >= Version("2.2")
NUMPY_GE_2_0_0 = NUMPY_VERSION >= (2, 0, 0)
PANDAS_GE_2_1_0 = PANDAS_VERSION >= (2, 1, 0)
PANDAS_GE_2_2_0 = PANDAS_VERSION >= (2, 2, 0)

# Types
generator_types = (zip, range, types.GeneratorType)
Expand Down Expand Up @@ -115,6 +116,14 @@ def __init__(self, msg, version=None, min_version=None, **kwargs):
super().__init__(msg, **kwargs)


def _no_import_version(name) -> tuple[int, int, int]:
""" Get version number without importing the library """
try:
return Version(version(name)).release
except PackageNotFoundError:
return (0, 0, 0)


class Config(param.ParameterizedFunction):
"""
Set of boolean configuration values to change HoloViews' global
Expand Down
4 changes: 2 additions & 2 deletions holoviews/element/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from ..core.operation import Operation
from ..core.sheetcoords import Slice
from ..core.util import (
PANDAS_GE_210,
PANDAS_GE_2_1_0,
cartesian_product,
datetime_types,
is_cyclic,
Expand Down Expand Up @@ -202,7 +202,7 @@ def _aggregate_dataset(self, obj):
def _aggregate_dataset_pandas(self, obj):
index_cols = [d.name for d in obj.kdims]
groupby_kwargs = {"sort": False}
if PANDAS_GE_210:
if PANDAS_GE_2_1_0:
groupby_kwargs["observed"] = False
df = obj.data.set_index(index_cols).groupby(index_cols, **groupby_kwargs).first()
label = 'unique' if len(df) == len(obj) else 'non-unique'
Expand Down
10 changes: 5 additions & 5 deletions holoviews/operation/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ def _process(self, element, key=None):
if self.p.filled:
vdims = [vdims[0].clone(range=crange)]

if Version(contourpy_version) >= Version('1.2'):
if Version(contourpy_version).release >= (1, 2, 0):
line_type = LineType.ChunkCombinedNan
else:
line_type = LineType.ChunkCombinedOffset
Expand Down Expand Up @@ -821,7 +821,7 @@ def _process(self, element, key=None, groupby=False):
is_cupy = is_cupy_array(data)
if is_cupy:
import cupy
full_cupy_support = Version(cupy.__version__) > Version('8.0')
full_cupy_support = Version(cupy.__version__).release > (8, 0, 0)
if not full_cupy_support and (normed or self.p.weight_dimension):
data = cupy.asnumpy(data)
is_cupy = False
Expand All @@ -830,17 +830,17 @@ def _process(self, element, key=None, groupby=False):

# Mask data
if is_ibis_expr(data):
from ..core.data.ibis import ibis5, ibis9_5
from ..core.data.ibis import IBIS_GE_5_0_0, IBIS_GE_9_5_0

mask = data.notnull()
if self.p.nonzero:
mask = mask & (data != 0)
if ibis5():
if IBIS_GE_5_0_0:
data = data.as_table()
else:
# to_projection removed in ibis 5.0.0
data = data.to_projection()
data = data.filter(mask) if ibis9_5() else data[mask]
data = data.filter(mask) if IBIS_GE_9_5_0 else data[mask]
no_data = not len(data.head(1).execute())
data = data[dim.name]
else:
Expand Down
2 changes: 1 addition & 1 deletion holoviews/plotting/bokeh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
from .stats import BivariatePlot, BoxWhiskerPlot, DistributionPlot, ViolinPlot
from .tabular import TablePlot
from .tiles import TilePlot
from .util import bokeh_version # noqa (API import)
from .util import BOKEH_VERSION # noqa (API import)

Store.renderers['bokeh'] = BokehRenderer.instance()

Expand Down
4 changes: 2 additions & 2 deletions holoviews/plotting/bokeh/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
line_properties,
text_properties,
)
from .util import bokeh32, date_to_integer
from .util import BOKEH_GE_3_2_0, date_to_integer

arrow_start = {'<->': NormalHead, '<|-|>': NormalHead}
arrow_end = {'->': NormalHead, '-[': TeeHead, '-|>': NormalHead,
Expand All @@ -39,7 +39,7 @@ class _SyntheticAnnotationPlot(ColorbarPlot):
_allow_implicit_categories = False

def __init__(self, element, **kwargs):
if not bokeh32:
if not BOKEH_GE_3_2_0:
name = type(getattr(element, "last", element)).__name__
msg = f'{name} element requires Bokeh >=3.2'
raise ImportError(msg)
Expand Down
4 changes: 2 additions & 2 deletions holoviews/plotting/bokeh/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
Tap,
)
from ...util.warnings import warn
from .util import bokeh33, convert_timestamp
from .util import BOKEH_GE_3_3_0, convert_timestamp


class Callback:
Expand Down Expand Up @@ -1569,7 +1569,7 @@ def initialize(self, plot_id=None):
renderer = self._path_initialize()
if stream.styles:
self._create_style_callback(cds, renderer.glyph)
if bokeh33:
if BOKEH_GE_3_3_0:
# First version with Quad support
box_tool = BoxEditTool(renderers=[renderer], **kwargs)
self.plot.state.tools.append(box_tool)
Expand Down
Loading

0 comments on commit 31ee32d

Please sign in to comment.