diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 708f68ad..e08d8ffe 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,8 +19,13 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.15.4 hooks: - - id: ruff - args: [--fix, --show-fixes] + - id: ruff-check + exclude: '(dev/.*|.*_)\.py$' + args: + - --line-length=120 + - --fix + - --exit-non-zero-on-fix + - --preview - id: ruff-format - repo: https://github.com/executablebooks/mdformat rev: 1.0.0 diff --git a/docs/notebooks/spatial/02-era5-reduce-data-over-geometries.ipynb b/docs/notebooks/spatial/02-era5-reduce-data-over-geometries.ipynb index 7c380fcd..651095f5 100644 --- a/docs/notebooks/spatial/02-era5-reduce-data-over-geometries.ipynb +++ b/docs/notebooks/spatial/02-era5-reduce-data-over-geometries.ipynb @@ -125,9 +125,7 @@ "metadata": {}, "outputs": [], "source": [ - "reduced_data = ekt.spatial.reduce(\n", - " era5_xr, nuts_data, mask_dim=\"FID\", extra_reduce_dims=\"valid_time\", all_touched=True\n", - ")\n", + "reduced_data = ekt.spatial.reduce(era5_xr, nuts_data, mask_dim=\"FID\", extra_reduce_dims=\"valid_time\", all_touched=True)\n", "reduced_data" ] }, diff --git a/docs/notebooks/temporal/02-era5-daily-monthly-statistics.ipynb b/docs/notebooks/temporal/02-era5-daily-monthly-statistics.ipynb index 9b82ae0a..7bc60253 100644 --- a/docs/notebooks/temporal/02-era5-daily-monthly-statistics.ipynb +++ b/docs/notebooks/temporal/02-era5-daily-monthly-statistics.ipynb @@ -197,9 +197,7 @@ "era5_monthly_mean.t2m.isel(**isel_kwargs).plot(label=\"Monthly mean\", ax=ax, color=\"black\")\n", "upper_m = era5_monthly_mean.t2m + era5_monthly_std.t2m\n", "lower_m = era5_monthly_mean.t2m - era5_monthly_std.t2m\n", - "upper_m.isel(**isel_kwargs).plot(\n", - " ax=ax, label=\"Monthly standard deviation spread\", linestyle=\"--\", color=\"black\"\n", - ")\n", + "upper_m.isel(**isel_kwargs).plot(ax=ax, label=\"Monthly standard deviation spread\", linestyle=\"--\", color=\"black\")\n", "lower_m.isel(**isel_kwargs).plot(ax=ax, linestyle=\"--\", color=\"black\")\n", "\n", "\n", diff --git a/docs/notebooks/temporal/03-seas5-daily-statistics.ipynb b/docs/notebooks/temporal/03-seas5-daily-statistics.ipynb index fdb0cdb8..3f9cec4d 100644 --- a/docs/notebooks/temporal/03-seas5-daily-statistics.ipynb +++ b/docs/notebooks/temporal/03-seas5-daily-statistics.ipynb @@ -108,9 +108,7 @@ "\n", "for itime in range(3):\n", " for number in range(25):\n", - " t_data = seas_daily_median_by_step.t2m.isel(\n", - " **isel_kwargs, number=number, forecast_reference_time=itime\n", - " )\n", + " t_data = seas_daily_median_by_step.t2m.isel(**isel_kwargs, number=number, forecast_reference_time=itime)\n", " if number == 0:\n", " extra_kwargs = {\"label\": f\"FC ref time: {str(t_data.forecast_reference_time.values)[:10]}\"}\n", " else:\n", diff --git a/docs/notebooks/temporal/05-accumulation-to-rate-examples.ipynb b/docs/notebooks/temporal/05-accumulation-to-rate-examples.ipynb index d961ce4d..24ac0c59 100644 --- a/docs/notebooks/temporal/05-accumulation-to-rate-examples.ipynb +++ b/docs/notebooks/temporal/05-accumulation-to-rate-examples.ipynb @@ -110,9 +110,7 @@ "color = \"tab:blue\"\n", "ax1.set_xlabel(\"Time\")\n", "ax1.set_ylabel(f\"Accumulation ({ds_era5['tp'].units})\", color=color)\n", - "ax1.bar(\n", - " ds_era5[\"valid_time\"], ds_era5[\"tp\"].isel(plot_point), color=color, label=\"Accumulation\", width=0.1, lw=0\n", - ")\n", + "ax1.bar(ds_era5[\"valid_time\"], ds_era5[\"tp\"].isel(plot_point), color=color, label=\"Accumulation\", width=0.1, lw=0)\n", "ax1.tick_params(axis=\"y\", labelcolor=color)\n", "\n", "ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis\n", @@ -319,9 +317,7 @@ "metadata": {}, "outputs": [], "source": [ - "ds_seas5_rate = ekt.temporal.accumulation_to_rate(\n", - " ds_seas5, accumulation_type=\"start_of_forecast\", from_first_step=True\n", - ")\n", + "ds_seas5_rate = ekt.temporal.accumulation_to_rate(ds_seas5, accumulation_type=\"start_of_forecast\", from_first_step=True)\n", "ds_seas5_rate" ] }, @@ -409,9 +405,7 @@ "metadata": {}, "outputs": [], "source": [ - "ds_seas5_deaccumulate = ekt.temporal.deaccumulate(\n", - " ds_seas5, accumulation_type=\"start_of_forecast\", from_first_step=True\n", - ")\n", + "ds_seas5_deaccumulate = ekt.temporal.deaccumulate(ds_seas5, accumulation_type=\"start_of_forecast\", from_first_step=True)\n", "ds_seas5_deaccumulate" ] }, diff --git a/pyproject.toml b/pyproject.toml index 67446cc6..3229f4fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,35 +62,29 @@ exclude = '^tests/legacy-api/' ignore_missing_imports = true [tool.ruff] -# Black line length is 88, but black does not format comments. -line-length = 110 -select = [ - # pyflakes - "F", - # pycodestyle - "E", - "W", - # isort - "I", - # pydocstyle - "D" -] +line-length = 120 [tool.ruff.lint] ignore = [ - # pydocstyle: Missing Docstrings - "D1" + "D1", # pydocstyle: Missing Docstrings + "D107", # pydocstyle: numpy convention + "D203", + "D205", + "D212", + "D213", + "D401", + "D402", + "D413", + "D415", + "D416", + "D417" ] select = [ - # pyflakes - "F", - # pycodestyle - "E", - "W", - # isort - "I", - # pydocstyle - "D" + "F", # pyflakes + "E", # pycodestyle + "W", # pycodestyle warnings + "I", # isort + "D" # pydocstyle ] [tool.setuptools.packages.find] diff --git a/src/earthkit/transforms/_tools.py b/src/earthkit/transforms/_tools.py index 5ae65440..8dd2f7af 100644 --- a/src/earthkit/transforms/_tools.py +++ b/src/earthkit/transforms/_tools.py @@ -248,9 +248,7 @@ def latitude_weights(dataarray: xr.DataArray, lat_key: str | None = None): xp = array_namespace_from_object(lat_array[lat_key]) return xp.cos(xp.radians(lat_array[lat_key])) - raise KeyError( - "Latitude variable name not detected or found in the dataarray. Please provide the correct key." - ) + raise KeyError("Latitude variable name not detected or found in the dataarray. Please provide the correct key.") HOW_METHODS = { @@ -495,9 +493,7 @@ def get_dim_key( # We have not been able to detect, so raise an error if raise_error: - raise ValueError( - f"Unable to find dimension key for axis '{axis}' in dataarray with dims: {dataarray.dims}." - ) + raise ValueError(f"Unable to find dimension key for axis '{axis}' in dataarray with dims: {dataarray.dims}.") return axis @@ -570,8 +566,7 @@ def groupby_time( grouped_data = dataarray.groupby(f"{time_dim}.{frequency}") except AttributeError: raise ValueError( - f"Invalid frequency '{frequency}' - see xarray documentation for " - f"a full list of valid frequencies." + f"Invalid frequency '{frequency}' - see xarray documentation for a full list of valid frequencies." ) return grouped_data @@ -590,8 +585,7 @@ def groupby_bins( grouped_data = dataarray.groupby_bins(f"{time_dim}.{frequency}", bin_widths) except AttributeError: raise ValueError( - f"Invalid frequency '{frequency}' - see xarray documentation for " - f"a full list of valid frequencies." + f"Invalid frequency '{frequency}' - see xarray documentation for a full list of valid frequencies." ) return grouped_data @@ -638,9 +632,7 @@ def _wrapper(_kwarg_types, _convert_types, *args, **kwargs): _convert_types = {key: _convert_types for key in convert_kwargs} convert_kwargs = [ - k - for k in convert_kwargs - if isinstance(kwargs[k], _ensure_tuple(_convert_types.get(k, ()))) + k for k in convert_kwargs if isinstance(kwargs[k], _ensure_tuple(_convert_types.get(k, ()))) ] # Transform args/kwargs diff --git a/src/earthkit/transforms/climatology/_aggregate.py b/src/earthkit/transforms/climatology/_aggregate.py index 72357997..a897298f 100644 --- a/src/earthkit/transforms/climatology/_aggregate.py +++ b/src/earthkit/transforms/climatology/_aggregate.py @@ -777,9 +777,7 @@ def _anomaly_dataarray( anomaly_array = groupby_time(dataarray, time_dim=time_dim, **groupby_kwargs) - climatology_da if relative: - anomaly_array = ( - groupby_time(anomaly_array, time_dim=time_dim, **groupby_kwargs) / climatology_da - ) * 100.0 + anomaly_array = (groupby_time(anomaly_array, time_dim=time_dim, **groupby_kwargs) / climatology_da) * 100.0 name_tag = "relative anomaly" update_attrs = {"units": "%"} else: @@ -788,9 +786,7 @@ def _anomaly_dataarray( anomaly_array = resample(anomaly_array, how="mean", **reduce_kwargs, **groupby_kwargs, dim=time_dim) - return _update_anomaly_array( - anomaly_array, dataarray, var_name, name_tag, update_attrs, how_label=how_label - ) + return _update_anomaly_array(anomaly_array, dataarray, var_name, name_tag, update_attrs, how_label=how_label) def _update_anomaly_array(anomaly_array, original_array, var_name, name_tag, update_attrs, how_label=None): diff --git a/src/earthkit/transforms/spatial/_aggregate.py b/src/earthkit/transforms/spatial/_aggregate.py index ba8d7f77..d418a782 100644 --- a/src/earthkit/transforms/spatial/_aggregate.py +++ b/src/earthkit/transforms/spatial/_aggregate.py @@ -475,9 +475,7 @@ def reduce( else: raise TypeError("Return as type not recognised or incompatible with inputs") else: - return _reduce_dataarray_as_xarray( - dataarray, geodataframe=geodataframe, mask_arrays=_mask_arrays, **kwargs - ) + return _reduce_dataarray_as_xarray(dataarray, geodataframe=geodataframe, mask_arrays=_mask_arrays, **kwargs) def _reduce_dataarray_as_xarray( @@ -717,8 +715,7 @@ def _reduce_dataarray_as_pandas( out_dims = {dim: dataarray[dim].data for dim in _out_dims} reduce_attrs[f"{out_xr.name}"].update({"dims": out_dims}) reduced_list = [ - out_xr.sel(**{mask_dim_name: mask_dim_value}).data - for mask_dim_value in out_xr[mask_dim_name].data + out_xr.sel(**{mask_dim_name: mask_dim_value}).data for mask_dim_value in out_xr[mask_dim_name].data ] out = out.assign(**{f"{out_xr.name}": reduced_list}) diff --git a/src/earthkit/transforms/temporal/_aggregate.py b/src/earthkit/transforms/temporal/_aggregate.py index a3461f93..dabdceb3 100644 --- a/src/earthkit/transforms/temporal/_aggregate.py +++ b/src/earthkit/transforms/temporal/_aggregate.py @@ -53,13 +53,9 @@ def standardise_time( try: source_times = [time_value.strftime(target_format) for time_value in dataarray[time_dim].data] except AttributeError: - source_times = [ - pd.to_datetime(time_value).strftime(target_format) for time_value in dataarray[time_dim].data - ] + source_times = [pd.to_datetime(time_value).strftime(target_format) for time_value in dataarray[time_dim].data] - standardised_times = np.array( - [pd.to_datetime(time_string).to_datetime64() for time_string in source_times] - ) + standardised_times = np.array([pd.to_datetime(time_string).to_datetime64() for time_string in source_times]) dataarray = dataarray.assign_coords({time_dim: standardised_times}) diff --git a/src/earthkit/transforms/temporal/_rates.py b/src/earthkit/transforms/temporal/_rates.py index 260ddd80..197c3d4d 100644 --- a/src/earthkit/transforms/temporal/_rates.py +++ b/src/earthkit/transforms/temporal/_rates.py @@ -372,19 +372,14 @@ def _accumulation_to_rate_dataarray( if "units" in dataarray.attrs: output.attrs.update({"units": dataarray.attrs["units"] + rate_units_str}) if "long_name" in dataarray.attrs: - output.attrs["long_name"] = " ".join( - filter(None, [dataarray.attrs["long_name"], rate_label.replace("_", " ")]) - ) + output.attrs["long_name"] = " ".join(filter(None, [dataarray.attrs["long_name"], rate_label.replace("_", " ")])) if provenance or "history" in dataarray.attrs: output.attrs["history"] = "\n".join( filter( None, [ dataarray.attrs.get("history", ""), - ( - "Converted from accumulation to rate using " - "earthkit.transforms.temporal.accumulation_to_rate." - ), + ("Converted from accumulation to rate using earthkit.transforms.temporal.accumulation_to_rate."), ], ) ) diff --git a/tests/legacy-api/test_legacy_10_tools.py b/tests/legacy-api/test_legacy_10_tools.py index 7d6d7e3a..df104662 100644 --- a/tests/legacy-api/test_legacy_10_tools.py +++ b/tests/legacy-api/test_legacy_10_tools.py @@ -35,9 +35,7 @@ def dummy_func2(dataarray, *args, time_dim=None, **kwargs): # Test case for the decorator when time_shift is provided def test_time_dim_decorator_time_shift_provided(): # Prepare test data - dataarray = xr.DataArray( - [1, 2, 3], dims=["time"], coords={"time": pd.date_range("2000-01-01", periods=3)} - ) + dataarray = xr.DataArray([1, 2, 3], dims=["time"], coords={"time": pd.date_range("2000-01-01", periods=3)}) # Call the decorated function with time_shift provided result, result_time_dim = time_dim_decorator(dummy_func)(dataarray, time_shift={"days": 1}) @@ -52,14 +50,10 @@ def test_time_dim_decorator_time_shift_provided(): # Test case for the decorator when both time_dim and time_shift are provided def test_time_dim_decorator_time_dim_and_time_shift_provided(): # Prepare test data - dataarray = xr.DataArray( - [1, 2, 3], dims=["dummy"], coords={"dummy": pd.date_range("2000-01-01", periods=3)} - ) + dataarray = xr.DataArray([1, 2, 3], dims=["dummy"], coords={"dummy": pd.date_range("2000-01-01", periods=3)}) # Call the decorated function with both time_dim and time_shift provided - result, result_time_dim = time_dim_decorator(dummy_func)( - dataarray, time_dim="dummy", time_shift={"days": 1} - ) + result, result_time_dim = time_dim_decorator(dummy_func)(dataarray, time_dim="dummy", time_shift={"days": 1}) # Check if the time dimension remains unchanged assert result_time_dim == "dummy" @@ -81,9 +75,7 @@ def test_time_dim_decorator_not_found_error(): # Test case for the decorator when time_shift is provided and remove_partial_periods=True def test_time_dim_decorator_time_shift_provided_trim_shifted(): # Prepare test data - dataarray = xr.DataArray( - [1, 2, 3], dims=["time"], coords={"time": pd.date_range("2000-01-01", periods=3)} - ) + dataarray = xr.DataArray([1, 2, 3], dims=["time"], coords={"time": pd.date_range("2000-01-01", periods=3)}) # Call the decorated function with time_shift provided result = time_dim_decorator(dummy_func2)(dataarray, time_shift={"days": 1}, remove_partial_periods=True) @@ -114,9 +106,7 @@ def test_groupby_kwargs_decorator_provided(): other_kwargs = {"method": "linear", "fill_value": 0} # Call the decorated function with groupby_kwargs provided - result_groupby_kwargs, result_kwargs = groupby_kwargs_decorator(gb_dummy_func)( - **groupby_kwargs, **other_kwargs - ) + result_groupby_kwargs, result_kwargs = groupby_kwargs_decorator(gb_dummy_func)(**groupby_kwargs, **other_kwargs) assert result_groupby_kwargs == groupby_kwargs assert result_kwargs == other_kwargs @@ -129,9 +119,7 @@ def test_groupby_kwargs_decorator_partial_provided(): other_kwargs = {"method": "linear"} # Call the decorated function with some groupby_kwargs provided as keyword arguments - result_groupby_kwargs, result_kwargs = groupby_kwargs_decorator(gb_dummy_func)( - **groupby_kwargs, **other_kwargs - ) + result_groupby_kwargs, result_kwargs = groupby_kwargs_decorator(gb_dummy_func)(**groupby_kwargs, **other_kwargs) assert result_groupby_kwargs == groupby_kwargs assert result_kwargs == other_kwargs @@ -209,9 +197,7 @@ def test_get_how_xp_np(): "data_object", ( xr.DataArray(np.random.rand(10, 10), dims=["x", "y"]), - xr.Dataset( - {"var": (["x", "y"], np.random.rand(10, 10))}, coords={"x": np.arange(10), "y": np.arange(10)} - ), + xr.Dataset({"var": (["x", "y"], np.random.rand(10, 10))}, coords={"x": np.arange(10), "y": np.arange(10)}), np.random.rand(10, 10), ), ) diff --git a/tests/legacy-api/test_legacy_30_temporal.py b/tests/legacy-api/test_legacy_30_temporal.py index e18d8991..c75f8a73 100644 --- a/tests/legacy-api/test_legacy_30_temporal.py +++ b/tests/legacy-api/test_legacy_30_temporal.py @@ -53,10 +53,7 @@ def test_standardise_time_basic(): def test_standardise_time_monthly(): data = get_data().to_xarray() data_standardised = temporal.standardise_time(data, target_format="%Y-%m-15") - assert all( - pd.to_datetime(time_value).day == 15 - for time_value in data_standardised.forecast_reference_time.values - ) + assert all(pd.to_datetime(time_value).day == 15 for time_value in data_standardised.forecast_reference_time.values) @pytest.mark.parametrize( diff --git a/tests/test_10_tools.py b/tests/test_10_tools.py index 7d6d7e3a..df104662 100644 --- a/tests/test_10_tools.py +++ b/tests/test_10_tools.py @@ -35,9 +35,7 @@ def dummy_func2(dataarray, *args, time_dim=None, **kwargs): # Test case for the decorator when time_shift is provided def test_time_dim_decorator_time_shift_provided(): # Prepare test data - dataarray = xr.DataArray( - [1, 2, 3], dims=["time"], coords={"time": pd.date_range("2000-01-01", periods=3)} - ) + dataarray = xr.DataArray([1, 2, 3], dims=["time"], coords={"time": pd.date_range("2000-01-01", periods=3)}) # Call the decorated function with time_shift provided result, result_time_dim = time_dim_decorator(dummy_func)(dataarray, time_shift={"days": 1}) @@ -52,14 +50,10 @@ def test_time_dim_decorator_time_shift_provided(): # Test case for the decorator when both time_dim and time_shift are provided def test_time_dim_decorator_time_dim_and_time_shift_provided(): # Prepare test data - dataarray = xr.DataArray( - [1, 2, 3], dims=["dummy"], coords={"dummy": pd.date_range("2000-01-01", periods=3)} - ) + dataarray = xr.DataArray([1, 2, 3], dims=["dummy"], coords={"dummy": pd.date_range("2000-01-01", periods=3)}) # Call the decorated function with both time_dim and time_shift provided - result, result_time_dim = time_dim_decorator(dummy_func)( - dataarray, time_dim="dummy", time_shift={"days": 1} - ) + result, result_time_dim = time_dim_decorator(dummy_func)(dataarray, time_dim="dummy", time_shift={"days": 1}) # Check if the time dimension remains unchanged assert result_time_dim == "dummy" @@ -81,9 +75,7 @@ def test_time_dim_decorator_not_found_error(): # Test case for the decorator when time_shift is provided and remove_partial_periods=True def test_time_dim_decorator_time_shift_provided_trim_shifted(): # Prepare test data - dataarray = xr.DataArray( - [1, 2, 3], dims=["time"], coords={"time": pd.date_range("2000-01-01", periods=3)} - ) + dataarray = xr.DataArray([1, 2, 3], dims=["time"], coords={"time": pd.date_range("2000-01-01", periods=3)}) # Call the decorated function with time_shift provided result = time_dim_decorator(dummy_func2)(dataarray, time_shift={"days": 1}, remove_partial_periods=True) @@ -114,9 +106,7 @@ def test_groupby_kwargs_decorator_provided(): other_kwargs = {"method": "linear", "fill_value": 0} # Call the decorated function with groupby_kwargs provided - result_groupby_kwargs, result_kwargs = groupby_kwargs_decorator(gb_dummy_func)( - **groupby_kwargs, **other_kwargs - ) + result_groupby_kwargs, result_kwargs = groupby_kwargs_decorator(gb_dummy_func)(**groupby_kwargs, **other_kwargs) assert result_groupby_kwargs == groupby_kwargs assert result_kwargs == other_kwargs @@ -129,9 +119,7 @@ def test_groupby_kwargs_decorator_partial_provided(): other_kwargs = {"method": "linear"} # Call the decorated function with some groupby_kwargs provided as keyword arguments - result_groupby_kwargs, result_kwargs = groupby_kwargs_decorator(gb_dummy_func)( - **groupby_kwargs, **other_kwargs - ) + result_groupby_kwargs, result_kwargs = groupby_kwargs_decorator(gb_dummy_func)(**groupby_kwargs, **other_kwargs) assert result_groupby_kwargs == groupby_kwargs assert result_kwargs == other_kwargs @@ -209,9 +197,7 @@ def test_get_how_xp_np(): "data_object", ( xr.DataArray(np.random.rand(10, 10), dims=["x", "y"]), - xr.Dataset( - {"var": (["x", "y"], np.random.rand(10, 10))}, coords={"x": np.arange(10), "y": np.arange(10)} - ), + xr.Dataset({"var": (["x", "y"], np.random.rand(10, 10))}, coords={"x": np.arange(10), "y": np.arange(10)}), np.random.rand(10, 10), ), ) diff --git a/tests/test_20_aggregate.py b/tests/test_20_aggregate.py index aea9231c..67c88610 100644 --- a/tests/test_20_aggregate.py +++ b/tests/test_20_aggregate.py @@ -141,9 +141,7 @@ def create_dataarray_rolling(weights=None): # Test case for reducing without weights using built-in method def test_rolling_reduce_dataarray(how, expected_result): dataarray = create_dataarray_rolling() - result = _rolling_reduce_dataarray( - dataarray, how_reduce=how, x=2, center=True, chunk=False, how_dropna="any" - ) + result = _rolling_reduce_dataarray(dataarray, how_reduce=how, x=2, center=True, chunk=False, how_dropna="any") assert isinstance(result, xr.DataArray) assert result.shape == (4, 5) assert result.values[0, 0] == expected_result diff --git a/tests/test_30_spatial.py b/tests/test_30_spatial.py index 1c3c2040..1e04f99a 100644 --- a/tests/test_30_spatial.py +++ b/tests/test_30_spatial.py @@ -250,9 +250,7 @@ def test_reduce_invalid_how(): def test_reduce_with_mask(): dataarray = create_test_dataarray() - mask = xr.DataArray( - np.random.randint(0, 2, size=dataarray.shape), coords=dataarray.coords, dims=dataarray.dims - ) + mask = xr.DataArray(np.random.randint(0, 2, size=dataarray.shape), coords=dataarray.coords, dims=dataarray.dims) result = _spatial._reduce_dataarray_as_xarray(dataarray, mask_arrays=[mask], how="sum") assert isinstance(result, xr.DataArray) @@ -260,9 +258,7 @@ def test_reduce_with_mask(): def test_return_geometry_as_coord(): dataarray = create_test_dataarray() geodataframe = create_test_geodataframe() - result = _spatial._reduce_dataarray_as_xarray( - dataarray, geodataframe=geodataframe, return_geometry_as_coord=True - ) + result = _spatial._reduce_dataarray_as_xarray(dataarray, geodataframe=geodataframe, return_geometry_as_coord=True) assert "geometry" in result.coords assert len(result.coords["geometry"].values) == len(geodataframe) @@ -284,9 +280,7 @@ def test_reduce_as_pandas_with_geodataframe(): def test_reduce_as_pandas_compact(): dataarray = create_test_dataarray() geodataframe = create_test_geodataframe() - result = _spatial._reduce_dataarray_as_pandas( - dataarray, geodataframe=geodataframe, compact=True, how="mean" - ) + result = _spatial._reduce_dataarray_as_pandas(dataarray, geodataframe=geodataframe, compact=True, how="mean") assert isinstance(result, pd.DataFrame) assert f"{dataarray.name}" in result.columns diff --git a/tests/test_30_temporal_aggregate.py b/tests/test_30_temporal_aggregate.py index 4ee8937b..9c1aac12 100644 --- a/tests/test_30_temporal_aggregate.py +++ b/tests/test_30_temporal_aggregate.py @@ -53,10 +53,7 @@ def test_standardise_time_basic(): def test_standardise_time_monthly(): data = get_data().to_xarray() data_standardised = temporal.standardise_time(data, target_format="%Y-%m-15") - assert all( - pd.to_datetime(time_value).day == 15 - for time_value in data_standardised.forecast_reference_time.values - ) + assert all(pd.to_datetime(time_value).day == 15 for time_value in data_standardised.forecast_reference_time.values) @pytest.mark.parametrize( diff --git a/tests/test_30_temporal_rates.py b/tests/test_30_temporal_rates.py index 6e91b282..6492b0db 100644 --- a/tests/test_30_temporal_rates.py +++ b/tests/test_30_temporal_rates.py @@ -136,9 +136,7 @@ def test_accumulation_to_rate_start_of_step_rate_units(rate_units, expected_unit numeric_test_sample = rate_data.isel(latitude=5, longitude=5, **{accum_time_dim: slice(0, 5)}) assert not np.all(np.isnan(numeric_test_sample.values)), "Sample array contains only NaN values" assert not np.all(numeric_test_sample.values == 0), "Sample array contains only zero values" - expected_sample = (data.isel(latitude=5, longitude=5, **{accum_time_dim: slice(0, 5)}).values) / ( - sample_sf - ) + expected_sample = (data.isel(latitude=5, longitude=5, **{accum_time_dim: slice(0, 5)}).values) / (sample_sf) np.testing.assert_allclose(numeric_test_sample.values, expected_sample) assert not np.all(np.isnan(numeric_test_sample.values)), "Array contains only NaN values" @@ -170,9 +168,7 @@ def test_accumulation_to_rate_start_of_forecast(time_dim_mode): np.testing.assert_allclose(numeric_test_sample.values, expected_sample) # Check the from_first_step=True option, should preserve first timestep - rate_data = temporal.accumulation_to_rate( - data, accumulation_type="start_of_forecast", from_first_step=True - ) + rate_data = temporal.accumulation_to_rate(data, accumulation_type="start_of_forecast", from_first_step=True) assert "tp_rate" == rate_data.name assert original_units + " s^-1" == rate_data.attrs["units"] assert "standard_name" not in rate_data.attrs @@ -202,18 +198,14 @@ def test_accumulation_to_rate_start_of_forecast(time_dim_mode): ("step_length", "", 1.0), ], ) -def test_accumulation_to_rate_start_of_forecast_rate_units( - rate_units, expected_units, sample_sf, time_dim_mode -): +def test_accumulation_to_rate_start_of_forecast_rate_units(rate_units, expected_units, sample_sf, time_dim_mode): test_file = "seas5-precip-3deg-202401.grib" accumulation_type = "start_of_forecast" accum_time_dim = ACCUM_TIME_DIM.get(time_dim_mode, time_dim_mode) data = get_data(test_file).to_xarray(**TO_XARRAY_KWARGS[time_dim_mode])["tp"] original_units = data.attrs["units"] - rate_data = temporal.accumulation_to_rate( - data, accumulation_type=accumulation_type, rate_units=rate_units - ) + rate_data = temporal.accumulation_to_rate(data, accumulation_type=accumulation_type, rate_units=rate_units) assert f"tp_{RATE_SUFFIX.get(rate_units, 'rate')}" == rate_data.name assert original_units + expected_units == rate_data.attrs["units"] assert rate_data.attrs["long_name"].endswith(f" {RATE_SUFFIX.get(rate_units, 'rate').replace('_', ' ')}") @@ -248,9 +240,7 @@ def test_accumulation_to_rate_start_of_day(time_dim_mode): assert rate_data[accum_time_dim][0].values == data[accum_time_dim][1].values isel_kwargs = {k: 1 for k in data.dims if k not in (accum_time_dim, "latitude", "longitude")} - numeric_test_sample = rate_data.isel( - **ERA5_LAND_TEST_POINT, **{accum_time_dim: slice(2, 22)}, **isel_kwargs - ) + numeric_test_sample = rate_data.isel(**ERA5_LAND_TEST_POINT, **{accum_time_dim: slice(2, 22)}, **isel_kwargs) assert not np.all(np.isnan(numeric_test_sample.values)), "Sample array contains only NaN values" assert not np.all(numeric_test_sample.values == 0), "Sample array contains only zero values" expected_sample = ( @@ -275,15 +265,11 @@ def test_accumulation_to_rate_start_of_day(time_dim_mode): numeric_test_sample = rate_data.isel(**ERA5_LAND_TEST_POINT, **{accum_time_dim: 25}, **isel_kwargs) assert not np.all(np.isnan(numeric_test_sample.values)), "Sample array contains only NaN values" assert not np.all(numeric_test_sample.values == 0), "Sample array contains only zero values" - expected_sample = ( - data.isel(**ERA5_LAND_TEST_POINT, **{accum_time_dim: 25}, **isel_kwargs).values - ) / 3600.0 + expected_sample = (data.isel(**ERA5_LAND_TEST_POINT, **{accum_time_dim: 25}, **isel_kwargs).values) / 3600.0 np.testing.assert_allclose(numeric_test_sample.values, expected_sample) # Check a period that is not the first day - numeric_test_sample = rate_data.isel( - **ERA5_LAND_TEST_POINT, **{accum_time_dim: slice(26, 31)}, **isel_kwargs - ) + numeric_test_sample = rate_data.isel(**ERA5_LAND_TEST_POINT, **{accum_time_dim: slice(26, 31)}, **isel_kwargs) assert not np.all(np.isnan(numeric_test_sample.values)), "Sample array contains only NaN values" assert not np.all(numeric_test_sample.values == 0), "Sample array contains only zero values" expected_sample = ( @@ -314,18 +300,14 @@ def test_accumulation_to_rate_start_of_day_rate_units(time_dim_mode, rate_units, data = get_data(test_file).to_xarray(**TO_XARRAY_KWARGS[time_dim_mode])["tp"] original_units = data.attrs["units"] - rate_data = temporal.accumulation_to_rate( - data, accumulation_type=accumulation_type, rate_units=rate_units - ) + rate_data = temporal.accumulation_to_rate(data, accumulation_type=accumulation_type, rate_units=rate_units) assert f"tp_{RATE_SUFFIX.get(rate_units, 'rate')}" == rate_data.name assert original_units + expected_units == rate_data.attrs["units"] assert rate_data.attrs["long_name"].endswith(f" {RATE_SUFFIX.get(rate_units, 'rate').replace('_', ' ')}") assert "standard_name" not in rate_data.attrs assert rate_data[accum_time_dim][0].values == data[accum_time_dim][1].values isel_kwargs = {k: 1 for k in data.dims if k not in (accum_time_dim, "latitude", "longitude")} - numeric_test_sample = rate_data.isel( - **ERA5_LAND_TEST_POINT, **{accum_time_dim: slice(6, 11)}, **isel_kwargs - ) + numeric_test_sample = rate_data.isel(**ERA5_LAND_TEST_POINT, **{accum_time_dim: slice(6, 11)}, **isel_kwargs) assert not np.all(np.isnan(numeric_test_sample.values)), "Sample array contains only NaN values" assert not np.all(numeric_test_sample.values == 0), "Sample array contains only zero values" expected_sample = ( @@ -378,15 +360,11 @@ def test_deaccumulate(time_dim_mode): assert "standard_name" not in deaccum_data.attrs # Check first timestep is unchanged - np.testing.assert_allclose( - deaccum_data.isel(**{accum_time_dim: 0}).values, data.isel(**{accum_time_dim: 0}).values - ) + np.testing.assert_allclose(deaccum_data.isel(**{accum_time_dim: 0}).values, data.isel(**{accum_time_dim: 0}).values) isel_kwargs = {k: 0 for k in data.dims if k not in (accum_time_dim, "latitude", "longitude")} - numeric_test_sample = deaccum_data.isel( - **{accum_time_dim: slice(1, 5)}, **SEAS5_TEST_POINT, **isel_kwargs - ) + numeric_test_sample = deaccum_data.isel(**{accum_time_dim: slice(1, 5)}, **SEAS5_TEST_POINT, **isel_kwargs) assert not np.all(np.isnan(numeric_test_sample.values)), "Sample array contains only NaN values" assert not np.all(numeric_test_sample.values == 0), "Sample array contains only zero values" expected_sample = ( @@ -403,9 +381,7 @@ def test_deaccumulate(time_dim_mode): isel_kwargs = {k: 0 for k in data.dims if k not in (accum_time_dim, "latitude", "longitude")} - numeric_test_sample = deaccum_data.isel( - **{accum_time_dim: slice(1, 5)}, **SEAS5_TEST_POINT, **isel_kwargs - ) + numeric_test_sample = deaccum_data.isel(**{accum_time_dim: slice(1, 5)}, **SEAS5_TEST_POINT, **isel_kwargs) assert not np.all(np.isnan(numeric_test_sample.values)), "Sample array contains only NaN values" assert not np.all(numeric_test_sample.values == 0), "Sample array contains only zero values" expected_sample = (