Skip to content

BUG: Indexing a void array scalar with (...,) does not return an ndarray #32742

Closed

Description

@eerovaher

Describe the issue:

Admittedly I have not found any documentation that explicitly states what indexing with (...,) should do, but I did find:

Array scalars can be indexed like 0-dimensional arrays: if *x* is an
array scalar,
- ``x[()]`` returns a copy of array scalar
- ``x[...]`` returns a 0-dimensional :class:`ndarray`

from which it can be deduced that x[y] should produce the same output as x[...][y] for any y, including y=(...,). This is indeed how it works with e.g. np.float64:

>>> import numpy as np
>>> x = np.float64(0)
>>> x[(...,)]
array(0.)
>>> x[...][(...,)]
array(0.)

but it is not how it works with void array scalars:

>>> v = np.void(3, dtype=[("x", np.int8)])
>>> v[(...,)]
np.void((3,), dtype=[('x', 'i1')])
>>> v[...][(...,)]
array((3,), dtype=[('x', 'i1')])

Furthermore, when running mypy on the code example below it reports

demo.py:7: note: Revealed type is "numpy.ndarray[tuple[()], numpy.dtype[numpy.void]]"
Success: no issues found in 1 source file

so the current runtime behavior is inconsistent with type annotations.

Reproduce the code example:

from typing import TYPE_CHECKING

import numpy as np

v = np.void(3, dtype=[("x", np.int8)])
if TYPE_CHECKING:
    reveal_type(v[(...,)])
assert isinstance(v[(...,)], np.ndarray)

Error message:

Traceback (most recent call last):
  File ".../demo.py", line 8, in <module>
    assert isinstance(v[(...,)], np.ndarray), type[v[(...,)]]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: type[np.void((3, 3), dtype=[('x', 'i1')])]

Python and NumPy Versions:

2.5.2
3.12.3 (main, Aug 31 2026, 10:18:26) [GCC 13.3.0]

Runtime Environment:

No response

How does this issue affect you or how did you find it:

I was working on adding type annotations to a library that uses custom dtypes, and I discovered that I could make the annotations consistent with numpy annotations or with runtime behavior but not both.

Activity

  1. jorenham commented on Sep 21, 2026

    @jorenham
    Member

    Thanks for reporting, and good to more people using static typing :).

    This looks more like a runtime issue than a stubs issue to me.

    I was able to repro on the current main branch:

    >>> import numpy as np
    >>> v = np.void(3, dtype=[("x", np.int8)])
    >>> type(v[(...,)])
    <class 'numpy.void'>
    >>> type(v[...])
    <class 'numpy.ndarray'>
    >>> type(v[...][(...,)]) 
    <class 'numpy.ndarray'>

    According to Astra 6 the problem lies in voidtype_subscript, where only a bare ... is special cased, but not a (...,):

    {
    npy_intp n;
    PyObject *ret, *res;
    /* structured voids will accept an integer index */
    if (PyDataType_HASFIELDS(self->descr)) {
    n = PyArray_PyIntAsIntp(ind);
    if (!error_converting(n)) {
    return voidtype_item(self, (Py_ssize_t)n);
    }
    PyErr_Clear();
    }
    res = PyArray_FromScalar((PyObject*)self, NULL);
    /* ellipsis should return 0d array */
    if(ind == Py_Ellipsis){
    return res;
    }
    /*
    * other cases (field names, empty tuple) will return either
    * scalar or non-0d array. Compute this using ndarray subscript.
    */
    ret = array_subscript((PyArrayObject *)res, ind);
    Py_DECREF(res);
    return PyArray_Return((PyArrayObject*)ret);
    }

  2. ikrommyd commented on Sep 21, 2026

    @ikrommyd
    Member

    I wouldn't like to fix this by adding another special case for the 1-element ellipsis tuple if we can help it.

  3. jorenham commented on Sep 21, 2026

    @jorenham
    Member

    I wouldn't like to fix this by adding another special case for the 1-element ellipsis tuple if we can help it.

    Why not? Unpacking single-element tuple arguments in __getitem__ is standard practice, as far as I'm aware.

  4. ikrommyd commented on Sep 21, 2026

    @ikrommyd
    Member

    Well my reasoning was other scalartypes that have no special casing and let array_subscript decide the answer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions