cf-xarray 0.10.0__tar.gz → 0.10.1__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 (95) hide show
  1. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.github/workflows/ci.yaml +5 -5
  2. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.github/workflows/pypi.yaml +2 -2
  3. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.github/workflows/upstream-dev-ci.yaml +1 -1
  4. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.pre-commit-config.yaml +7 -19
  5. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.readthedocs.yml +2 -1
  6. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/PKG-INFO +2 -2
  7. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/__init__.py +1 -1
  8. cf_xarray-0.10.1/cf_xarray/_version.py +1 -0
  9. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/accessor.py +14 -6
  10. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/datasets.py +7 -7
  11. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/geometry.py +10 -1
  12. cf_xarray-0.10.1/cf_xarray/groupers.py +34 -0
  13. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/options.py +0 -1
  14. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/__init__.py +1 -2
  15. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/test_accessor.py +4 -3
  16. cf_xarray-0.10.1/cf_xarray/tests/test_groupers.py +45 -0
  17. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/utils.py +6 -0
  18. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray.egg-info/PKG-INFO +2 -2
  19. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray.egg-info/SOURCES.txt +2 -0
  20. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/ci/doc.yml +1 -1
  21. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/api.rst +8 -1
  22. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/bounds.md +1 -1
  23. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/coord_axes.md +2 -2
  24. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/custom-criteria.md +1 -1
  25. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/flags.md +32 -0
  26. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/selecting.md +3 -3
  27. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/sgrid_ugrid.md +1 -1
  28. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/units.md +2 -2
  29. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/pyproject.toml +9 -7
  30. cf_xarray-0.10.0/cf_xarray/_version.py +0 -1
  31. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.binder/environment.yml +0 -0
  32. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.deepsource.toml +0 -0
  33. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.github/dependabot.yml +0 -0
  34. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.github/release.yml +0 -0
  35. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.github/workflows/parse_logs.py +0 -0
  36. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.github/workflows/testpypi-release.yaml +0 -0
  37. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.gitignore +0 -0
  38. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/.tributors +0 -0
  39. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/CITATION.cff +0 -0
  40. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/LICENSE +0 -0
  41. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/README.rst +0 -0
  42. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/coding.py +0 -0
  43. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/criteria.py +0 -0
  44. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/formatting.py +0 -0
  45. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/helpers.py +0 -0
  46. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/parametric.py +0 -0
  47. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/py.typed +0 -0
  48. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/scripts/make_doc.py +0 -0
  49. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/scripts/print_versions.py +0 -0
  50. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/sgrid.py +0 -0
  51. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/conftest.py +0 -0
  52. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/test_coding.py +0 -0
  53. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/test_geometry.py +0 -0
  54. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/test_helpers.py +0 -0
  55. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/test_options.py +0 -0
  56. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/test_parametric.py +0 -0
  57. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/test_scripts.py +0 -0
  58. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/tests/test_units.py +0 -0
  59. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray/units.py +0 -0
  60. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray.egg-info/dependency_links.txt +0 -0
  61. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray.egg-info/requires.txt +0 -0
  62. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/cf_xarray.egg-info/top_level.txt +0 -0
  63. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/ci/environment-no-optional-deps.yml +0 -0
  64. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/ci/environment.yml +0 -0
  65. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/ci/upstream-dev-env.yml +0 -0
  66. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/codecov.yml +0 -0
  67. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/2D_bounds_averaged.png +0 -0
  68. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/2D_bounds_error.png +0 -0
  69. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/2D_bounds_nonunique.png +0 -0
  70. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/Makefile +0 -0
  71. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/_static/dataset-diagram-logo.tex +0 -0
  72. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/_static/full-logo.png +0 -0
  73. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/_static/logo.png +0 -0
  74. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/_static/logo.svg +0 -0
  75. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/_static/rich-repr-example.png +0 -0
  76. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/_static/style.css +0 -0
  77. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/cartopy_rotated_pole.png +0 -0
  78. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/coding.md +0 -0
  79. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/conf.py +0 -0
  80. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/contributing.rst +0 -0
  81. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/dsg.md +0 -0
  82. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/examples/introduction.ipynb +0 -0
  83. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/faq.md +0 -0
  84. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/geometry.md +0 -0
  85. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/grid_mappings.md +0 -0
  86. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/howtouse.md +0 -0
  87. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/index.rst +0 -0
  88. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/make.bat +0 -0
  89. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/parametricz.md +0 -0
  90. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/plotting.md +0 -0
  91. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/provenance.md +0 -0
  92. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/quickstart.md +0 -0
  93. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/roadmap.rst +0 -0
  94. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/doc/whats-new.rst +0 -0
  95. {cf_xarray-0.10.0 → cf_xarray-0.10.1}/setup.cfg +0 -0
