Source code for vocalpy.validators.validators

"""Validation functions."""

from __future__ import annotations

import numpy as np
import numpy.typing as npt

__all__ = ["have_same_dtype", "is_1d_ndarray", "is_valid_boundaries_array"]


[docs] def is_1d_ndarray(y: npt.NDArray, name: str | None = None) -> bool: """Validates that ``y`` is a 1-dimensional :class:`numpy.ndarray`. Parameters ---------- y: numpy.ndarray Array to be validated. name: str, optional Name of array in calling function. Used in any error message if supplied. Returns ------- is_1d_ndarray: bool True if ``y`` is valid. Examples -------- >>> y = np.array([0, 1, 2]) >>> vocalpy.validators.is_1d_ndarray(y) True """ if name: name += " " else: name = "" if not isinstance(y, np.ndarray): raise TypeError( f"Input {name}should be a numpy array, but type was: {type(y)}" ) if not len(y.shape) == 1: raise ValueError( f"Input {name}should be a 1-dimensional numpy array, " f"but number of dimensions was: {y.ndim}" ) return True
[docs] def is_valid_boundaries_array(y: npt.NDArray, name: str | None = None) -> bool: """Validates that ``y`` is a valid array of boundaries found with a segmentation algorithm, e.g., onsets or offsets of segments returned by :func:`vocalpy.segment.meansquared`. To be a valid array of boundaries, ``y`` must meet the following conditions: - Be a one dimensional numpy array, as validated with :func:`vocalpy.validators.is_1d_ndarray`. - Have a dtype that is a float or int, e.g. ``np.float64`` or ``np.int32``. - Have values that are all non-negative, i.e. ``np.all(y >= 0.0)`` - Have values that are strictly increasing, i.e. ``np.all(y[1:] > y[:-1])`` An empty array or an array with a single value are also considered valid, as long as the dtype is correct and any value is non-negative. Parameters ---------- y: numpy.ndarray Array to be validated. name: str, optional Name of array in calling function. Used in any error message if supplied. Returns ------- is_valid_boundaries_array: bool True if ``y`` is valid. Examples -------- >>> vocalpy.validators.is_valid_boundaries_array(np.array([1, 2, 3], dtype=np.int16)) True >>> vocalpy.validators.is_valid_boundaries_array(np.array([1.0, 2.0, 3.0], dtype=np.float32)) True >>> vocalpy.validators.is_valid_boundaries_array(np.array([], dtype=np.float32)) True >>> vocalpy.validators.is_valid_boundaries_array(np.array([1.0], dtype=np.float32)) True """ is_1d_ndarray(y, name) if name: name += " " else: name = "" if not ( issubclass(y.dtype.type, np.floating) or issubclass(y.dtype.type, np.integer) ): raise TypeError( f"Dtype of boundaries array {name}must be either float or int but was: {y.dtype}" ) if not np.all(y >= 0.0): raise ValueError( f"Values of boundaries array {name}must all be non-negative" ) if y.size <= 1: # It's a valid boundary array but there's no boundaries or just one boundary, # so we don't check that values are strictly increasing return True if not np.all(y[1:] > y[:-1]): raise ValueError( f"Values of boundaries array {name}must be strictly increasing" ) return True
[docs] def have_same_dtype( arr1: npt.NDArray, arr2: npt.NDArray, name1: str | None = None, name2: str | None = None, ) -> bool: """Validates that two arrays, ``arr1`` and ``arr2``, have the same :class:`~numpy.dtype`. Parameters ---------- arr1 : numpy.ndarray First array to be validated. arr2 : numpy.ndarray Second array to be validated. name1 : str, optional Name of first array in calling function. Used in any error message if both ``name1`` and ``name2`` are supplied. name2 : str, optional Name of second array in calling function. Used in any error message if both ``name1`` and ``name2`` are supplied. Returns ------- have_same_dtype : bool True if ``arr1`` and ``arr2`` have the same :class:`~numpy.dtype`. """ if not arr1.dtype == arr2.dtype: if name1 and name2: names = f"{name1} and {name2} " else: names = "" raise ValueError( f"Two arrays {names}must have the same dtype, but dtypes were: {arr1.dtype} and {arr2.dtype}" ) return True