From baa69b10a452c92ec98623c6d22435b151e991d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8xbro=20Hansen?= Date: Fri, 15 Mar 2024 09:31:27 +0100 Subject: [PATCH] Bump ruff and remove Bokeh rc workarounds (#6152) --- .github/workflows/test.yaml | 27 ++++++++++----------------- .pre-commit-config.yaml | 2 +- holoviews/core/dimension.py | 10 ++++++---- holoviews/core/io.py | 3 +-- holoviews/element/raster.py | 20 ++++++++++++-------- holoviews/ipython/archive.py | 3 +-- holoviews/operation/datashader.py | 7 ++++--- holoviews/plotting/bokeh/element.py | 12 +++++------- holoviews/plotting/plot.py | 5 +++-- holoviews/plotting/plotly/element.py | 23 +++++++++-------------- holoviews/plotting/util.py | 12 ++++++------ holoviews/streams.py | 7 ++++--- holoviews/tests/utils.py | 6 ++---- holoviews/util/__init__.py | 10 ++++------ scripts/check_latest_packages.py | 2 +- 15 files changed, 69 insertions(+), 80 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 151127c47a..4b2486c528 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -129,7 +129,7 @@ jobs: name: unit_test_suite python-version: ${{ matrix.python-version }} channel-priority: flexible - channels: pyviz/label/dev,bokeh/label/dev,conda-forge,nodefaults + channels: pyviz/label/dev,conda-forge,nodefaults envs: "-o flakes -o tests -o examples_tests -o tests_ci" cache: ${{ github.event.inputs.cache || github.event.inputs.cache == '' }} conda-update: true @@ -138,14 +138,8 @@ jobs: if: needs.setup.outputs.code_change == 'true' run: | conda activate test-environment - touch ${CONDA_PREFIX}/etc/OpenCL/vendors/mute || true # https://github.com/conda-forge/ocl-icd-feedstock/issues/29 - - name: Force latest Panel and Bokeh dev releases - if: needs.setup.outputs.code_change == 'true' - run: | - conda activate test-environment - conda uninstall panel bokeh --force --offline -y || true - pip install bokeh panel --pre - echo "Installing dev releases of Panel and Bokeh" >> $GITHUB_STEP_SUMMARY + # https://github.com/conda-forge/ocl-icd-feedstock/issues/29 + touch ${CONDA_PREFIX}/etc/OpenCL/vendors/mute || true - name: Check packages latest version if: needs.setup.outputs.code_change == 'true' run: | @@ -195,7 +189,7 @@ jobs: with: name: ui_test_suite python-version: ${{ matrix.python-version }} - channels: pyviz/label/dev,bokeh/label/dev,conda-forge,nodefaults + channels: pyviz/label/dev,conda-forge,nodefaults envs: "-o recommended -o tests -o build -o tests_ci" cache: ${{ github.event.inputs.cache || github.event.inputs.cache == '' }} playwright: true @@ -205,13 +199,6 @@ jobs: run: | conda activate test-environment touch ${CONDA_PREFIX}/etc/OpenCL/vendors/mute || true # https://github.com/conda-forge/ocl-icd-feedstock/issues/29 - - name: Force latest Panel and Bokeh dev releases - if: needs.setup.outputs.code_change == 'true' - run: | - conda activate test-environment - conda uninstall panel bokeh --force --offline -y || true - pip install bokeh panel --pre - echo "Installing dev releases of Panel and Bokeh" >> $GITHUB_STEP_SUMMARY - name: doit test_ui if: needs.setup.outputs.code_change == 'true' run: | @@ -266,6 +253,12 @@ jobs: if: needs.setup.outputs.code_change == 'true' run: | python -m pip install -ve '.[tests_core, tests_ci]' + - name: install panel pre + if: needs.setup.outputs.code_change == 'true' + run: | + python -m pip install panel --pre --upgrade + python -m pip install bokeh --upgrade + echo "Installing dev release of Panel" >> $GITHUB_STEP_SUMMARY - name: Download data if: needs.setup.outputs.code_change == 'true' run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7e752370a6..cd84663faf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: - id: check-json - id: detect-private-key - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.0 + rev: v0.3.2 hooks: - id: ruff files: holoviews/|scripts/ diff --git a/holoviews/core/dimension.py b/holoviews/core/dimension.py index 6ff601295c..59218185f9 100644 --- a/holoviews/core/dimension.py +++ b/holoviews/core/dimension.py @@ -109,10 +109,12 @@ def process_dimensions(kdims, vdims): elif isinstance(dims, (tuple, str, Dimension, dict)): dims = [dims] elif not isinstance(dims, list): - raise ValueError("{} argument expects a Dimension or list of dimensions, " - "specified as tuples, strings, dictionaries or Dimension " - "instances, not a {} type. Ensure you passed the data as the " - "first argument.".format(group, type(dims).__name__)) + raise ValueError( + f"{group} argument expects a Dimension or list of dimensions, " + "specified as tuples, strings, dictionaries or Dimension " + f"instances, not a {type(dims).__name__} type. " + "Ensure you passed the data as the first argument." + ) dimensions[group] = [asdim(d) for d in dims] return dimensions diff --git a/holoviews/core/io.py b/holoviews/core/io.py index 13ddd9b45e..774238ece4 100644 --- a/holoviews/core/io.py +++ b/holoviews/core/io.py @@ -370,8 +370,7 @@ def save(self_or_cls, obj, filename, key=None, info=None, **kwargs): components = list(obj.data.values()) entries = entries if len(entries) > 1 else [entries[0]+'(L)'] else: - entries = ['{}.{}'.format(group_sanitizer(obj.group, False), - label_sanitizer(obj.label, False))] + entries = [f'{group_sanitizer(obj.group, False)}.{label_sanitizer(obj.label, False)}'] components = [obj] for component, entry in zip(components, entries): diff --git a/holoviews/element/raster.py b/holoviews/element/raster.py index 19cf97e28e..8075bfff3b 100644 --- a/holoviews/element/raster.py +++ b/holoviews/element/raster.py @@ -278,10 +278,12 @@ def __init__(self, data, kdims=None, vdims=None, bounds=None, extents=None, Dataset.__init__(self, data, kdims=kdims, vdims=vdims, extents=extents, **params) if not self.interface.gridded: - raise DataError("{} type expects gridded data, {} is columnar. " - "To display columnar data as gridded use the HeatMap " - "element or aggregate the data (e.g. using rasterize " - "or np.histogram2d).".format(type(self).__name__, self.interface.__name__)) + raise DataError( + f"{type(self).__name__} type expects gridded data, " + f"{self.interface.__name__} is columnar. " + "To display columnar data as gridded use the HeatMap " + "element or aggregate the data (e.g. using np.histogram2d)." + ) dim2, dim1 = self.interface.shape(self, gridded=True)[:2] if bounds is None: @@ -800,10 +802,12 @@ def __init__(self, data, kdims=None, vdims=None, **params): data = ([], [], np.zeros((0, 0))) super().__init__(data, kdims, vdims, **params) if not self.interface.gridded: - raise DataError("{} type expects gridded data, {} is columnar. " - "To display columnar data as gridded use the HeatMap " - "element or aggregate the data (e.g. using " - "np.histogram2d).".format(type(self).__name__, self.interface.__name__)) + raise DataError( + f"{type(self).__name__} type expects gridded data, " + f"{self.interface.__name__} is columnar. " + "To display columnar data as gridded use the HeatMap " + "element or aggregate the data (e.g. using np.histogram2d)." + ) def trimesh(self): """ diff --git a/holoviews/ipython/archive.py b/holoviews/ipython/archive.py index 5eefa4f873..e6acd4d67f 100644 --- a/holoviews/ipython/archive.py +++ b/holoviews/ipython/archive.py @@ -147,8 +147,7 @@ def export(self, timestamp=None): tstamp = time.strftime(self.timestamp_format, self._timestamp) export_name = self._format(self.export_name, {'timestamp':tstamp, 'notebook':self.notebook_name}) - print(('Export name: {!r}\nDirectory {!r}'.format(export_name, - os.path.join(os.path.abspath(self.root)))) + print((f'Export name: {export_name!r}\nDirectory {os.path.join(os.path.abspath(self.root))!r}') + '\n\nIf no output appears, please check holoviews.archive.last_export_status()') display(Javascript(cmd)) diff --git a/holoviews/operation/datashader.py b/holoviews/operation/datashader.py index 08f2688661..d527d689fd 100644 --- a/holoviews/operation/datashader.py +++ b/holoviews/operation/datashader.py @@ -194,9 +194,10 @@ def _get_agg_params(self, element, x, y, agg_fn, bounds): elif column: dims = [d for d in element.dimensions('ranges') if d == column] if not dims: - raise ValueError("Aggregation column '{}' not found on '{}' element. " - "Ensure the aggregator references an existing " - "dimension.".format(column,element)) + raise ValueError( + f"Aggregation column '{column}' not found on '{element}' element. " + "Ensure the aggregator references an existing dimension." + ) if isinstance(agg_fn, (ds.count, ds.count_cat)): if vdim_prefix: vdim_name = f'{vdim_prefix}{column} Count' diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py index 2d49588b7e..05972603ec 100644 --- a/holoviews/plotting/bokeh/element.py +++ b/holoviews/plotting/bokeh/element.py @@ -1577,14 +1577,12 @@ def _apply_transforms(self, element, data, ranges, style, group=None): if not util.isscalar(val): if k in self._nonvectorized_styles: element = type(element).__name__ - raise ValueError('Mapping a dimension to the "{style}" ' + raise ValueError(f'Mapping a dimension to the "{k}" ' 'style option is not supported by the ' - '{element} element using the {backend} ' - 'backend. To map the "{dim}" dimension ' - 'to the {style} use a groupby operation ' - 'to overlay your data along the dimension.'.format( - style=k, dim=v.dimension, element=element, - backend=self.renderer.backend)) + f'{element} element using the {self.renderer.backend} ' + f'backend. To map the "{v.dimension}" dimension ' + f'to the {k} use a groupby operation ' + 'to overlay your data along the dimension.') elif data and len(val) != len(next(iter(data.values()))): if isinstance(element, VectorField): val = np.tile(val, 3) diff --git a/holoviews/plotting/plot.py b/holoviews/plotting/plot.py index d8b4c94d5b..7df8aa5e64 100644 --- a/holoviews/plotting/plot.py +++ b/holoviews/plotting/plot.py @@ -1828,8 +1828,9 @@ def _create_subplot(self, key, obj, streams, ranges): plottype = registry.get(vtype, None) if plottype is None: self.param.warning( - "No plotting class for {} type and {} backend " - "found. ".format(vtype.__name__, self.renderer.backend)) + f"No plotting class for {vtype.__name__} type " + f"and {self.renderer.backend} backend found. " + ) return None # Get zorder and style counter diff --git a/holoviews/plotting/plotly/element.py b/holoviews/plotting/plotly/element.py index 504c7dcdea..564f67139f 100644 --- a/holoviews/plotting/plotly/element.py +++ b/holoviews/plotting/plotly/element.py @@ -174,11 +174,8 @@ def generate_plot(self, key, ranges, element=None, is_geo=False): ] if unsupported_opts: raise ValueError( - "The following {typ} style options are not supported by the Plotly " - "backend when overlaid on Tiles:\n" - " {unsupported_opts}".format( - typ=type(element).__name__, unsupported_opts=unsupported_opts - ) + f"The following {type(element).__name__} style options are not supported by the Plotly " + f"backend when overlaid on Tiles:\n {unsupported_opts}" ) # Get data and options and merge them @@ -352,8 +349,8 @@ def _apply_transforms(self, element, ranges, style): continue elif (not v.applies(element) and v.dimension not in self.overlay_dims): new_style.pop(k) - self.param.warning('Specified {} dim transform {!r} could not be applied, as not all ' - 'dimensions could be resolved.'.format(k, v)) + self.param.warning(f'Specified {k} dim transform {v!r} could not be applied, as not all ' + 'dimensions could be resolved.') continue if len(v.ops) == 0 and v.dimension in self.overlay_dims: @@ -368,14 +365,12 @@ def _apply_transforms(self, element, ranges, style): if not util.isscalar(val): if k in self._nonvectorized_styles: element = type(element).__name__ - raise ValueError('Mapping a dimension to the "{style}" ' + raise ValueError(f'Mapping a dimension to the "{k}" ' 'style option is not supported by the ' - '{element} element using the {backend} ' - 'backend. To map the "{dim}" dimension ' - 'to the {style} use a groupby operation ' - 'to overlay your data along the dimension.'.format( - style=k, dim=v.dimension, element=element, - backend=self.renderer.backend)) + f'{element} element using the {self.renderer.backend} ' + f'backend. To map the "{v.dimension}" dimension ' + f'to the {k} use a groupby operation ' + 'to overlay your data along the dimension.') # If color is not valid colorspec add colormapper numeric = isinstance(val, np.ndarray) and val.dtype.kind in 'uifMm' diff --git a/holoviews/plotting/util.py b/holoviews/plotting/util.py index d03e9bbe2f..3cc2947bae 100644 --- a/holoviews/plotting/util.py +++ b/holoviews/plotting/util.py @@ -83,12 +83,12 @@ def collate(obj): return obj.collate() if isinstance(obj, HoloMap): display_warning.param.warning( - "Nesting {0}s within a {1} makes it difficult to access " - "your data or control how it appears; we recommend " - "calling .collate() on the {1} in order to follow the " - "recommended nesting structure shown in the Composing " - "Data user guide (https://goo.gl/2YS8LJ)".format( - obj.type.__name__, type(obj).__name__)) + f"Nesting {obj.type.__name__}s within a {type(obj).__name__} " + "makes it difficult to access your data or control how it appears; " + f"we recommend calling .collate() on the {type(obj).__name__} " + "in order to follow the recommended nesting structure shown " + "in the Composing Data user guide (https://goo.gl/2YS8LJ)" + ) return obj.collate() elif isinstance(obj, (Layout, NdLayout)): try: diff --git a/holoviews/streams.py b/holoviews/streams.py index 75f66af7af..7a61a00cdf 100644 --- a/holoviews/streams.py +++ b/holoviews/streams.py @@ -240,12 +240,13 @@ def _process_streams(cls, streams): if overlap: pname = type(s.parameterized).__name__ param.main.param.warning( - 'The {} parameter(s) on the {} object have ' + f'The {sorted([p.name for p in overlap])} parameter(s) ' + f'on the {pname} object have ' 'already been supplied in another stream. ' 'Ensure that the supplied streams only specify ' 'each parameter once, otherwise multiple ' - 'events will be triggered when the parameter ' - 'changes.'.format(sorted([p.name for p in overlap]), pname)) + 'events will be triggered when the parameter changes.' + ) parameterizeds[pid] |= set(s.parameters) valid.append(s) return valid, invalid diff --git a/holoviews/tests/utils.py b/holoviews/tests/utils.py index c763122272..35c5670886 100644 --- a/holoviews/tests/utils.py +++ b/holoviews/tests/utils.py @@ -59,8 +59,7 @@ def assertEndsWith(self, level, substring): msg='\n\n{method}: {last_line}\ndoes not end with:\n{substring}' last_line = self.tail(level, n=1) if len(last_line) == 0: - raise AssertionError('Missing {method} output: {substring}'.format( - method=self.param_methods[level], substring=repr(substring))) + raise AssertionError(f'Missing {self.param_methods[level]} output: {substring!r}') if not last_line[0].endswith(substring): raise AssertionError(msg.format(method=self.param_methods[level], last_line=repr(last_line[0]), @@ -77,8 +76,7 @@ def assertContains(self, level, substring): msg='\n\n{method}: {last_line}\ndoes not contain:\n{substring}' last_line = self.tail(level, n=1) if len(last_line) == 0: - raise AssertionError('Missing {method} output: {substring}'.format( - method=self.param_methods[level], substring=repr(substring))) + raise AssertionError(f'Missing {self.param_methods[level]} output: {substring!r}') if substring not in last_line[0]: raise AssertionError(msg.format(method=self.param_methods[level], last_line=repr(last_line[0]), diff --git a/holoviews/util/__init__.py b/holoviews/util/__init__.py index 34d384e32c..fd11c49441 100644 --- a/holoviews/util/__init__.py +++ b/holoviews/util/__init__.py @@ -139,9 +139,7 @@ def _group_kwargs_to_options(cls, obj, kwargs): # Not targets specified - add current object as target sanitized_group = util.group_sanitizer(obj.group) if obj.label: - identifier = ('{}.{}.{}'.format( - obj.__class__.__name__, sanitized_group, - util.label_sanitizer(obj.label))) + identifier = (f'{obj.__class__.__name__}.{sanitized_group}.{util.label_sanitizer(obj.label)}') elif sanitized_group != obj.__class__.__name__: identifier = f'{obj.__class__.__name__}.{sanitized_group}' else: @@ -333,10 +331,10 @@ def _expand_options(cls, options, backend=None): "holoviews.plotting before applying any " "options.") elif current_backend not in Store.renderers: - raise ValueError("Currently selected plotting extension {ext} " + raise ValueError(f"Currently selected plotting extension {current_backend!r} " "has not been loaded, ensure you load it " - "with hv.extension({ext}) before setting " - "options".format(ext=repr(current_backend))) + f"with hv.extension({current_backend!r}) before setting " + "options") try: backend_options = Store.options(backend=backend or current_backend) diff --git a/scripts/check_latest_packages.py b/scripts/check_latest_packages.py index 407f24a2a0..e99f485efd 100644 --- a/scripts/check_latest_packages.py +++ b/scripts/check_latest_packages.py @@ -30,7 +30,7 @@ def main(*packages): ).date() version_check = Version(current) >= Version(latest) - date_check = current_release_date >= allowed_date + date_check = latest_release_date >= allowed_date is_latest = version_check or date_check all_latest &= is_latest