ronantakizawa/codereview-bench huggingface dataset:
Repository: numpy/numpy
File: numpy/_core/overrides.pyi (Python)

Code before:
from collections.abc import Callable, Iterable
from typing import Any, Final, NamedTuple, ParamSpec, TypeVar

from numpy._typing import _SupportsArrayFunc

_T = TypeVar("_T")
_Tss = ParamSpec("_Tss")
_FuncT = TypeVar("_FuncT", bound=Callable[..., object])

###

ARRAY_FUNCTIONS: set[Callable[..., Any]] = ...
array_function_like_doc: Final[str] = ...

class ArgSpec(NamedTuple):
    args: list[str]
    varargs: str | None
    keywords: str | None
    defaults: tuple[Any, ...]

def get_array_function_like_doc(public_api: Callable[..., Any], docstring_template: str = "") -> str: ...
def finalize_array_function_like(public_api: _FuncT) -> _FuncT: ...

#
def verify_matching_signatures(
    implementation: Callable[_Tss, object],
    dispatcher: Callable[_Tss, Iterable[_SupportsArrayFunc]],
) -> None: ...

# NOTE: This actually returns a `_ArrayFunctionDispatcher` callable wrapper object, with
# the original wrapped callable stored in the `._implementation` attribute. It checks
# for any `__array_function__` of the values of specific arguments that the dispatcher
# specifies. Since the dispatcher only returns an iterable of passed array-like args,

Review comment (bug):
```suggestion
_Dispatcher: TypeAlias = Callable[_Tss, Sequence[object]]
```
But with that, please just merge if you are happy.  If I understand correctly, this is the function that returns the relevant arguments.  Returning iterables is actually wrong there, because we iterate it multiple times.

Code after:
from collections.abc import Callable, Iterable
from typing import Any, Final, NamedTuple, ParamSpec, TypeAlias, TypeVar

_T = TypeVar("_T")
_Tss = ParamSpec("_Tss")
_FuncLikeT = TypeVar("_FuncLikeT", bound=type | Callable[..., object])

_Dispatcher: TypeAlias = Callable[_Tss, Iterable[object]]

###

ARRAY_FUNCTIONS: set[Callable[..., Any]] = ...
array_function_like_doc: Final[str] = ...

class ArgSpec(NamedTuple):
    args: list[str]
    varargs: str | None
    keywords: str | None
    defaults: tuple[Any, ...]

def get_array_function_like_doc(public_api: Callable[..., object], docstring_template: str = "") -> str: ...
def finalize_array_function_like(public_api: _FuncLikeT) -> _FuncLikeT: ...

#
def verify_matching_signatures(implementation: Callable[_Tss, object], dispatcher: _Dispatcher[_Tss]) -> None: ...

# NOTE: This actually returns a `_ArrayFunctionDispatcher` callable wrapper object, with
# the original wrapped callable stored in the `._implementation` attribute. It checks
# for any `__array_function__` of the values of specific arguments that the dispatcher
# specifies. Since the dispatcher only returns an iterable of passed array-like args,
# this overridable behaviour is impossible to annotate.
def array_function_dispatch(
    dispatcher: _Dispatcher[_Tss] | None = None,
Repository: numpy/numpy
File: numpy/_core/fromnumeric.py (Python)

Code before:
        Number of elements along the specified axis.

    See Also
    --------
    shape : dimensions of array
    ndarray.shape : dimensions of array
    ndarray.size : number of elements in array

    Examples
    --------
    >>> import numpy as np
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> np.size(a)
    6
    >>> np.size(a,1)
    3
    >>> np.size(a,0)
    2

    """
    if axis is None:
        try:
            return a.size
        except AttributeError:
            return asarray(a).size
    elif isinstance(axis, tuple):
        try:
            shape = a.shape
        except AttributeError:
            shape = asarray(a).shape
        return math.prod(shape[ax] for ax in axis)
    else:
        try:
            return a.shape[axis]
        except AttributeError:
            return asarray(a).shape[axis]


def _round_dispatcher(a, decimals=None, out=None):
    return (a, out)


@array_function_dispatch(_round_dispatcher)
def round(a, decimals=0, out=None):
    """
    Evenly round to the given number of decimals.

    Parameters
    ----------
    a : array_like
        Input data.

Review comment (suggestion):
It'll add a bit of overhead, but I think you should just call: `normalize_axis_tuple` here and work with that (if we don't like that overhead, it should just be moved to C).

