diff --git a/.github/workflows/cache-pixi-lock.yml b/.github/workflows/cache-pixi-lock.yml index e938a7664dd..da67294d62e 100644 --- a/.github/workflows/cache-pixi-lock.yml +++ b/.github/workflows/cache-pixi-lock.yml @@ -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/setup-pixi@v0.9.3 if: ${{ !steps.restore.outputs.cache-hit }} with: diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 6db22ef1071..95f6318bf25 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -27,6 +27,12 @@ New Features brings improved alignment between h5netcdf and libnetcdf4 in the storage of complex numbers (:pull:`11068`). By `Mark Harfouche `_. +- 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 `_. + - :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. diff --git a/pyproject.toml b/pyproject.toml index c8fd153dd52..917f202da1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -138,6 +138,7 @@ module = [ "bottleneck.*", "cartopy.*", "cf_units.*", + "cf_xarray.*", "cfgrib.*", "cftime.*", "cloudpickle.*", @@ -146,6 +147,7 @@ module = [ "fsspec.*", "h5netcdf.*", "h5py.*", + "hvplot.*", "iris.*", "mpl_toolkits.*", "nc_time_axis.*", @@ -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.*", diff --git a/xarray/accessors.py b/xarray/accessors.py new file mode 100644 index 00000000000..d87628b6b94 --- /dev/null +++ b/xarray/accessors.py @@ -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 + + +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]] diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index 706c35e5459..b4625efc43d 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -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 @@ -259,6 +260,7 @@ class DataArray( DataWithCoords, DataArrayArithmetic, DataArrayAggregations, + DataArrayExternalAccessorMixin, ): """N-dimensional array with labeled coordinates and dimensions. diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index e15f1077639..e1f01c2e1f0 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -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 @@ -197,6 +198,7 @@ class Dataset( DataWithCoords, DatasetAggregations, DatasetArithmetic, + DatasetExternalAccessorMixin, Mapping[Hashable, "DataArray"], ): """A multi-dimensional, in memory, array database. diff --git a/xarray/core/datatree.py b/xarray/core/datatree.py index e079332780c..d46fd236feb 100644 --- a/xarray/core/datatree.py +++ b/xarray/core/datatree.py @@ -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 @@ -464,6 +465,7 @@ class DataTree( DataTreeAggregations, DataTreeOpsMixin, TreeAttrAccessMixin, + DataTreeExternalAccessorMixin, Mapping[str, "DataArray | DataTree"], ): """