Skip to content

Move Xarray custom exceptions into a new xarray.errors module #10285

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
14 changes: 7 additions & 7 deletions doc/api.rst
Original file line number Diff line number Diff line change
@@ -1644,10 +1644,10 @@ Exceptions
.. autosummary::
:toctree: generated/

AlignmentError
CoordinateValidationError
MergeError
SerializationWarning
errors.AlignmentError
errors.CoordinateValidationError
errors.MergeError
errors.SerializationWarning

DataTree
--------
@@ -1657,9 +1657,9 @@ Exceptions raised when manipulating trees.
.. autosummary::
:toctree: generated/

TreeIsomorphismError
InvalidTreeError
NotFoundInTreeError
errors.TreeIsomorphismError
errors.InvalidTreeError
errors.NotFoundInTreeError

Advanced API
============
2 changes: 1 addition & 1 deletion doc/user-guide/combining.rst
Original file line number Diff line number Diff line change
@@ -99,7 +99,7 @@ coordinates:
other = xr.Dataset({"bar": ("x", [1, 2, 3, 4]), "x": list("abcd")})
xr.merge([ds, other])

This ensures that ``merge`` is non-destructive. ``xarray.MergeError`` is raised
This ensures that ``merge`` is non-destructive. ``xarray.errors.MergeError`` is raised
if you attempt to merge two variables with the same name but different values:

.. ipython::
2 changes: 1 addition & 1 deletion doc/user-guide/data-structures.rst
Original file line number Diff line number Diff line change
@@ -610,7 +610,7 @@ We have created a tree with three nodes in it:

Consistency checks are enforced. For instance, if we try to create a cycle,
where the root node is also a child of a descendant, the constructor will raise
an (:py:class:`~xarray.InvalidTreeError`):
an (:py:class:`~xarray.errors.InvalidTreeError`):