I am a bit surprised we even have this function, but accepting a tuple for an axis is an obviously good generalization, IMO.

Code after:
    Returns
    -------
    element_count : int
        Number of elements along the specified axis.

    See Also
    --------
    shape : dimensions of array
    ndarray.shape : dimensions of array
    ndarray.size : number of elements in array

    Examples
    --------
    >>> import numpy as np
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> np.size(a)
    6
    >>> np.size(a,axis=1)
    3
    >>> np.size(a,axis=0)
    2
    >>> np.size(a,axis=(0,1))
    6

    """
    if axis is None:
        try:
            return a.size
        except AttributeError:
            return asarray(a).size
    else:
        _shape = shape(a)
        from .numeric import normalize_axis_tuple
        axis = normalize_axis_tuple(axis, len(_shape), allow_duplicate=False)
        return math.prod(_shape[ax] for ax in axis)


def _round_dispatcher(a, decimals=None, out=None):
    return (a, out)


@array_function_dispatch(_round_dispatcher)
def round(a, decimals=0, out=None):
    """
    Evenly round to the given number of decimals.

    Parameters
    ----------
    a : array_like
        Input data.
    decimals : int, optional
Repository: numpy/numpy
File: numpy/_core/fromnumeric.py (Python)

Code before:
    >>> np.ndim(1)
    0

    """
    try:
        return a.ndim
    except AttributeError:
        return asarray(a).ndim


def _size_dispatcher(a, axis=None):
    return (a,)


@array_function_dispatch(_size_dispatcher)
def size(a, axis=None):
    """
    Return the number of elements along a given axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the elements are counted.  By default, give
        the total number of elements.

    Returns
    -------
    element_count : int
        Number of elements along the specified axis.

    See Also
    --------
    shape : dimensions of array
    ndarray.shape : dimensions of array
    ndarray.size : number of elements in array

    Examples
    --------
    >>> import numpy as np
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> np.size(a)
    6
    >>> np.size(a,1)
    3
    >>> np.size(a,0)
    2

    """
    if axis is None:

Review comment (suggestion):
Ah, this should also have a `.. versionchanged::` directive (you can search for similar ones it would be 2.4).
(Somehow, I don't care too much about the release note, but maybe best even if rather minor.)

Code after:
    >>> np.ndim(1)
    0

    """
    try:
        return a.ndim
    except AttributeError:
        return asarray(a).ndim


def _size_dispatcher(a, axis=None):
    return (a,)


