Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/benchmarks-last-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:

- name: "Get Previous tag"
id: previoustag
uses: WyriHaximus/github-action-get-previous-tag@61819f33034117e6c686e6a31dba995a85afc9de # v2.0.0
uses: WyriHaximus/github-action-get-previous-tag@83f26fea93bc7efcbca2eb5591f5eaaf66b8f206 # v2.1.0
# with:
# fallback: 1.0.0 # Optional fallback tag to use when no tag can be found

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/ci-additional.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ jobs:
pixi run -e ${{env.PIXI_ENV}} -- python -m mypy --install-types --non-interactive --cobertura-xml-report mypy_report

- name: Upload mypy coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
files: mypy_report/cobertura.xml
flags: mypy
Expand Down Expand Up @@ -185,7 +185,7 @@ jobs:
pixi run -e ${{env.PIXI_ENV}} -- python -m mypy --install-types --non-interactive --cobertura-xml-report mypy_report

- name: Upload mypy coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
files: mypy_report/cobertura.xml
flags: mypy-min
Expand Down Expand Up @@ -286,7 +286,7 @@ jobs:
pixi run -e ${{ matrix.pixi-env }} -- python -m pyright xarray/

- name: Upload pyright coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
files: pyright_report/cobertura.xml
flags: pyright
Expand Down Expand Up @@ -348,4 +348,4 @@ jobs:
persist-credentials: false

- name: Run zizmor
uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3
uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
22 changes: 18 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -155,22 +155,36 @@ jobs:
run: |
pixi run -e ${{ matrix.pixi-env }} -- python -c "import xarray"

# caches are immutable, so use a unique key per job and restore the latest cache
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache
- name: Restore cached hypothesis directory
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .hypothesis/
key: cache-hypothesis
key: cache-hypothesis-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }}-${{ strategy.job-index }}
restore-keys: |
cache-hypothesis-${{ runner.os }}-
cache-hypothesis-
enableCrossOsArchive: true
save-always: true

- name: Run tests
id: tests
run: |
pixi run -e ${{ matrix.pixi-env }} -- python -m pytest -n ${{ matrix.numprocesses || 4 }} \
--timeout 180 \
--cov=xarray \
--cov-report=xml \
--junitxml=pytest.xml

# explicitly save the cache so it gets updated, also do this even if the tests fail
- name: Save cached hypothesis directory
if: always() && steps.tests.outcome != 'skipped'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .hypothesis/
key: cache-hypothesis-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }}-${{ strategy.job-index }}
enableCrossOsArchive: true

- name: Upload test results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand All @@ -179,7 +193,7 @@ jobs:
path: pytest.xml

- name: Upload code coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nightly-wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:

- name: Upload wheel
id: upload
uses: scientific-python/upload-nightly-action@e76cfec8a4611fd02808a801b0ff5a7d7c1b2d99 # 0.6.4
uses: scientific-python/upload-nightly-action@16fa02eacee1655195143de09f03676e60ef2bf5 # 0.6.5
with:
anaconda_nightly_upload_token: ${{ secrets.ANACONDA_NIGHTLY }}
artifacts_path: dist
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/upstream-dev-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ jobs:
run: |
pixi run --manifest-path "$MANIFEST_PATH" -e $ENV -- python -m mypy --install-types --non-interactive --cobertura-xml-report mypy_report
- name: Upload mypy coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
files: mypy_report/cobertura.xml
flags: mypy
Expand Down
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ repos:
- id: rst-inline-touching-normal
- id: text-unicode-replacement-char
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.20
rev: v0.16.6
hooks:
- id: ruff-check
args: ["--fix", "--show-fixes"]
Expand All @@ -37,12 +37,12 @@ repos:
# make sure this is the most recent version of black
additional_dependencies: ["black==25.11.0"]
- repo: https://github.com/rbubley/mirrors-prettier
rev: v3.9.4
rev: v3.9.6
hooks:
- id: prettier
args: ["--cache-location=.prettier_cache/cache"]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v2.1.0
rev: v2.3.1
hooks:
- id: mypy
# Copied from setup.cfg
Expand Down Expand Up @@ -71,16 +71,16 @@ repos:
- id: taplo-lint
args: ["--no-schema"]
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.25
rev: "0.26"
hooks:
- id: validate-pyproject
additional_dependencies: ["validate-pyproject-schema-store[all]"]
- repo: https://github.com/adhtruong/mirrors-typos
rev: v1.48.0
rev: v1.50.1
hooks:
- id: typos
- repo: https://github.com/zizmorcore/zizmor-pre-commit
rev: v1.26.1
rev: v1.30.0
hooks:
- id: zizmor
args: ["--offline"]
Empty file modified ci/numpydoc-public-api.py
100644 → 100755
Empty file.
Empty file modified ci/recipe/prepare_recipe.py
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion ci/requirements/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ dependencies:
- nc-time-axis
- netcdf4
- numba
- numbagg
- numbagg!=0.9.5
- numexpr
- numpy>=2.2
- opt_einsum
Expand Down
12 changes: 12 additions & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,18 @@
# mermaid config
mermaid_version = "11.6.0"

