Repository: numpy/numpy
File: numpy/lib/_function_base_impl.py (Python)

Code before:
    if interpolation is not None:
        method = _check_interpolation_as_method(
            method, interpolation, "quantile")

    a = np.asanyarray(a)
    if a.dtype.kind == "c":
        raise TypeError("a must be an array of real numbers")

    # Use dtype of array if possible (e.g., if q is a python int or float).
    if isinstance(q, (int, float)) and a.dtype.kind == "f":
        q = np.asanyarray(q, dtype=a.dtype)
    else:
        q = np.asanyarray(q)

    if not _quantile_is_valid(q):
        raise ValueError("Quantiles must be in the range [0, 1]")

    if weights is not None:
        if method != "inverted_cdf":
            msg = ("Only method 'inverted_cdf' supports weights. "
                   f"Got: {method}.")
            raise ValueError(msg)
        if axis is not None:
            axis = _nx.normalize_axis_tuple(axis, a.ndim, argname="axis")
        weights = _weights_are_valid(weights=weights, a=a, axis=axis)
        if weights.dtype != object:
            if np.any(np.isinf(weights)):
                raise ValueError("Weights must be finite.")
            elif np.any(np.isnan(weights)):
                raise ValueError("At least one weight is nan.")
        # Since np.isinf and np.isnan do not work in dtype object arrays
        # Also, dtpye object arrays with np.nan in them break <, > and == opperators
        # This specific handling had to be done (Can be improved)   
        elif weights.dtype == object:
            for w in weights: 
                if np.isnan(w):
                    raise ValueError("At least one weight is nan.")
                if np.isinf(w):
                    raise ValueError("Weights must be finite.")
                
        if np.any(weights < 0):
            raise ValueError("Weights must be non-negative.")
        elif np.all(weights == 0):
            raise ValueError("At least one weight must be non-zero.")
        

    return _quantile_unchecked(
        a, q, axis, out, overwrite_input, method, keepdims, weights)


def _quantile_unchecked(a,

Review comment (suggestion):
A general comment: I think these checks should happen inside `_weights_ar_valid` - this will ensure they are used for `percentile` as well.

Code after:
        for i in range(q.size):
            if not (0.0 <= q[i] <= 1.0):
                return False
    elif not (q.min() >= 0 and q.max() <= 1):
        return False
    return True


def _compute_virtual_index(n, quantiles, alpha: float, beta: float):
    """
    Compute the floating point indexes of an array for the linear
    interpolation of quantiles.
    n : array_like
        The sample sizes.
    quantiles : array_like
        The quantiles values.
    alpha : float
        A constant used to correct the index computed.
    beta : float
        A constant used to correct the index computed.

    alpha and beta values depend on the chosen method
    (see quantile documentation)

    Reference:
    Hyndman&Fan paper "Sample Quantiles in Statistical Packages",
    DOI: 10.1080/00031305.1996.10473566
    """
    return n * quantiles + (
            alpha + quantiles * (1 - alpha - beta)
    ) - 1


def _get_gamma(virtual_indexes, previous_indexes, method, dtype):
    """
    Compute gamma (a.k.a 'm' or 'weight') for the linear interpolation
    of quantiles.

    virtual_indexes : array_like
        The indexes where the percentile is supposed to be found in the sorted
        sample.
    previous_indexes : array_like
        The floor values of virtual_indexes.
    method : dict
        The interpolation method chosen, which may have a specific rule
        modifying gamma.

    gamma is usually the fractional part of virtual_indexes but can be modified
    by the interpolation method.
    """
    gamma = np.asanyarray(virtual_indexes - previous_indexes)