@array_function_dispatch(_size_dispatcher)
def size(a, axis=None):
    """
    Return the number of elements along a given axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the elements are counted.  By default, give
        the total number of elements.

        .. versionchanged:: 2.4
           Extended to accept multiple axes.

    Returns
    -------
    element_count : int
        Number of elements along the specified axis.

    See Also
    --------
    shape : dimensions of array
    ndarray.shape : dimensions of array
    ndarray.size : number of elements in array

    Examples
    --------
    >>> import numpy as np
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> np.size(a)
    6
    >>> np.size(a,axis=1)
    3
    >>> np.size(a,axis=0)
    2
Repository: numpy/numpy
File: numpy/_core/fromnumeric.pyi (Python)

Code before:
    include_initial: bool = ...,
) -> NDArray[_ScalarT]: ...
@overload
def cumulative_prod(
    x: _ArrayLikeComplex_co | _ArrayLikeObject_co,
    /,
    *,
    axis: SupportsIndex | None = ...,
    dtype: DTypeLike = ...,
    out: None = ...,
    include_initial: bool = ...,
) -> NDArray[Any]: ...
@overload
def cumulative_prod(
    x: _ArrayLikeComplex_co | _ArrayLikeObject_co,
    /,
    *,
    axis: SupportsIndex | None = ...,
    dtype: DTypeLike = ...,
    out: _ArrayT,
    include_initial: bool = ...,
) -> _ArrayT: ...

def ndim(a: ArrayLike) -> int: ...

def size(a: ArrayLike, axis: int | None | tuple[int, ...] = ...) -> int: ...

@overload
def around(
    a: _BoolLike_co,
    decimals: SupportsIndex = ...,
    out: None = ...,
) -> float16: ...
@overload
def around(
    a: _NumberOrObjectT,
    decimals: SupportsIndex = ...,
    out: None = ...,
) -> _NumberOrObjectT: ...
@overload
def around(
    a: _ComplexLike_co | object_,
    decimals: SupportsIndex = ...,
    out: None = ...,
) -> Any: ...
@overload
def around(
    a: _ArrayLikeBool_co,
    decimals: SupportsIndex = ...,
    out: None = ...,
) -> NDArray[float16]: ...

Review comment (suggestion):
By convention, `None`, should be last in a union. 

```suggestion
def size(a: ArrayLike, axis: int | tuple[int, ...] | None = ...) -> int: ...
```

Code after:
    include_initial: bool = ...,
) -> NDArray[_ScalarT]: ...
@overload
def cumulative_prod(
    x: _ArrayLikeComplex_co | _ArrayLikeObject_co,
    /,
    *,
    axis: SupportsIndex | None = ...,
    dtype: DTypeLike = ...,
    out: None = ...,
    include_initial: bool = ...,
) -> NDArray[Any]: ...
@overload
def cumulative_prod(
    x: _ArrayLikeComplex_co | _ArrayLikeObject_co,
    /,
    *,
    axis: SupportsIndex | None = ...,
    dtype: DTypeLike = ...,
    out: _ArrayT,
    include_initial: bool = ...,
) -> _ArrayT: ...

def ndim(a: ArrayLike) -> int: ...

def size(a: ArrayLike, axis: int | tuple[int, ...] | None = ...) -> int: ...

@overload
def around(
    a: _BoolLike_co,
    decimals: SupportsIndex = ...,
    out: None = ...,
) -> float16: ...
@overload
def around(
    a: _NumberOrObjectT,
    decimals: SupportsIndex = ...,
    out: None = ...,
) -> _NumberOrObjectT: ...
@overload
def around(
    a: _ComplexLike_co | object_,
    decimals: SupportsIndex = ...,
    out: None = ...,
) -> Any: ...
@overload
def around(
    a: _ArrayLikeBool_co,
    decimals: SupportsIndex = ...,
    out: None = ...,
) -> NDArray[float16]: ...
Repository: numpy/numpy
File: numpy/_core/fromnumeric.py (Python)

Code before:
    Return the number of elements along a given axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the elements are counted.  By default, give
        the total number of elements.

    Returns
    -------
    element_count : int
        Number of elements along the specified axis.

    See Also
    --------
    shape : dimensions of array
    ndarray.shape : dimensions of array
    ndarray.size : number of elements in array

    Notes
    -----

    .. versionchanged:: 2.3.1
       Extended to accept multiple axes.

    Examples
    --------
    >>> import numpy as np
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> np.size(a)
    6
    >>> np.size(a,axis=1)
    3
    >>> np.size(a,axis=0)
    2
    >>> np.size(a,axis=(0,1))
    6

    """
    if axis is None:
        try:
            return a.size
        except AttributeError:
            return asarray(a).size
    else:
        _shape = shape(a)
        from .numeric import normalize_axis_tuple
        axis = normalize_axis_tuple(axis, len(_shape), allow_duplicate=False)
        return math.prod(_shape[ax] for ax in axis)

Review comment (suggestion):
We should wrap this, up.  But it would be a bit nicer to just add it to the `axis :` parameter description rather than the notes section, just because that's what we usually do.

