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

Code before:
    r = PyArray_NewFromDescrAndBase(
            &PyArray_Type, descr,
            nd, shape, strides, view->buf,
            flags, NULL, memoryview);
    return r;


fail:
    Py_XDECREF(r);
    Py_XDECREF(descr);
    return NULL;

}

/*
 * Retrieves the array parameters for viewing/converting an arbitrary
 * PyObject* to a NumPy array. This allows the "innate type and shape"
 * of Python list-of-lists to be discovered without
 * actually converting to an array.
 *
 * In some cases, such as structured arrays and the __array__ interface,
 * a data type needs to be used to make sense of the object.  When
 * this is needed, provide a Descr for 'requested_dtype', otherwise
 * provide NULL. This reference is not stolen. Also, if the requested
 * dtype doesn't modify the interpretation of the input, out_dtype will
 * still get the "innate" dtype of the object, not the dtype passed
 * in 'requested_dtype'.
 *
 * If writing to the value in 'op' is desired, set the boolean
 * 'writeable' to 1.  This raises an error when 'op' is a scalar, list
 * of lists, or other non-writeable 'op'.
 *
 * Result: When success (0 return value) is returned, either out_arr
 *         is filled with a non-NULL PyArrayObject and
 *         the rest of the parameters are untouched, or out_arr is
 *         filled with NULL, and the rest of the parameters are
 *         filled.
 *
 * Typical usage:
 *
 *      PyArrayObject *arr = NULL;
 *      PyArray_Descr *dtype = NULL;
 *      int ndim = 0;
 *      npy_intp dims[NPY_MAXDIMS];
 *
 *      if (PyArray_GetArrayParamsFromObject(op, NULL, 1, &dtype,
 *                                          &ndim, dims, &arr, NULL) < 0) {
 *          return NULL;
 *      }
 *      if (arr == NULL) {
 *          ... validate/change dtype, validate flags, ndim, etc ...

Review comment (bug):
```suggestion
            && PyArray_FailUnlessWriteable((PyArrayObject *)tmp,
```

Code after:
    }

    /*
     * If op supports the __array_struct__ or __array_interface__ interface.
     */
    tmp = PyArray_FromStructInterface(op);
    if (tmp == NULL) {
        return NULL;
    }
    if (tmp == Py_NotImplemented) {
        /* Until the return, NotImplemented is always a borrowed reference*/
        tmp = PyArray_FromInterface(op);
        if (tmp == NULL) {
            return NULL;
        }
    }

    /*
     * If op supplies the __array__ function.
     * The documentation says this should produce a copy, so
     * we skip this method if writeable is true, because the intent
     * of writeable is to modify the operand.
     * XXX: If the implementation is wrong, and/or if actual
     *      usage requires this behave differently,
     *      this should be changed!
     */
    if (!writeable && tmp == Py_NotImplemented) {
        tmp = PyArray_FromArrayAttr(op, requested_dtype, context);
        if (tmp == NULL) {
            return NULL;
        }
    }

    if (tmp != Py_NotImplemented) {
        if (writeable &&
                PyArray_FailUnlessWriteable((PyArrayObject *)tmp,
                        "array interface object") < 0) {
            Py_DECREF(tmp);
            return NULL;
        }
        return tmp;
    }

    /* Until here Py_NotImplemented was borrowed */
    Py_INCREF(Py_NotImplemented);
    return Py_NotImplemented;
}


/*
 * Retrieves the array parameters for viewing/converting an arbitrary