@@ -36,7 +36,7 @@ jobs:
36
36
  run: |
37
37
  echo "PYTHON_VERSION=${{ matrix.python-version }}" >> $GITHUB_ENV
38
38
  - name: Set up conda environment
39
- uses: mamba-org/setup-micromamba@v1
39
+ uses: mamba-org/setup-micromamba@v2
40
40
  with:
41
41
  environment-file: ci/environment.yml
42
42
  environment-name: cf_xarray_test
@@ -50,7 +50,7 @@ jobs:
50
50
  run: |
51
51
  pytest -n auto --cov=./ --cov-report=xml
52
52
  - name: Upload code coverage to Codecov
53
- uses: codecov/codecov-action@v4.5.0
53
+ uses: codecov/codecov-action@v5.4.0
54
54
  with:
55
55
  file: ./coverage.xml
56
56
  flags: unittests
@@ -70,7 +70,7 @@ jobs:
70
70
  # need to fetch all tags to get a correct version
71
71
  fetch-depth: 0 # fetch all branches and tags
72
72
  - name: Set up conda environment
73
- uses: mamba-org/setup-micromamba@v1
73
+ uses: mamba-org/setup-micromamba@v2
74
74
  with:
75
75
  environment-file: ci/environment-no-optional-deps.yml
76
76
  environment-name: cf_xarray_test
@@ -97,7 +97,7 @@ jobs:
97
97
  with:
98
98
  fetch-depth: 0 # Fetch all history for all branches and tags.
99
99
  - name: Set up conda environment
100
- uses: mamba-org/setup-micromamba@v1
100
+ uses: mamba-org/setup-micromamba@v2
101
101
  with:
102
102
  environment-file: ci/environment.yml
103
103
  environment-name: cf_xarray_test
@@ -114,7 +114,7 @@ jobs:
114
114
  run: |
115
115
  python -m mypy --install-types --non-interactive --cobertura-xml-report mypy_report cf_xarray/
116
116
  - name: Upload mypy coverage to Codecov
117
- uses: codecov/codecov-action@v4.5.0
117
+ uses: codecov/codecov-action@v5.4.0
118
118
  with:
119
119
  file: mypy_report/cobertura.xml
120
120
  flags: mypy
@@ -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.10.2
75
+ uses: pypa/gh-action-pypi-publish@v1.12.4
76
76
  with:
77
77
  password: ${{ secrets.TESTPYPI_TOKEN }}
78
78
  repository_url: https://test.pypi.org/legacy/
@@ -96,6 +96,6 @@ jobs:
96
96
  name: releases
97
97
  path: dist
98
98
  - name: Publish package to PyPI
99
- uses: pypa/gh-action-pypi-publish@v1.10.2
99
+ uses: pypa/gh-action-pypi-publish@v1.12.4
100
100
  with:
101
101
  verbose: true
@@ -38,7 +38,7 @@ jobs:
38
38
  run: |
39
39
  echo "PYTHON_VERSION=${{ matrix.python-version }}" >> $GITHUB_ENV
40
40
  - name: Set up conda environment
41
- uses: mamba-org/setup-micromamba@v1
41
+ uses: mamba-org/setup-micromamba@v2
42
42
  with:
43
43
  environment-file: ci/upstream-dev-env.yml
44
44
  environment-name: cf_xarray_test
@@ -3,22 +3,18 @@ ci:
3
3
 
4
4
  repos:
5
5
  - repo: https://github.com/asottile/pyupgrade
6
- rev: v3.17.0
6
+ rev: v3.19.1
7
7
  hooks:
8
8
  - id: pyupgrade
9
9
  args: ["--py310-plus"]
10
10
 
11
11
  - repo: https://github.com/astral-sh/ruff-pre-commit
12
12
  # Ruff version.
