Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: fix oldest-supported-dependencies test workflow #2783

Merged
merged 5 commits into from
Oct 30, 2023
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
87 changes: 33 additions & 54 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,16 @@ jobs:
python -m pip install build
python -m build -w awkward-cpp

- name: Install awkward-cpp
run: python -m pip install -v @(get-childitem -path awkward-cpp/dist/*.whl)

- name: Build & install awkward
run: python -m pip install -v .
- name: Install awkward, awkward-cpp, and dependencies
run: >-
python -m pip install --only-binary "numpy,pandas,pyarrow,numexpr,numexpr"
-v . @(get-childitem -path awkward-cpp/dist/*.whl)
pytest-github-actions-annotate-failures
-r requirements-test.txt

- name: Print versions
run: python -m pip list

- name: Check if kernel specification is sorted
run: pipx run nox -s diagnostics -- --check-spec-sorted

- name: Install test requirements
run: python -m pip install -v -r requirements-test.txt pytest-github-actions-annotate-failures

- name: Test specification
if: steps.cache-awkward-cpp-wheel.outputs.cache-hit != 'true'
run: python -m pytest -vv -rs awkward-cpp/tests-spec
Expand Down Expand Up @@ -156,21 +151,17 @@ jobs:
python -m pip install build
python -m build -w ./awkward-cpp

- name: Install awkward-cpp
run: python -m pip install -v ./awkward-cpp/dist/*.whl

- name: Build & install awkward
run: python -m pip install -v .
- name: Install awkward, awkward-cpp, dask-awkward, and dependencies
run: >-
python -m pip install --only-binary "numpy,pandas,pyarrow,numexpr"
-v . ./awkward-cpp/dist/*.whl
pytest-github-actions-annotate-failures
dask-awkward
-r requirements-test.txt

- name: Print versions
run: python -m pip list

- name: Check if kernel specification is sorted
run: pipx run nox -s diagnostics -- --check-spec-sorted

- name: Install test requirements
run: python -m pip install -v -r requirements-test.txt pytest-github-actions-annotate-failures

- name: Test specification
if: steps.cache-awkward-cpp-wheel.outputs.cache-hit != 'true'
run: python -m pytest -vv -rs awkward-cpp/tests-spec
Expand All @@ -190,24 +181,16 @@ jobs:
strategy:
matrix:
python-version:
- '3.12'
- '3.11'
- '3.10'
- '3.9'
- '3.8'
numpy-package:
- "numpy"
pyarrow-package:
- "pyarrow"
extra-pip-constraints:
- "-r requirements-test.txt"
include:
# Lower bounds
- python-version: '3.8'
numpy-package: "numpy==1.18.0"
pyarrow-package: "pyarrow"
- python-version: '3.8'
numpy-package: "numpy"
pyarrow-package: "pyarrow==7.0.0"
- python-version: '3.12'
numpy-package: "numpy>=1.26.0b1"
pyarrow-package: "pyarrow;python_version<'3.12'"
extra-pip-constraints: "-r requirements-test-minimal.txt"

runs-on: ubuntu-22.04

Expand Down Expand Up @@ -246,21 +229,21 @@ jobs:
python -m pip install build
python -m build -w ./awkward-cpp

- name: Install awkward-cpp
run: python -m pip install -v ./awkward-cpp/dist/*.whl "${{ matrix.numpy-package }}" "${{ matrix.pyarrow-package }}"

- name: Build & install awkward
run: python -m pip install -v .
- name: Install awkward, awkward-cpp, and dependencies
run: >-
python -m pip install --only-binary "numpy,pandas,pyarrow,numexpr"
-v . ./awkward-cpp/dist/*.whl
pytest-github-actions-annotate-failures
${{ matrix.extra-pip-constraints }}

- name: Print versions
run: python -m pip list

- name: Check if kernel specification is sorted
# We don't need to run this all the time
if: matrix.python-version == '3.12'
run: pipx run nox -s diagnostics -- --check-spec-sorted

- name: Install test requirements
run: python -m pip install -v -r requirements-test.txt pytest-github-actions-annotate-failures

- name: Test specification
if: steps.cache-awkward-cpp-wheel.outputs.cache-hit != 'true'
run: python -m pytest -vv -rs awkward-cpp/tests-spec
Expand Down Expand Up @@ -332,20 +315,16 @@ jobs:
python3 -m pip install build
python3 -m build -w ./awkward-cpp

- name: Install awkward-cpp
run: python3 -m pip install -v ./awkward-cpp/dist/*.whl

- name: Build & install awkward
run: python3 -m pip install -v .

- name: Also install dask-awkward
run: python3 -m pip install dask-awkward
- name: Install awkward, awkward-cpp, dask-awkward, and dependencies
run: >-
python -m pip install --only-binary "numpy,pandas,pyarrow,numexpr"
-v . ./awkward-cpp/dist/*.whl
pytest-github-actions-annotate-failures
dask-awkward
-r requirements-test.txt

- name: Print versions
run: python -m pip list

- name: Install test requirements
run: python -m pip install -v -r requirements-test.txt pytest-github-actions-annotate-failures

- name: Test
run: python -m pytest -vv -rs tests
6 changes: 6 additions & 0 deletions requirements-test-minimal.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fsspec;sys_platform != "win32"
numpy==1.18.0
pyarrow==7.0.0
pytest>=6
pytest-cov
pytest-xdist
4 changes: 2 additions & 2 deletions requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
fsspec;sys_platform != "win32"
jax[cpu]>=0.2.15;sys_platform != "win32" and python_version < "3.12"
numba>=0.50.0,!=0.58.0rc1;python_version < "3.12"
numexpr; python_version < "3.12"
numexpr>=2.7; python_version < "3.12"
pandas>=0.24.0;sys_platform != "win32" and python_version < "3.12"
pyarrow>=7.0.0;sys_platform != "win32" and python_version < "3.12"
pytest>=6
pytest-cov
pytest-xdist
uproot
uproot>=5
110 changes: 81 additions & 29 deletions src/awkward/_nplikes/array_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
from __future__ import annotations

import math
from functools import lru_cache

import numpy
import packaging.version

from awkward._nplikes.numpylike import (
ArrayLike,
Expand All @@ -18,6 +20,20 @@
from awkward._typing import Any, Final, Literal

np = NumpyMetadata.instance()
NUMPY_HAS_NEP_50 = packaging.version.Version(
numpy.__version__
) >= packaging.version.Version("1.24")


@lru_cache
def _nplike_concatenate_has_casting(module: Any) -> bool:
x = module.zeros(2)
try:
module.concatenate((x, x), casting="same_kind")
except TypeError:
return False
else:
return True


class ArrayModuleNumpyLike(NumpyLike):
Expand Down Expand Up @@ -128,12 +144,15 @@ def meshgrid(

def array_equal(
self, x1: ArrayLike, x2: ArrayLike, *, equal_nan: bool = False
) -> ArrayLike:
) -> bool:
assert not isinstance(x1, PlaceholderArray)
assert not isinstance(x2, PlaceholderArray)
return self._module.asarray(
self._module.array_equal(x1, x2, equal_nan=equal_nan)
)
if equal_nan:
both_nan = self._module.logical_and(x1 == np.nan, x2 == np.nan)
both_equal = x1 == x2
return self._module.all(self._module.logical_or(both_equal, both_nan))
else:
return self._module.array_equal(x1, x2)

def searchsorted(
self,
Expand All @@ -150,28 +169,57 @@ def searchsorted(

############################ manipulation

def apply_ufunc(
self,
ufunc: UfuncLike,
method: str,
args: list[Any],
kwargs: dict[str, Any] | None = None,
) -> ArrayLike | tuple[ArrayLike]:
# Determine input argument dtypes
input_arg_dtypes = [getattr(obj, "dtype", type(obj)) for obj in args]
# Resolve these for the given ufunc
arg_dtypes = tuple(input_arg_dtypes + [None] * ufunc.nout)
resolved_dtypes = ufunc.resolve_dtypes(arg_dtypes)
# Interpret the arguments under these dtypes
resolved_args = [
self.asarray(arg, dtype=dtype) for arg, dtype in zip(args, resolved_dtypes)
]
# Broadcast these resolved arguments
broadcasted_args = self.broadcast_arrays(*resolved_args)
# Allow other nplikes to replace implementation
impl = self.prepare_ufunc(ufunc)
# Compute the result
return impl(*broadcasted_args, **kwargs)
# Does NumPy support value-less ufunc resolution?
if NUMPY_HAS_NEP_50:

def apply_ufunc(
self,
ufunc: UfuncLike,
method: str,
args: list[Any],
kwargs: dict[str, Any] | None = None,
) -> ArrayLike | tuple[ArrayLike]:
# Determine input argument dtypes
input_arg_dtypes = [getattr(obj, "dtype", type(obj)) for obj in args]
# Resolve these for the given ufunc
arg_dtypes = tuple(input_arg_dtypes + [None] * ufunc.nout)
resolved_dtypes = ufunc.resolve_dtypes(arg_dtypes)
# Interpret the arguments under these dtypes, converting scalars to length-1 arrays
resolved_args = [
self.asarray(arg, dtype=dtype)
for arg, dtype in zip(args, resolved_dtypes)
]
# Broadcast to ensure all-scalar or all-nd-array
broadcasted_args = self.broadcast_arrays(*resolved_args)
# Allow other nplikes to replace implementation
impl = self.prepare_ufunc(ufunc)
# Compute the result
return impl(*broadcasted_args, **(kwargs or {}))

else:
# Otherwise, perform default NumPy coercion (value-dependent)
def apply_ufunc(
self,
ufunc: UfuncLike,
method: str,
args: list[Any],
kwargs: dict[str, Any] | None = None,
) -> ArrayLike | tuple[ArrayLike]:
# Convert np.generic to scalar arrays
resolved_args = [
self.asarray(arg, dtype=arg.dtype) if hasattr(arg, "dtype") else arg
for arg in args
]
broadcasted_args = self.broadcast_arrays(*resolved_args)
# Choose the broadcasted argument if it wasn't a Python scalar
non_generic_value_promoted_args = [
y if hasattr(x, "ndim") else x
for x, y in zip(resolved_args, broadcasted_args)
]
# Allow other nplikes to replace implementation
impl = self.prepare_ufunc(ufunc)
# Compute the result
return impl(*non_generic_value_promoted_args, **(kwargs or {}))

def broadcast_arrays(self, *arrays: ArrayLike) -> list[ArrayLike]:
assert not any(isinstance(x, PlaceholderArray) for x in arrays)
Expand Down Expand Up @@ -327,7 +375,10 @@ def concat(
axis: int | None = 0,
) -> ArrayLike:
assert not any(isinstance(x, PlaceholderArray) for x in arrays)
return self._module.concatenate(arrays, axis=axis, casting="same_kind")
if _nplike_concatenate_has_casting(self._module):
return self._module.concatenate(arrays, axis=axis, casting="same_kind")
else:
return self._module.concatenate(arrays, axis=axis)

def repeat(
self,
Expand Down Expand Up @@ -507,10 +558,11 @@ def max(
return self._module.max(x, axis=axis, keepdims=keepdims, out=maybe_out)

def count_nonzero(
self, x: ArrayLike, *, axis: int | None = None, keepdims: bool = False
self, x: ArrayLike, *, axis: int | tuple[int, ...] | None = None
) -> ArrayLike:
assert not isinstance(x, PlaceholderArray)
return self._module.count_nonzero(x, axis=axis, keepdims=keepdims)
assert isinstance(axis, int) or axis is None
return self._module.count_nonzero(x, axis=axis)

def cumsum(
self,
Expand Down
13 changes: 6 additions & 7 deletions src/awkward/_nplikes/cupy.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ def frombuffer(
np_array = numpy.frombuffer(buffer, dtype=dtype, count=count)
return self._module.asarray(np_array)

def array_equal(self, x1: ArrayLike, x2: ArrayLike, *, equal_nan: bool = False):
def array_equal(
self, x1: ArrayLike, x2: ArrayLike, *, equal_nan: bool = False
) -> bool:
assert not isinstance(x1, PlaceholderArray)
assert not isinstance(x2, PlaceholderArray)
if x1.shape != x2.shape:
return False
else:
return self._module.all(x1 - x2 == 0)
return self._module.array_equal(x1, x2, equal_nan=equal_nan).get()

def repeat(
self, x: ArrayLike, repeats: ArrayLike | int, *, axis: int | None = None
Expand Down Expand Up @@ -106,13 +108,10 @@ def any(
return out

def count_nonzero(
self,
x: ArrayLike,
*,
axis: int | tuple[int, ...] | None = None,
keepdims: bool = False,
self, x: ArrayLike, *, axis: int | tuple[int, ...] | None = None
) -> ArrayLike:
assert not isinstance(x, PlaceholderArray)
assert isinstance(axis, int) or axis is None
out = self._module.count_nonzero(x, axis=axis)
if axis is None and isinstance(out, self._module.ndarray):
return out.item()
Expand Down
2 changes: 1 addition & 1 deletion src/awkward/_nplikes/numpylike.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ def max(

@abstractmethod
def count_nonzero(
self, x: ArrayLike, *, axis: int | None = None, keepdims: bool = False
self, x: ArrayLike, *, axis: int | tuple[int, ...] | None = None
) -> ArrayLike:
...

Expand Down
Loading