Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci-gpu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: hynek/setup-cached-uv@v2
- uses: astral-sh/setup-uv@v6
with:
cache-dependency-path: pyproject.toml
enable-cache: true # "auto" is `false` on non-GitHub runners
- name: Install package
run: uv pip install --system -e .[test,full] cupy-cuda12x --extra-index-url=https://pypi.nvidia.com --index-strategy=unsafe-best-match
- name: List installed packages
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
steps:
- uses: actions/checkout@v5
with: { fetch-depth: 0, filter: "blob:none" }
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- uses: astral-sh/setup-uv@v7
Expand All @@ -90,7 +90,7 @@ jobs:
steps:
- uses: actions/checkout@v5
with: { fetch-depth: 0, filter: "blob:none" }
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- uses: astral-sh/setup-uv@v7
Expand All @@ -110,7 +110,7 @@ jobs:
steps:
- uses: actions/checkout@v5
with: { fetch-depth: 0, filter: "blob:none" }
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- uses: pre-commit/action@v3.0.1
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ jobs:
permissions:
id-token: write # to authenticate as Trusted Publisher to pypi.org
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.x"
cache: pip
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 2
build:
os: ubuntu-24.04
tools:
python: "3.12"
python: "3.13"
python:
install:
- method: pip
Expand Down
9 changes: 7 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@
from typing import TYPE_CHECKING

from docutils.nodes import Text
from sphinx.util import logging


if TYPE_CHECKING:
from typing import Final

from docutils.nodes import TextElement, reference
from sphinx.addnodes import pending_xref
from sphinx.application import Sphinx
from sphinx.environment import BuildEnvironment


HERE = Path(__file__).parent
HERE: Final = Path(__file__).parent
LOGGER: Final = logging.getLogger("fast_array_utils")


