diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index b166996..4ef6c29 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -22,48 +22,52 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install base dependencies
- run: pip install tabulate pytest
+ run: pip install tabulate pytest pytest-subtests html5lib
- name: Test minimums
run: pytest tests/test_basic.py tests/test_list_like.py
- - name: Install test dependencies
- if: ${{ !contains(matrix.python-version, 'pypy') }} # no scipy wheels for pypy
- run: pip install pytest pytest-subtests html5lib scipy
+ - name: Install NumPy and SciPy
+ run: |
+ pip install --only-binary ":all:" numpy
+ pip install --only-binary ":all:" scipy || true
- - name: Python only scipy
- if: ${{ !contains(matrix.python-version, 'pypy') }} # no scipy wheels for pypy
+ - name: Test only SciPy
run: pytest
- name: Install other supported packages
- if: ${{ !contains(matrix.python-version, 'pypy') && matrix.python-version != '3.7' }} # no wheels for pypy and old python
run: |
- pip install suitesparse-graphblas==7.4.4.1a1
- pip install python-graphblas
- pip install sparse
- pip install torch
- pip install tensorflow
+ echo "=== Install Python-graphblas =================="
+ pip install --only-binary ":all:" python-graphblas || true
+ echo ""
+ echo "=== Install PyData/Sparse ====================="
+ pip install --only-binary ":all:" sparse || true
+ echo ""
+ echo "=== Install PyTorch ==========================="
+ pip install --only-binary ":all:" "torch>=2.0.0" || true
+ echo ""
+ echo "=== Install TensorFlow ========================="
+ pip install --only-binary ":all:" tensorflow || true
- name: Python Test without Jupyter
- if: ${{ !contains(matrix.python-version, 'pypy') }} # no scipy wheels for pypy
run: pytest
- name: Install Jupyter
- if: ${{ !contains(matrix.python-version, 'pypy') }} # no scipy wheels for pypy
+ if: ${{ !contains(matrix.python-version, 'pypy') }}
run: pip install jupyter
- name: Python Test with Jupyter
- if: ${{ !contains(matrix.python-version, 'pypy') }} # no scipy wheels for pypy
+ if: ${{ !contains(matrix.python-version, 'pypy') }}
run: pytest
- name: Python Test with Coverage
- if: ${{ contains(matrix.os, 'ubuntu') && !contains(matrix.python-version, 'pypy') }}
+ if: ${{ contains(matrix.os, 'ubuntu') }}
run: |
pip install pytest-cov
pytest --cov=matrepr --cov-report term --cov-report=xml
- name: Upload Coverage to Codecov
- if: ${{ contains(matrix.os, 'ubuntu') && !contains(matrix.python-version, 'pypy') }}
+ if: ${{ contains(matrix.os, 'ubuntu') }}
uses: codecov/codecov-action@v3
with:
gcov: true
diff --git a/matrepr/adapters/sparse_impl.py b/matrepr/adapters/sparse_impl.py
index c5fe4f4..1035283 100644
--- a/matrepr/adapters/sparse_impl.py
+++ b/matrepr/adapters/sparse_impl.py
@@ -37,9 +37,14 @@ def describe(self) -> str:
if hasattr(self.mat, "nbytes"):
parts.append(sizeof_fmt(self.mat.nbytes))
+ try:
+ fmt = self.mat.format
+ except AttributeError:
+ fmt = self.mat.__class__.__name__
+
return describe(shape=self.mat.shape,
nnz=self.mat.nnz, nz_type=self.mat.dtype,
- layout=self.mat.format,
+ layout=fmt,
notes=", ".join(parts))
diff --git a/pyproject.toml b/pyproject.toml
index 0215957..39abe33 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -43,4 +43,4 @@ repository = "https://github.com/alugowski/matrepr"
[project.optional-dependencies]
test = ["pytest", "html5lib", "scipy"]
-supported = ["scipy", "numpy", "python-graphblas", "sparse", "torch", "tensorflow"]
+supported = ["scipy", "numpy", "python-graphblas", "sparse", "torch>=2.0.0", "tensorflow"]
diff --git a/tests/test_graphblas.py b/tests/test_graphblas.py
index 2e7eb90..f63291b 100644
--- a/tests/test_graphblas.py
+++ b/tests/test_graphblas.py
@@ -13,10 +13,7 @@
# Context initialization must happen before any other imports
gb.init("suitesparse", blocking=False)
-
- have_gb = True
except ImportError:
- have_gb = False
gb = None
@@ -34,7 +31,7 @@ def generate_fixed_value(m, n):
return gb.Matrix.from_coo(rows, cols, data, nrows=m, ncols=n, dtype='int64'), data
-@unittest.skipIf(not have_gb, "python-graphblas not installed")
+@unittest.skipIf(not gb, "python-graphblas not installed")
class GraphBLASMatrixTests(unittest.TestCase):
def setUp(self):
mat = gb.Matrix.from_coo([0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], nrows=5, ncols=5)
@@ -81,7 +78,7 @@ def test_truncate(self):
self.assertEqual(expected_count, count)
-@unittest.skipIf(not have_gb, "python-graphblas not installed")
+@unittest.skipIf(not gb, "python-graphblas not installed")
class GraphBLASVectorTests(unittest.TestCase):
def setUp(self):
vec = gb.Vector.from_coo([0, 3, 4, 6], [12.1, -5.4, 2.9, 2.2], size=8)
@@ -121,7 +118,7 @@ def test_truncate(self):
self.assertIn(f"
{value} | ", res)
-@unittest.skipIf(not have_gb, "python-graphblas not installed")
+@unittest.skipIf(not gb, "python-graphblas not installed")
class PatchGraphBLASTests(unittest.TestCase):
def test_patch_graphblas(self):
mat = gb.Matrix.from_coo([0, 1], [0, 1], [111, 222], nrows=5, ncols=5),
diff --git a/tests/test_html.py b/tests/test_html.py
index 88cea9b..b92b112 100644
--- a/tests/test_html.py
+++ b/tests/test_html.py
@@ -6,12 +6,17 @@
import unittest
import html5lib
-import numpy.random
-import scipy.sparse
+try:
+ import scipy
+ import scipy.sparse
-from matrepr import to_html
+ import numpy.random
+ numpy.random.seed(123)
+except ImportError:
+ scipy = None
+ numpy = None
-numpy.random.seed(123)
+from matrepr import to_html
def generate_fixed_value(m, n):
@@ -28,6 +33,7 @@ def generate_fixed_value(m, n):
return scipy.sparse.coo_matrix((data, (rows, cols)), shape=(m, n), dtype='int64')
+@unittest.skipIf(scipy is None, "scipy not installed")
class ToHTMLTests(unittest.TestCase):
def setUp(self):
self.mats = [
diff --git a/tests/test_latex.py b/tests/test_latex.py
index d9c66da..9960628 100644
--- a/tests/test_latex.py
+++ b/tests/test_latex.py
@@ -4,12 +4,17 @@
import unittest
-import numpy.random
-import scipy.sparse
+try:
+ import scipy
+ import scipy.sparse
-from matrepr import to_latex
+ import numpy.random
+ numpy.random.seed(123)
+except ImportError:
+ scipy = None
+ numpy = None
-numpy.random.seed(123)
+from matrepr import to_latex
def generate_fixed_value(m, n):
@@ -26,6 +31,7 @@ def generate_fixed_value(m, n):
return scipy.sparse.coo_matrix((data, (rows, cols)), shape=(m, n), dtype='int64')
+@unittest.skipIf(scipy is None, "scipy not installed")
class ToLatexTests(unittest.TestCase):
def setUp(self):
self.mats = [
diff --git a/tests/test_numpy.py b/tests/test_numpy.py
index 65e4df1..b2e1712 100644
--- a/tests/test_numpy.py
+++ b/tests/test_numpy.py
@@ -4,13 +4,17 @@
import unittest
-import numpy as np
+try:
+ import numpy as np
-from matrepr import to_html, to_latex, to_str
+ np.random.seed(123)
+except ImportError:
+ np = None
-np.random.seed(123)
+from matrepr import to_html, to_latex, to_str
+@unittest.skipIf(np is None, "numpy not installed")
class NumpyTests(unittest.TestCase):
def setUp(self):
self.mats = [
diff --git a/tests/test_performance.py b/tests/test_performance.py
index 6153600..51a166f 100644
--- a/tests/test_performance.py
+++ b/tests/test_performance.py
@@ -5,14 +5,20 @@
import unittest
import time
-import numpy.random
-import scipy.sparse
+try:
+ import scipy
+ import scipy.sparse
-from matrepr import to_html
+ import numpy.random
+ numpy.random.seed(123)
+except ImportError:
+ scipy = None
+ numpy = None
-numpy.random.seed(123)
+from matrepr import to_html
+@unittest.skipIf(scipy is None, "scipy not installed")
class PerformanceTests(unittest.TestCase):
def test_to_html_speed(self):
# warmup, just in case
diff --git a/tests/test_scipy.py b/tests/test_scipy.py
index 6401f97..5be7391 100644
--- a/tests/test_scipy.py
+++ b/tests/test_scipy.py
@@ -4,12 +4,17 @@
import unittest
-import numpy.random
-import scipy.sparse
+try:
+ import scipy
+ import scipy.sparse
-from matrepr import to_html, to_latex, to_str
+ import numpy.random
+ numpy.random.seed(123)
+except ImportError:
+ scipy = None
+ numpy = None
-numpy.random.seed(123)
+from matrepr import to_html, to_latex, to_str
def generate_fixed_value(m, n):
@@ -26,6 +31,7 @@ def generate_fixed_value(m, n):
return scipy.sparse.coo_matrix((data, (rows, cols)), shape=(m, n), dtype='int64')
+@unittest.skipIf(scipy is None, "scipy not installed")
class SciPyTests(unittest.TestCase):
def setUp(self):
self.mats = [
@@ -66,6 +72,7 @@ def test_formats(self):
self.assertEqual(expected[i], res)
+@unittest.skipIf(scipy is None, "scipy not installed")
class PatchSciPyTests(unittest.TestCase):
def test_patch_scipy(self):
source_mat = scipy.sparse.coo_matrix(([111, 222], ([0, 1], [0, 1])), shape=(10, 10))
diff --git a/tests/test_sparse.py b/tests/test_sparse.py
index 35b6859..7bfec1a 100644
--- a/tests/test_sparse.py
+++ b/tests/test_sparse.py
@@ -10,11 +10,17 @@
except ImportError:
sparse = None
-from matrepr import to_html, to_latex, to_str
+try:
+ import scipy
+ import scipy.sparse
-import scipy
-import numpy as np
-np.random.seed(123)
+ import numpy.random
+ numpy.random.seed(123)
+except ImportError:
+ scipy = None
+ numpy = None
+
+from matrepr import to_html, to_latex, to_str
def generate_fixed_value(m, n):
@@ -39,10 +45,13 @@ def setUp(self):
sparse.COO(coords=np.array([1, 4]), data=np.array([11, 44]), shape=(10,)),
sparse.COO(np.empty(shape=(10, 10))),
sparse.random((10, 10), density=0.4),
- sparse.COO.from_scipy_sparse(generate_fixed_value(10, 10)),
sparse.COO(coords=np.array([[0, 0], [0, 0]]), data=np.array([111, 222]), shape=(13, 13)), # has dupes
sparse.COO(coords=np.array([[0, 1], [3, 2], [1, 3]]), data=np.array([111, 222]), shape=(5, 5, 5)),
]
+ if scipy is not None:
+ self.mats.append(
+ sparse.COO.from_scipy_sparse(generate_fixed_value(10, 10))
+ )
with warnings.catch_warnings():
# COO will incorrectly complain that the object is not ndarray when it is.
@@ -103,6 +112,7 @@ def test_truncate_1d(self):
for value in [1000, 1009]:
self.assertIn(f"{value} | ", res)
+ @unittest.skipIf(scipy is None, "scipy not installed")
def test_contents_2d(self):
mat = generate_fixed_value(10, 10)
sparse_mat = sparse.COO.from_scipy_sparse(mat)
@@ -110,6 +120,7 @@ def test_contents_2d(self):
for value in mat.data:
self.assertIn(f"{value} | ", res)
+ @unittest.skipIf(scipy is None, "scipy not installed")
def test_truncate_2d(self):
mat = generate_fixed_value(20, 20)
sparse_mat = sparse.COO.from_scipy_sparse(mat)
diff --git a/tests/test_str.py b/tests/test_str.py
index ca99636..59311fa 100644
--- a/tests/test_str.py
+++ b/tests/test_str.py
@@ -4,7 +4,15 @@
import unittest
-import scipy.sparse
+try:
+ import scipy
+ import scipy.sparse
+
+ import numpy.random
+ numpy.random.seed(123)
+except ImportError:
+ scipy = None
+ numpy = None
from matrepr import to_str
from matrepr.string_formatter import max_line_width
@@ -24,6 +32,7 @@ def generate_fixed_value(m, n):
return scipy.sparse.coo_matrix((data, (rows, cols)), shape=(m, n), dtype='int64')
+@unittest.skipIf(scipy is None, "scipy not installed")
class ToStrTests(unittest.TestCase):
def setUp(self):
self.mats = [
diff --git a/tests/test_torch.py b/tests/test_torch.py
index 6972bb0..12aa256 100644
--- a/tests/test_torch.py
+++ b/tests/test_torch.py
@@ -5,17 +5,17 @@
import unittest
import warnings
-import numpy as np
-
try:
import torch
+
+ import numpy.random
+ numpy.random.seed(123)
except ImportError:
torch = None
+ numpy = None
from matrepr import to_html, to_latex, to_str
-np.random.seed(123)
-
def generate_fixed_value(m, n):
row_factor = 10**(1+len(str(n)))