Source code for xarray_units.utils

__all__ = [
    "UnitsError",
    "UnitsConversionError",
    "UnitsExistError",
    "UnitsNotFoundError",
    "UnitsNotValidError",
    "unitsof",
]


# standard library
from typing import Any, Literal, Optional, TypeVar, Union, overload


# dependencies
from astropy.units import Quantity, Unit, UnitBase
from typing_extensions import ParamSpec
from xarray import DataArray


# type hints
P = ParamSpec("P")
TDataArray = TypeVar("TDataArray", bound=DataArray)
UnitsLike = Union[UnitBase, str]


# constants
TESTER = 1
UNITS = "units"


[docs] class UnitsError(Exception): """Base exception for handling units.""" pass
[docs] class UnitsConversionError(UnitsError): """Units conversion is not successful.""" pass
[docs] class UnitsExistError(UnitsError): """Units already exist in a DataArray.""" pass
[docs] class UnitsNotFoundError(UnitsError): """Units do not exist in a DataArray.""" pass
[docs] class UnitsNotValidError(UnitsError): """Units are not valid for a DataArray.""" pass
@overload def unitsof( obj: Any, /, *, format: None = None, strict: Literal[False] = False, **kwargs: Any, ) -> Optional[UnitBase]: ... @overload def unitsof( obj: Any, /, *, format: str, strict: Literal[False] = False, **kwargs: Any, ) -> Optional[str]: ... @overload def unitsof( obj: Any, /, *, format: None = None, strict: Literal[True] = True, **kwargs: Any, ) -> UnitBase: ... @overload def unitsof( obj: Any, /, *, format: str, strict: Literal[True] = True, **kwargs: Any, ) -> str: ...
[docs] def unitsof( obj: Any, /, *, format: Optional[str] = None, strict: bool = False, **kwargs: Any, ) -> Optional[UnitsLike]: """Return units of an object if they exist and are valid. Args: obj: Any object from which units are extracted. format: Format of units. If given, the return value will be ``string``. Otherwise, it will be ``UnitBase``. strict: Whether to allow ``None`` as the return value when units do not exist in the object. **kwargs: Keyword arguments of the formatting. Returns: Extracted units from the object. Raises: UnitsConversionError: Raised if ``format`` is given but units cannot be formatted to it. UnitsNotFoundError: Raised if ``strict`` is ``True`` but units do not exist in the object. UnitsNotValidError: Raised if units exist in the object but they cannot be converted to ``UnitBase``. """ if isinstance(obj, DataArray): units = obj.attrs.get(UNITS) elif isinstance(obj, Quantity): units = obj.unit else: units = None if units is None: if not strict: return None raise UnitsNotFoundError(repr(obj)) try: units = Unit(units) # type: ignore except Exception: raise UnitsNotValidError(repr(obj)) if not isinstance(units, UnitBase): raise UnitsNotValidError(repr(obj)) if format is None: return units try: return units.to_string(format, **kwargs) # type: ignore except ValueError as error: raise UnitsConversionError(error)