13
- rev: 'v0.6.9'
13
+ rev: 'v0.9.3'
14
14
  hooks:
15
15
  - id: ruff
16
- args: ["--show-fixes", "--fix"]
17
-
18
- - repo: https://github.com/psf/black-pre-commit-mirror
19
- rev: 24.10.0
20
- hooks:
21
- - id: black
16
+ args: ["--fix", "--show-fixes"]
17
+ - id: ruff-format
22
18
 
23
19
  - repo: https://github.com/rstcheck/rstcheck
24
20
  rev: v6.2.4
@@ -28,7 +24,7 @@ repos:
28
24
  args: ['--config', 'pyproject.toml']
29
25
 
30
26
  - repo: https://github.com/executablebooks/mdformat
31
- rev: 0.7.17
27
+ rev: 0.7.21
32
28
  hooks:
33
29
  - id: mdformat
34
30
  additional_dependencies:
@@ -36,10 +32,8 @@ repos:
36
32
  - mdformat-myst
37
33
 
38
34
  - repo: https://github.com/nbQA-dev/nbQA
39
- rev: 1.8.7
35
+ rev: 1.9.1
40
36
  hooks:
41
- - id: nbqa-black
42
- - id: nbqa-ruff
43
37
  - id: nbqa
44
38
  entry: nbqa mdformat
45
39
  name: nbqa-mdformat
@@ -55,19 +49,13 @@ repos:
55
49
  - id: check-yaml
56
50
  - id: debug-statements
57
51
 
58
- - repo: https://github.com/keewis/blackdoc
59
- rev: v0.3.9
60
- hooks:
61
- - id: blackdoc
62
- files: .+\.py$
63
-
64
52
  - repo: https://github.com/citation-file-format/cff-converter-python
65
53
  rev: "44e8fc9"
66
54
  hooks:
67
55
  - id: validate-cff
68
56
 
69
57
  - repo: https://github.com/abravalheri/validate-pyproject
70
- rev: v0.20.2
58
+ rev: v0.23
71
59
  hooks:
72
60
  - id: validate-pyproject
73
61
 
@@ -1,5 +1,6 @@
1
1
  version: 2
2
-
2
+ sphinx:
3
+ configuration: doc/conf.py
3
4
  build:
4
5
  os: ubuntu-lts-latest
5
6
  tools:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: cf_xarray
3
- Version: 0.10.0
3
+ Version: 0.10.1
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
@@ -9,6 +9,6 @@ from .helpers import bounds_to_vertices, vertices_to_bounds # noqa
9
9
  from .options import set_options # noqa
10
10
  from .utils import _get_version
11
11
 
12
- from . import geometry # noqa
12
+ from . import geometry, groupers # noqa
13
13
 
14
14
  __version__ = _get_version()
@@ -0,0 +1 @@
1
+ __version__ = "0.10.1"
@@ -680,7 +680,7 @@ def _getattr(
680
680
  None,
681
681
  ):
682
682
  raise AttributeError(
683
- f"{obj.__class__.__name__+'.cf'!r} object has no attribute {attr!r}"
683
+ f"{obj.__class__.__name__ + '.cf'!r} object has no attribute {attr!r}"
684
684
  ) from None
