diff --git a/.github/workflows/pypi-test.yml b/.github/workflows/pypi-test.yml index 332bf3e..901a65f 100644 --- a/.github/workflows/pypi-test.yml +++ b/.github/workflows/pypi-test.yml @@ -1,7 +1,4 @@ -# This workflow will install Python dependencies, run tests and lint with a single version of Python -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Test the library +name: Unit tests on: push: @@ -13,17 +10,22 @@ jobs: build: runs-on: ubuntu-latest + strategy: + matrix: + python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] + name: Python ${{ matrix.python-version }} steps: - uses: actions/checkout@v2 - - name: Set up Python 3.9 + - name: Setup Python uses: actions/setup-python@v2 with: - python-version: 3.9 + python-version: ${{ matrix.python-version }} + cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip - pip install flake8 pytest tox scipy + pip install flake8 pytest tox # - name: Lint with flake8 # run: | # # stop the build if there are Python syntax errors or undefined names diff --git a/setup.cfg b/setup.cfg index 3f11686..b8f4945 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,7 +41,7 @@ package_dir = =src # Require a min/specific Python version (comma-separated conditions) -# python_requires = >=3.8 +python_requires = >=3.8 # Add here dependencies of your project (line-separated), e.g. requests>=2.2,<3.0. # Version specifiers like >=2.2,<3.0 avoid problems due to API changes in @@ -50,6 +50,7 @@ package_dir = install_requires = importlib-metadata; python_version<"3.8" numpy + biocutils [options.packages.find] diff --git a/src/delayedarray/SparseNdarray.py b/src/delayedarray/SparseNdarray.py index edfae90..3bbf4d3 100644 --- a/src/delayedarray/SparseNdarray.py +++ b/src/delayedarray/SparseNdarray.py @@ -1463,7 +1463,7 @@ def _recursive_concatenate_SparseNdarray(contents: list, final_shape: Tuple[int, return new_contents -def _concatenate_SparseNdarray(xs: list[SparseNdarray], along: int): +def _concatenate_SparseNdarray(xs: List[SparseNdarray], along: int): all_contents = [] all_shapes = [] for x in xs: diff --git a/src/delayedarray/chunk_shape.py b/src/delayedarray/chunk_shape.py index 6dc4f7b..d60a69d 100644 --- a/src/delayedarray/chunk_shape.py +++ b/src/delayedarray/chunk_shape.py @@ -1,6 +1,7 @@ from functools import singledispatch from typing import Any, Tuple from numpy import ndarray +from biocutils.package_utils import is_package_installed from .SparseNdarray import SparseNdarray @@ -51,28 +52,23 @@ def chunk_shape_SparseNdarray(x: SparseNdarray): # If scipy is installed, we add all the methods for the various scipy.sparse matrices. -has_sparse = False -try: - import scipy.sparse - has_sparse = True -except: - pass +if is_package_installed("scipy"): + import scipy.sparse as sp -if has_sparse: @chunk_shape.register - def chunk_shape_csc_matrix(x: scipy.sparse.csc_matrix): + def chunk_shape_csc_matrix(x: sp.csc_matrix): """See :py:meth:`~delayedarray.chunk_shape.chunk_shape`.""" return (x.shape[0], 1) @chunk_shape.register - def chunk_shape_csr_matrix(x: scipy.sparse.csr_matrix): + def chunk_shape_csr_matrix(x: sp.csr_matrix): """See :py:meth:`~delayedarray.chunk_shape.chunk_shape`.""" return (1, x.shape[1]) @chunk_shape.register - def chunk_shape_coo_matrix(x: scipy.sparse.coo_matrix): + def chunk_shape_coo_matrix(x: sp.coo_matrix): """See :py:meth:`~delayedarray.chunk_shape.chunk_shape`.""" return x.shape # ???? well, let's just do our best. diff --git a/src/delayedarray/extract_dense_array.py b/src/delayedarray/extract_dense_array.py index 261a140..a2ac8f8 100644 --- a/src/delayedarray/extract_dense_array.py +++ b/src/delayedarray/extract_dense_array.py @@ -1,6 +1,7 @@ from functools import singledispatch from numpy import array, ndarray, ix_, asfortranarray from typing import Any, Optional, Tuple, Sequence +from biocutils.package_utils import is_package_installed from ._subset import _spawn_indices, _is_subset_noop from .SparseNdarray import SparseNdarray, _extract_dense_array_from_SparseNdarray @@ -58,17 +59,9 @@ def _sanitize_to_fortran(x): else: return asfortranarray(x) +if is_package_installed("scipy"): + import scipy.sparse as sp -# If scipy is installed, we add all the methods for the various scipy.sparse matrices. -has_sparse = False -try: - import scipy.sparse - has_sparse = True -except: - pass - - -if has_sparse: def _extract_dense_array_sparse(x, subset: Optional[Tuple[Sequence[int], ...]] = None): if _is_subset_noop(x.shape, subset): tmp = x @@ -77,21 +70,26 @@ def _extract_dense_array_sparse(x, subset: Optional[Tuple[Sequence[int], ...]] = return tmp.toarray(order="F") @extract_dense_array.register - def extract_dense_array_csc_matrix(x: scipy.sparse.csc_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): + def extract_dense_array_csc_matrix(x: sp.csc_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): """See :py:meth:`~delayedarray.extract_dense_array.extract_dense_array`.""" return _extract_dense_array_sparse(x, subset) @extract_dense_array.register - def extract_dense_array_csr_matrix(x: scipy.sparse.csr_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): + def extract_dense_array_csr_matrix(x: sp.csr_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): """See :py:meth:`~delayedarray.extract_dense_array.extract_dense_array`.""" return _extract_dense_array_sparse(x, subset) @extract_dense_array.register - def extract_dense_array_coo_matrix(x: scipy.sparse.coo_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): + def extract_dense_array_coo_matrix(x: sp.coo_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): """See :py:meth:`~delayedarray.extract_dense_array.extract_dense_array`.""" return _extract_dense_array_sparse(x, subset) - @extract_dense_array.register - def extract_dense_array_sparse_array(x: scipy.sparse.sparray, subset: Optional[Tuple[Sequence[int], ...]] = None): + def extract_dense_array_sparse_array(x, subset: Optional[Tuple[Sequence[int], ...]] = None): """See :py:meth:`~delayedarray.extract_dense_array.extract_dense_array`.""" return _extract_dense_array_sparse(x, subset) + + try: + extract_dense_array.register(sp.sparray, extract_dense_array_sparse_array) + except Exception: + pass + diff --git a/src/delayedarray/extract_sparse_array.py b/src/delayedarray/extract_sparse_array.py index 45bd98d..edd1123 100644 --- a/src/delayedarray/extract_sparse_array.py +++ b/src/delayedarray/extract_sparse_array.py @@ -2,6 +2,7 @@ from numpy import array, ndarray, ix_ from bisect import bisect_left from typing import Any, Optional, Tuple, Sequence +from biocutils.package_utils import is_package_installed from ._subset import _spawn_indices, _is_subset_noop, _is_subset_consecutive from .SparseNdarray import SparseNdarray, _extract_sparse_array_from_SparseNdarray @@ -44,17 +45,9 @@ def extract_sparse_array_SparseNdarray(x: SparseNdarray, subset: Optional[Tuple[ else: return _extract_sparse_array_from_SparseNdarray(x, subset) +if is_package_installed("scipy"): + import scipy.sparse as sp -# If scipy is installed, we add all the methods for the various scipy.sparse matrices. -has_sparse = False -try: - import scipy.sparse - has_sparse = True -except: - pass - - -if has_sparse: def _set_empty_contents(contents): for x in contents: if x is not None: @@ -62,7 +55,7 @@ def _set_empty_contents(contents): return contents @extract_sparse_array.register - def extract_sparse_array_csc_matrix(x: scipy.sparse.csc_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): + def extract_sparse_array_csc_matrix(x: sp.csc_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): """See :py:meth:`~delayedarray.extract_sparse_array.extract_sparse_array`.""" if subset is None: subset = _spawn_indices(x.shape) @@ -120,7 +113,7 @@ def extract_sparse_array_csc_matrix(x: scipy.sparse.csc_matrix, subset: Optional return SparseNdarray((*final_shape,), new_contents, dtype=x.dtype, index_dtype=x.indices.dtype, check=False) @extract_sparse_array.register - def extract_sparse_array_csr_matrix(x: scipy.sparse.csr_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): + def extract_sparse_array_csr_matrix(x: sp.csr_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): """See :py:meth:`~delayedarray.extract_sparse_array.extract_sparse_array`.""" if subset is None: subset = _spawn_indices(x.shape) @@ -180,7 +173,7 @@ def extract_sparse_array_csr_matrix(x: scipy.sparse.csr_matrix, subset: Optional return SparseNdarray((*final_shape,), new_contents, dtype=x.dtype, index_dtype=x.indices.dtype, check=False) @extract_sparse_array.register - def extract_sparse_array_coo_matrix(x: scipy.sparse.coo_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): + def extract_sparse_array_coo_matrix(x: sp.coo_matrix, subset: Optional[Tuple[Sequence[int], ...]] = None): """See :py:meth:`~delayedarray.extract_sparse_array.extract_sparse_array`.""" if subset is None: subset = _spawn_indices(x.shape) diff --git a/src/delayedarray/is_sparse.py b/src/delayedarray/is_sparse.py index ee61ea5..fbe915b 100644 --- a/src/delayedarray/is_sparse.py +++ b/src/delayedarray/is_sparse.py @@ -1,5 +1,6 @@ from functools import singledispatch from typing import Any +from biocutils.package_utils import is_package_installed from .SparseNdarray import SparseNdarray @@ -29,26 +30,21 @@ def is_sparse_SparseNdarray(x: SparseNdarray): # If scipy is installed, we add all the methods for the various scipy.sparse matrices. -has_sparse = False -try: - import scipy.sparse - has_sparse = True -except: - pass +if is_package_installed("scipy"): + import scipy.sparse as sp -if has_sparse: @is_sparse.register - def is_sparse_csc_matrix(x: scipy.sparse.csc_matrix): + def is_sparse_csc_matrix(x: sp.csc_matrix): """See :py:meth:`~delayedarray.is_sparse.is_sparse`.""" return True @is_sparse.register - def is_sparse_csr_matrix(x: scipy.sparse.csr_matrix): + def is_sparse_csr_matrix(x: sp.csr_matrix): """See :py:meth:`~delayedarray.is_sparse.is_sparse`.""" return True @is_sparse.register - def is_sparse_coo_matrix(x: scipy.sparse.coo_matrix): + def is_sparse_coo_matrix(x: sp.coo_matrix): """See :py:meth:`~delayedarray.is_sparse.is_sparse`.""" return True