cf-xarray 0.9.5__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.
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.github/workflows/ci.yaml +5 -5
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.github/workflows/pypi.yaml +2 -2
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.github/workflows/upstream-dev-ci.yaml +1 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.pre-commit-config.yaml +8 -20
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.readthedocs.yml +2 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/CITATION.cff +4 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/PKG-INFO +3 -3
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/__init__.py +1 -1
- cf_xarray-0.10.1/cf_xarray/_version.py +1 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/accessor.py +34 -53
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/coding.py +6 -3
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/datasets.py +7 -7
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/formatting.py +2 -2
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/geometry.py +11 -2
- cf_xarray-0.10.1/cf_xarray/groupers.py +34 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/options.py +0 -1
- cf_xarray-0.10.1/cf_xarray/parametric.py +821 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/scripts/make_doc.py +3 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/sgrid.py +2 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/tests/__init__.py +1 -2
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/tests/test_accessor.py +18 -47
- cf_xarray-0.10.1/cf_xarray/tests/test_groupers.py +45 -0
- cf_xarray-0.10.1/cf_xarray/tests/test_parametric.py +615 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/utils.py +9 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray.egg-info/PKG-INFO +3 -3
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray.egg-info/SOURCES.txt +4 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray.egg-info/requires.txt +1 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/ci/doc.yml +1 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/api.rst +8 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/bounds.md +1 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/coord_axes.md +2 -2
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/custom-criteria.md +1 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/flags.md +32 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/parametricz.md +1 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/selecting.md +3 -3
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/sgrid_ugrid.md +1 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/units.md +2 -2
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/whats-new.rst +1 -3
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/pyproject.toml +11 -9
- cf_xarray-0.9.5/cf_xarray/_version.py +0 -1
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.binder/environment.yml +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.deepsource.toml +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.github/dependabot.yml +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.github/release.yml +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.github/workflows/parse_logs.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.github/workflows/testpypi-release.yaml +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.gitignore +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/.tributors +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/LICENSE +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/README.rst +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/criteria.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/helpers.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/py.typed +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/scripts/print_versions.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/tests/conftest.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/tests/test_coding.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/tests/test_geometry.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/tests/test_helpers.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/tests/test_options.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/tests/test_scripts.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/tests/test_units.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray/units.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray.egg-info/dependency_links.txt +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/cf_xarray.egg-info/top_level.txt +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/ci/environment-no-optional-deps.yml +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/ci/environment.yml +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/ci/upstream-dev-env.yml +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/codecov.yml +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/2D_bounds_averaged.png +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/2D_bounds_error.png +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/2D_bounds_nonunique.png +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/Makefile +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/_static/dataset-diagram-logo.tex +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/_static/full-logo.png +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/_static/logo.png +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/_static/logo.svg +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/_static/rich-repr-example.png +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/_static/style.css +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/cartopy_rotated_pole.png +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/coding.md +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/conf.py +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/contributing.rst +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/dsg.md +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/examples/introduction.ipynb +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/faq.md +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/geometry.md +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/grid_mappings.md +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/howtouse.md +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/index.rst +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/make.bat +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/plotting.md +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/provenance.md +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/quickstart.md +0 -0
- {cf_xarray-0.9.5 → cf_xarray-0.10.1}/doc/roadmap.rst +0 -0
- {cf_xarray-0.9.5 → 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@
|
|
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@
|
|
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@
|
|
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@
|
|
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@
|
|
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.
|
|
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.
|
|
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@
|
|
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.
|
|
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.
|
|
13
|
+
rev: 'v0.9.3'
|
|
14
14
|
hooks:
|
|
15
15
|
- id: ruff
|
|
16
|
-
args: ["--
|
|
17
|
-
|
|
18
|
-
- repo: https://github.com/psf/black-pre-commit-mirror
|
|
19
|
-
rev: 24.8.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.
|
|
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.
|
|
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
|
|
@@ -47,7 +41,7 @@ repos:
|
|
|
47
41
|
additional_dependencies: [mdformat==0.7.17]
|
|
48
42
|
|
|
49
43
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
50
|
-
rev:
|
|
44
|
+
rev: v5.0.0
|
|
51
45
|
hooks:
|
|
52
46
|
- id: trailing-whitespace
|
|
53
47
|
- id: end-of-file-fixer
|
|
@@ -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.
|
|
58
|
+
rev: v0.23
|
|
71
59
|
hooks:
|
|
72
60
|
- id: validate-pyproject
|
|
73
61
|
|
|
@@ -83,6 +83,10 @@ authors:
|
|
|
83
83
|
- family-names: Haëck
|
|
84
84
|
given-names: Clément
|
|
85
85
|
affiliation: Laboratoire d'Océanographie et du Climat (LOCEAN), Paris
|
|
86
|
+
- family-names: Boutte
|
|
87
|
+
given-names: Jason
|
|
88
|
+
orcid: 'https://orcid.org/0009-0009-3996-3772'
|
|
89
|
+
affiliation: Lawrence Livermore National Laboratory
|
|
86
90
|
identifiers:
|
|
87
91
|
- type: doi
|
|
88
92
|
value: 10.5281/zenodo.4749735
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: cf_xarray
|
|
3
|
-
Version: 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
|
|
@@ -220,7 +220,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
220
220
|
Requires-Python: >=3.10
|
|
221
221
|
Description-Content-Type: text/x-rst
|
|
222
222
|
License-File: LICENSE
|
|
223
|
-
Requires-Dist: xarray
|
|
223
|
+
Requires-Dist: xarray>=2022.03.0
|
|
224
224
|
Provides-Extra: all
|
|
225
225
|
Requires-Dist: matplotlib; extra == "all"
|
|
226
226
|
Requires-Dist: pint!=0.24.0,>=0.18; extra == "all"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.10.1"
|
|
@@ -18,7 +18,6 @@ from typing import (
|
|
|
18
18
|
Any,
|
|
19
19
|
Literal,
|
|
20
20
|
TypeVar,
|
|
21
|
-
Union,
|
|
22
21
|
cast,
|
|
23
22
|
overload,
|
|
24
23
|
)
|
|
@@ -31,7 +30,7 @@ from xarray.core.resample import Resample
|
|
|
31
30
|
from xarray.core.rolling import Coarsen, Rolling
|
|
32
31
|
from xarray.core.weighted import Weighted
|
|
33
32
|
|
|
34
|
-
from . import sgrid
|
|
33
|
+
from . import parametric, sgrid
|
|
35
34
|
from .criteria import (
|
|
36
35
|
_DSG_ROLES,
|
|
37
36
|
_GEOMETRY_TYPES,
|
|
@@ -89,7 +88,7 @@ ATTRS["time"] = ATTRS["T"]
|
|
|
89
88
|
ATTRS["vertical"] = ATTRS["Z"]
|
|
90
89
|
|
|
91
90
|
# Type for Mapper functions
|
|
92
|
-
Mapper = Callable[[
|
|
91
|
+
Mapper = Callable[[DataArray | Dataset, Hashable], list[Hashable]]
|
|
93
92
|
|
|
94
93
|
# Type for decorators
|
|
95
94
|
F = TypeVar("F", bound=Callable[..., Any])
|
|
@@ -538,7 +537,7 @@ def _get_coords(obj: DataArray | Dataset, key: Hashable) -> list[Hashable]:
|
|
|
538
537
|
def _variables(func: F) -> F:
|
|
539
538
|
@functools.wraps(func)
|
|
540
539
|
def wrapper(obj: DataArray | Dataset, key: Hashable) -> list[DataArray]:
|
|
541
|
-
return [obj[k] for k in func(obj, key)]
|
|
540
|
+
return [obj[k] for k in func(obj, key)]
|
|
542
541
|
|
|
543
542
|
return cast(F, wrapper)
|
|
544
543
|
|
|
@@ -681,7 +680,7 @@ def _getattr(
|
|
|
681
680
|
None,
|
|
682
681
|
):
|
|
683
682
|
raise AttributeError(
|
|
684
|
-
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}"
|
|
685
684
|
) from None
|
|
686
685
|
raise AttributeError(
|
|
687
686
|
f"{attr!r} is not a valid attribute on the underlying xarray object."
|
|
@@ -1150,9 +1149,10 @@ def create_flag_dict(da) -> Mapping[Hashable, FlagParam]:
|
|
|
1150
1149
|
)
|
|
1151
1150
|
|
|
1152
1151
|
flag_params = tuple(
|
|
1153
|
-
FlagParam(mask, value)
|
|
1152
|
+
FlagParam(mask, value)
|
|
1153
|
+
for mask, value in zip(flag_masks, flag_values, strict=False)
|
|
1154
1154
|
)
|
|
1155
|
-
return dict(zip(flag_meanings, flag_params))
|
|
1155
|
+
return dict(zip(flag_meanings, flag_params, strict=False))
|
|
1156
1156
|
|
|
1157
1157
|
|
|
1158
1158
|
class CFAccessor:
|
|
@@ -1368,13 +1368,17 @@ class CFAccessor:
|
|
|
1368
1368
|
kwargs: dict[str, Any] | None = None,
|
|
1369
1369
|
):
|
|
1370
1370
|
if coords is not None:
|
|
1371
|
-
if isinstance(coords,
|
|
1371
|
+
if isinstance(coords, Hashable | DataArray):
|
|
1372
1372
|
coords_iter: Iterable[Hashable | DataArray] = [coords]
|
|
1373
1373
|
else:
|
|
1374
1374
|
coords_iter = coords
|
|
1375
1375
|
coords = [
|
|
1376
1376
|
apply_mapper(
|
|
1377
|
-
[_single(_get_coords)],
|
|
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)],
|
|
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
|
]
|
|
@@ -2754,18 +2762,13 @@ class CFDatasetAccessor(CFAccessor):
|
|
|
2754
2762
|
"""
|
|
2755
2763
|
ds = self._obj
|
|
2756
2764
|
|
|
2757
|
-
requirements = {
|
|
2758
|
-
"ocean_s_coordinate_g1": {"depth_c", "depth", "s", "C", "eta"},
|
|
2759
|
-
"ocean_s_coordinate_g2": {"depth_c", "depth", "s", "C", "eta"},
|
|
2760
|
-
"ocean_sigma_coordinate": {"sigma", "eta", "depth"},
|
|
2761
|
-
}
|
|
2762
|
-
|
|
2763
2765
|
allterms = self.formula_terms
|
|
2766
|
+
|
|
2764
2767
|
for dim in allterms:
|
|
2765
2768
|
if prefix is None:
|
|
2766
|
-
assert (
|
|
2767
|
-
|
|
2768
|
-
)
|
|
2769
|
+
assert outnames is not None, (
|
|
2770
|
+
"if prefix is None, outnames must be provided"
|
|
2771
|
+
)
|
|
2769
2772
|
# set outnames here
|
|
2770
2773
|
try:
|
|
2771
2774
|
zname = outnames[dim]
|
|
@@ -2782,6 +2785,7 @@ class CFDatasetAccessor(CFAccessor):
|
|
|
2782
2785
|
suffix = dim.split("_")
|
|
2783
2786
|
zname = f"{prefix}_" + "_".join(suffix[1:])
|
|
2784
2787
|
|
|
2788
|
+
# never touched, if standard name is missing it's not included in allterms
|
|
2785
2789
|
if "standard_name" not in ds[dim].attrs:
|
|
2786
2790
|
continue
|
|
2787
2791
|
stdname = ds[dim].attrs["standard_name"]
|
|
@@ -2790,46 +2794,23 @@ class CFDatasetAccessor(CFAccessor):
|
|
|
2790
2794
|
terms = {}
|
|
2791
2795
|
for key, value in allterms[dim].items():
|
|
2792
2796
|
if value not in ds:
|
|
2797
|
+
# is this ever hit, if variable is missing it's missing in decoded allterms
|
|
2793
2798
|
raise KeyError(
|
|
2794
2799
|
f"Variable {value!r} is required to decode coordinate for {dim!r}"
|
|
2795
2800
|
" but it is absent in the Dataset."
|
|
2796
2801
|
)
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
absent_terms = requirements[stdname] - set(terms)
|
|
2800
|
-
if absent_terms:
|
|
2801
|
-
raise KeyError(f"Required terms {absent_terms} absent in dataset.")
|
|
2802
|
-
|
|
2803
|
-
if stdname == "ocean_s_coordinate_g1":
|
|
2804
|
-
# S(k,j,i) = depth_c * s(k) + (depth(j,i) - depth_c) * C(k)
|
|
2805
|
-
S = (
|
|
2806
|
-
terms["depth_c"] * terms["s"]
|
|
2807
|
-
+ (terms["depth"] - terms["depth_c"]) * terms["C"]
|
|
2808
|
-
)
|
|
2809
|
-
|
|
2810
|
-
# z(n,k,j,i) = S(k,j,i) + eta(n,j,i) * (1 + S(k,j,i) / depth(j,i))
|
|
2811
|
-
ztemp = S + terms["eta"] * (1 + S / terms["depth"])
|
|
2802
|
+
# keys should be case insensitive
|
|
2803
|
+
terms[key.lower()] = ds[value]
|
|
2812
2804
|
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
terms["depth_c"] + terms["depth"]
|
|
2818
|
-
)
|
|
2819
|
-
|
|
2820
|
-
# z(n,k,j,i) = eta(n,j,i) + (eta(n,j,i) + depth(j,i)) * S(k,j,i)
|
|
2821
|
-
ztemp = terms["eta"] + (terms["eta"] + terms["depth"]) * S
|
|
2822
|
-
|
|
2823
|
-
elif stdname == "ocean_sigma_coordinate":
|
|
2824
|
-
# z(n,k,j,i) = eta(n,j,i) + sigma(k)*(depth(j,i)+eta(n,j,i))
|
|
2825
|
-
ztemp = terms["eta"] + terms["sigma"] * (terms["depth"] + terms["eta"])
|
|
2826
|
-
|
|
2827
|
-
else:
|
|
2805
|
+
try:
|
|
2806
|
+
transform = parametric.TRANSFORM_FROM_STDNAME[stdname]
|
|
2807
|
+
except KeyError:
|
|
2808
|
+
# Should occur since stdname is check before
|
|
2828
2809
|
raise NotImplementedError(
|
|
2829
|
-
f"Coordinate function for {stdname!r} not
|
|
2830
|
-
)
|
|
2810
|
+
f"Coordinate function for {stdname!r} not implmented yet. Contributions welcome!"
|
|
2811
|
+
) from None
|
|
2831
2812
|
|
|
2832
|
-
ds.coords[zname] =
|
|
2813
|
+
ds.coords[zname] = transform.from_terms(terms)
|
|
2833
2814
|
|
|
2834
2815
|
|
|
2835
2816
|
@xr.register_dataarray_accessor("cf")
|
|
@@ -3024,7 +3005,7 @@ class CFDataArrayAccessor(CFAccessor):
|
|
|
3024
3005
|
x = self._obj.astype("i")
|
|
3025
3006
|
bit_comp = x & bit_mask
|
|
3026
3007
|
|
|
3027
|
-
for i, (flag, value) in enumerate(zip(flags_reduced, values)):
|
|
3008
|
+
for i, (flag, value) in enumerate(zip(flags_reduced, values, strict=False)):
|
|
3028
3009
|
bit = bit_comp.isel(_mask=i)
|
|
3029
3010
|
if value is not None:
|
|
3030
3011
|
out[flag] = bit == value
|
|
@@ -46,7 +46,7 @@ def encode_multi_index_as_compress(ds, idxnames=None):
|
|
|
46
46
|
encoded = ds.reset_index(idxnames)
|
|
47
47
|
for idxname in idxnames:
|
|
48
48
|
mindex = ds.indexes[idxname]
|
|
49
|
-
coords = dict(zip(mindex.names, mindex.levels))
|
|
49
|
+
coords = dict(zip(mindex.names, mindex.levels, strict=False))
|
|
50
50
|
encoded.update(coords)
|
|
51
51
|
for c in coords:
|
|
52
52
|
encoded[c].attrs = ds[c].attrs
|
|
@@ -112,13 +112,16 @@ def decode_compress_to_multi_index(encoded, idxnames=None):
|
|
|
112
112
|
|
|
113
113
|
variables = {
|
|
114
114
|
dim: encoded[dim].isel({dim: xr.Variable(data=index, dims=idxname)})
|
|
115
|
-
for dim, index in zip(names, indices)
|
|
115
|
+
for dim, index in zip(names, indices, strict=False)
|
|
116
116
|
}
|
|
117
117
|
decoded = decoded.assign_coords(variables).set_xindex(
|
|
118
118
|
names, PandasMultiIndex
|
|
119
119
|
)
|
|
120
120
|
except ImportError:
|
|
121
|
-
arrays = [
|
|
121
|
+
arrays = [
|
|
122
|
+
encoded[dim].data[index]
|
|
123
|
+
for dim, index in zip(names, indices, strict=False)
|
|
124
|
+
]
|
|
122
125
|
mindex = pd.MultiIndex.from_arrays(arrays, names=names)
|
|
123
126
|
decoded.coords[idxname] = mindex
|
|
124
127
|
|
|
@@ -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"),
|
|
@@ -268,14 +268,14 @@ def _format_flags(accessor, rich):
|
|
|
268
268
|
table.add_column("Value", justify="right")
|
|
269
269
|
table.add_column("Bits", justify="center")
|
|
270
270
|
|
|
271
|
-
for val, bit, key in zip(value_text, bit_text, flag_dict):
|
|
271
|
+
for val, bit, key in zip(value_text, bit_text, flag_dict, strict=False):
|
|
272
272
|
table.add_row(_format_cf_name(key, rich), val, bit)
|
|
273
273
|
|
|
274
274
|
return table
|
|
275
275
|
|
|
276
276
|
else:
|
|
277
277
|
rows = []
|
|
278
|
-
for val, bit, key in zip(value_text, bit_text, flag_dict):
|
|
278
|
+
for val, bit, key in zip(value_text, bit_text, flag_dict, strict=False):
|
|
279
279
|
rows.append(
|
|
280
280
|
f"{TAB}{_format_cf_name(key, rich):>{key_width}}: {TAB} {val} {bit}"
|
|
281
281
|
)
|
|
@@ -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.
|
|
@@ -324,7 +328,7 @@ def encode_geometries(ds: xr.Dataset):
|
|
|
324
328
|
# TODO: this is incomplete. It works for vector data cubes where one of the geometry vars
|
|
325
329
|
# is a dimension coordinate.
|
|
326
330
|
if name in var.dims:
|
|
327
|
-
var = var.copy()
|
|
331
|
+
var = var.copy(deep=False)
|
|
328
332
|
var._attrs = copy.deepcopy(var._attrs)
|
|
329
333
|
var.attrs["geometry"] = container_name
|
|
330
334
|
# The grid_mapping and coordinates attributes can be carried by the geometry container
|
|
@@ -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(
|
|
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
|
|