cf-xarray 0.10.11__tar.gz → 0.11.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.github/workflows/ci.yaml +2 -2
  2. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.github/workflows/pypi.yaml +5 -5
  3. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.github/workflows/testpypi-release.yaml +2 -2
  4. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.pre-commit-config.yaml +2 -2
  5. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/PKG-INFO +1 -1
  6. cf_xarray-0.11.0/cf_xarray/_version.py +1 -0
  7. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/accessor.py +5 -10
  8. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/helpers.py +16 -17
  9. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/test_accessor.py +50 -4
  10. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray.egg-info/PKG-INFO +1 -1
  11. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/index.rst +1 -1
  12. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/uv.lock +265 -235
  13. cf_xarray-0.10.11/cf_xarray/_version.py +0 -1
  14. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.binder/environment.yml +0 -0
  15. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.deepsource.toml +0 -0
  16. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.github/dependabot.yml +0 -0
  17. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.github/release.yml +0 -0
  18. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.github/workflows/parse_logs.py +0 -0
  19. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.github/workflows/upstream-dev-ci.yaml +0 -0
  20. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.gitignore +0 -0
  21. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.readthedocs.yml +0 -0
  22. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/.tributors +0 -0
  23. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/CITATION.cff +0 -0
  24. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/LICENSE +0 -0
  25. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/README.rst +0 -0
  26. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/__init__.py +0 -0
  27. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/coding.py +0 -0
  28. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/criteria.py +0 -0
  29. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/datasets.py +0 -0
  30. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/formatting.py +0 -0
  31. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/geometry.py +0 -0
  32. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/groupers.py +0 -0
  33. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/options.py +0 -0
  34. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/parametric.py +0 -0
  35. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/py.typed +0 -0
  36. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/scripts/make_doc.py +0 -0
  37. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/scripts/print_versions.py +0 -0
  38. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/sgrid.py +0 -0
  39. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/__init__.py +0 -0
  40. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/conftest.py +0 -0
  41. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/test_coding.py +0 -0
  42. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/test_geometry.py +0 -0
  43. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/test_groupers.py +0 -0
  44. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/test_helpers.py +0 -0
  45. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/test_options.py +0 -0
  46. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/test_parametric.py +0 -0
  47. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/test_scripts.py +0 -0
  48. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/tests/test_units.py +0 -0
  49. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/units.py +0 -0
  50. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray/utils.py +0 -0
  51. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray.egg-info/SOURCES.txt +0 -0
  52. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray.egg-info/dependency_links.txt +0 -0
  53. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray.egg-info/requires.txt +0 -0
  54. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/cf_xarray.egg-info/top_level.txt +0 -0
  55. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/codecov.yml +0 -0
  56. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/2D_bounds_averaged.png +0 -0
  57. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/2D_bounds_error.png +0 -0
  58. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/2D_bounds_nonunique.png +0 -0
  59. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/Makefile +0 -0
  60. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/_static/dataset-diagram-logo.tex +0 -0
  61. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/_static/full-logo.png +0 -0
  62. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/_static/logo.png +0 -0
  63. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/_static/logo.svg +0 -0
  64. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/_static/rich-repr-example.png +0 -0
  65. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/_static/style.css +0 -0
  66. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/api.rst +0 -0
  67. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/bounds.md +0 -0
  68. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/cartopy_rotated_pole.png +0 -0
  69. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/coding.md +0 -0
  70. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/conf.py +0 -0
  71. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/contributing.rst +0 -0
  72. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/coord_axes.md +0 -0
  73. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/custom-criteria.md +0 -0
  74. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/dsg.md +0 -0
  75. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/examples/introduction.ipynb +0 -0
  76. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/faq.md +0 -0
  77. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/flags.md +0 -0
  78. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/geometry.md +0 -0
  79. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/grid_mappings.md +0 -0
  80. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/howtouse.md +0 -0
  81. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/make.bat +0 -0
  82. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/parametricz.md +0 -0
  83. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/plotting.md +0 -0
  84. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/provenance.md +0 -0
  85. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/quickstart.md +0 -0
  86. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/roadmap.rst +0 -0
  87. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/selecting.md +0 -0
  88. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/sgrid_ugrid.md +0 -0
  89. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/units.md +0 -0
  90. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/doc/whats-new.rst +0 -0
  91. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/pyproject.toml +0 -0
  92. {cf_xarray-0.10.11 → cf_xarray-0.11.0}/setup.cfg +0 -0