685
685
  raise AttributeError(
686
686
  f"{attr!r} is not a valid attribute on the underlying xarray object."
@@ -1374,7 +1374,11 @@ class CFAccessor:
1374
1374
  coords_iter = coords
1375
1375
  coords = [
1376
1376
  apply_mapper(
1377
- [_single(_get_coords)], self._obj, v, error=False, default=[v] # type: ignore[arg-type]
1377
+ [_single(_get_coords)], # type:ignore[arg-type]
1378
+ self._obj,
1379
+ v,
1380
+ error=False,
1381
+ default=[v],
1378
1382
  )[0]
1379
1383
  for v in coords_iter
1380
1384
  ]
@@ -1385,7 +1389,11 @@ class CFAccessor:
1385
1389
  reduce_dims_iter = list(reduce_dims)
1386
1390
  reduce_dims = [
1387
1391
  apply_mapper(
1388
- [_single(_get_dims)], self._obj, v, error=False, default=[v] # type: ignore[arg-type]
1392
+ [_single(_get_dims)], # type:ignore[arg-type]
1393
+ self._obj,
1394
+ v,
1395
+ error=False,
1396
+ default=[v],
1389
1397
  )[0]
1390
1398
  for v in reduce_dims_iter
1391
1399
  ]
@@ -2758,9 +2766,9 @@ class CFDatasetAccessor(CFAccessor):
2758
2766
 
2759
2767
  for dim in allterms:
2760
2768
  if prefix is None:
2761
- assert (
2762
- outnames is not None
2763
- ), "if prefix is None, outnames must be provided"
2769
+ assert outnames is not None, (
2770
+ "if prefix is None, outnames must be provided"
2771
+ )
2764
2772
  # set outnames here
2765
2773
  try:
2766
2774
  zname = outnames[dim]
@@ -21,15 +21,14 @@ ds_with_tuple = airds.rename({"air": (1, 2, 3)})
21
21
 
22
22
  # POM dataset
23
23
  pomds = xr.Dataset()
24
+ # fmt: off
24
25
  pomds["sigma"] = (
25
- # fmt: off
26
26
  "sigma",
27
27
  [-0.983333, -0.95 , -0.916667, -0.883333, -0.85 , -0.816667,
28
28
  -0.783333, -0.75 , -0.716667, -0.683333, -0.65 , -0.616667,
29
29
  -0.583333, -0.55 , -0.516667, -0.483333, -0.45 , -0.416667,
30
30
  -0.383333, -0.35 , -0.316667, -0.283333, -0.25 , -0.216667,
31
31
  -0.183333, -0.15 , -0.116667, -0.083333, -0.05 , -0.016667],
32
- # fmt: on
33
32
  {
34
33
  "units": "sigma_level",
35
34
  "long_name": "Sigma Stretched Vertical Coordinate at Nodes",
@@ -38,6 +37,7 @@ pomds["sigma"] = (
38
37
  "formula_terms": "sigma: sigma eta: zeta depth: depth",
39
38
  }
40
39
  )
40
+ # fmt: on
41
41
  pomds["depth"] = 175.0
42
42
  pomds["zeta"] = ("ocean_time", [-0.155356, -0.127435])
43
43
 
@@ -109,15 +109,14 @@ multiple["v2"] = (("x2", "y2"), np.ones((10, 5)) * 15)
109
109
 
110
110
 
111
111
  romsds = xr.Dataset()
112
+ # fmt: off
112
113
  romsds["s_rho"] = (
113
- # fmt: off
114
114
  "s_rho",
115
115
  [-0.983333, -0.95 , -0.916667, -0.883333, -0.85 , -0.816667,
116
116
  -0.783333, -0.75 , -0.716667, -0.683333, -0.65 , -0.616667,
117
117
  -0.583333, -0.55 , -0.516667, -0.483333, -0.45 , -0.416667,
118
118
  -0.383333, -0.35 , -0.316667, -0.283333, -0.25 , -0.216667,
119
119
  -0.183333, -0.15 , -0.116667, -0.083333, -0.05 , -0.016667],
120
- # fmt: on
121
120
  {
122
121
  "long_name": "S-coordinate at RHO-points",
123
122
  "valid_min": -1.0,
@@ -125,13 +124,14 @@ romsds["s_rho"] = (
125
124
  "standard_name": "ocean_s_coordinate_g2",
126
125
  "formula_terms": "s: s_rho C: Cs_r eta: zeta depth: h depth_c: hc",
127
126
  "field": "s_rho, scalar",
128
- }
127
+ },
129
128
  )
129
+ # fmt: on
130
130
  romsds.coords["hc"] = 20.0
131
131
  romsds.coords["h"] = 603.9
132
132
  romsds.coords["Vtransform"] = 2.0
133
+ # fmt: off
133
134
  romsds.coords["Cs_r"] = (
134
- # fmt: off
135
135
  "s_rho",
136
136
  [-9.33010396e-01, -8.09234736e-01, -6.98779853e-01, -6.01008926e-01,
137
137
  -5.15058562e-01, -4.39938913e-01, -3.74609181e-01, -3.18031817e-01,
@@ -141,8 +141,8 @@ romsds.coords["Cs_r"] = (
141
141
  -2.53860004e-02, -1.95414261e-02, -1.46880431e-02, -1.06952600e-02,
142
142
  -7.45515186e-03, -4.87981407e-03, -2.89916971e-03, -1.45919898e-03,
143
143
  -5.20560097e-04, -5.75774004e-05],
144
- # fmt: on
145
144
  )
145
+ # fmt: on
146
146
  romsds["zeta"] = ("ocean_time", [-0.155356, -0.127435])
147
147
  romsds["temp"] = (
148
148
  ("ocean_time", "s_rho"),
@@ -4,6 +4,7 @@ import copy
4
4
  from collections import ChainMap
5
5
  from collections.abc import Hashable, Sequence
6
6
  from dataclasses import dataclass
7
+ from typing import TYPE_CHECKING
7
8
 
8
9
  import numpy as np
9
10
  import pandas as pd
@@ -21,6 +22,9 @@ __all__ = [
21
22
  ]
22
23
 
23
24
 
25
+ if TYPE_CHECKING:
26
+ from shapely import MultiPoint, Point
27
+
24
28
  # Useful convention language:
25
29
  # 1. Whether linked to normal CF space-time coordinates with a nodes attribute or not, inclusion of such coordinates is
26
30
  # recommended to maintain backward compatibility with software that has not implemented geometry capabilities.
@@ -547,7 +551,11 @@ def cf_to_shapely(ds: xr.Dataset, *, container: Hashable = GEOMETRY_CONTAINER_NA
547
551
  return geometries.rename("geometry")
548
552
 
549
553
 
550
- def points_to_cf(pts: xr.DataArray | Sequence, *, names: GeometryNames | None = None):
554
+ def points_to_cf(
555
+ pts: xr.DataArray | Sequence[Point | MultiPoint],
556
+ *,
557
+ names: GeometryNames | None = None,
558
+ ):
551
559
  """Get a list of points (shapely.geometry.[Multi]Point) and return a CF-compliant geometry dataset.
552
560
 
553
561
  Parameters
@@ -563,6 +571,7 @@ def points_to_cf(pts: xr.DataArray | Sequence, *, names: GeometryNames | None =
563
571
  """
564
572
  from shapely.geometry import MultiPoint
565
573
 
574
+ pts_: Sequence[Point | MultiPoint]
566
575
  if isinstance(pts, xr.DataArray):
567
576
  # TODO: Fix this hardcoding
568
577
  if pts.ndim != 1:
@@ -0,0 +1,34 @@
1
+ from dataclasses import dataclass
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from xarray.groupers import EncodedGroups, UniqueGrouper
6
+
7
+
8
+ @dataclass
9
+ class FlagGrouper(UniqueGrouper):
10
+ def factorize(self, group) -> EncodedGroups:
11
+ if "flag_values" not in group.attrs or "flag_meanings" not in group.attrs:
12
+ raise ValueError(
13
+ "FlagGrouper can only be used with flag variables that have"
14
+ "`flag_values` and `flag_meanings` specified in attrs."
15
+ )
16
+
17
+ values = np.array(group.attrs["flag_values"])
18
+ full_index = pd.Index(group.attrs["flag_meanings"].split(" "))
19
+
20
+ self.labels = values
21
+
22
+ # TODO: we could optimize here, since `group` is already factorized,
23
+ # but there are subtleties. For example, the attrs must be up to date,
24
+ # any value that is not in flag_values will cause an error, etc.
25
+ ret = super().factorize(group)
26
+
27
+ ret.codes.attrs.pop("flag_values")
28
+ ret.codes.attrs.pop("flag_meanings")
29
+
30
+ return EncodedGroups(
31
+ codes=ret.codes,
32
+ full_index=full_index,
33
+ group_indices=ret.group_indices,
34
+ )
@@ -38,7 +38,6 @@ class set_options: # numpydoc ignore=PR01,PR02
38
38
  >>> ds = xr.Dataset({"elev": np.arange(1000)})
39
39
  >>> with cf_xarray.set_options(custom_criteria=my_custom_criteria):
40
40
  ... xr.testing.assert_identical(ds["elev"], ds.cf["ssh"])
41
- ...
42
41
 
43
42
  Or to set global options:
44
43
 
@@ -32,8 +32,7 @@ class CountingScheduler:
32
32
  self.total_computes += 1
33
33
  if self.total_computes > self.max_computes:
34
34
  raise RuntimeError(
35
- "Too many computes. Total: %d > max: %d."
36
- % (self.total_computes, self.max_computes)
35
+ f"Too many computes. Total:{self.total_computes} > max: {self.max_computes}."
37
36
  )
38
37
  return dask.get(dsk, keys, **kwargs)
39
38
 
@@ -453,7 +453,7 @@ def test_rename_like() -> None:
453
453
  @pytest.mark.parametrize(
454
454
  "attr, xrkwargs, cfkwargs",
455
455
  (
456
- ("resample", {"time": "M"}, {"T": "M"}),
456
+ ("resample", {"time": "ME"}, {"T": "ME"}),
457
457
  ("rolling", {"lat": 5}, {"Y": 5}),
458
458
  ("groupby", {"group": "time"}, {"group": "T"}),
459
459
  ("groupby", {"group": "time.month"}, {"group": "T.month"}),
@@ -1748,7 +1748,7 @@ def test_add_canonical_attributes(override, skip, verbose, capsys):
1748
1748
 
1749
1749
  # Attributes have been added
1750
1750
  for var in sum(ds.cf.standard_names.values(), []):
1751
- assert set(ds[var].attrs) < set(cf_ds[var].attrs)
1751
+ assert set(ds[var].attrs) <= set(cf_ds[var].attrs)
1752
1752
 
1753
1753
  # Time units did not change
1754
1754
  assert ds["time"].attrs.get("units") is cf_ds["time"].attrs.get("units") is None
@@ -2047,7 +2047,8 @@ def test_ancillary_variables_extra_dim():
2047
2047
  ),
2048
2048
  }
2049
2049
  )
2050
- assert_identical(ds.cf["X"], ds["x"])
2050
+ with pytest.warns(UserWarning):
2051
+ assert_identical(ds.cf["X"], ds["x"])
2051
2052
 
2052
2053
 
2053
2054
  def test_geometry_association(geometry_ds):
@@ -0,0 +1,45 @@
1
+ import numpy as np
2
+ import pytest
3
+ import xarray as xr
4
+ from xarray.testing import assert_identical
5
+
6
+ from cf_xarray.datasets import flag_excl
7
+ from cf_xarray.groupers import FlagGrouper
8
+
9
+
10
+ def test_flag_grouper():
11
+ ds = flag_excl.to_dataset().set_coords("flag_var").copy(deep=True)
12
+ ds["foo"] = ("time", np.arange(8))
13
+ actual = ds.groupby(flag_var=FlagGrouper()).mean()
14
+ expected = ds.groupby("flag_var").mean()
15
+ expected["flag_var"] = ["flag_1", "flag_2", "flag_3"]
16
+ expected["flag_var"].attrs["standard_name"] = "flag_mutual_exclusive"
17
+ assert_identical(actual, expected)
18
+
19
+ del ds.flag_var.attrs["flag_values"]
20
+ with pytest.raises(ValueError):
21
+ ds.groupby(flag_var=FlagGrouper())
22
+
23
+ ds.flag_var.attrs["flag_values"] = [0, 1, 2]
24
+ del ds.flag_var.attrs["flag_meanings"]
25
+ with pytest.raises(ValueError):
26
+ ds.groupby(flag_var=FlagGrouper())
27
+
28
+
29
+ @pytest.mark.parametrize(
30
+ "values",
31
+ [
32
+ [1, 2],
33
+ [1, 2, 3], # value out of range of flag_values
34
+ ],
35
+ )
36
+ def test_flag_grouper_optimized(values):
37
+ ds = xr.Dataset(
38
+ {"foo": ("x", values, {"flag_values": [0, 1, 2], "flag_meanings": "a b c"})}
39
+ )
40
+ ret = FlagGrouper().factorize(ds.foo)
41
+ expected = ds.foo
42
+ expected.data[ds.foo.data > 2] = -1
43
+ del ds.foo.attrs["flag_meanings"]
44
+ del ds.foo.attrs["flag_values"]
45
+ assert_identical(ret.codes, ds.foo)
@@ -108,10 +108,16 @@ def parse_cf_standard_name_table(source=None):
108
108
  if not source:
109
109
  import pooch
110
110
 
111
+ downloader = pooch.HTTPDownloader(
112
+ # https://github.com/readthedocs/readthedocs.org/issues/11763
113
+ headers={"User-Agent": "cf-xarray"}
114
+ )
115
+
111
116
  source = pooch.retrieve(
112
117
  "https://raw.githubusercontent.com/cf-convention/cf-convention.github.io/"
113
118
  "master/Data/cf-standard-names/current/src/cf-standard-name-table.xml",
114
119
  known_hash=None,
120
+ downloader=downloader,
115
121
  )
116
122
  root = ElementTree.parse(source).getroot()
117
123
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: cf_xarray
3
- Version: 0.10.0
3
+ Version: 0.10.1
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
@@ -24,6 +24,7 @@ cf_xarray/criteria.py
24
24
  cf_xarray/datasets.py
25
25
  cf_xarray/formatting.py
26
26
  cf_xarray/geometry.py
27
+ cf_xarray/groupers.py
27
28
  cf_xarray/helpers.py
28
29
  cf_xarray/options.py
29
30
  cf_xarray/parametric.py
@@ -43,6 +44,7 @@ cf_xarray/tests/conftest.py
43
44
  cf_xarray/tests/test_accessor.py
44
45
  cf_xarray/tests/test_coding.py
45
46
  cf_xarray/tests/test_geometry.py
47
+ cf_xarray/tests/test_groupers.py
46
48
  cf_xarray/tests/test_helpers.py
47
49
  cf_xarray/tests/test_options.py
48
50
  cf_xarray/tests/test_parametric.py
@@ -8,7 +8,7 @@ dependencies:
8
8
  - netcdf4
9
9
  - pooch
10
10
  - xarray
11
- - sphinx
11
+ - sphinx<8
12
12
  - sphinx-copybutton
13
13
  - numpydoc
14
14
  - sphinx-autosummary-accessors
@@ -21,13 +21,20 @@ Geometries
21
21
  ----------
22
22
  .. autosummary::
23
23
  :toctree: generated/
24
-
25
24
  geometry.decode_geometries
25
+
26
26
  geometry.encode_geometries
27
27
  geometry.shapely_to_cf
28
28
  geometry.cf_to_shapely
29
29
  geometry.GeometryNames
30
30
 
31
+
32
+ Groupers
33
+ --------
34
+ .. autosummary::
35
+ :toctree: generated/
36
+ groupers.FlagGrouper
37
+
31
38
  .. currentmodule:: xarray
32
39
 
33
40
  DataArray
@@ -14,7 +14,7 @@
14
14
 
15
15
  `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.
16
16
 
17
- 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.
17
+ 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.
18
18
 
19
19
  ![2d bounds error](2D_bounds_error.png)
20
20
 
@@ -55,7 +55,7 @@ This table lists these internal criteria
55
55
  :stub-columns: 1
56
56
  ```
57
57
 
58
- 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.
58
+ 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.
59
59
 
60
60
  ## Axis Names
61
61
 
@@ -68,7 +68,7 @@ Similar criteria exist for the concept of "axes".
68
68
  :stub-columns: 1
69
69
  ```
70
70
 
71
- ## `.axes` and `.coordinates` properties
71
+ ## `.axes` and `.coordinates` properties
72
72
 
73
73
  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).
74
74
 
@@ -73,7 +73,7 @@ with cfxr.set_options(custom_criteria=salt_criteria):
73
73
  salty
74
74
  ```
75
75
 
76
- Note that `salty` contains both `salt1` and `salt2`. Without setting these criteria, we would only get `salt1` by default
76
+ Note that `salty` contains both `salt1` and `salt2`. Without setting these criteria, we would only get `salt1` by default
77
77
 
78
78
  ```{code-cell}
79
79
  ds.cf[["sea_water_salinity"]]
@@ -60,6 +60,38 @@ You can also check whether a DataArray has the appropriate attributes to be reco
60
60
  da.cf.is_flag_variable
61
61
  ```
62
62
 
63
+ ## GroupBy
64
+
65
+ Flag variables, such as that above, are naturally used for GroupBy operations.
66
+ cf-xarray provides a `FlagGrouper` that understands the `flag_meanings` and `flag_values` attributes.
67
+
68
+ Let's load an example dataset where the `flag_var` array has the needed attributes.
69
+
70
+ ```{code-cell}
71
+ import cf_xarray as cfxr
72
+ import numpy as np
73
+
74
+ from cf_xarray.datasets import flag_excl
75
+
76
+ ds = flag_excl.to_dataset().set_coords('flag_var')
77
+ ds["foo"] = ("time", np.arange(8))
78
+ ds.flag_var
79
+ ```
80
+
81
+ Now use the :py:class:`~cf_xarray.groupers.FlagGrouper` to group by this flag variable:
82
+
83
+ ```{code-cell}
84
+ from cf_xarray.groupers import FlagGrouper
85
+
86
+ ds.groupby(flag_var=FlagGrouper()).mean()
87
+ ```
88
+
89
+ Note how the output coordinate has the values from `flag_meanings`!
90
+
91
+ ```{seealso}
92
+ See the Xarray docs on using [Grouper objects](https://docs.xarray.dev/en/stable/user-guide/groupby.html#grouper-objects).
93
+ ```
94
+
63
95
  ## Flag Masks
64
96
 
65
97
  ```{warning}
@@ -30,7 +30,7 @@ CF conventions on
30
30
  1. [ancillary data](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#ancillary-data)
31
31
  ```
32
32
 
33
- 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.
33
+ 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.
34
34
 
35
35
  To demonstrate this, let's load a few datasets
36
36
 
@@ -91,7 +91,7 @@ anc
91
91
 
92
92
  ## Selecting multiple variables
93
93
 
94
- 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
94
+ 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
95
95
 
96
96
  ```{code-cell}
97
97
  multiple.cf[["X"]]
@@ -103,7 +103,7 @@ pop.cf[["longitude"]]
103
103
 
104
104
  ## Mixing names
105
105
 
106
- 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`)
106
+ 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`)
107
107
 
108
108
  ```{code-cell}
109
109
  pop.cf[["sea_water_potential_temperature", "UVEL"]]
@@ -65,7 +65,7 @@ variable `grid` list many more dimension names.
65
65
 
66
66
  ### Topology variable
67
67
 
68
- `cf_xarray` supports identifying the `mesh_topology` variable using the `cf_role` attribute.
68
+ `cf_xarray` supports identifying the `mesh_topology` variable using the `cf_role` attribute.
69
69
 
70
70
  ## More?
71
71
 
@@ -14,9 +14,9 @@ hide-toc: true
14
14
  1. [CF conventions on units](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#units)
15
15
  ```
16
16
 
17
- 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).
17
+ 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).
18
18
 
19
- `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.
19
+ `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.
20
20
 
21
21
  ## Formatting units
22
22
 
@@ -53,9 +53,6 @@ write_to = "cf_xarray/_version.py"
53
53
  write_to_template= '__version__ = "{version}"'
54
54
  tag_regex= "^(?P<prefix>v)?(?P<version>[^\\+]+)(?P<suffix>.*)?$"
55
55
 
56
- [tool.black]
57
- target-version = ["py310"]
58
-
59
56
  [tool.ruff]
60
57
  target-version = "py310"
61
58
  builtins = ["ellipsis"]
@@ -66,14 +63,18 @@ exclude = [
66
63
 
67
64
  [tool.ruff.lint]
68
65
  # E402: module level import not at top of file
69
- # E501: line too long - let ruff worry about that
66
+ # E501: line too long - let black worry about that
67
+ # E731: do not assign a lambda expression, use a def
70
68
  ignore = [
71
69
  "E402",
72
70
  "E501",
71
+ "E731",
73
72
  "B018",
74
73
  "B015",
75
74
  ]
76
75
  select = [
76
+ # Bugbear
77
+ "B",
77
78
  # Pyflakes
78
79
  "F",
79
80
  # Pycodestyle
@@ -84,9 +85,6 @@ select = [
84
85
  # Pyupgrade
85
86
  "UP",
86
87
  ]
87
- extend-select = [
88
- "B", # flake8-bugbear
89
- ]
90
88
 
91
89
  [tool.ruff.lint.isort]
92
90
  known-first-party = ["cf_xarray"]
@@ -103,6 +101,10 @@ known-third-party = [
103
101
  "xarray"
104
102
  ]
105
103
 
104
+ [tool.ruff.format]
105
+ # Enable reformatting of code snippets in docstrings.
106
+ docstring-code-format = true
107
+
106
108
 
107
109
  [tool.pytest]
108
110
  python_files = "test_*.py"
@@ -1 +0,0 @@
1
- __version__ = "0.10.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes