diff --git a/docs/generated/sparse.COO.__array__.rst b/docs/generated/sparse.COO.__array__.rst new file mode 100644 index 00000000..d2ff7ba3 --- /dev/null +++ b/docs/generated/sparse.COO.__array__.rst @@ -0,0 +1,6 @@ +COO\.\_\_array\_\_ +================== + +.. currentmodule:: sparse + +.. automethod:: COO.__array__ diff --git a/docs/generated/sparse.COO.rst b/docs/generated/sparse.COO.rst index 99fcb719..21826cfb 100644 --- a/docs/generated/sparse.COO.rst +++ b/docs/generated/sparse.COO.rst @@ -68,6 +68,7 @@ COO COO.to_scipy_sparse COO.tocsc COO.tocsr + COO.__array__ .. rubric:: :doc:`Other operations <../user_manual/operations/other>` .. autosummary:: diff --git a/sparse/core.py b/sparse/core.py index ecf59639..47a98fdf 100644 --- a/sparse/core.py +++ b/sparse/core.py @@ -488,6 +488,31 @@ def nbytes(self): """ return self.data.nbytes + self.coords.nbytes + def __array__(self, dtype=None): + """ + Helper function that gets called during :code:`np.array(x)` conversion. + We deliberately return :code:`NotImplemented` to prevent accidental + densification. + + Parameters + ---------- + dtype: type + Datatype requested by :code:`np.array(x)`. Has no effect on + output. + + Returns + ------- + NotImplemented + We do not implement this function, so we return + :obj:`NotImplemented`. + + See Also + -------- + numpy.ndarray.__array__ : Numpy equivalent function. + + """ + return NotImplemented + def __len__(self): """ Get "length" of array, which is by definition the size of the first @@ -2374,7 +2399,8 @@ def maybe_densify(self, allowed_nnz=1000, allowed_fraction=0.25): >>> s.maybe_densify(allowed_nnz=5, allowed_fraction=0.25) Traceback (most recent call last): ... - NotImplementedError: Operation would require converting large sparse array to dense + NotImplementedError: Operation would require converting large sparse \ +array to dense. Use .todense() to force densification. """ elements = np.prod(self.shape) @@ -2382,7 +2408,8 @@ def maybe_densify(self, allowed_nnz=1000, allowed_fraction=0.25): return self.todense() else: raise NotImplementedError("Operation would require converting " - "large sparse array to dense") + "large sparse array to dense. Use " + ".todense() to force densification.") def tensordot(a, b, axes=2): diff --git a/sparse/tests/test_core.py b/sparse/tests/test_core.py index 94800a26..b9e7513b 100644 --- a/sparse/tests/test_core.py +++ b/sparse/tests/test_core.py @@ -887,3 +887,16 @@ def test_scalar_shape_construction(): def test_len(): s = sparse.random((20, 30, 40)) assert len(s) == 20 + + +def test_numpy_todense(): + # make sure that .astype(int) is never all zeros + s = sparse.random((20, 30, 40)) * 100 + with pytest.raises(ValueError): + assert np.array(s) + + with pytest.raises(ValueError): + assert np.array(s, dtype=int) + + with pytest.raises(ValueError): + assert np.allclose(s, s.todense())