@@ -58,7 +58,7 @@ jobs:
58
58
  pytest -n auto --cov=./ --cov-report=xml
59
59
 
60
60
  - name: Upload code coverage to Codecov
61
- uses: codecov/codecov-action@v5.5.2
61
+ uses: codecov/codecov-action@v6.0.0
62
62
  with:
63
63
  file: ./coverage.xml
64
64
  flags: unittests
@@ -98,7 +98,7 @@ jobs:
98
98
  python -m mypy --install-types --non-interactive --cobertura-xml-report mypy_report cf_xarray/
99
99
 
100
100
  - name: Upload mypy coverage to Codecov
101
- uses: codecov/codecov-action@v5.5.2
101
+ uses: codecov/codecov-action@v6.0.0
102
102
  with:
103
103
  file: mypy_report/cobertura.xml
104
104
  flags: mypy
@@ -41,7 +41,7 @@ jobs:
41
41
  else
42
42
  echo "✅ Looks good"
43
43
  fi
44
- - uses: actions/upload-artifact@v6
44
+ - uses: actions/upload-artifact@v7
45
45
  with:
46
46
  name: releases
47
47
  path: dist
@@ -54,7 +54,7 @@ jobs:
54
54
  name: Install Python
55
55
  with:
56
56
  python-version: "3.11"
57
- - uses: actions/download-artifact@v7
57
+ - uses: actions/download-artifact@v8
58
58
  with:
59
59
  name: releases
60
60
  path: dist
@@ -72,7 +72,7 @@ jobs:
72
72
 
73
73
  - name: Publish package to TestPyPI
74
74
  if: github.event_name == 'push'
75
- uses: pypa/gh-action-pypi-publish@v1.13.0
75
+ uses: pypa/gh-action-pypi-publish@v1.14.0
76
76
  with:
77
77
  password: ${{ secrets.TESTPYPI_TOKEN }}
78
78
  repository_url: https://test.pypi.org/legacy/
@@ -91,11 +91,11 @@ jobs:
91
91
  id-token: write
92
92
 
93
93
  steps:
94
- - uses: actions/download-artifact@v7
94
+ - uses: actions/download-artifact@v8
95
95
  with:
96
96
  name: releases
97
97
  path: dist
98
98
  - name: Publish package to PyPI
99
- uses: pypa/gh-action-pypi-publish@v1.13.0
99
+ uses: pypa/gh-action-pypi-publish@v1.14.0
100
100
  with:
101
101
  verbose: true
@@ -53,7 +53,7 @@ jobs:
53
53
  echo "✅ Looks good"
54
54
  fi
55
55
 
56
- - uses: actions/upload-artifact@v6
56
+ - uses: actions/upload-artifact@v7
57
57
  with:
58
58
  name: releases
59
59
  path: dist
@@ -66,7 +66,7 @@ jobs:
66
66
  name: Install Python
67
67
  with:
68
68
  python-version: "3.11"
69
- - uses: actions/download-artifact@v7
69
+ - uses: actions/download-artifact@v8
70
70
  with:
71
71
  name: releases
72
72
  path: dist
@@ -10,7 +10,7 @@ repos:
10
10
 
11
11
  - repo: https://github.com/astral-sh/ruff-pre-commit
12
12
  # Ruff version.
13
- rev: 'v0.14.10'
13
+ rev: 'v0.15.9'
14
14
  hooks:
15
15
  - id: ruff
16
16
  args: ["--fix", "--show-fixes"]
@@ -55,7 +55,7 @@ repos:
55
55
  - id: validate-cff
56
56
 
57
57
  - repo: https://github.com/abravalheri/validate-pyproject
58
- rev: v0.24.1
58
+ rev: v0.25
59
59
  hooks:
60
60
  - id: validate-pyproject
61
61
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cf_xarray
3
- Version: 0.10.11
3
+ Version: 0.11.0
4
4
  Summary: A convenience wrapper for using CF attributes on xarray objects
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -0,0 +1 @@
1
+ __version__ = "0.11.0"
@@ -48,6 +48,11 @@ except ImportError:
48
48
  Weighted,