# -- General configuration ------------------------------------------------
Expand Down Expand Up @@ -134,7 +138,8 @@ def resolve_type_aliases(app: Sphinx, env: BuildEnvironment, node: pending_xref,
ref = resolve_reference_any_inventory(env=env, honor_disabled_refs=False, node=node, contnode=contnode)
if ref is None:
msg = f"Could not resolve {typ} {target} (from {node['reftarget']})"
raise AssertionError(msg)
LOGGER.warning(msg, type="ref")
return ref
if name:
ref.children[:] = [Text(name)]
return ref
Expand Down
7 changes: 3 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ license = "MPL-2.0"
authors = [
{ name = "Philipp A.", email = "flying-sheep@web.de" },
]
requires-python = ">=3.11"
requires-python = ">=3.12"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
Expand Down Expand Up @@ -107,11 +106,11 @@ overrides.matrix.resolution.dependencies = [
]

[[tool.hatch.envs.hatch-test.matrix]]
python = [ "3.13", "3.11" ]
python = [ "3.13", "3.12" ]
extras = [ "full", "min" ]

[[tool.hatch.envs.hatch-test.matrix]]
python = [ "3.11" ]
python = [ "3.12" ]
extras = [ "full" ]
resolution = [ "lowest" ]

Expand Down
2 changes: 1 addition & 1 deletion src/fast_array_utils/conv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from typing import TYPE_CHECKING, overload

from ..typing import CpuArray, DiskArray, GpuArray # noqa: TC001
from ._to_dense import to_dense_


Expand All @@ -15,6 +14,7 @@
from numpy.typing import NDArray

from .. import types
from ..typing import CpuArray, DiskArray, GpuArray


__all__ = ["to_dense"]
Expand Down
3 changes: 2 additions & 1 deletion src/fast_array_utils/conv/_to_dense.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
import numpy as np

from .. import types
from ..typing import CpuArray, DiskArray, GpuArray # noqa: TC001


if TYPE_CHECKING:
from typing import Any, Literal

from numpy.typing import NDArray

from ..typing import CpuArray, DiskArray, GpuArray


# fallback’s arg0 type has to include types of registered functions
@singledispatch
Expand Down
2 changes: 1 addition & 1 deletion src/fast_array_utils/stats/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from typing import TYPE_CHECKING, cast, get_args, overload

from .._validation import validate_axis
from ..typing import CpuArray, DiskArray, GpuArray # noqa: TC001
from ._generic_ops import DtypeOps


Expand All @@ -22,6 +21,7 @@
from optype.numpy import ToDType

from .. import types
from ..typing import CpuArray, DiskArray, GpuArray
from ._generic_ops import Ops
from ._typing import NoDtypeOps, StatFunDtype, StatFunNoDtype

Expand Down
4 changes: 2 additions & 2 deletions src/fast_array_utils/stats/_generic_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@


if TYPE_CHECKING:
from typing import Any, Literal, TypeAlias
from typing import Any, Literal

from numpy.typing import DTypeLike, NDArray

from ..typing import CpuArray, DiskArray, GpuArray
from ._typing import Ops

ComplexAxis: TypeAlias = tuple[Literal[0], Literal[1]] | tuple[Literal[0, 1]] | Literal[0, 1] | None
type ComplexAxis = tuple[Literal[0], Literal[1]] | tuple[Literal[0, 1]] | Literal[0, 1] | None


def _run_numpy_op(
Expand Down
5 changes: 1 addition & 4 deletions src/fast_array_utils/stats/_is_constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@


if TYPE_CHECKING:
from collections.abc import Callable
from typing import Any, Literal, TypeVar
from typing import Any, Literal

from numpy.typing import NDArray

C = TypeVar("C", bound=Callable[..., Any])


@singledispatch
def is_constant_(
Expand Down
11 changes: 3 additions & 8 deletions src/fast_array_utils/stats/_power.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,15 @@


if TYPE_CHECKING:
from typing import TypeAlias, TypeVar

from numpy.typing import DTypeLike

from fast_array_utils.typing import CpuArray, GpuArray

# All supported array types except for disk ones and CSDataset
Array: TypeAlias = CpuArray | GpuArray | types.DaskArray

_Arr = TypeVar("_Arr", bound=Array)
_Mat = TypeVar("_Mat", bound=types.CSBase | types.CupyCSMatrix)
type Array = CpuArray | GpuArray | types.DaskArray


def power(x: _Arr, n: int, /, dtype: DTypeLike | None = None) -> _Arr:
def power[Arr: Array](x: Arr, n: int, /, dtype: DTypeLike | None = None) -> Arr:
"""Take array or matrix to a power."""
# This wrapper is necessary because TypeVars can’t be used in `singledispatch` functions
return _power(x, n, dtype=dtype) # type: ignore[return-value]
Expand All @@ -37,7 +32,7 @@ def _power(x: Array, n: int, /, dtype: DTypeLike | None = None) -> Array:


@_power.register(types.CSBase | types.CupyCSMatrix)
def _power_cs(x: _Mat, n: int, /, dtype: DTypeLike | None = None) -> _Mat:
def _power_cs[Mat: types.CSBase | types.CupyCSMatrix](x: Mat, n: int, /, dtype: DTypeLike | None = None) -> Mat:
new_data = power(x.data, n, dtype=dtype)
return type(x)((new_data, x.indices, x.indptr), shape=x.shape, dtype=new_data.dtype) # type: ignore[call-overload,return-value]

Expand Down
21 changes: 9 additions & 12 deletions src/fast_array_utils/stats/_typing.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: MPL-2.0
from __future__ import annotations

from typing import TYPE_CHECKING, Generic, Literal, Protocol, TypedDict, TypeVar
from typing import TYPE_CHECKING, Literal, Protocol, TypedDict

import numpy as np

Expand All @@ -11,17 +11,17 @@


if TYPE_CHECKING:
from typing import Any, TypeAlias
from typing import Any

from numpy.typing import DTypeLike, NDArray


Array: TypeAlias = CpuArray | GpuArray | DiskArray | types.CSDataset | types.DaskArray
type Array = CpuArray | GpuArray | DiskArray | types.CSDataset | types.DaskArray

DTypeIn: TypeAlias = np.float32 | np.float64 | np.int32 | np.bool_
DTypeOut: TypeAlias = np.float32 | np.float64 | np.int64
type DTypeIn = np.float32 | np.float64 | np.int32 | np.bool_
type DTypeOut = np.float32 | np.float64 | np.int64

NdAndAx: TypeAlias = tuple[Literal[1], None] | tuple[Literal[2], Literal[0, 1] | None]
type NdAndAx = tuple[Literal[1], None] | tuple[Literal[2], Literal[0, 1] | None]


class StatFunNoDtype(Protocol):
Expand All @@ -48,11 +48,8 @@ def __call__(

NoDtypeOps = Literal["max", "min"]
DtypeOps = Literal["sum"]
Ops: TypeAlias = NoDtypeOps | DtypeOps
type Ops = NoDtypeOps | DtypeOps


_DT = TypeVar("_DT", bound="DTypeLike")


class DTypeKw(TypedDict, Generic[_DT], total=False):
dtype: _DT
class DTypeKw[DT: DTypeLike](TypedDict, total=False):
dtype: DT
16 changes: 6 additions & 10 deletions src/fast_array_utils/stats/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@
from __future__ import annotations

from functools import partial
from typing import TYPE_CHECKING, Literal, TypeVar, cast, get_args
from typing import TYPE_CHECKING, Literal, cast, get_args

import numpy as np
from numpy.exceptions import AxisError

from .. import types
from ..typing import GpuArray
from ._typing import DtypeOps


if TYPE_CHECKING:
from typing import Any, Literal, TypeAlias
from typing import Any, Literal

from numpy.typing import DTypeLike, NDArray

from ..typing import CpuArray
from ..typing import CpuArray, GpuArray
from ._typing import DTypeKw, Ops

ComplexAxis: TypeAlias = tuple[Literal[0], Literal[1]] | tuple[Literal[0, 1]] | Literal[0, 1] | None
type ComplexAxis = tuple[Literal[0], Literal[1]] | tuple[Literal[0, 1]] | Literal[0, 1] | None


__all__ = ["_dask_inner"]
Expand Down Expand Up @@ -71,7 +70,7 @@ def _dask_block(
from . import max, min, sum

if computing_meta: # dask.blockwise doesn’t allow to pass `meta` in, and reductions below don’t handle a 0d matrix
return (types.CupyArray if isinstance(a, GpuArray) else np.ndarray)((), dtype or a.dtype)
return (types.CupyArray if isinstance(a, types.CupyArray | types.CupyCSMatrix) else np.ndarray)((), dtype or a.dtype)

fns = {fn.__name__: fn for fn in (min, max, sum)}

Expand Down Expand Up @@ -114,8 +113,5 @@ def _get_shape(a: NDArray[Any] | np.number[Any] | types.CupyArray, *, axis: Lite
raise AssertionError(msg)


DT = TypeVar("DT", bound="DTypeLike")


def _dtype_kw(dtype: DT | None, op: Ops) -> DTypeKw[DT]:
def _dtype_kw[DT: DTypeLike](dtype: DT | None, op: Ops) -> DTypeKw[DT]:
return {"dtype": dtype} if dtype is not None and op in get_args(DtypeOps) else {}
4 changes: 1 addition & 3 deletions src/fast_array_utils/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from __future__ import annotations

from importlib.util import find_spec
from typing import TYPE_CHECKING, TypeVar
from typing import TYPE_CHECKING


__all__ = [
Expand Down Expand Up @@ -34,8 +34,6 @@
"spmatrix",
]

T_co = TypeVar("T_co", covariant=True)


# scipy sparse
if TYPE_CHECKING:
Expand Down
7 changes: 4 additions & 3 deletions src/fast_array_utils/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@

__all__ = ["CpuArray", "DiskArray", "GpuArray"]

# change to `type` syntax once this is released: https://github.com/sphinx-doc/sphinx/pull/13508

CpuArray: TypeAlias = NDArray[Any] | types.CSBase
CpuArray: TypeAlias = NDArray[Any] | types.CSBase # noqa: UP040
"""Arrays and matrices stored in CPU memory."""

GpuArray: TypeAlias = types.CupyArray | types.CupyCSMatrix
GpuArray: TypeAlias = types.CupyArray | types.CupyCSMatrix # noqa: UP040
"""Arrays and matrices stored in GPU memory."""

# TODO(flying-sheep): types.CSDataset # noqa: TD003
DiskArray: TypeAlias = types.H5Dataset | types.ZarrArray
DiskArray: TypeAlias = types.H5Dataset | types.ZarrArray # noqa: UP040
"""Arrays and matrices stored on disk."""
Loading
Loading