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
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
14 changes: 7 additions & 7 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1644,10 +1644,10 @@ Exceptions
.. autosummary::
:toctree: generated/

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

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

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

Advanced API
============
Expand Down
2 changes: 1 addition & 1 deletion doc/user-guide/combining.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down
2 changes: 1 addition & 1 deletion doc/user-guide/data-structures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions doc/user-guide/hierarchical-data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
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,
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -69,6 +75,7 @@
__all__ = ( # noqa: RUF022
# Sub-packages
"coders",
"errors",
"groupers",
"testing",
"tutorial",
Expand Down
2 changes: 1 addition & 1 deletion xarray/backends/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 0 additions & 4 deletions xarray/coding/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

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

from xarray.coding.common import (
SerializationWarning,
VariableCoder,
lazy_elemwise_func,
pop_to,
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion xarray/coding/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import pandas as pd

from xarray.coding.common import (
SerializationWarning,
VariableCoder,
lazy_elemwise_func,
pop_to,
Expand All @@ -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]
Expand Down Expand Up @@ -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

View workflow job for this annotation

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

View workflow job for this annotation

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

View workflow job for this annotation

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

View workflow job for this annotation

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

View workflow job for this annotation

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

View workflow job for this annotation

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

View workflow job for this annotation

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

View workflow job for this annotation

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

View workflow job for this annotation

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

View workflow job for this annotation

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(
Expand Down
3 changes: 2 additions & 1 deletion xarray/conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand Down
5 changes: 1 addition & 4 deletions xarray/core/coordinates.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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],
Expand Down
3 changes: 2 additions & 1 deletion xarray/core/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions xarray/core/indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 1 addition & 12 deletions xarray/core/treenode.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""

Expand Down Expand Up @@ -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, ...]]]:
Expand Down
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
Expand Up @@ -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
Expand All @@ -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],
Expand Down Expand Up @@ -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
Expand Down
10 changes: 2 additions & 8 deletions xarray/structure/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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
------
Expand Down
Loading
Loading