Code after:
    Return the number of elements along a given axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the elements are counted.  By default, give
        the total number of elements.

        .. versionchanged:: 2.4
           Extended to accept multiple axes.

    Returns
    -------
    element_count : int
        Number of elements along the specified axis.

    See Also
    --------
    shape : dimensions of array
    ndarray.shape : dimensions of array
    ndarray.size : number of elements in array

    Examples
    --------
    >>> import numpy as np
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> np.size(a)
    6
    >>> np.size(a,axis=1)
    3
    >>> np.size(a,axis=0)
    2
    >>> np.size(a,axis=(0,1))
    6

    """
    if axis is None:
        try:
            return a.size
        except AttributeError:
            return asarray(a).size
    else:
        _shape = shape(a)
        from .numeric import normalize_axis_tuple
        axis = normalize_axis_tuple(axis, len(_shape), allow_duplicate=False)
        return math.prod(_shape[ax] for ax in axis)


def _round_dispatcher(a, decimals=None, out=None):
Repository: numpy/numpy
File: numpy/_core/fromnumeric.py (Python)

Code before:

    """
    try:
        return a.ndim
    except AttributeError:
        return asarray(a).ndim


def _size_dispatcher(a, axis=None):
    return (a,)


@array_function_dispatch(_size_dispatcher)
def size(a, axis=None):
    """
    Return the number of elements along a given axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the elements are counted.  By default, give
        the total number of elements.

        .. versionchanged:: 2.3.1
           Extended to accept multiple axes.

    Returns
    -------
    element_count : int
        Number of elements along the specified axis.

    See Also
    --------
    shape : dimensions of array
    ndarray.shape : dimensions of array
    ndarray.size : number of elements in array

    Examples
    --------
    >>> import numpy as np
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> np.size(a)
    6
    >>> np.size(a,axis=1)
    3
    >>> np.size(a,axis=0)
    2
    >>> np.size(a,axis=(0,1))
    6

Review comment (suggestion):
```suggestion
        .. versionchanged:: 2.4
```

Code after:

    """
    try:
        return a.ndim
    except AttributeError:
        return asarray(a).ndim


def _size_dispatcher(a, axis=None):
    return (a,)


