Repository: scikit-learn/scikit-learn
File: sklearn/utils/_array_api.py (Python)

Code before:
        return xp, True

    arrays = _remove_non_arrays(
        *arrays,
        remove_none=remove_none,
        remove_types=remove_types,
    )

    if not arrays:
        return np_compat, False

    _check_array_api_dispatch(array_api_dispatch)

    try:
        namespace = array_api_compat.get_namespace(*arrays)
        is_array_api_compliant = True
    except TypeError:
        # Since get_namespace can be used by helper functions that are called
        # in estimators or function that do not necessarily support array API
        # (yet), anything not supported by array_api_compat falls back to numpy
        # to preserve backward compatibility when enabling array_api_dispatch.
        # The most common such case are "_cyutility._memoryviewslice"
        # instances passed to array-api compatible helper functions from Cython
        # code.
        namespace = np_compat
        is_array_api_compliant = False

    if namespace.__name__ == "array_api_strict" and hasattr(
        namespace, "set_array_api_strict_flags"
    ):
        namespace.set_array_api_strict_flags(api_version="2024.12")

    return namespace, is_array_api_compliant


def get_namespace_and_device(
    *array_list, remove_none=True, remove_types=(str,), xp=None
):
    """Combination into one single function of `get_namespace` and `device`.

    Parameters
    ----------
    *array_list : array objects
        Array objects.
    remove_none : bool, default=True
        Whether to ignore None objects passed in arrays.
    remove_types : tuple or list, default=(str,)
        Types to ignore in the arrays.
    xp : module, default=None
        Precomputed array namespace module. When passed, typically from a caller
        that has already performed inspection of its own inputs, skips array

Review comment (refactor):
Note to reviewers: I considered adding `_cyutility._memoryviewslice` to the list of `removed_types` but since it's a private internal detail of Cython, I thought it would be too brittle and went for a more direct handling of unexpected types in `get_namespace` inputs.

Code after:

    remove_types : tuple or list, default=(str, list, tuple)
        Types to ignore in the arrays.

    xp : module, default=None
        Precomputed array namespace module. When passed, typically from a caller
        that has already performed inspection of its own inputs, skips array
        namespace inspection.

    Returns
    -------
    namespace : module
        Namespace shared by array objects. If any of the `arrays` are not arrays,
        the namespace defaults to the NumPy namespace.

    is_array_api_compliant : bool
        True if the arrays are containers that implement the array API spec (see
        https://data-apis.org/array-api/latest/index.html).
        Always False when array_api_dispatch=False.
    """
    array_api_dispatch = get_config()["array_api_dispatch"]
    if not array_api_dispatch:
        if xp is not None:
            return xp, False
        else:
            return np_compat, False

    if xp is not None:
        return xp, True

    arrays = _remove_non_arrays(
        *arrays,
        remove_none=remove_none,
        remove_types=remove_types,
    )

    # get_namespace can be called by helper functions that are used both in
    # array API compatible code and non-array API Cython related code. To
    # support the latter on NumPy inputs without raising a TypeError, we
    # unwrap potential Cython memoryview slices here.
    arrays = _unwrap_memoryviewslices(*arrays)

    if not arrays:
        return np_compat, False

    _check_array_api_dispatch(array_api_dispatch)

    namespace = array_api_compat.get_namespace(*arrays)
    is_array_api_compliant = True

    if namespace.__name__ == "array_api_strict" and hasattr(