Skip to content
Open
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/cache-pixi-lock.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
with:
path: |
pixi.lock
key: ${{ steps.date.outputs.date }}_${{ inputs.pixi-version }}_${{hashFiles('pixi.toml')}}
key: ${{ steps.date.outputs.date }}_${{ inputs.pixi-version }}_${{hashFiles('pixi.toml', 'pyproject.toml')}}
- uses: prefix-dev/[email protected]
if: ${{ !steps.restore.outputs.cache-hit }}
with:
Expand Down
6 changes: 6 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ New Features
brings improved alignment between h5netcdf and libnetcdf4 in the storage of
complex numbers (:pull:`11068`). By `Mark Harfouche
<https://github.com/hmaarrfk>`_.
- Added typed properties for external accessor packages (hvplot, cf-xarray,
pint-xarray, rioxarray, xarray-plotly), enabling full IDE support including
autocompletion, parameter hints, and docstrings. For uninstalled packages,
``hasattr()`` returns ``False`` to keep the namespace clean (:pull:`11079`).
By `Your Name <https://github.com/FBumann>`_.

- :py:func:`set_options` now supports an ``arithmetic_compat`` option which determines how non-index coordinates
of the same name are compared for potential conflicts when performing binary operations. The default for it is
``arithmetic_compat='minimal'`` which matches the existing behaviour.
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ module = [
"bottleneck.*",
"cartopy.*",
"cf_units.*",
"cf_xarray.*",
"cfgrib.*",
"cftime.*",
"cloudpickle.*",
Expand All @@ -146,6 +147,7 @@ module = [
"fsspec.*",
"h5netcdf.*",
"h5py.*",
"hvplot.*",
"iris.*",
"mpl_toolkits.*",
"nc_time_axis.*",
Expand All @@ -154,14 +156,17 @@ module = [
"numcodecs.*",
"opt_einsum.*",
"pint.*",
"pint_xarray.*",
"pooch.*",
"pyarrow.*",
"pydap.*",
"rioxarray.*",
"scipy.*",
"seaborn.*",
"setuptools",
"sparse.*",
"toolz.*",
"xarray_plotly.*",
"zarr.*",
"numpy.exceptions.*", # remove once support for `numpy<2.0` has been dropped
"array_api_strict.*",
Expand Down
53 changes: 53 additions & 0 deletions xarray/accessors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""
External accessor support for xarray.

This module provides mixin classes with typed properties for external accessor
packages, enabling full IDE support (autocompletion, parameter hints, docstrings)
for packages like hvplot, cf-xarray, pint-xarray, rioxarray, and xarray-plotly.

Properties are defined statically for IDE support
"""

from __future__ import annotations

from typing import TYPE_CHECKING, ClassVar

if TYPE_CHECKING:
from cf_xarray.accessor import CFAccessor
from hvplot.xarray import hvPlotAccessor
from pint_xarray import PintDataArrayAccessor, PintDatasetAccessor
from rioxarray import RasterArray, RasterDataset
from xarray_plotly import DataArrayPlotlyAccessor, DatasetPlotlyAccessor
Comment on lines +15 to +20
Copy link
Member

@TomNicholas TomNicholas Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So do all of these unrelated packages now have to be installed in our CI (in the same environment too)? Plotly at least is new.

Copy link
Member Author

@jsignell jsignell Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the mypy environment

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually they don't need to be installed at all since they are only imported within the TYPE_CHECKING block. So we just need some explicit mypy ignores (which @FBumann had already figured out).

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsignell Pretty elegant solution with the MixIn. I like it!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the IDE completion/hints still work even if not all of these are installed?

Copy link

@FBumann FBumann Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DocOtak Yes they do. But they are deprioritized (at least in my IDE), saying they are not at the top of the list

Here with only xarray-plotly installed, I only see the plotly accessor.

image image

But after I type in .hv, also see that accessor with type hints.

Completion after the accessor name is only available for installed accessors:

image image

One more thing:
The data_vars overwrite the accessor. This is a good thing imo!
image

The existing .plot accessor behaves differently. It overwrites the data_var
image

This means with conflicting var_names and accessor names, the code behaviour is backwards compatible. Only conflict in type hints, not at Runtime.



class DataArrayExternalAccessorMixin:
"""Mixin providing typed external accessor properties for DataArray."""

__slots__ = ()

hvplot: ClassVar[type[hvPlotAccessor]]
cf: ClassVar[type[CFAccessor]]
pint: ClassVar[type[PintDataArrayAccessor]]
rio: ClassVar[type[RasterArray]]
plotly: ClassVar[type[DataArrayPlotlyAccessor]]


class DatasetExternalAccessorMixin:
"""Mixin providing typed external accessor properties for Dataset."""

__slots__ = ()

hvplot: ClassVar[type[hvPlotAccessor]]
cf: ClassVar[type[CFAccessor]]
pint: ClassVar[type[PintDatasetAccessor]]
rio: ClassVar[type[RasterDataset]]
plotly: ClassVar[type[DatasetPlotlyAccessor]]


class DataTreeExternalAccessorMixin:
"""Mixin providing typed external accessor properties for DataTree."""

__slots__ = ()

hvplot: ClassVar[type[hvPlotAccessor]]
cf: ClassVar[type[CFAccessor]]
2 changes: 2 additions & 0 deletions xarray/core/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import numpy as np
import pandas as pd

from xarray.accessors import DataArrayExternalAccessorMixin
from xarray.coding.calendar_ops import convert_calendar, interp_calendar
from xarray.coding.cftimeindex import CFTimeIndex
from xarray.computation import computation, ops
Expand Down Expand Up @@ -259,6 +260,7 @@ class DataArray(
DataWithCoords,
DataArrayArithmetic,
DataArrayAggregations,
DataArrayExternalAccessorMixin,
):
"""N-dimensional array with labeled coordinates and dimensions.

Expand Down
2 changes: 2 additions & 0 deletions xarray/core/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import numpy as np
import pandas as pd

from xarray.accessors import DatasetExternalAccessorMixin
from xarray.coding.calendar_ops import convert_calendar, interp_calendar
from xarray.coding.cftimeindex import CFTimeIndex, _parse_array_of_cftime_strings
from xarray.compat.array_api_compat import to_like_array
Expand Down Expand Up @@ -197,6 +198,7 @@ class Dataset(
DataWithCoords,
DatasetAggregations,
DatasetArithmetic,
DatasetExternalAccessorMixin,
Mapping[Hashable, "DataArray"],
):
"""A multi-dimensional, in memory, array database.
Expand Down
2 changes: 2 additions & 0 deletions xarray/core/datatree.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
overload,
)

from xarray.accessors import DataTreeExternalAccessorMixin
from xarray.core import utils
from xarray.core._aggregations import DataTreeAggregations
from xarray.core._typed_ops import DataTreeOpsMixin
Expand Down Expand Up @@ -464,6 +465,7 @@ class DataTree(
DataTreeAggregations,
DataTreeOpsMixin,
TreeAttrAccessMixin,
DataTreeExternalAccessorMixin,
Mapping[str, "DataArray | DataTree"],
):
"""
Expand Down
Loading