Repository: numpy/numpy
File: numpy/_core/src/multiarray/methods.c (C)

Code before:
        Py_INCREF(PyArray_DESCR(self));
        new = (PyArrayObject *)PyArray_NewFromDescrAndBase(
                &PyArray_Type,
                PyArray_DESCR(self),
                PyArray_NDIM(self),
                PyArray_DIMS(self),
                PyArray_STRIDES(self),
                PyArray_DATA(self),
                PyArray_FLAGS(self),
                NULL,
                (PyObject *)self
        );
        if (new == NULL) {
            return NULL;
        }
        self = new;
    }
    else {
        Py_INCREF(self);
    }

    if (copy == NPY_COPY_ALWAYS) {
        if (newtype == NULL) {
            newtype = PyArray_DESCR(self);
        }
        Py_INCREF(newtype);
        ret = PyArray_CastToType(self, newtype, 0);
        Py_DECREF(self);
        return ret;
    } else { // copy == NPY_COPY_IF_NEEDED || copy == NPY_COPY_NEVER
        if (newtype == NULL || PyArray_EquivTypes(PyArray_DESCR(self), newtype)) {
            return (PyObject *)self;
        }
        if (copy == NPY_COPY_IF_NEEDED) {
            Py_INCREF(newtype);
            ret = PyArray_CastToType(self, newtype, 0);
            Py_DECREF(self);
            return ret;
        } else { // copy == NPY_COPY_NEVER
            PyErr_SetString(PyExc_ValueError, npy_no_copy_err_msg);
            Py_DECREF(self);
            return NULL;
        }
    }
}

/*
 * Check whether any of the input and output args have a non-default
 * __array_ufunc__ method. Return 1 if so, 0 if not, and -1 on error.
 *
 * This function primarily exists to help ndarray.__array_ufunc__ determine

Review comment (bug):
What about the case when you pass an explicit dtype?

With this change, the following test fails:
```python
dt2 = np.dtype(np.float32)
old_refcount2 = sys.getrefcount(dt2)
np.array(MyArray(), dtype=dt2)
assert_equal(old_refcount2, sys.getrefcount(dt2))
```

For this case, the following seems to fix it:

```suggestion
        if (newtype == NULL) {
            newtype = PyArray_DESCR(self);
            Py_INCREF(newtype);
        }
```

Code after:

    /* convert to PyArray_Type */
    if (!PyArray_CheckExact(self)) {
        PyArrayObject *new;

        Py_INCREF(PyArray_DESCR(self));
        new = (PyArrayObject *)PyArray_NewFromDescrAndBase(
                &PyArray_Type,
                PyArray_DESCR(self),
                PyArray_NDIM(self),
                PyArray_DIMS(self),
                PyArray_STRIDES(self),
                PyArray_DATA(self),
                PyArray_FLAGS(self),
                NULL,
                (PyObject *)self
        );
        if (new == NULL) {
            Py_DECREF(newtype);
            return NULL;
        }
        self = new;
    }
    else {
        Py_INCREF(self);
    }

    if (copy == NPY_COPY_ALWAYS) {
        ret = PyArray_CastToType(self, newtype, 0);  // steals newtype reference
        Py_DECREF(self);
        return ret;
    } else { // copy == NPY_COPY_IF_NEEDED || copy == NPY_COPY_NEVER
        if (PyArray_EquivTypes(PyArray_DESCR(self), newtype)) {
            Py_DECREF(newtype);
            return (PyObject *)self;
        }
        if (copy == NPY_COPY_IF_NEEDED) {
            ret = PyArray_CastToType(self, newtype, 0);  // steals newtype reference.
            Py_DECREF(self);
            return ret;
        } else { // copy == NPY_COPY_NEVER
            PyErr_SetString(PyExc_ValueError, npy_no_copy_err_msg);
            Py_DECREF(newtype);
            Py_DECREF(self);
            return NULL;
        }
    }
}

/*
 * Check whether any of the input and output args have a non-default