Repository: numpy/numpy
File: numpy/core/src/multiarray/ctors.c (C)

Code before:
        else if (PyErr_Occurred()) {
            if (PyErr_ExceptionMatches(PyExc_BufferError) ||
                    PyErr_ExceptionMatches(PyExc_TypeError)) {
                PyErr_Clear();
            } else {
                return -1;
            }
        }
        else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) {
            d[0] = buffer_view.len;
            *maxndim = 1;
            PyBuffer_Release(&buffer_view);
            _dealloc_cached_buffer_info(obj);
            return 0;
        }
        else if (PyErr_Occurred()) {
            if (PyErr_ExceptionMatches(PyExc_BufferError) ||
                    PyErr_ExceptionMatches(PyExc_TypeError)) {
                PyErr_Clear();
            } else {
                return -1;
            }
        }
    }

    /* obj has the __array_struct__ interface */
    e = PyArray_LookupSpecial_OnInstance(obj, "__array_struct__");
    if (e != NULL) {
        int nd = -1;

        if (NpyCapsule_Check(e)) {
            PyArrayInterface *inter;
            inter = (PyArrayInterface *)NpyCapsule_AsVoidPtr(e);
            if (inter->two == 2) {
                nd = inter->nd;
                if (nd >= 0) {
                    if (nd < *maxndim) {
                        *maxndim = nd;
                    }
                    for (i=0; i<*maxndim; i++) {
                        d[i] = inter->shape[i];
                    }
                }
            }
        }
        Py_DECREF(e);
        if (nd >= 0) {
            return 0;
        }
    }
    else if (PyErr_Occurred()) {

Review comment (suggestion):
Shouldn't this be `e` not `obj`?
```suggestion
        _discover_dimensions_array((PyArrayObject *)e, maxndim, d);
```

Code after:
    /* obj is a Tuple, but tuples aren't expanded */
    if (stop_at_tuple && PyTuple_Check(obj)) {
        *maxndim = 0;
        return 0;
    }

    /*
     * In the future, the result of `_array_from_array_like` should possibly
     * be cached. This may require passing the correct dtype/writable
     * information already in the dimension discovery step (if they are
     * distinct steps).
     */
    e = _array_from_array_like(obj, NULL, NPY_FALSE, NULL);
    if (e == Py_NotImplemented) {
        Py_DECREF(e);
    }
    else if (e != NULL) {
        _discover_dimensions_array((PyArrayObject *)e, maxndim, d);
        Py_DECREF(e);
        return 0;
    }
    else if (PyErr_Occurred()) {
        /* TODO[gh-14801]: propagate crashes during attribute access? */
        PyErr_Clear();
    }

    seq = PySequence_Fast(obj, "Could not convert object to sequence");
    if (seq == NULL) {
        /*
         * PySequence_Check detects whether an old type object is a
         * sequence by the presence of the __getitem__ attribute, and
         * for new type objects that aren't dictionaries by the
         * presence of the __len__ attribute as well. In either case it
         * is possible to have an object that tests as a sequence but
         * doesn't behave as a sequence and consequently, the
         * PySequence_GetItem call can fail. When that happens and the
         * object looks like a dictionary, we truncate the dimensions
         * and set the object creation flag, otherwise we pass the
         * error back up the call chain.
         */
        if (PyErr_ExceptionMatches(PyExc_KeyError)) {
            PyErr_Clear();
            *maxndim = 0;
            *out_is_object = DISCOVERED_OBJECT;
            return 0;
        }
        else {
            return -1;
        }
    }
    n = PySequence_Fast_GET_SIZE(seq);