# sphinx-llm config
# the markdown builder used for llms.txt can't render these nodes; they are omitted
# from the generated markdown, so don't turn the warnings into build errors
llms_txt_suppress_unknown_node_warnings = [
"abbreviation",
"classifier",
"desc_optional",
"label",
"mermaid",
"PassthroughTextElement",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates", sphinx_autosummary_accessors.templates_path]

Expand Down
8 changes: 4 additions & 4 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ aiobotocore = "*"

[feature.numba.dependencies]
numba = "*"
numbagg = "*"
numbagg = "!=0.9.5" # 0.9.5 rejects list axes passed by dask.array.nanmedian

[feature.dask.dependencies]
dask = "*"
Expand Down Expand Up @@ -181,11 +181,11 @@ python = "3.12.*"
kerchunk = "*"
ipykernel = "*"
ipywidgets = "*" # silence nbsphinx warning
iris = "!=3.16.0" # avoid ncdata failing. See https://github.com/SciTools/ncdata/issues/255
iris = "*"
ipython = "*"
jupyter_client = "*"
jupyter_sphinx = "*"
ncdata = "*"
ncdata = ">=0.4" # support for iris>=3.16. See https://github.com/SciTools/ncdata/issues/255
pydata-sphinx-theme = "*"
pyproj = "*"
rich = "*" # for Zarr tree()
Expand All @@ -194,7 +194,7 @@ sphinx-autosummary-accessors = "*"
sphinx-copybutton = "*"
sphinx-design = "*"
sphinx-inline-tabs = "*"
sphinx-llm = ">=0.2.1"
sphinx-llm = ">=1.1" # for llms_txt_suppress_unknown_node_warnings
sphinx = ">=8,<9"
sphinxcontrib-mermaid = "*"
sphinxcontrib-srclinks = "*"
Expand Down
19 changes: 17 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ dependencies = ["numpy>=1.26", "packaging>=24.2", "pandas>=2.2"]
accel = [
"scipy>=1.15",
"bottleneck",
"numbagg>=0.9",
"numba>=0.62", # numba 0.62 added support for numpy 2.3
"numbagg>=0.9,!=0.9.5", # 0.9.5 breaks dask.array.nanmedian
"numba>=0.62", # numba 0.62 added support for numpy 2.3
"flox>=0.10",
"opt_einsum",
]
Expand Down Expand Up @@ -172,6 +172,14 @@ module = [
"array_api_strict.*",
]

# pint>=0.26's annotations send mypy into infinite recursion (segfault / RecursionError)
# when optype is installed, so don't analyse pint at all.
# Fixed upstream in https://github.com/python/mypy/pull/22036; remove this override
# once we require mypy > 2.3.1.
[[tool.mypy.overrides]]
follow_imports = "skip"
module = ["pint.*"]

# Gradually we want to add more modules to this list, ratcheting up our total
# coverage. Once a module is here, functions are checked by mypy regardless of
# whether they have type annotations. It would be especially useful to have test
Expand Down Expand Up @@ -290,6 +298,13 @@ ignore = [
"RUF003", # comment contains ambiguous no-break space unicode character
"RUF005", # consider unpacking operator instead of concatenation
"RUF012", # mutable class attributes
# rules added to the default set in ruff 0.16
"BLE001", # blind `except Exception`: used on purpose, e.g. in print_versions
"DTZ001", # `datetime()` without `tzinfo`: xarray works with naive datetimes
"N999", # invalid module name: `netCDF4_`
"S110", # `try`-`except`-`pass`
"TRY002", # raising vanilla `Exception`
"TRY004", # prefer `TypeError`: switching would change the raised exceptions
]

[tool.ruff.lint.per-file-ignores]
Expand Down
2 changes: 1 addition & 1 deletion xarray/backends/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,7 @@ def open_mfdataset(
preprocess: Callable[[Dataset], Dataset] | None = None,
engine: T_Engine = None,
data_vars: (
Literal["all", "minimal", "different"] | None | list[str] | CombineKwargDefault
Literal["all", "minimal", "different"] | list[str] | CombineKwargDefault | None
) = _DATA_VARS_DEFAULT,
coords=_COORDS_DEFAULT,
combine: Literal["by_coords", "nested"] = "by_coords",
Expand Down
6 changes: 3 additions & 3 deletions xarray/backends/file_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def __init__(
*args: Any,
mode: Any = _OMIT_MODE,
kwargs: Mapping[str, Any] | None = None,
lock: Lock | None | Literal[False] = None,
lock: Lock | Literal[False] | None = None,
cache: MutableMapping[Any, T_File] | None = None,
manager_id: Hashable | None = None,
ref_counts: dict[Any, int] | None = None,
Expand Down Expand Up @@ -355,7 +355,7 @@ def __init__(
opener: Callable[..., T_File],
*args: Any,
mode: Any = _OMIT_MODE,
lock: Lock | None | Literal[False] = None,
lock: Lock | Literal[False] | None = None,
kwargs: Mapping[str, Any] | None = None,
):
kwargs = {} if kwargs is None else dict(kwargs)
Expand Down Expand Up @@ -458,7 +458,7 @@ def __init__(
value: T_File,
*,
close: Callable[[], None] | None = None,
lock: Lock | None | Literal[False] = None,
lock: Lock | Literal[False] | None = None,
):
if close is None:
close = value.close
Expand Down
2 changes: 1 addition & 1 deletion xarray/backends/locks.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ def combine_locks(locks: Sequence[Lock]) -> Lock:
return DummyLock()


def ensure_lock(lock: Lock | None | Literal[False]) -> Lock:
def ensure_lock(lock: Lock | Literal[False] | None) -> Lock:
"""Ensure that the given object is a lock."""
if lock is None or lock is False:
return DummyLock()
Expand Down
4 changes: 0 additions & 4 deletions xarray/backends/store.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

from collections.abc import Iterable
from typing import TYPE_CHECKING

from xarray import conventions
from xarray.backends.common import (
Expand All @@ -13,9 +12,6 @@
from xarray.core.coordinates import Coordinates
from xarray.core.dataset import Dataset

if TYPE_CHECKING:
pass


class StoreBackendEntrypoint(BackendEntrypoint):
description = "Open AbstractDataStore instances in Xarray"
Expand Down
8 changes: 6 additions & 2 deletions xarray/backends/writers.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,11 @@ def to_netcdf(
auto_complex=auto_complex,
)
if group is not None:
store = store.get_child_store(group)
try:
store = store.get_child_store(group)
except Exception:
store.close()
raise

writer = ArrayWriter()

Expand Down Expand Up @@ -801,7 +805,7 @@ def _datatree_to_netcdf(
compute: bool = True,
invalid_netcdf: bool = False,
auto_complex: bool | None = None,
) -> None | memoryview | Delayed:
) -> memoryview | Delayed | None:
"""Implementation of `DataTree.to_netcdf`."""

if format not in [None, *get_args(T_DataTreeNetcdfTypes)]:
Expand Down
2 changes: 1 addition & 1 deletion xarray/coding/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def encode(self, variable: Variable, name=None) -> Variable:
# which all backends support natively (GH11199)
if data.dtype.kind == "T":
data = np.asarray(data, dtype=object)
data[data == None] = "" # noqa: E711
data[data == None] = ""
data = np.asarray(data, dtype="U")
variable = Variable(dims, data, attrs, encoding)

Expand Down
2 changes: 1 addition & 1 deletion xarray/coding/times.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ def _encode_datetime_with_cftime(dates, units: str, calendar: str) -> np.ndarray
dates = np.atleast_1d(dates)

# Find all the None position
none_position = dates == None # noqa: E711
none_position = dates == None
filtered_dates = dates[~none_position]

# Since netCDF files do not support storing float128 values, we ensure
Expand Down
4 changes: 2 additions & 2 deletions xarray/core/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -3677,13 +3677,13 @@ def interpolate_na(
limit: int | None = None,
use_coordinate: bool | str = True,
max_gap: (
None
| int
int
| float
| str
| pd.Timedelta
| np.timedelta64
| datetime.timedelta
| None
) = None,
keep_attrs: bool | None = None,
**kwargs: Any,
Expand Down
2 changes: 1 addition & 1 deletion xarray/core/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1491,7 +1491,7 @@ def __setitem__(
f" been successfully updated:\n{processed}"
) from e
else:
raise e
raise

elif utils.hashable(key):
if isinstance(value, Dataset):
Expand Down
4 changes: 2 additions & 2 deletions xarray/core/datatree.py
Original file line number Diff line number Diff line change
Expand Up @@ -1811,7 +1811,7 @@ def map_over_datasets(

def map_over_datasets(
self,
func: Callable[..., Dataset | None | tuple[Dataset | None, ...]],
func: Callable[..., Dataset | tuple[Dataset | None, ...] | None],
*args: Any,
kwargs: Mapping[str, Any] | None = None,
) -> DataTree | tuple[DataTree, ...]:
Expand Down Expand Up @@ -2034,7 +2034,7 @@ def to_netcdf(
write_inherited_coords: bool = False,
compute: bool = True,
**kwargs,
) -> None | memoryview | Delayed:
) -> memoryview | Delayed | None:
"""
Write datatree contents to a netCDF file.

Expand Down
Loading
Loading