@array_function_dispatch(_size_dispatcher)
def size(a, axis=None):
    """
    Return the number of elements along a given axis.

    Parameters
    ----------
    a : array_like
        Input data.
    axis : None or int or tuple of ints, optional
        Axis or axes along which the elements are counted.  By default, give
        the total number of elements.

        .. versionchanged:: 2.4
           Extended to accept multiple axes.

    Returns
    -------
    element_count : int
        Number of elements along the specified axis.

    See Also
    --------
    shape : dimensions of array
    ndarray.shape : dimensions of array
    ndarray.size : number of elements in array

    Examples
    --------
    >>> import numpy as np
    >>> a = np.array([[1,2,3],[4,5,6]])
    >>> np.size(a)
    6
    >>> np.size(a,axis=1)
    3
    >>> np.size(a,axis=0)
    2
    >>> np.size(a,axis=(0,1))
    6
Repository: numpy/numpy
File: numpy/lib/_arraypad_impl.pyi (Python)

Code before:
        vector: NDArray[Any],
        iaxis_pad_width: tuple[int, int],
        iaxis: int,
        kwargs: dict[str, Any],
        /,
    ) -> None: ...

_ModeKind: TypeAlias = L[
    "constant",
    "edge",
    "linear_ramp",
    "maximum",
    "mean",
    "median",
    "minimum",
    "reflect",
    "symmetric",
    "wrap",
    "empty",
]

# TODO: In practice each keyword argument is exclusive to one or more
# specific modes. Consider adding more overloads to express this in the future.

# Expand `**kwargs` into explicit keyword-only arguments
PadWidthType: TypeAlias = (
    _ArrayLikeInt
    | dict[int, int]
    | dict[int, tuple[int, int]]
    | dict[int, int | tuple[int, int]]
)
@overload
def pad(
    array: _ArrayLike[_ScalarT],
    pad_width: PadWidthType,
    mode: _ModeKind = ...,
    *,
    stat_length: _ArrayLikeInt | None = ...,
    constant_values: ArrayLike = ...,
    end_values: ArrayLike = ...,
    reflect_type: L["odd", "even"] = ...,
) -> NDArray[_ScalarT]: ...
@overload
def pad(
    array: ArrayLike,
    pad_width: PadWidthType,
    mode: _ModeKind = ...,
    *,
    stat_length: _ArrayLikeInt | None = ...,
    constant_values: ArrayLike = ...,
    end_values: ArrayLike = ...,

Review comment (suggestion):
this type alias is not public API (and this one doesn't exist even), so needs a a leading underscore

```suggestion
_PadWidth: TypeAlias = (
```

And naming-wise; a `*Type` suffix is conventionally used to indicate that the type alias is a `type`, for example `IntType: TypeAlias = type[int]`. 

Code after:
        vector: NDArray[Any],
        iaxis_pad_width: tuple[int, int],
        iaxis: int,
        kwargs: dict[str, Any],
        /,
    ) -> None: ...

_ModeKind: TypeAlias = L[
    "constant",
    "edge",
    "linear_ramp",
    "maximum",
    "mean",
    "median",
    "minimum",
    "reflect",
    "symmetric",
    "wrap",
    "empty",
]

# TODO: In practice each keyword argument is exclusive to one or more
# specific modes. Consider adding more overloads to express this in the future.

_PadWidth: TypeAlias = (
    _ArrayLikeInt
    | dict[int, int]
    | dict[int, tuple[int, int]]
    | dict[int, int | tuple[int, int]]
)
# Expand `**kwargs` into explicit keyword-only arguments
@overload
def pad(
    array: _ArrayLike[_ScalarT],
    pad_width: _PadWidth,
    mode: _ModeKind = ...,
    *,
    stat_length: _ArrayLikeInt | None = ...,
    constant_values: ArrayLike = ...,
    end_values: ArrayLike = ...,
    reflect_type: L["odd", "even"] = ...,
) -> NDArray[_ScalarT]: ...
@overload
def pad(
    array: ArrayLike,
    pad_width: _PadWidth,
    mode: _ModeKind = ...,
    *,
    stat_length: _ArrayLikeInt | None = ...,
    constant_values: ArrayLike = ...,
    end_values: ArrayLike = ...,
Repository: numpy/numpy
File: numpy/lib/_arraypad_impl.pyi (Python)

Code before:
        self,
        vector: NDArray[Any],
        iaxis_pad_width: tuple[int, int],
        iaxis: int,
        kwargs: dict[str, Any],
        /,
    ) -> None: ...

_ModeKind: TypeAlias = L[
    "constant",
    "edge",
    "linear_ramp",
    "maximum",
    "mean",
    "median",
    "minimum",
    "reflect",
    "symmetric",
    "wrap",
    "empty",
]

# TODO: In practice each keyword argument is exclusive to one or more
# specific modes. Consider adding more overloads to express this in the future.

# Expand `**kwargs` into explicit keyword-only arguments
PadWidthType: TypeAlias = (
    _ArrayLikeInt
    | dict[int, int]
    | dict[int, tuple[int, int]]
    | dict[int, int | tuple[int, int]]
)
@overload
def pad(
    array: _ArrayLike[_ScalarT],
    pad_width: PadWidthType,
    mode: _ModeKind = ...,
    *,
    stat_length: _ArrayLikeInt | None = ...,
    constant_values: ArrayLike = ...,
    end_values: ArrayLike = ...,
    reflect_type: L["odd", "even"] = ...,
) -> NDArray[_ScalarT]: ...
@overload
def pad(
    array: ArrayLike,
    pad_width: PadWidthType,
    mode: _ModeKind = ...,
    *,
    stat_length: _ArrayLikeInt | None = ...,
    constant_values: ArrayLike = ...,

Review comment (suggestion):
this comment applies to the `pad` function, not the type alias, so the type alias should be above here

Code after:
        self,
        vector: NDArray[Any],
        iaxis_pad_width: tuple[int, int],
        iaxis: int,
        kwargs: dict[str, Any],
        /,
    ) -> None: ...

_ModeKind: TypeAlias = L[
    "constant",
    "edge",
    "linear_ramp",
    "maximum",
    "mean",
    "median",
    "minimum",
    "reflect",
    "symmetric",
    "wrap",
    "empty",
]

# TODO: In practice each keyword argument is exclusive to one or more
# specific modes. Consider adding more overloads to express this in the future.

_PadWidth: TypeAlias = (
    _ArrayLikeInt
    | dict[int, int]
    | dict[int, tuple[int, int]]
    | dict[int, int | tuple[int, int]]
)
# Expand `**kwargs` into explicit keyword-only arguments
@overload
def pad(
    array: _ArrayLike[_ScalarT],
    pad_width: _PadWidth,
    mode: _ModeKind = ...,
    *,
    stat_length: _ArrayLikeInt | None = ...,
    constant_values: ArrayLike = ...,
    end_values: ArrayLike = ...,
    reflect_type: L["odd", "even"] = ...,
) -> NDArray[_ScalarT]: ...
@overload
def pad(
    array: ArrayLike,
    pad_width: _PadWidth,
    mode: _ModeKind = ...,
    *,
    stat_length: _ArrayLikeInt | None = ...,
    constant_values: ArrayLike = ...,
Repository: numpy/numpy
File: numpy/_core/include/numpy/halffloat.h (C/C++)

Code before:
#ifndef NUMPY_CORE_INCLUDE_NUMPY_HALFFLOAT_H_
#define NUMPY_CORE_INCLUDE_NUMPY_HALFFLOAT_H_

/* Any file that includes Python.h must include it before any other files */
/* https://docs.python.org/3/extending/extending.html#a-simple-example */
/* npy_common.h includes Python.h so it also counts in this list */
#include <Python.h>
#include <numpy/npy_math.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Half-precision routines
 */

/* Conversions */
float npy_half_to_float(npy_half h);
double npy_half_to_double(npy_half h);
npy_half npy_float_to_half(float f);
npy_half npy_double_to_half(double d);
/* Comparisons */
int npy_half_eq(npy_half h1, npy_half h2);
int npy_half_ne(npy_half h1, npy_half h2);
int npy_half_le(npy_half h1, npy_half h2);
int npy_half_lt(npy_half h1, npy_half h2);
int npy_half_ge(npy_half h1, npy_half h2);
int npy_half_gt(npy_half h1, npy_half h2);
/* faster *_nonan variants for when you know h1 and h2 are not NaN */
int npy_half_eq_nonan(npy_half h1, npy_half h2);

Review comment (suggestion):
If we're going to touch every single header, I'd prefer it if this comment could be formatted like other comments in the numpy repo

```suggestion
/* 
   Any file that includes Python.h must include it before any other files
   https://docs.python.org/3/extending/extending.html#a-simple-example            
*/
```

I also think the addendum about `npy_common.h` is only relevant for files that include it, and even then is maybe more confusing than helpful, since the most important thing is that `Python.h` comes first and the comment makes that clear.

Code after:
#ifndef NUMPY_CORE_INCLUDE_NUMPY_HALFFLOAT_H_
#define NUMPY_CORE_INCLUDE_NUMPY_HALFFLOAT_H_

#include <Python.h>
#include <numpy/npy_math.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Half-precision routines
 */

/* Conversions */
float npy_half_to_float(npy_half h);
double npy_half_to_double(npy_half h);
npy_half npy_float_to_half(float f);
npy_half npy_double_to_half(double d);
/* Comparisons */
int npy_half_eq(npy_half h1, npy_half h2);
int npy_half_ne(npy_half h1, npy_half h2);
int npy_half_le(npy_half h1, npy_half h2);
int npy_half_lt(npy_half h1, npy_half h2);
int npy_half_ge(npy_half h1, npy_half h2);
int npy_half_gt(npy_half h1, npy_half h2);
/* faster *_nonan variants for when you know h1 and h2 are not NaN */
int npy_half_eq_nonan(npy_half h1, npy_half h2);
int npy_half_lt_nonan(npy_half h1, npy_half h2);
int npy_half_le_nonan(npy_half h1, npy_half h2);
/* Miscellaneous functions */