diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index be082c47..00babcfd 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -79,12 +79,12 @@ jobs: fail-fast: true matrix: os: ["ubuntu-latest", "macos-latest", "windows-latest"] - python-version: ["3.7", "3.13"] + python-version: ["3.8", "3.13"] exclude: # Latest macos runner does not support older Python versions # https://github.com/actions/setup-python/issues/852 - os: macos-latest - python-version: "3.7" + python-version: "3.8" steps: - uses: actions/checkout@v4 with: @@ -100,10 +100,10 @@ jobs: python -m pip install --upgrade pip wheel python -m pip install --editable .[dev] - name: Downgrade numpy - if: ${{ matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.8' }} run: | # test with older numpy version to ensure compatibility - python -m pip install numpy==1.15 + python -m pip install numpy~=1.17.5 - name: Test with pytest run: | pytest -v --benchmark-disable -n auto @@ -129,7 +129,7 @@ jobs: platforms: arm64 - uses: pypa/cibuildwheel@v2.21.3 env: - CIBW_SKIP: cp36-* pp*-win* pp*-macosx* *_i686 + CIBW_SKIP: cp36-* cp37-* pp*-win* pp*-macosx* *_i686 CIBW_TEST_SKIP: "*-win_arm64" CIBW_ARCHS_LINUX: "x86_64 aarch64" CIBW_ARCHS_MACOS: "x86_64 arm64 universal2" diff --git a/README.md b/README.md index 09d46e83..e4c7b3b4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for full details. ### Prerequisites - Git and Git LFS -- Python >= 3.7 +- Python >= 3.8 - Miniconda3 - C compiler such as GCC or Clang diff --git a/cryosparc/dataset.py b/cryosparc/dataset.py index 037c7a8a..1030f718 100644 --- a/cryosparc/dataset.py +++ b/cryosparc/dataset.py @@ -36,11 +36,13 @@ Generator, Generic, List, + Literal, Mapping, MutableMapping, Optional, Sequence, Set, + SupportsIndex, Tuple, Type, Union, @@ -48,7 +50,6 @@ ) import numpy as n -from typing_extensions import Literal, SupportsIndex from .column import Column from .core import Data, DsetType, Stream diff --git a/cryosparc/dtype.py b/cryosparc/dtype.py index c5e350ba..682584a2 100644 --- a/cryosparc/dtype.py +++ b/cryosparc/dtype.py @@ -3,10 +3,9 @@ """ import json -from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type, Union +from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Sequence, Tuple, Type, TypedDict, Union import numpy as n -from typing_extensions import Literal, Sequence, TypedDict from .core import Data, DsetType diff --git a/cryosparc/errors.py b/cryosparc/errors.py index 15847544..24f72e1e 100644 --- a/cryosparc/errors.py +++ b/cryosparc/errors.py @@ -2,9 +2,7 @@ Definitions for various error classes raised by cryosparc-tools functions """ -from typing import Any, List - -from typing_extensions import TypedDict +from typing import Any, List, TypedDict from .spec import Datafield, Datatype, SlotSpec diff --git a/cryosparc/job.py b/cryosparc/job.py index e5d7349c..c9c5bfa3 100644 --- a/cryosparc/job.py +++ b/cryosparc/job.py @@ -10,10 +10,9 @@ from io import BytesIO from pathlib import PurePath, PurePosixPath from time import sleep, time -from typing import IO, TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Pattern, Union, overload +from typing import IO, TYPE_CHECKING, Any, Dict, Iterable, List, Literal, Optional, Pattern, Union, overload import numpy as n -from typing_extensions import Literal from .command import CommandError, make_json_request, make_request from .dataset import DEFAULT_FORMAT, Dataset diff --git a/cryosparc/spec.py b/cryosparc/spec.py index 0e05777c..8482331b 100644 --- a/cryosparc/spec.py +++ b/cryosparc/spec.py @@ -20,12 +20,7 @@ """ from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, Dict, Generic, List, Optional, Tuple, TypeVar, Union - -from typing_extensions import Literal, TypedDict - -if TYPE_CHECKING: - from typing_extensions import Self # not present in typing-extensions=3.7 +from typing import Any, Dict, Generic, List, Literal, Optional, Tuple, TypedDict, TypeVar, Union # Database document D = TypeVar("D") @@ -964,6 +959,6 @@ def doc(self) -> D: return self._doc @abstractmethod - def refresh(self) -> "Self": + def refresh(self): # Must be implemented in subclasses return self diff --git a/cryosparc/star.py b/cryosparc/star.py index d1640db2..924c89df 100644 --- a/cryosparc/star.py +++ b/cryosparc/star.py @@ -3,10 +3,23 @@ """ from pathlib import PurePath -from typing import IO, TYPE_CHECKING, Any, Callable, Dict, List, Mapping, Optional, Tuple, Type, Union, overload +from typing import ( + IO, + TYPE_CHECKING, + Any, + Callable, + Dict, + List, + Literal, + Mapping, + Optional, + Tuple, + Type, + Union, + overload, +) import numpy as n -from typing_extensions import Literal if TYPE_CHECKING: from numpy.typing import NDArray # type: ignore diff --git a/cryosparc/stream.py b/cryosparc/stream.py index b1ab6d13..8c5a1af6 100644 --- a/cryosparc/stream.py +++ b/cryosparc/stream.py @@ -4,21 +4,20 @@ from pathlib import PurePath from typing import ( IO, - TYPE_CHECKING, Any, AsyncGenerator, + AsyncIterable, AsyncIterator, BinaryIO, Generator, + Iterable, Iterator, Optional, + Protocol, Union, ) -from typing_extensions import Protocol - -if TYPE_CHECKING: - from typing_extensions import Self # not present in typing-extensions=3.7 +from typing_extensions import Self class AsyncBinaryIO(Protocol): @@ -93,7 +92,7 @@ async def read(self, n: Optional[int] = None): out = [] if n is None or n < 0: while True: - m = self._read1() + m = await self._read1() if not m: break out.append(m) @@ -153,8 +152,8 @@ async def from_async_iterator(cls, iterator: Union[AsyncIterator[bytes], AsyncGe return await cls.from_async_stream(AsyncBinaryIteratorIO(iterator)) @abstractmethod - def stream(self) -> Generator[bytes, None, None]: ... + def stream(self) -> Iterable[bytes]: ... - async def astream(self): + async def astream(self) -> AsyncIterable[bytes]: for chunk in self.stream(): yield chunk diff --git a/cryosparc/util.py b/cryosparc/util.py index cf46df91..941380e0 100644 --- a/cryosparc/util.py +++ b/cryosparc/util.py @@ -310,10 +310,7 @@ def default_rng(seed=None) -> "n.random.Generator": Returns: numpy.random.Generator: Random number generator """ - try: - return n.random.default_rng(seed) - except AttributeError: - return n.random.RandomState(seed) # type: ignore + return n.random.default_rng(seed) def random_integers( @@ -337,11 +334,7 @@ def random_integers( Returns: NDArray: Numpy array of randomly-generated integers. """ - try: - f = rng.integers - except AttributeError: - f = rng.randint # type: ignore - return f(low=low, high=high, size=size, dtype=dtype) # type: ignore + return rng.integers(low=low, high=high, size=size, dtype=dtype) # type: ignore def print_table(headings: List[str], rows: List[List[str]]): diff --git a/docs/intro.md b/docs/intro.md index 7179f17d..13d3d52d 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -23,7 +23,7 @@ Source code is [available on GitHub](https://github.com/cryoem-uoft/cryosparc-to ## Pre-requisites -- [Python ≥ 3.7](https://www.python.org/downloads/) +- [Python ≥ 3.8](https://www.python.org/downloads/) - [CryoSPARC ≥ v4.1](https://cryosparc.com/download) CryoSPARC installation must be accessible via one of the following methods: diff --git a/pyproject.toml b/pyproject.toml index dc64e932..45e74284 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "cryosparc-tools" version = "4.6.1" description = "Toolkit for interfacing with CryoSPARC" readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.8" authors = [ { name = "Structura Biotechnology Inc.", email = "info@structura.bio" }, ] @@ -20,7 +20,10 @@ classifiers = [ "Topic :: Software Development :: Libraries", ] license = { file = "LICENSE" } -dependencies = ["numpy >= 1.15, < 3.0", "typing-extensions >= 3.7"] +dependencies = [ + "numpy >= 1.17, < 3.0", + "typing-extensions >= 4.0", +] [project.optional-dependencies] dev = [ diff --git a/tests/test_dataset.py b/tests/test_dataset.py index b4c3036a..7aa42b61 100644 --- a/tests/test_dataset.py +++ b/tests/test_dataset.py @@ -320,7 +320,7 @@ def test_column_aggregation(t20s_dset): assert not isinstance(n.mean(t20s_dset["uid"]), n.ndarray) -@pytest.mark.skipif(n.__version__.startswith("1.15."), reason="works with newer numpy versions, use case is limited") +@pytest.mark.skipif(n.__version__.startswith("1.17."), reason="works with newer numpy versions, use case is limited") def test_row_array_type(t20s_dset): rowarr = n.array(t20s_dset.rows()) assert isinstance(rowarr[0], Row)