From 1ea2ce2dbe9ec16e2dce5e9270e6a06924e95f87 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 28 May 2025 17:29:06 +0200 Subject: [PATCH 1/8] Apply ruff/flake8-simplify rule SIM102 SIM102 Use a single `if` statement instead of nested `if` statements --- xarray/backends/h5netcdf_.py | 21 ++++++++++----------- xarray/backends/netcdf3.py | 9 ++++----- xarray/coding/times.py | 11 +++++------ xarray/computation/computation.py | 10 ++++------ xarray/core/dataset.py | 25 ++++++++++++------------- xarray/core/formatting.py | 5 ++--- xarray/core/groupby.py | 11 ++++++----- xarray/core/variable.py | 17 ++++++++--------- xarray/plot/utils.py | 19 +++++++++---------- xarray/structure/concat.py | 6 ++---- xarray/tests/test_computation.py | 10 ++++------ 11 files changed, 66 insertions(+), 78 deletions(-) diff --git a/xarray/backends/h5netcdf_.py b/xarray/backends/h5netcdf_.py index 6e0e5a2cf3f..ba3a6d20e37 100644 --- a/xarray/backends/h5netcdf_.py +++ b/xarray/backends/h5netcdf_.py @@ -68,17 +68,16 @@ def _read_attributes(h5netcdf_var): # bytes attributes to strings attrs = {} for k, v in h5netcdf_var.attrs.items(): - if k not in ["_FillValue", "missing_value"]: - if isinstance(v, bytes): - try: - v = v.decode("utf-8") - except UnicodeDecodeError: - emit_user_level_warning( - f"'utf-8' codec can't decode bytes for attribute " - f"{k!r} of h5netcdf object {h5netcdf_var.name!r}, " - f"returning bytes undecoded.", - UnicodeWarning, - ) + if k not in ["_FillValue", "missing_value"] and isinstance(v, bytes): + try: + v = v.decode("utf-8") + except UnicodeDecodeError: + emit_user_level_warning( + f"'utf-8' codec can't decode bytes for attribute " + f"{k!r} of h5netcdf object {h5netcdf_var.name!r}, " + f"returning bytes undecoded.", + UnicodeWarning, + ) attrs[k] = v return attrs diff --git a/xarray/backends/netcdf3.py b/xarray/backends/netcdf3.py index 70ddbdd1e01..3ae024c9760 100644 --- a/xarray/backends/netcdf3.py +++ b/xarray/backends/netcdf3.py @@ -111,11 +111,10 @@ def _maybe_prepare_times(var): data = var.data if data.dtype.kind in "iu": units = var.attrs.get("units", None) - if units is not None: - if coding.variables._is_time_like(units): - mask = data == np.iinfo(np.int64).min - if mask.any(): - data = np.where(mask, var.attrs.get("_FillValue", np.nan), data) + if units is not None and coding.variables._is_time_like(units): + mask = data == np.iinfo(np.int64).min + if mask.any(): + data = np.where(mask, var.attrs.get("_FillValue", np.nan), data) return data diff --git a/xarray/coding/times.py b/xarray/coding/times.py index bec374e4fd9..adea7c4186a 100644 --- a/xarray/coding/times.py +++ b/xarray/coding/times.py @@ -429,12 +429,11 @@ def _check_date_is_after_shift( # if we are outside the well-defined date range # proleptic_gregorian and standard/gregorian are only equivalent # if reference date and date range is >= 1582-10-15 - if calendar != "proleptic_gregorian": - if date < type(date)(1582, 10, 15): - raise OutOfBoundsDatetime( - f"Dates before 1582-10-15 cannot be decoded " - f"with pandas using {calendar!r} calendar: {date}" - ) + if calendar != "proleptic_gregorian" and date < type(date)(1582, 10, 15): + raise OutOfBoundsDatetime( + f"Dates before 1582-10-15 cannot be decoded " + f"with pandas using {calendar!r} calendar: {date}" + ) def _check_higher_resolution( diff --git a/xarray/computation/computation.py b/xarray/computation/computation.py index 941df87e8b3..4ec9651dc07 100644 --- a/xarray/computation/computation.py +++ b/xarray/computation/computation.py @@ -144,9 +144,8 @@ def cov( "Only xr.DataArray is supported." f"Given {[type(arr) for arr in [da_a, da_b]]}." ) - if weights is not None: - if not isinstance(weights, DataArray): - raise TypeError(f"Only xr.DataArray is supported. Given {type(weights)}.") + if weights is not None and not isinstance(weights, DataArray): + raise TypeError(f"Only xr.DataArray is supported. Given {type(weights)}.") return _cov_corr(da_a, da_b, weights=weights, dim=dim, ddof=ddof, method="cov") @@ -248,9 +247,8 @@ def corr( "Only xr.DataArray is supported." f"Given {[type(arr) for arr in [da_a, da_b]]}." ) - if weights is not None: - if not isinstance(weights, DataArray): - raise TypeError(f"Only xr.DataArray is supported. Given {type(weights)}.") + if weights is not None and not isinstance(weights, DataArray): + raise TypeError(f"Only xr.DataArray is supported. Given {type(weights)}.") return _cov_corr(da_a, da_b, weights=weights, dim=dim, method="corr") diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 7298d3e994b..bb97c9f5e5b 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -8141,19 +8141,18 @@ def quantile( for name, var in self.variables.items(): reduce_dims = [d for d in var.dims if d in dims] if reduce_dims or not var.dims: - if name not in self.coords: - if ( - not numeric_only - or np.issubdtype(var.dtype, np.number) - or var.dtype == np.bool_ - ): - variables[name] = var.quantile( - q, - dim=reduce_dims, - method=method, - keep_attrs=keep_attrs, - skipna=skipna, - ) + if name not in self.coords and ( + not numeric_only + or np.issubdtype(var.dtype, np.number) + or var.dtype == np.bool_ + ): + variables[name] = var.quantile( + q, + dim=reduce_dims, + method=method, + keep_attrs=keep_attrs, + skipna=skipna, + ) else: variables[name] = var diff --git a/xarray/core/formatting.py b/xarray/core/formatting.py index 7aa333ffb2e..756ca0b9803 100644 --- a/xarray/core/formatting.py +++ b/xarray/core/formatting.py @@ -1054,9 +1054,8 @@ def diff_datatree_repr(a: DataTree, b: DataTree, compat): f"Left and right {type(a).__name__} objects are not {_compat_to_str(compat)}" ] - if compat == "identical": - if diff_name := diff_name_summary(a, b): - summary.append(diff_name) + if compat == "identical" and (diff_name := diff_name_summary(a, b)): + summary.append(diff_name) treestructure_diff = diff_treestructure(a, b) diff --git a/xarray/core/groupby.py b/xarray/core/groupby.py index e1541a98af0..c049ca78f45 100644 --- a/xarray/core/groupby.py +++ b/xarray/core/groupby.py @@ -979,11 +979,12 @@ def _maybe_reindex(self, combined): index = combined._indexes.get(grouper.name, None) if has_missing_groups and index is not None: indexers[grouper.name] = grouper.full_index - elif len(self.groupers) > 1: - if not isinstance( - grouper.full_index, pd.RangeIndex - ) and not index.index.equals(grouper.full_index): - indexers[grouper.name] = grouper.full_index + elif ( + len(self.groupers) > 1 + and not isinstance(grouper.full_index, pd.RangeIndex) + and not index.index.equals(grouper.full_index) + ): + indexers[grouper.name] = grouper.full_index if indexers: combined = combined.reindex(**indexers) return combined diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 4e58b0d4b20..828860ef76a 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -168,15 +168,14 @@ def as_variable( f"explicit list of dimensions: {obj!r}" ) - if auto_convert: - if name is not None and name in obj.dims and obj.ndim == 1: - # automatically convert the Variable into an Index - emit_user_level_warning( - f"variable {name!r} with name matching its dimension will not be " - "automatically converted into an `IndexVariable` object in the future.", - FutureWarning, - ) - obj = obj.to_index_variable() + if auto_convert and name is not None and name in obj.dims and obj.ndim == 1: + # automatically convert the Variable into an Index + emit_user_level_warning( + f"variable {name!r} with name matching its dimension will not be " + "automatically converted into an `IndexVariable` object in the future.", + FutureWarning, + ) + obj = obj.to_index_variable() return obj diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 80c6d9e275d..b36e7fd88ce 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1278,16 +1278,15 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): else: add_quiverkey = False - if (add_guide or add_guide is None) and funcname == "streamplot": - if hue: - add_colorbar = True - if not hue_style: - hue_style = "continuous" - elif hue_style != "continuous": - raise ValueError( - "hue_style must be 'continuous' or None for .plot.quiver or " - ".plot.streamplot" - ) + if (add_guide or add_guide is None) and funcname == "streamplot" and hue: + add_colorbar = True + if not hue_style: + hue_style = "continuous" + elif hue_style != "continuous": + raise ValueError( + "hue_style must be 'continuous' or None for .plot.quiver or " + ".plot.streamplot" + ) if hue_style is not None and hue_style not in ["discrete", "continuous"]: raise ValueError("hue_style must be either None, 'discrete' or 'continuous'.") diff --git a/xarray/structure/concat.py b/xarray/structure/concat.py index 81269320e1c..5d803400a9a 100644 --- a/xarray/structure/concat.py +++ b/xarray/structure/concat.py @@ -336,10 +336,8 @@ def _calc_concat_over(datasets, dim, dim_names, data_vars: T_DataVars, coords, c concat_dim_lengths = [] for ds in datasets: - if concat_over_existing_dim: - if dim not in ds.dims: - if dim in ds: - ds = ds.set_coords(dim) + if concat_over_existing_dim and dim not in ds.dims and dim in ds: + ds = ds.set_coords(dim) concat_over.update(k for k, v in ds.variables.items() if dim in v.dims) concat_dim_lengths.append(ds.sizes.get(dim, 1)) diff --git a/xarray/tests/test_computation.py b/xarray/tests/test_computation.py index ef9d67b99d6..2bf6205acc1 100644 --- a/xarray/tests/test_computation.py +++ b/xarray/tests/test_computation.py @@ -2014,9 +2014,8 @@ def apply_truncate_x_x_valid(obj): @pytest.mark.parametrize("use_dask", [True, False]) def test_dot(use_dask: bool) -> None: - if use_dask: - if not has_dask: - pytest.skip("test for dask.") + if use_dask and not has_dask: + pytest.skip("test for dask.") a = np.arange(30 * 4).reshape(30, 4) b = np.arange(30 * 4 * 5).reshape(30, 4, 5) @@ -2146,9 +2145,8 @@ def test_dot(use_dask: bool) -> None: def test_dot_align_coords(use_dask: bool) -> None: # GH 3694 - if use_dask: - if not has_dask: - pytest.skip("test for dask.") + if use_dask and not has_dask: + pytest.skip("test for dask.") a = np.arange(30 * 4).reshape(30, 4) b = np.arange(30 * 4 * 5).reshape(30, 4, 5) From e376d25df9a2ed8070b9d6621b8f49c84ca25171 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 28 May 2025 17:55:45 +0200 Subject: [PATCH 2/8] Apply ruff/flake8-simplify rule SIM102 SIM102 Use a single `if` statement instead of nested `if` statements While the `if` statement may become more complex, the following lines get unindented. I feel this improves readability in most cases. Of course, the alternative would be to let the programer decide about readability. --- xarray/conventions.py | 31 +++++++++++++------------- xarray/core/missing.py | 9 ++++---- xarray/core/parallel.py | 14 +++++++----- xarray/core/variable.py | 18 +++++++-------- xarray/groupers.py | 9 ++++---- xarray/structure/alignment.py | 41 +++++++++++++++++------------------ 6 files changed, 61 insertions(+), 61 deletions(-) diff --git a/xarray/conventions.py b/xarray/conventions.py index ab41804fd62..eee3f00d1dd 100644 --- a/xarray/conventions.py +++ b/xarray/conventions.py @@ -276,12 +276,11 @@ def _update_bounds_attributes(variables: T_Variables) -> None: attrs = v.attrs units = attrs.get("units") has_date_units = isinstance(units, str) and "since" in units - if has_date_units and "bounds" in attrs: - if attrs["bounds"] in variables: - bounds_attrs = variables[attrs["bounds"]].attrs - bounds_attrs.setdefault("units", attrs["units"]) - if "calendar" in attrs: - bounds_attrs.setdefault("calendar", attrs["calendar"]) + if has_date_units and "bounds" in attrs and attrs["bounds"] in variables: + bounds_attrs = variables[attrs["bounds"]].attrs + bounds_attrs.setdefault("units", attrs["units"]) + if "calendar" in attrs: + bounds_attrs.setdefault("calendar", attrs["calendar"]) def _update_bounds_encoding(variables: T_Variables) -> None: @@ -325,12 +324,11 @@ def _update_bounds_encoding(variables: T_Variables) -> None: f"{name} before writing to a file.", ) - if has_date_units and "bounds" in attrs: - if attrs["bounds"] in variables: - bounds_encoding = variables[attrs["bounds"]].encoding - bounds_encoding.setdefault("units", encoding["units"]) - if "calendar" in encoding: - bounds_encoding.setdefault("calendar", encoding["calendar"]) + if has_date_units and "bounds" in attrs and attrs["bounds"] in variables: + bounds_encoding = variables[attrs["bounds"]].encoding + bounds_encoding.setdefault("units", encoding["units"]) + if "calendar" in encoding: + bounds_encoding.setdefault("calendar", encoding["calendar"]) T = TypeVar("T") @@ -805,8 +803,11 @@ def cf_encoder(variables: T_Variables, attributes: T_Attrs): "leap_year", "month_lengths", ]: - if attr in new_vars[bounds].attrs and attr in var.attrs: - if new_vars[bounds].attrs[attr] == var.attrs[attr]: - new_vars[bounds].attrs.pop(attr) + if ( + attr in new_vars[bounds].attrs + and attr in var.attrs + and new_vars[bounds].attrs[attr] == var.attrs[attr] + ): + new_vars[bounds].attrs.pop(attr) return new_vars, attributes diff --git a/xarray/core/missing.py b/xarray/core/missing.py index cf66487c775..ded6c85e0d3 100644 --- a/xarray/core/missing.py +++ b/xarray/core/missing.py @@ -364,11 +364,10 @@ def interp_na( # Convert to float max_gap = timedelta_to_numeric(max_gap) - if not use_coordinate: - if not isinstance(max_gap, Number | np.number): - raise TypeError( - f"Expected integer or floating point max_gap since use_coordinate=False. Received {max_type}." - ) + if not use_coordinate and not isinstance(max_gap, Number | np.number): + raise TypeError( + f"Expected integer or floating point max_gap since use_coordinate=False. Received {max_type}." + ) # method index = get_clean_interp_index(self, dim, use_coordinate=use_coordinate) diff --git a/xarray/core/parallel.py b/xarray/core/parallel.py index 996325e179a..8bb98118081 100644 --- a/xarray/core/parallel.py +++ b/xarray/core/parallel.py @@ -363,12 +363,14 @@ def _wrapper( # check that index lengths and values are as expected for name, index in result._indexes.items(): - if name in expected["shapes"]: - if result.sizes[name] != expected["shapes"][name]: - raise ValueError( - f"Received dimension {name!r} of length {result.sizes[name]}. " - f"Expected length {expected['shapes'][name]}." - ) + if ( + name in expected["shapes"] + and result.sizes[name] != expected["shapes"][name] + ): + raise ValueError( + f"Received dimension {name!r} of length {result.sizes[name]}. " + f"Expected length {expected['shapes'][name]}." + ) # ChainMap wants MutableMapping, but xindexes is Mapping merged_indexes = collections.ChainMap( diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 828860ef76a..190da4b2f06 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -2929,15 +2929,15 @@ def broadcast_variables(*variables: Variable) -> tuple[Variable, ...]: def _broadcast_compat_data(self, other): - if not OPTIONS["arithmetic_broadcast"]: - if (isinstance(other, Variable) and self.dims != other.dims) or ( - is_duck_array(other) and self.ndim != other.ndim - ): - raise ValueError( - "Broadcasting is necessary but automatic broadcasting is disabled via " - "global option `'arithmetic_broadcast'`. " - "Use `xr.set_options(arithmetic_broadcast=True)` to enable automatic broadcasting." - ) + if not OPTIONS["arithmetic_broadcast"] and ( + (isinstance(other, Variable) and self.dims != other.dims) + or (is_duck_array(other) and self.ndim != other.ndim) + ): + raise ValueError( + "Broadcasting is necessary but automatic broadcasting is disabled via " + "global option `'arithmetic_broadcast'`. " + "Use `xr.set_options(arithmetic_broadcast=True)` to enable automatic broadcasting." + ) if all(hasattr(other, attr) for attr in ["dims", "data", "shape", "encoding"]): # `other` satisfies the necessary Variable API for broadcast_variables diff --git a/xarray/groupers.py b/xarray/groupers.py index 226f98256f7..0ae8e3c87cd 100644 --- a/xarray/groupers.py +++ b/xarray/groupers.py @@ -716,11 +716,10 @@ def find_independent_seasons(seasons: Sequence[str]) -> Sequence[SeasonsGroup]: # Loop through remaining groups, and look for overlaps for j, second in enumerate(season_inds[i:]): - if not (set(chain(*grouped[idx])) & set(second)): - if second not in seen: - grouped[idx].append(second) - codes[idx].append(j + i) - seen.add(second) + if not (set(chain(*grouped[idx])) & set(second)) and second not in seen: + grouped[idx].append(second) + codes[idx].append(j + i) + seen.add(second) if len(seen) == len(seasons): break # found all non-overlapping groups for this row, increment and start over diff --git a/xarray/structure/alignment.py b/xarray/structure/alignment.py index 88f9835df7b..b89dbb15964 100644 --- a/xarray/structure/alignment.py +++ b/xarray/structure/alignment.py @@ -526,27 +526,26 @@ def _get_dim_pos_indexers( for key, aligned_idx in self.aligned_indexes.items(): obj_idx = matching_indexes.get(key) - if obj_idx is not None: - if self.reindex[key]: - indexers = obj_idx.reindex_like(aligned_idx, **self.reindex_kwargs) - for dim, idxer in indexers.items(): - if dim in self.exclude_dims: - raise AlignmentError( - f"cannot reindex or align along dimension {dim!r} because " - "it is explicitly excluded from alignment. This is likely caused by " - "wrong results returned by the `reindex_like` method of this index:\n" - f"{obj_idx!r}" - ) - if dim in dim_pos_indexers and not np.array_equal( - idxer, dim_pos_indexers[dim] - ): - raise AlignmentError( - f"cannot reindex or align along dimension {dim!r} because " - "of conflicting re-indexers returned by multiple indexes\n" - f"first index: {obj_idx!r}\nsecond index: {dim_index[dim]!r}\n" - ) - dim_pos_indexers[dim] = idxer - dim_index[dim] = obj_idx + if obj_idx is not None and self.reindex[key]: + indexers = obj_idx.reindex_like(aligned_idx, **self.reindex_kwargs) + for dim, idxer in indexers.items(): + if dim in self.exclude_dims: + raise AlignmentError( + f"cannot reindex or align along dimension {dim!r} because " + "it is explicitly excluded from alignment. This is likely caused by " + "wrong results returned by the `reindex_like` method of this index:\n" + f"{obj_idx!r}" + ) + if dim in dim_pos_indexers and not np.array_equal( + idxer, dim_pos_indexers[dim] + ): + raise AlignmentError( + f"cannot reindex or align along dimension {dim!r} because " + "of conflicting re-indexers returned by multiple indexes\n" + f"first index: {obj_idx!r}\nsecond index: {dim_index[dim]!r}\n" + ) + dim_pos_indexers[dim] = idxer + dim_index[dim] = obj_idx return dim_pos_indexers From b0e51c51d3dbf1918873d292f5f2f38f4b2cff33 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 28 May 2025 18:01:18 +0200 Subject: [PATCH 3/8] Apply ruff/flake8-simplify rule SIM105 SIM105 Use `contextlib.suppress(OutOfBoundsDatetime, ValueError)` instead of `try`-`except`-`pass` Sometimes this adds an import (contextlib). Is it worth it? --- xarray/coding/times.py | 9 ++++----- xarray/core/utils.py | 4 +--- xarray/tests/test_backends.py | 4 +--- xarray/tests/test_backends_datatree.py | 5 ++--- xarray/tests/test_dataset.py | 6 +++--- xarray/tests/test_distributed.py | 6 +++--- xarray/tests/test_interp.py | 5 ++--- xarray/tests/test_plot.py | 8 ++------ xarray/tests/test_units.py | 5 ++--- xarray/util/print_versions.py | 5 ++--- 10 files changed, 22 insertions(+), 35 deletions(-) diff --git a/xarray/coding/times.py b/xarray/coding/times.py index adea7c4186a..000d2c27a44 100644 --- a/xarray/coding/times.py +++ b/xarray/coding/times.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import re import warnings from collections.abc import Callable, Hashable @@ -928,12 +929,10 @@ def _cleanup_netcdf_time_units(units: str) -> str: time_units = time_units.lower() if not time_units.endswith("s"): time_units = f"{time_units}s" - try: + # don't worry about reifying the units if they're out of bounds or + # formatted badly + with contextlib.suppress(OutOfBoundsDatetime, ValueError): units = f"{time_units} since {format_timestamp(ref_date)}" - except (OutOfBoundsDatetime, ValueError): - # don't worry about reifying the units if they're out of bounds or - # formatted badly - pass return units diff --git a/xarray/core/utils.py b/xarray/core/utils.py index da20d7b306e..7ede0bb9f08 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -704,10 +704,8 @@ def try_read_magic_number_from_path(pathlike, count=8) -> bytes | None: def try_read_magic_number_from_file_or_path(filename_or_obj, count=8) -> bytes | None: magic_number = try_read_magic_number_from_path(filename_or_obj, count) if magic_number is None: - try: + with contextlib.suppress(TypeError): magic_number = read_magic_number_from_file(filename_or_obj, count) - except TypeError: - pass return magic_number diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 4aed826db14..6a14142a7ff 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -100,10 +100,8 @@ create_test_data, ) -try: +with contextlib.suppress(ImportError): import netCDF4 as nc4 -except ImportError: - pass try: import dask diff --git a/xarray/tests/test_backends_datatree.py b/xarray/tests/test_backends_datatree.py index 2d189299b2f..6b3674e1a8c 100644 --- a/xarray/tests/test_backends_datatree.py +++ b/xarray/tests/test_backends_datatree.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import re from collections.abc import Callable, Generator, Hashable from pathlib import Path @@ -26,10 +27,8 @@ if TYPE_CHECKING: from xarray.core.datatree_io import T_DataTreeNetcdfEngine -try: +with contextlib.suppress(ImportError): import netCDF4 as nc4 -except ImportError: - pass def diff_chunks( diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index aba7760bf4d..31dce65f279 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -21,6 +21,8 @@ except ImportError: from numpy import RankWarning # type: ignore[no-redef,attr-defined,unused-ignore] +import contextlib + import xarray as xr from xarray import ( AlignmentError, @@ -77,10 +79,8 @@ from pandas.core.computation.ops import UndefinedVariableError -try: +with contextlib.suppress(ImportError): import dask.array as da -except ImportError: - pass # from numpy version 2.0 trapz is deprecated and renamed to trapezoid # remove once numpy 2.0 is the oldest supported version diff --git a/xarray/tests/test_distributed.py b/xarray/tests/test_distributed.py index 77caf6c6750..bc3a63060de 100644 --- a/xarray/tests/test_distributed.py +++ b/xarray/tests/test_distributed.py @@ -17,6 +17,8 @@ da = pytest.importorskip("dask.array") distributed = pytest.importorskip("distributed") +import contextlib + from dask.distributed import Client, Lock from distributed.client import futures_of from distributed.utils_test import ( # noqa: F401 @@ -238,10 +240,8 @@ def zarr(client): # an IO loop. Here we clean up these resources to avoid leaking threads # In normal operations, this is done as by an atexit handler when Zarr # is shutting down. - try: + with contextlib.suppress(AttributeError): zarr_lib.core.sync.cleanup_resources() - except AttributeError: - pass @requires_zarr diff --git a/xarray/tests/test_interp.py b/xarray/tests/test_interp.py index df265029250..3d6fbcf025f 100644 --- a/xarray/tests/test_interp.py +++ b/xarray/tests/test_interp.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib from itertools import combinations, permutations, product from typing import cast, get_args @@ -29,10 +30,8 @@ ) from xarray.tests.test_dataset import create_test_data -try: +with contextlib.suppress(ImportError): import scipy -except ImportError: - pass ALL_1D = get_args(Interp1dOptions) + get_args(InterpolantOptions) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index bfa87386dbc..47389f74d9b 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -50,10 +50,8 @@ except ImportError: pass -try: +with contextlib.suppress(ImportError): import cartopy -except ImportError: - pass @contextlib.contextmanager @@ -2303,10 +2301,8 @@ def test_robust(self) -> None: numbers = set() alltxt = text_in_fig() for txt in alltxt: - try: + with contextlib.suppress(ValueError): numbers.add(float(txt)) - except ValueError: - pass largest = max(abs(x) for x in numbers) assert largest < 21 diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index ede065eac37..ab4ec36ea97 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import functools import operator @@ -20,10 +21,8 @@ from xarray.tests.test_plot import PlotTestCase from xarray.tests.test_variable import _PAD_XR_NP_ARGS -try: +with contextlib.suppress(ImportError): import matplotlib.pyplot as plt -except ImportError: - pass pint = pytest.importorskip("pint") diff --git a/xarray/util/print_versions.py b/xarray/util/print_versions.py index afcea8fa29d..8f3be73ee68 100644 --- a/xarray/util/print_versions.py +++ b/xarray/util/print_versions.py @@ -1,5 +1,6 @@ """Utility functions for printing version information.""" +import contextlib import importlib import locale import os @@ -29,10 +30,8 @@ def get_sys_info(): else: if pipe.returncode == 0: commit = so - try: + with contextlib.suppress(ValueError): commit = so.decode("utf-8") - except ValueError: - pass commit = commit.strip().strip('"') blob.append(("commit", commit)) From 32a0cf108bd0e6132ee158f5e68aee998e3a9d5c Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 28 May 2025 18:08:33 +0200 Subject: [PATCH 4/8] Apply ruff/flake8-simplify rule SIM114 SIM114 Combine `if` branches using logical `or` operator --- xarray/backends/locks.py | 4 +--- xarray/core/groupby.py | 4 +--- xarray/indexes/range_index.py | 4 +--- xarray/plot/utils.py | 12 ++++++------ xarray/tests/test_dataset.py | 6 +----- 5 files changed, 10 insertions(+), 20 deletions(-) diff --git a/xarray/backends/locks.py b/xarray/backends/locks.py index 7cff53d6267..c6a06dd714e 100644 --- a/xarray/backends/locks.py +++ b/xarray/backends/locks.py @@ -118,9 +118,7 @@ def _get_lock_maker(scheduler=None): dask.utils.get_scheduler_lock """ - if scheduler is None: - return _get_threaded_lock - elif scheduler == "threaded": + if scheduler is None or scheduler == "threaded": return _get_threaded_lock elif scheduler == "multiprocessing": return _get_multiprocessing_lock diff --git a/xarray/core/groupby.py b/xarray/core/groupby.py index c049ca78f45..889655a7d9f 100644 --- a/xarray/core/groupby.py +++ b/xarray/core/groupby.py @@ -977,9 +977,7 @@ def _maybe_reindex(self, combined): indexers = {} for grouper in self.groupers: index = combined._indexes.get(grouper.name, None) - if has_missing_groups and index is not None: - indexers[grouper.name] = grouper.full_index - elif ( + if (has_missing_groups and index is not None) or ( len(self.groupers) > 1 and not isinstance(grouper.full_index, pd.RangeIndex) and not index.index.equals(grouper.full_index) diff --git a/xarray/indexes/range_index.py b/xarray/indexes/range_index.py index 230acde828c..b04c86e1a5d 100644 --- a/xarray/indexes/range_index.py +++ b/xarray/indexes/range_index.py @@ -320,9 +320,7 @@ def isel( if isinstance(idxer, slice): return RangeIndex(self.transform.slice(idxer)) - elif isinstance(idxer, Variable) and idxer.ndim > 1: - return None - elif np.ndim(idxer) == 0: + elif (isinstance(idxer, Variable) and idxer.ndim > 1) or np.ndim(idxer) == 0: return None else: values = self.transform.forward({self.dim: np.asarray(idxer)})[ diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index b36e7fd88ce..4ee32bc8ad4 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -798,16 +798,16 @@ def _update_axes( """ if xincrease is None: pass - elif xincrease and ax.xaxis_inverted(): - ax.invert_xaxis() - elif not xincrease and not ax.xaxis_inverted(): + elif (xincrease and ax.xaxis_inverted()) or ( + not xincrease and not ax.xaxis_inverted() + ): ax.invert_xaxis() if yincrease is None: pass - elif yincrease and ax.yaxis_inverted(): - ax.invert_yaxis() - elif not yincrease and not ax.yaxis_inverted(): + elif (yincrease and ax.yaxis_inverted()) or ( + not yincrease and not ax.yaxis_inverted() + ): ax.invert_yaxis() # The default xscale, yscale needs to be None. diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 31dce65f279..2ec2b20cac5 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -7034,11 +7034,7 @@ def test_pad(self, padded_dim_name, constant_values) -> None: if utils.is_dict_like(constant_values): if ( expected := constant_values.get(data_var_name, None) - ) is not None: - self._test_data_var_interior( - ds[data_var_name], data_var, padded_dim_name, expected - ) - elif ( + ) is not None or ( expected := constant_values.get(padded_dim_name, None) ) is not None: self._test_data_var_interior( From 415212e48b98606ee299a9db5d32bebd2bd79eb6 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 28 May 2025 18:11:06 +0200 Subject: [PATCH 5/8] Apply ruff/flake8-simplify rule SIM201 SIM201 Use `... != ...` instead of `not ... == ...` --- xarray/backends/zarr.py | 2 +- xarray/coding/frequencies.py | 2 +- xarray/core/missing.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/xarray/backends/zarr.py b/xarray/backends/zarr.py index 1a46346dda7..17256a22d5c 100644 --- a/xarray/backends/zarr.py +++ b/xarray/backends/zarr.py @@ -562,7 +562,7 @@ def _validate_datatypes_for_zarr_append(vname, existing_var, new_var): # in the dataset, and with dtypes which are not known to be easy-to-append, necessitate # exact dtype equality, as checked below. pass - elif not new_var.dtype == existing_var.dtype: + elif new_var.dtype != existing_var.dtype: raise ValueError( f"Mismatched dtypes for variable {vname} between Zarr store on disk " f"and dataset to append. Store has dtype {existing_var.dtype} but " diff --git a/xarray/coding/frequencies.py b/xarray/coding/frequencies.py index cf137839f03..34f01aadeef 100644 --- a/xarray/coding/frequencies.py +++ b/xarray/coding/frequencies.py @@ -137,7 +137,7 @@ def get_freq(self): return self._infer_daily_rule() # There is no possible intraday frequency with a non-unique delta # Different from pandas: we don't need to manage DST and business offsets in cftime - elif not len(self.deltas) == 1: + elif len(self.deltas) != 1: return None if _is_multiple(delta, _ONE_HOUR): diff --git a/xarray/core/missing.py b/xarray/core/missing.py index ded6c85e0d3..3a41f558700 100644 --- a/xarray/core/missing.py +++ b/xarray/core/missing.py @@ -498,7 +498,7 @@ def _get_interpolator( # take higher dimensional data but scipy.interp1d can. if ( method == "linear" - and not kwargs.get("fill_value") == "extrapolate" + and kwargs.get("fill_value") != "extrapolate" and not vectorizeable_only ): kwargs.update(method=method) From 65043d36bf8cc91e632c9335ded10567de0c4a4b Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 28 May 2025 18:12:20 +0200 Subject: [PATCH 6/8] Apply ruff/flake8-simplify rule SIM210 SIM210 Remove unnecessary `True if ... else False` --- xarray/backends/zarr.py | 2 +- xarray/conventions.py | 2 +- xarray/plot/utils.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/xarray/backends/zarr.py b/xarray/backends/zarr.py index 17256a22d5c..e506e6aece8 100644 --- a/xarray/backends/zarr.py +++ b/xarray/backends/zarr.py @@ -1233,7 +1233,7 @@ def set_variables(self, variables, check_encoding_set, writer, unlimited_dims=No else: encoded_attrs[DIMENSION_KEY] = dims - encoding["overwrite"] = True if self._mode == "w" else False + encoding["overwrite"] = self._mode == "w" zarr_array = self._create_new_array( name=name, diff --git a/xarray/conventions.py b/xarray/conventions.py index eee3f00d1dd..4d8e8a96ad8 100644 --- a/xarray/conventions.py +++ b/xarray/conventions.py @@ -178,7 +178,7 @@ def decode_cf_variable( if isinstance(decode_times, CFDatetimeCoder): decode_timedelta = CFTimedeltaCoder(time_unit=decode_times.time_unit) else: - decode_timedelta = True if decode_times else False + decode_timedelta = bool(decode_times) if concat_characters: if stack_char_dim: diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 4ee32bc8ad4..a35128cadb6 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -1253,8 +1253,8 @@ def _infer_meta_data(ds, x, y, hue, hue_style, add_guide, funcname): ) if add_guide is None or add_guide is True: - add_colorbar = True if hue_style == "continuous" else False - add_legend = True if hue_style == "discrete" else False + add_colorbar = hue_style == "continuous" + add_legend = hue_style == "discrete" else: add_colorbar = False add_legend = False From d55bb502b588739652fd0789d2f391b5272d7d1e Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 28 May 2025 18:13:53 +0200 Subject: [PATCH 7/8] Apply ruff/flake8-simplify rule SIM211 SIM211 Use `not ...` instead of `False if ... else True` --- xarray/plot/facetgrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/plot/facetgrid.py b/xarray/plot/facetgrid.py index 2c50c5e1176..719b1fde619 100644 --- a/xarray/plot/facetgrid.py +++ b/xarray/plot/facetgrid.py @@ -549,7 +549,7 @@ def map_plot1d( ) if add_legend: - use_legend_elements = False if func.__name__ == "hist" else True + use_legend_elements = not func.__name__ == "hist" if use_legend_elements: self.add_legend( use_legend_elements=use_legend_elements, From 16a50cb69c554bc0ab336e4bca9f951981d3bb6c Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 28 May 2025 18:14:26 +0200 Subject: [PATCH 8/8] Apply ruff/flake8-simplify rule SIM910 SIM910 Use `.get(...)` instead of `.get(..., None)` --- xarray/coding/times.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/coding/times.py b/xarray/coding/times.py index 000d2c27a44..e727a0f3664 100644 --- a/xarray/coding/times.py +++ b/xarray/coding/times.py @@ -1410,7 +1410,7 @@ def decode(self, variable: Variable, name: T_Name = None) -> Variable: def has_timedelta64_encoding_dtype(attrs_or_encoding: dict) -> bool: - dtype = attrs_or_encoding.get("dtype", None) + dtype = attrs_or_encoding.get("dtype") return isinstance(dtype, str) and dtype.startswith("timedelta64")