.. ipython:: python
:okexcept:
4 changes: 2 additions & 2 deletions doc/user-guide/hierarchical-data.rst
Original file line number Diff line number Diff line change
@@ -143,7 +143,7 @@ We can add Herbert to the family tree without displacing Homer by :py:meth:`~xar

Certain manipulations of our tree are forbidden, if they would create an inconsistent result.
In episode 51 of the show Futurama, Philip J. Fry travels back in time and accidentally becomes his own Grandfather.
If we try similar time-travelling hijinks with Homer, we get a :py:class:`~xarray.InvalidTreeError` raised:
If we try similar time-travelling hijinks with Homer, we get a :py:class:`~xarray.errors.InvalidTreeError` raised:

.. ipython:: python
:okexcept:
@@ -621,7 +621,7 @@ each tree needs to have the same structure. Specifically two trees can only be c
or "isomorphic", if the full paths to all of their descendent nodes are the same.

Applying :py:func:`~xarray.group_subtrees` to trees with different structures
raises :py:class:`~xarray.TreeIsomorphismError`:
raises :py:class:`~xarray.errors.TreeIsomorphismError`:

.. ipython:: python
:okexcept:
23 changes: 15 additions & 8 deletions xarray/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from importlib.metadata import version as _version

from xarray import coders, groupers, testing, tutorial, ufuncs
from xarray import coders, errors, groupers, testing, tutorial, ufuncs
from xarray.backends.api import (
load_dataarray,
load_dataset,
@@ -26,9 +26,9 @@
polyval,
where,
)
from xarray.conventions import SerializationWarning, decode_cf
from xarray.conventions import decode_cf
from xarray.core.common import ALL_DIMS, full_like, ones_like, zeros_like
from xarray.core.coordinates import Coordinates, CoordinateValidationError
from xarray.core.coordinates import Coordinates
from xarray.core.dataarray import DataArray
from xarray.core.dataset import Dataset
from xarray.core.datatree import DataTree
@@ -42,19 +42,25 @@
from xarray.core.indexing import IndexSelResult
from xarray.core.options import get_options, set_options
from xarray.core.parallel import map_blocks
from xarray.core.treenode import (
from xarray.core.treenode import group_subtrees
from xarray.core.variable import IndexVariable, Variable, as_variable

# import custom error classes in root namespace for backward compatibility
from xarray.errors import (
AlignmentError,
CoordinateValidationError,
InvalidTreeError,
MergeError,
NotFoundInTreeError,
SerializationWarning,
TreeIsomorphismError,
group_subtrees,
)
from xarray.core.variable import IndexVariable, Variable, as_variable
from xarray.namedarray.core import NamedArray
from xarray.structure.alignment import AlignmentError, align, broadcast
from xarray.structure.alignment import align, broadcast
from xarray.structure.chunks import unify_chunks
from xarray.structure.combine import combine_by_coords, combine_nested
from xarray.structure.concat import concat
from xarray.structure.merge import Context, MergeError, merge
from xarray.structure.merge import Context, merge
from xarray.util.print_versions import show_versions

try:
@@ -69,6 +75,7 @@
__all__ = ( # noqa: RUF022
# Sub-packages
"coders",
"errors",
"groupers",
"testing",
"tutorial",
2 changes: 1 addition & 1 deletion xarray/backends/common.py
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@
import pandas as pd

from xarray.coding import strings, variables
from xarray.coding.variables import SerializationWarning
from xarray.conventions import cf_encoder
from xarray.core import indexing
from xarray.core.datatree import DataTree, Variable
@@ -24,6 +23,7 @@
emit_user_level_warning,
is_remote_uri,
)
from xarray.errors import SerializationWarning
from xarray.namedarray.parallelcompat import get_chunked_array_type
from xarray.namedarray.pycompat import is_chunked_array
from xarray.namedarray.utils import is_duck_dask_array
4 changes: 0 additions & 4 deletions xarray/coding/common.py
Original file line number Diff line number Diff line change
@@ -15,10 +15,6 @@
T_Name = Union[Hashable, None]


class SerializationWarning(RuntimeWarning):
"""Warnings about encoding/decoding issues in serialization."""


class VariableCoder:
"""Base class for encoding and decoding transformations on variables.

2 changes: 1 addition & 1 deletion xarray/coding/times.py
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@
from pandas.errors import OutOfBoundsDatetime, OutOfBoundsTimedelta

from xarray.coding.common import (
SerializationWarning,
VariableCoder,
lazy_elemwise_func,
pop_to,
@@ -27,6 +26,7 @@
from xarray.core.formatting import first_n_items, format_timestamp, last_item
from xarray.core.utils import attempt_import, emit_user_level_warning
from xarray.core.variable import Variable
from xarray.errors import SerializationWarning
from xarray.namedarray.parallelcompat import T_ChunkedArray, get_chunked_array_type
from xarray.namedarray.pycompat import is_chunked_array, to_numpy
from xarray.namedarray.utils import is_duck_dask_array
2 changes: 1 addition & 1 deletion xarray/coding/variables.py
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@
import pandas as pd

from xarray.coding.common import (
SerializationWarning,
VariableCoder,
lazy_elemwise_func,
pop_to,
@@ -22,6 +21,7 @@
from xarray.coding.times import CFDatetimeCoder, CFTimedeltaCoder
from xarray.core import dtypes, duck_array_ops, indexing
from xarray.core.variable import Variable
from xarray.errors import SerializationWarning

if TYPE_CHECKING:
T_VarTuple = tuple[tuple[Hashable, ...], Any, dict, dict]
@@ -234,7 +234,7 @@
# otherwise numpy unsigned ints will silently cast to the signed counterpart
fill_value = fill_value.item()
# passes if provided fill value fits in encoded on-disk type
new_fill = encoded_dtype.type(fill_value)

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).

Check warning on line 237 in xarray/coding/variables.py

GitHub Actions / ubuntu-latest py3.10 min-all-deps

NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays. The conversion of 255 to int8 will fail in the future. For the old behavior, usually: np.array(value).astype(dtype)` will give the desired result (the cast overflows).
except OverflowError:
encoded_kind_str = "signed" if encoded_dtype.kind == "i" else "unsigned"
warnings.warn(
3 changes: 2 additions & 1 deletion xarray/conventions.py
Original file line number Diff line number Diff line change
@@ -10,14 +10,15 @@

from xarray.coders import CFDatetimeCoder, CFTimedeltaCoder
from xarray.coding import strings, variables
from xarray.coding.variables import SerializationWarning, pop_to
from xarray.coding.variables import pop_to
from xarray.core import indexing
from xarray.core.common import (
_contains_datetime_like_objects,
contains_cftime_datetimes,
)
from xarray.core.utils import emit_user_level_warning
from xarray.core.variable import IndexVariable, Variable
from xarray.errors import SerializationWarning
from xarray.namedarray.utils import is_duck_dask_array

CF_RELATED_DATA = (
5 changes: 1 addition & 4 deletions xarray/core/coordinates.py
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@
emit_user_level_warning,
)
from xarray.core.variable import Variable, as_variable, calculate_dimensions
from xarray.errors import CoordinateValidationError
from xarray.structure.alignment import Aligner
from xarray.structure.merge import merge_coordinates_without_align, merge_coords

@@ -1146,10 +1147,6 @@ def create_coords_with_default_indexes(
return new_coords


class CoordinateValidationError(ValueError):
"""Error class for Xarray coordinate validation failures."""


def validate_dataarray_coords(
shape: tuple[int, ...],
coords: Coordinates | Mapping[Hashable, Variable],
3 changes: 2 additions & 1 deletion xarray/core/dataarray.py
Original file line number Diff line number Diff line change
@@ -72,6 +72,7 @@
as_compatible_data,
as_variable,
)
from xarray.errors import MergeError
from xarray.plot.accessor import DataArrayPlotAccessor
from xarray.plot.utils import _get_units_from_attrs
from xarray.structure import alignment
@@ -81,7 +82,7 @@
align,
)
from xarray.structure.chunks import unify_chunks
from xarray.structure.merge import PANDAS_TYPES, MergeError
from xarray.structure.merge import PANDAS_TYPES
from xarray.util.deprecation_helpers import _deprecate_positional_args, deprecate_dims

if TYPE_CHECKING:
4 changes: 2 additions & 2 deletions xarray/core/indexes.py
Original file line number Diff line number Diff line change
@@ -220,8 +220,8 @@ def should_add_coord_to_array(

Returning ``False`` will either:

- raise a :py:class:`CoordinateValidationError` when passing the
coordinate directly to a new or an existing DataArray, e.g., via
- raise a :py:class:`~xarray.errors.CoordinateValidationError` when passing
the coordinate directly to a new or an existing DataArray, e.g., via
``DataArray.__init__()`` or ``DataArray.assign_coords()``

- drop the coordinate (and therefore drop the index) when a new
13 changes: 1 addition & 12 deletions xarray/core/treenode.py
Original file line number Diff line number Diff line change
@@ -13,19 +13,12 @@

from xarray.core.types import Self
from xarray.core.utils import Frozen, is_dict_like
from xarray.errors import InvalidTreeError, NotFoundInTreeError, TreeIsomorphismError

if TYPE_CHECKING:
from xarray.core.types import T_DataArray


class InvalidTreeError(Exception):
"""Raised when user attempts to create an invalid tree in some way."""


class NotFoundInTreeError(ValueError):
"""Raised when operation can't be completed because one node is not part of the expected tree."""


class NodePath(PurePosixPath):
"""Represents a path from one node to another within a tree."""

@@ -799,10 +792,6 @@ def _path_to_ancestor(self, ancestor: NamedNode) -> NodePath:
return NodePath(path_upwards)


class TreeIsomorphismError(ValueError):
"""Error raised if two tree objects do not share the same node structure."""


def group_subtrees(
*trees: AnyNamedNode,
) -> Iterator[tuple[str, tuple[AnyNamedNode, ...]]]:
41 changes: 41 additions & 0 deletions xarray/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
This module exposes Xarray's custom exceptions & warnings.
"""


class AlignmentError(ValueError):
"""Error class for alignment failures due to incompatible arguments."""


class CoordinateValidationError(ValueError):
"""Error class for Xarray coordinate validation failures."""


class MergeError(ValueError):
"""Error class for merge failures due to incompatible arguments."""


class InvalidTreeError(Exception):
"""Raised when user attempts to create an invalid tree in some way."""


class NotFoundInTreeError(ValueError):
"""Raised when operation can't be completed because one node is not part of the expected tree."""


class TreeIsomorphismError(ValueError):
"""Error raised if two tree objects do not share the same node structure."""


class SerializationWarning(RuntimeWarning):
"""Warnings about encoding/decoding issues in serialization."""


__all__ = [
"AlignmentError",
"CoordinateValidationError",
"InvalidTreeError",
"MergeError",
"SerializationWarning",
"TreeIsomorphismError",
]
7 changes: 2 additions & 5 deletions xarray/structure/alignment.py
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
from xarray.core.types import T_Alignable
from xarray.core.utils import is_dict_like, is_full_slice
from xarray.core.variable import Variable, as_compatible_data, calculate_dimensions
from xarray.errors import AlignmentError

if TYPE_CHECKING:
from xarray.core.dataarray import DataArray
@@ -35,10 +36,6 @@
)


class AlignmentError(ValueError):
"""Error class for alignment failures due to incompatible arguments."""


def reindex_variables(
variables: Mapping[Any, Variable],
dim_pos_indexers: Mapping[Any, Any],
@@ -837,7 +834,7 @@ def align(
>>> a, b = xr.align(x, y, join="exact")
Traceback (most recent call last):
...
xarray.structure.alignment.AlignmentError: cannot align objects with join='exact' ...
xarray.errors.AlignmentError: cannot align objects with join='exact' ...

>>> a, b = xr.align(x, y, join="override")
>>> a
10 changes: 2 additions & 8 deletions xarray/structure/merge.py
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
)
from xarray.core.utils import Frozen, compat_dict_union, dict_equiv, equivalent
from xarray.core.variable import Variable, as_variable, calculate_dimensions
from xarray.errors import MergeError
from xarray.structure.alignment import deep_align

if TYPE_CHECKING:
@@ -78,13 +79,6 @@ def broadcast_dimension_size(variables: list[Variable]) -> dict[Hashable, int]:
return dims


class MergeError(ValueError):
"""Error class for merge failures due to incompatible arguments."""

# inherits from ValueError for backward compatibility
# TODO: move this to an xarray.exceptions module?


def unique_variable(
name: Hashable,
variables: list[Variable],
@@ -942,7 +936,7 @@ def merge(
>>> xr.merge([x, y, z], join="exact")
Traceback (most recent call last):
...
xarray.structure.alignment.AlignmentError: cannot align objects with join='exact' where ...
xarray.errors.AlignmentError: cannot align objects with join='exact' where ...

Raises
------
Loading
Oops, something went wrong.
Loading
Oops, something went wrong.