Skip to content

Commit

Permalink
Maintenance (#553)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
dcherian and pre-commit-ci[bot] authored Jan 30, 2025
1 parent 8c9cd90 commit 6d81913
Show file tree
Hide file tree
Showing 15 changed files with 64 additions and 57 deletions.
26 changes: 7 additions & 19 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@ ci:

repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.17.0
rev: v3.19.1
hooks:
- id: pyupgrade
args: ["--py310-plus"]

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: 'v0.6.9'
rev: 'v0.9.3'
hooks:
- id: ruff
args: ["--show-fixes", "--fix"]

- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.10.0
hooks:
- id: black
args: ["--fix", "--show-fixes"]
- id: ruff-format

- repo: https://github.com/rstcheck/rstcheck
rev: v6.2.4
Expand All @@ -28,18 +24,16 @@ repos:
args: ['--config', 'pyproject.toml']

- repo: https://github.com/executablebooks/mdformat
rev: 0.7.17
rev: 0.7.21
hooks:
- id: mdformat
additional_dependencies:
- mdformat-black
- mdformat-myst

- repo: https://github.com/nbQA-dev/nbQA
rev: 1.8.7
rev: 1.9.1
hooks:
- id: nbqa-black
- id: nbqa-ruff
- id: nbqa
entry: nbqa mdformat
name: nbqa-mdformat
Expand All @@ -55,19 +49,13 @@ repos:
- id: check-yaml
- id: debug-statements

- repo: https://github.com/keewis/blackdoc
rev: v0.3.9
hooks:
- id: blackdoc
files: .+\.py$

- repo: https://github.com/citation-file-format/cff-converter-python
rev: "44e8fc9"
hooks:
- id: validate-cff

- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.20.2
rev: v0.23
hooks:
- id: validate-pyproject

Expand Down
3 changes: 2 additions & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
version: 2

sphinx:
configuration: doc/conf.py
build:
os: ubuntu-lts-latest
tools:
Expand Down
20 changes: 14 additions & 6 deletions cf_xarray/accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ def _getattr(
None,
):
raise AttributeError(
f"{obj.__class__.__name__+'.cf'!r} object has no attribute {attr!r}"
f"{obj.__class__.__name__ + '.cf'!r} object has no attribute {attr!r}"
) from None
raise AttributeError(
f"{attr!r} is not a valid attribute on the underlying xarray object."
Expand Down Expand Up @@ -1374,7 +1374,11 @@ def curvefit(
coords_iter = coords
coords = [
apply_mapper(
[_single(_get_coords)], self._obj, v, error=False, default=[v] # type: ignore[arg-type]
[_single(_get_coords)], # type:ignore[arg-type]
self._obj,
v,
error=False,
default=[v],
)[0]
for v in coords_iter
]
Expand All @@ -1385,7 +1389,11 @@ def curvefit(
reduce_dims_iter = list(reduce_dims)
reduce_dims = [
apply_mapper(
[_single(_get_dims)], self._obj, v, error=False, default=[v] # type: ignore[arg-type]
[_single(_get_dims)], # type:ignore[arg-type]
self._obj,
v,
error=False,
default=[v],
)[0]
for v in reduce_dims_iter
]
Expand Down Expand Up @@ -2758,9 +2766,9 @@ def decode_vertical_coords(self, *, outnames=None, prefix=None):

for dim in allterms:
if prefix is None:
assert (
outnames is not None
), "if prefix is None, outnames must be provided"
assert outnames is not None, (
"if prefix is None, outnames must be provided"
)
# set outnames here
try:
zname = outnames[dim]
Expand Down
14 changes: 7 additions & 7 deletions cf_xarray/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@

# POM dataset
pomds = xr.Dataset()
# fmt: off
pomds["sigma"] = (
# fmt: off
"sigma",
[-0.983333, -0.95 , -0.916667, -0.883333, -0.85 , -0.816667,
-0.783333, -0.75 , -0.716667, -0.683333, -0.65 , -0.616667,
-0.583333, -0.55 , -0.516667, -0.483333, -0.45 , -0.416667,
-0.383333, -0.35 , -0.316667, -0.283333, -0.25 , -0.216667,
-0.183333, -0.15 , -0.116667, -0.083333, -0.05 , -0.016667],
# fmt: on
{
"units": "sigma_level",
"long_name": "Sigma Stretched Vertical Coordinate at Nodes",
Expand All @@ -38,6 +37,7 @@
"formula_terms": "sigma: sigma eta: zeta depth: depth",
}
)
# fmt: on
pomds["depth"] = 175.0
pomds["zeta"] = ("ocean_time", [-0.155356, -0.127435])

Expand Down Expand Up @@ -109,29 +109,29 @@


romsds = xr.Dataset()
# fmt: off
romsds["s_rho"] = (
# fmt: off
"s_rho",
[-0.983333, -0.95 , -0.916667, -0.883333, -0.85 , -0.816667,
-0.783333, -0.75 , -0.716667, -0.683333, -0.65 , -0.616667,
-0.583333, -0.55 , -0.516667, -0.483333, -0.45 , -0.416667,
-0.383333, -0.35 , -0.316667, -0.283333, -0.25 , -0.216667,
-0.183333, -0.15 , -0.116667, -0.083333, -0.05 , -0.016667],
# fmt: on
{
"long_name": "S-coordinate at RHO-points",
"valid_min": -1.0,
"valid_max": 0.0,
"standard_name": "ocean_s_coordinate_g2",
"formula_terms": "s: s_rho C: Cs_r eta: zeta depth: h depth_c: hc",
"field": "s_rho, scalar",
}
},
)
# fmt: on
romsds.coords["hc"] = 20.0
romsds.coords["h"] = 603.9
romsds.coords["Vtransform"] = 2.0
# fmt: off
romsds.coords["Cs_r"] = (
# fmt: off
"s_rho",
[-9.33010396e-01, -8.09234736e-01, -6.98779853e-01, -6.01008926e-01,
-5.15058562e-01, -4.39938913e-01, -3.74609181e-01, -3.18031817e-01,
Expand All @@ -141,8 +141,8 @@
-2.53860004e-02, -1.95414261e-02, -1.46880431e-02, -1.06952600e-02,
-7.45515186e-03, -4.87981407e-03, -2.89916971e-03, -1.45919898e-03,
-5.20560097e-04, -5.75774004e-05],
# fmt: on
)
# fmt: on
romsds["zeta"] = ("ocean_time", [-0.155356, -0.127435])
romsds["temp"] = (
("ocean_time", "s_rho"),
Expand Down
11 changes: 10 additions & 1 deletion cf_xarray/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from collections import ChainMap
from collections.abc import Hashable, Sequence
from dataclasses import dataclass
from typing import TYPE_CHECKING

import numpy as np
import pandas as pd
Expand All @@ -21,6 +22,9 @@
]


if TYPE_CHECKING:
from shapely import MultiPoint, Point

# Useful convention language:
# 1. Whether linked to normal CF space-time coordinates with a nodes attribute or not, inclusion of such coordinates is
# recommended to maintain backward compatibility with software that has not implemented geometry capabilities.
Expand Down Expand Up @@ -547,7 +551,11 @@ def cf_to_shapely(ds: xr.Dataset, *, container: Hashable = GEOMETRY_CONTAINER_NA
return geometries.rename("geometry")


def points_to_cf(pts: xr.DataArray | Sequence, *, names: GeometryNames | None = None):
def points_to_cf(
pts: xr.DataArray | Sequence[Point | MultiPoint],
*,
names: GeometryNames | None = None,
):
"""Get a list of points (shapely.geometry.[Multi]Point) and return a CF-compliant geometry dataset.
Parameters
Expand All @@ -563,6 +571,7 @@ def points_to_cf(pts: xr.DataArray | Sequence, *, names: GeometryNames | None =
"""
from shapely.geometry import MultiPoint

pts_: Sequence[Point | MultiPoint]
if isinstance(pts, xr.DataArray):
# TODO: Fix this hardcoding
if pts.ndim != 1:
Expand Down
1 change: 0 additions & 1 deletion cf_xarray/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class set_options: # numpydoc ignore=PR01,PR02
>>> ds = xr.Dataset({"elev": np.arange(1000)})
>>> with cf_xarray.set_options(custom_criteria=my_custom_criteria):
... xr.testing.assert_identical(ds["elev"], ds.cf["ssh"])
...
Or to set global options:
Expand Down
3 changes: 1 addition & 2 deletions cf_xarray/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ def __call__(self, dsk, keys, **kwargs):
self.total_computes += 1
if self.total_computes > self.max_computes:
raise RuntimeError(
"Too many computes. Total: %d > max: %d."
% (self.total_computes, self.max_computes)
f"Too many computes. Total:{self.total_computes} > max: {self.max_computes}."
)
return dask.get(dsk, keys, **kwargs)

Expand Down
7 changes: 4 additions & 3 deletions cf_xarray/tests/test_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ def test_rename_like() -> None:
@pytest.mark.parametrize(
"attr, xrkwargs, cfkwargs",
(
("resample", {"time": "M"}, {"T": "M"}),
("resample", {"time": "ME"}, {"T": "ME"}),
("rolling", {"lat": 5}, {"Y": 5}),
("groupby", {"group": "time"}, {"group": "T"}),
("groupby", {"group": "time.month"}, {"group": "T.month"}),
Expand Down Expand Up @@ -1748,7 +1748,7 @@ def test_add_canonical_attributes(override, skip, verbose, capsys):

# Attributes have been added
for var in sum(ds.cf.standard_names.values(), []):
assert set(ds[var].attrs) < set(cf_ds[var].attrs)
assert set(ds[var].attrs) <= set(cf_ds[var].attrs)

# Time units did not change
assert ds["time"].attrs.get("units") is cf_ds["time"].attrs.get("units") is None
Expand Down Expand Up @@ -2047,7 +2047,8 @@ def test_ancillary_variables_extra_dim():
),
}
)
assert_identical(ds.cf["X"], ds["x"])
with pytest.warns(UserWarning):
assert_identical(ds.cf["X"], ds["x"])


def test_geometry_association(geometry_ds):
Expand Down
2 changes: 1 addition & 1 deletion doc/bounds.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

`cf_xarray` supports parsing [coordinate bounds](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.10/cf-conventions.html#cell-boundaries) as encoded in the CF `bounds` attribute. A useful feature for incomplete dataset is also the automatic bounds estimation possible through `cf.add_bounds`. This method will estimate the missing bounds by finding the middle points between elements of the given coordinate, but also by extrapolating to find the outer bounds of the grid. This linear estimation works well with rectilinear grids, but it is only a coarse approximation for curvilinear and simple irregular grids.

As an example, we present a "rotated pole" grid. It is defined on a rotated rectilinear grid which uses the `rlat` and `rlon` 1D coordinates, over North America at a resolution of 0.44°. The datasets comes with 2D `lat` and `lon` coordinates. `cf_xarray` will estimate the bounds by linear interpolation (extrapolation at the edges) of the existing `lon` and `lat`, which yields good results on parts of the grid where the rotation is small. However the errors is larger in other places, as seen when visualizing the distance in degrees between the estimated bounds and the true bounds.
As an example, we present a "rotated pole" grid. It is defined on a rotated rectilinear grid which uses the `rlat` and `rlon` 1D coordinates, over North America at a resolution of 0.44°. The datasets comes with 2D `lat` and `lon` coordinates. `cf_xarray` will estimate the bounds by linear interpolation (extrapolation at the edges) of the existing `lon` and `lat`, which yields good results on parts of the grid where the rotation is small. However the errors is larger in other places, as seen when visualizing the distance in degrees between the estimated bounds and the true bounds.

![2d bounds error](2D_bounds_error.png)

Expand Down
4 changes: 2 additions & 2 deletions doc/coord_axes.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ This table lists these internal criteria
:stub-columns: 1
```

Any DataArray that has `standard_name: "latitude"` or `_CoordinateAxisType: "Lat"` or `"units": "degrees_north"` in its `attrs` will be identified as the `"latitude"` variable by cf-xarray. Similarly for other coordinate names.
Any DataArray that has `standard_name: "latitude"` or `_CoordinateAxisType: "Lat"` or `"units": "degrees_north"` in its `attrs` will be identified as the `"latitude"` variable by cf-xarray. Similarly for other coordinate names.

## Axis Names

Expand All @@ -68,7 +68,7 @@ Similar criteria exist for the concept of "axes".
:stub-columns: 1
```

## `.axes` and `.coordinates` properties
## `.axes` and `.coordinates` properties

Alternatively use the special properties {py:attr}`DataArray.cf.axes` or {py:attr}`DataArray.cf.coordinates` to access the variable names. These properties return dictionaries that map "CF names" to a list of variable names. Note that a list is always returned even if only one variable name matches the name `"latitude"` (for example).

Expand Down
2 changes: 1 addition & 1 deletion doc/custom-criteria.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ with cfxr.set_options(custom_criteria=salt_criteria):
salty
```

Note that `salty` contains both `salt1` and `salt2`. Without setting these criteria, we would only get `salt1` by default
Note that `salty` contains both `salt1` and `salt2`. Without setting these criteria, we would only get `salt1` by default

```{code-cell}
ds.cf[["sea_water_salinity"]]
Expand Down
6 changes: 3 additions & 3 deletions doc/selecting.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ CF conventions on
1. [ancillary data](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#ancillary-data)
```

A powerful feature of `cf_xarray` is the ability select DataArrays using special "CF names" like the "latitude", or "longitude" coordinate names, "X" or "Y" axes names, oreven using the `standard_name` attribute if present.
A powerful feature of `cf_xarray` is the ability select DataArrays using special "CF names" like the "latitude", or "longitude" coordinate names, "X" or "Y" axes names, oreven using the `standard_name` attribute if present.

To demonstrate this, let's load a few datasets

Expand Down Expand Up @@ -91,7 +91,7 @@ anc

## Selecting multiple variables

Sometimes a Dataset may contain multiple `X` or multiple `longitude` variables. In that case a simple `.cf["X"]` will raise an error. Instead follow Xarray convention and pass a list `.cf[["X"]]` to receive a Dataset with all available `"X"` variables
Sometimes a Dataset may contain multiple `X` or multiple `longitude` variables. In that case a simple `.cf["X"]` will raise an error. Instead follow Xarray convention and pass a list `.cf[["X"]]` to receive a Dataset with all available `"X"` variables

```{code-cell}
multiple.cf[["X"]]
Expand All @@ -103,7 +103,7 @@ pop.cf[["longitude"]]

## Mixing names

cf_xarray aims to be as friendly as possible, so it is possible to mix "CF names" and normal variable names. Here we select `UVEL` and `TEMP` by using the `standard_name` of `TEMP` (which is `sea_water_potential_temperature`)
cf_xarray aims to be as friendly as possible, so it is possible to mix "CF names" and normal variable names. Here we select `UVEL` and `TEMP` by using the `standard_name` of `TEMP` (which is `sea_water_potential_temperature`)

```{code-cell}
pop.cf[["sea_water_potential_temperature", "UVEL"]]
Expand Down
2 changes: 1 addition & 1 deletion doc/sgrid_ugrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ variable `grid` list many more dimension names.

### Topology variable

`cf_xarray` supports identifying the `mesh_topology` variable using the `cf_role` attribute.
`cf_xarray` supports identifying the `mesh_topology` variable using the `cf_role` attribute.

## More?

Expand Down
4 changes: 2 additions & 2 deletions doc/units.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ hide-toc: true
1. [CF conventions on units](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#units)
```

The xarray ecosystem supports unit-aware arrays using [pint](https://pint.readthedocs.io) and [pint-xarray](https://pint-xarray.readthedocs.io). Some changes are required to make these packages work well with [UDUNITS format recommended by the CF conventions](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#units).
The xarray ecosystem supports unit-aware arrays using [pint](https://pint.readthedocs.io) and [pint-xarray](https://pint-xarray.readthedocs.io). Some changes are required to make these packages work well with [UDUNITS format recommended by the CF conventions](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#units).

`cf_xarray` makes those recommended changes when you `import cf_xarray.units`. These changes allow pint to parse and format UDUNIT units strings, and add several custom units like `degrees_north` for latitude, `psu` for ocean salinity, etc. Be aware that pint supports some units that UDUNITS does not recognize but `cf-xarray` will not try to detect them and raise an error. For example, a temperature subtraction returns "delta_degC" units in pint, which does not exist in UDUNITS.
`cf_xarray` makes those recommended changes when you `import cf_xarray.units`. These changes allow pint to parse and format UDUNIT units strings, and add several custom units like `degrees_north` for latitude, `psu` for ocean salinity, etc. Be aware that pint supports some units that UDUNITS does not recognize but `cf-xarray` will not try to detect them and raise an error. For example, a temperature subtraction returns "delta_degC" units in pint, which does not exist in UDUNITS.

## Formatting units

Expand Down
Loading

0 comments on commit 6d81913

Please sign in to comment.