Repository: numpy/numpy
File: numpy/_core/tests/test_api.py (Python)

Code before:
    assert_equal(np.array([(None,) * 10], dtype=np.float64),
                 np.full((1, 10), np.nan, dtype=np.float64))
    assert_equal(np.array([(None,) * 10] * 10, dtype=np.float64),
                 np.full((10, 10), np.nan, dtype=np.float64))

    assert_equal(np.array((1.0,) * 10, dtype=np.float64),
                 np.ones((10,), dtype=np.float64))
    assert_equal(np.array([(1.0,)] * 10, dtype=np.float64),
                 np.ones((10, 1), dtype=np.float64))
    assert_equal(np.array([(1.0,) * 10], dtype=np.float64),
                 np.ones((1, 10), dtype=np.float64))
    assert_equal(np.array([(1.0,) * 10] * 10, dtype=np.float64),
                 np.ones((10, 10), dtype=np.float64))


@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
def test___array___refcount():
    class MyArray:
        def __init__(self, dtype):
            self.val = np.array(-1, dtype=dtype)

        def __array__(self, dtype=None, copy=None):
            return self.val.__array__(dtype=dtype, copy=copy)

    # test all possible scenarios:
    # dtype(none | same | different) x copy(true | false)
    dt = np.dtype(np.int32)
    old_refcount = sys.getrefcount(dt)
    np.array(MyArray(dt))
    assert_equal(old_refcount, sys.getrefcount(dt))
    np.array(MyArray(dt), dtype=dt)
    assert_equal(old_refcount, sys.getrefcount(dt))
    np.array(MyArray(dt), copy=None)
    assert_equal(old_refcount, sys.getrefcount(dt))
    np.array(MyArray(dt), dtype=dt, copy=None)
    assert_equal(old_refcount, sys.getrefcount(dt))
    dt2 = np.dtype(np.int16)
    old_refcount2 = sys.getrefcount(dt2)
    np.array(MyArray(dt), dtype=dt2)
    assert_equal(old_refcount2, sys.getrefcount(dt2))
    np.array(MyArray(dt), dtype=dt2, copy=None)
    assert_equal(old_refcount2, sys.getrefcount(dt2))


@pytest.mark.parametrize("array", [True, False])
def test_array_impossible_casts(array):
    # All builtin types can be forcibly cast, at least theoretically,
    # but user dtypes cannot necessarily.
    rt = rational(1, 2)
    if array:
        rt = np.array(rt)

Review comment (bug):
I just realized you haven't fully tested the COPY_NEVER case.  Really, you should be testing `copy(True | False | None)`.  Currently, you're actually testing `copy(True | None)`.

This test fails:
```python
with pytest.raises(ValueError):
    np.array(MyArray(dt), dtype=dt2, copy=False)
assert_equal(old_refcount2, sys.getrefcount(dt2))
```

Adding `Py_DECREF(newtype);` to the `npy_no_copy_err_msg` branch fixes it.

I'm also suspicious about the `if (!PyArray_CheckExact(self))` branch (I think at the very least there should be `Py_XDECREF(newtype)` before the `return NULL;`, and possibly more than that), but I'm not totally sure how to test it.

Code after:
    assert_equal(np.array([(None,) * 10], dtype=np.float64),
                 np.full((1, 10), np.nan, dtype=np.float64))
    assert_equal(np.array([(None,) * 10] * 10, dtype=np.float64),
                 np.full((10, 10), np.nan, dtype=np.float64))

    assert_equal(np.array((1.0,) * 10, dtype=np.float64),
                 np.ones((10,), dtype=np.float64))
    assert_equal(np.array([(1.0,)] * 10, dtype=np.float64),
                 np.ones((10, 1), dtype=np.float64))
    assert_equal(np.array([(1.0,) * 10], dtype=np.float64),
                 np.ones((1, 10), dtype=np.float64))
    assert_equal(np.array([(1.0,) * 10] * 10, dtype=np.float64),
                 np.ones((10, 10), dtype=np.float64))


@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
def test___array___refcount():
    class MyArray:
        def __init__(self, dtype):
            self.val = np.array(-1, dtype=dtype)

        def __array__(self, dtype=None, copy=None):
            return self.val.__array__(dtype=dtype, copy=copy)

    # test all possible scenarios:
    # dtype(none | same | different) x copy(true | false | none)
    dt = np.dtype(np.int32)
    old_refcount = sys.getrefcount(dt)
    np.array(MyArray(dt))
    assert_equal(old_refcount, sys.getrefcount(dt))
    np.array(MyArray(dt), dtype=dt)
    assert_equal(old_refcount, sys.getrefcount(dt))
    np.array(MyArray(dt), copy=None)
    assert_equal(old_refcount, sys.getrefcount(dt))
    np.array(MyArray(dt), dtype=dt, copy=None)
    assert_equal(old_refcount, sys.getrefcount(dt))
    dt2 = np.dtype(np.int16)
    old_refcount2 = sys.getrefcount(dt2)
    np.array(MyArray(dt), dtype=dt2)
    assert_equal(old_refcount2, sys.getrefcount(dt2))
    np.array(MyArray(dt), dtype=dt2, copy=None)
    assert_equal(old_refcount2, sys.getrefcount(dt2))
    with pytest.raises(ValueError):
        np.array(MyArray(dt), dtype=dt2, copy=False)
    assert_equal(old_refcount2, sys.getrefcount(dt2))


@pytest.mark.parametrize("array", [True, False])
def test_array_impossible_casts(array):
    # All builtin types can be forcibly cast, at least theoretically,
    # but user dtypes cannot necessarily.