49
49
  )
50
50
 
51
+ try:
52
+ from regex import match as regex_match
53
+ except ImportError:
54
+ from re import match as regex_match # type: ignore[no-redef]
55
+
51
56
 
52
57
  from . import parametric, sgrid
53
58
  from .criteria import (
@@ -305,12 +310,6 @@ def _get_custom_criteria(
305
310
  List[str]
306
311
  Variable name(s) in parent xarray object that matches axis, coordinate, or custom ``key``
307
312
  """
308
-
309
- try:
310
- from regex import match as regex_match
311
- except ImportError:
312
- from re import match as regex_match # type: ignore[no-redef]
313
-
314
313
  if criteria is None:
315
314
  if not OPTIONS["custom_criteria"]:
316
315
  return []
@@ -1814,10 +1813,6 @@ class CFAccessor:
1814
1813
  for k, v in value.items()
1815
1814
  )
1816
1815
  )
1817
-
1818
- elif value is Ellipsis:
1819
- pass
1820
-
1821
1816
  else:
1822
1817
  # things like sum which have dim
1823
1818
  newvalue = [
@@ -17,24 +17,23 @@ def _guess_bounds_1d(da, dim):
17
17
  """
18
18
  if dim not in da.dims:
19
19
  (dim,) = da.cf.axes[dim]
20
- ADDED_INDEX = False
21
- if dim not in da.coords:
22
- # For proper alignment in the lines below, we need an index on dim.
23
- da = da.assign_coords({dim: da[dim]})
24
- ADDED_INDEX = True
25
-
26
- diff = da.diff(dim)
27
- lower = da - diff / 2
28
- upper = da + diff / 2
29
- bounds = xr.concat([lower, upper], dim="bounds")
30
-
31
- first = (bounds.isel({dim: 0}) - diff.isel({dim: 0})).assign_coords(
32
- {dim: da[dim][0]}
20
+
21
+ bound_position = 0.5
22
+
23
+ diff = da.diff(dim).pad({dim: (1, 1)}, mode="edge")
24
+ lower = da.copy(
25
+ deep=False,
26
+ data=da.data - bound_position * diff.isel({dim: slice(0, -1)}).data,
27
+ )
28
+ upper = da.copy(
29
+ deep=False,
30
+ data=da.data + bound_position * diff.isel({dim: slice(1, None)}).data,
31
+ )
32
+ return (
33
+ xr.concat([lower, upper], dim="bounds")
34
+ .transpose(..., "bounds")
35
+ .drop_attrs(deep=False)
33
36
  )
34
- result = xr.concat([first, bounds], dim=dim).transpose(..., "bounds")
35
- if ADDED_INDEX:
36
- result = result.drop_vars(dim)
37
- return result.drop_attrs(deep=False)
38
37
 
39
38
 
40
39
  def _guess_bounds_2d(da, dims):
@@ -3,6 +3,7 @@ import pickle
3
3
  import warnings
4
4
  from textwrap import dedent
5
5
 
6
+ import dask.array
6
7
  import matplotlib as mpl
7
8
  import numpy as np
8
9
  import pandas as pd
@@ -839,6 +840,51 @@ def test_add_bounds(dims):
839
840
  _check_unchanged(original, ds)
840
841
 
841
842
 
843
+ def test_add_bounds_preserves_array_type() -> None:
844
+ # Test that the array type of the bounds variable is the same as the original variable.
845
+ ds = airds
846
+ original = ds.copy(deep=True)
847
+ ds = ds.drop_indexes("lat").rename_dims(lat="x")
848
+ ds["lat"] = ds.lat.copy(data=dask.array.asarray(ds.lat.data))
849
+ added = ds.cf.add_bounds("lat")
850
+
851
+ assert isinstance(added.lat.data, dask.array.Array)
852
+ assert isinstance(added.lat_bounds.data, dask.array.Array)
853
+
854
+ assert isinstance(ds.lat.data, dask.array.Array)
855
+ _check_unchanged(original, ds)
856
+
857
+
858
+ def test_add_irregularly_spaced_bounds_do_not_overlap() -> None:
859
+ # Test that added bounds with irregular spacing do not overlap.
860
+ ds = airds
861
+ original = ds.copy(deep=True)
862
+ ds["time"] = ds["time"].copy(data=pd.date_range("2013-01", "2013-04", freq="MS"))
863
+ expected = xr.DataArray(
864
+ data=[
865
+ pd.to_datetime(t)
866
+ for t in [
867
+ ["2012-12-16T12", "2013-01-16T12"],
868
+ ["2013-01-16T12", "2013-02-15T00"],
869
+ ["2013-02-15T00", "2013-03-16T12"],
870
+ ["2013-03-16T12", "2013-04-16T12"],
871
+ ]
872
+ ],
873
+ dims=["time", "bounds"],
874
+ name="time_bounds",
875
+ coords={"time": ds.time.data},
876
+ )
877
+ added = ds.copy(deep=False)
878
+ added = added.cf.add_bounds("time")
879
+
880
+ name = "time_bounds"
881
+ assert name in added.coords
882
+ assert added["time"].attrs["bounds"] == name
883
+ assert_allclose(added[name].reset_coords(drop=True), expected)
884
+
885
+ _check_unchanged(original, ds)
886
+
887
+
842
888
  def test_add_bounds_multiple() -> None:
843
889
  # Test multiple dimensions
844
890
  assert not {"x1_bounds", "x2_bounds"} <= set(multiple.variables)
@@ -853,7 +899,7 @@ def test_add_bounds_nd_variable() -> None:
853
899
 
854
900
  # 2D
855
901
  expected = (
856
- vertices_to_bounds( # type: ignore[misc]
902
+ vertices_to_bounds(
857
903
  xr.DataArray(
858
904
  np.arange(0, 13, 3).reshape(5, 1) + np.arange(-2, 2).reshape(1, 4),
859
905
  dims=("x", "y"),
@@ -861,7 +907,7 @@ def test_add_bounds_nd_variable() -> None:
861
907
  out_dims=("bounds", "x", "y"),
862
908
  )
863
909
  .rename("z_bounds")
864
- .assign_coords(**ds.coords)
910
+ .assign_coords(**ds.coords) # type: ignore[arg-type]
865
911
  )
866
912
  actual = ds.cf.add_bounds("z").z_bounds.reset_coords(drop=True)
867
913
  xr.testing.assert_identical(actual, expected)
@@ -882,11 +928,11 @@ def test_add_bounds_nd_variable() -> None:
882
928
  expected = (
883
929
  xr.concat([ds.z - 1.5, ds.z + 1.5], dim="bounds")
884
930
  .rename("z_bounds")
885
- .transpose("bounds", "y", "x")
931
+ .transpose(..., "bounds")
886
932
  )
887
933
 
888
934
  actual = ds.cf.add_bounds("z", dim="x").z_bounds.reset_coords(drop=True)
889
- xr.testing.assert_identical(expected.transpose(..., "bounds"), actual)
935
+ xr.testing.assert_identical(expected, actual)
890
936
 
891
937
  # Requesting bounds on a non-variable dimension
892
938
  with pytest.raises(ValueError, match="are dimensions with no index."):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cf_xarray
3
- Version: 0.10.11
3
+ Version: 0.11.0
4
4
  Summary: A convenience wrapper for using CF attributes on xarray objects
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -35,7 +35,7 @@ or using ``conda``
35
35
  examples/introduction
36
36
  EarthCube 2021 demo <https://earthcube2021.github.io/ec21_book/notebooks/ec21_cherian_etal/DC_01_cf-xarray.html>
37
37
  CESM ocean model demo <https://pop-tools.readthedocs.io/en/latest/examples/cesm-cmip-cf-xarray.html>
38
- COSIMA ocean-sea ice model demo <https://cosima-recipes.readthedocs.io/en/latest/Tutorials/Model_Agnostic_Analysis.html>
38
+ COSIMA ocean-sea ice model demo <https://cosima-recipes.readthedocs.io/en/latest/01-Cooking-Lessons-101/02-Advanced/Model_Agnostic_Analysis.html>
39
39
 
40
40
  .. toctree::
41
41
  :maxdepth: 2