diff --git a/.github/workflows/array-api-tests-numpy-dev.yml b/.github/workflows/array-api-tests-numpy-dev.yml new file mode 100644 index 00000000..eef4269d --- /dev/null +++ b/.github/workflows/array-api-tests-numpy-dev.yml @@ -0,0 +1,11 @@ +name: Array API Tests (NumPy dev) + +on: [push, pull_request] + +jobs: + array-api-tests-numpy-dev: + uses: ./.github/workflows/array-api-tests.yml + with: + package-name: numpy + extra-requires: '--pre --extra-index https://pypi.anaconda.org/scientific-python-nightly-wheels/simple' + xfails-file-extra: '-dev' diff --git a/.github/workflows/array-api-tests.yml b/.github/workflows/array-api-tests.yml index 6e15bcad..c7e2af5c 100644 --- a/.github/workflows/array-api-tests.yml +++ b/.github/workflows/array-api-tests.yml @@ -6,6 +6,12 @@ on: package-name: required: true type: string + module-name: + required: false + type: string + extra-requires: + required: false + type: string package-version: required: false type: string @@ -49,17 +55,18 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Install dependencies - # NumPy 1.21 doesn't support Python 3.11. There doesn't seem to be a way - # to put this in the numpy 1.21 config file. - if: "! (matrix.python-version == '3.11' && inputs.package-name == 'numpy' && contains(inputs.package-version, '1.21'))" + # NumPy 1.21 doesn't support Python 3.11. NumPy 2.0 doesn't support + # Python 3.8. There doesn't seem to be a way to put this in the numpy + # 1.21 config file. + if: "! ((matrix.python-version == '3.11' && inputs.package-name == 'numpy' && contains(inputs.package-version, '1.21')) || (matrix.python-version == '3.8' && inputs.package-name == 'numpy' && contains(inputs.xfails-file-extra, 'dev')))" run: | python -m pip install --upgrade pip - python -m pip install '${{ inputs.package-name }} ${{ inputs.package-version }}' + python -m pip install '${{ inputs.package-name }} ${{ inputs.package-version }}' ${{ inputs.extra-requires }} python -m pip install -r ${GITHUB_WORKSPACE}/array-api-tests/requirements.txt - name: Run the array API testsuite (${{ inputs.package-name }}) - if: "! (matrix.python-version == '3.11' && inputs.package-name == 'numpy' && contains(inputs.package-version, '1.21'))" + if: "! ((matrix.python-version == '3.11' && inputs.package-name == 'numpy' && contains(inputs.package-version, '1.21')) || (matrix.python-version == '3.8' && inputs.package-name == 'numpy' && contains(inputs.xfails-file-extra, 'dev')))" env: - ARRAY_API_TESTS_MODULE: array_api_compat.${{ inputs.package-name }} + ARRAY_API_TESTS_MODULE: array_api_compat.${{ inputs.module-name || inputs.package-name }} # This enables the NEP 50 type promotion behavior (without it a lot of # tests fail on bad scalar type promotion behavior) NPY_PROMOTION_STATE: weak diff --git a/array_api_compat/common/_helpers.py b/array_api_compat/common/_helpers.py index 5cb029dc..c1b0aef3 100644 --- a/array_api_compat/common/_helpers.py +++ b/array_api_compat/common/_helpers.py @@ -71,9 +71,7 @@ def your_function(x, y): """ namespaces = set() for x in xs: - if hasattr(x, '__array_namespace__'): - namespaces.add(x.__array_namespace__(api_version=api_version)) - elif _is_numpy_array(x): + if _is_numpy_array(x): _check_api_version(api_version) if _use_compat: from .. import numpy as numpy_namespace @@ -97,6 +95,8 @@ def your_function(x, y): else: import torch namespaces.add(torch) + elif hasattr(x, '__array_namespace__'): + namespaces.add(x.__array_namespace__(api_version=api_version)) else: # TODO: Support Python scalars? raise TypeError(f"{type(x).__name__} is not a supported array type") diff --git a/numpy-dev-xfails.txt b/numpy-dev-xfails.txt new file mode 100644 index 00000000..5e270a95 --- /dev/null +++ b/numpy-dev-xfails.txt @@ -0,0 +1,57 @@ +# asarray(copy=False) is not yet implemented +array_api_tests/test_creation_functions.py::test_asarray_arrays + +# finfo(float32).eps returns float32 but should return float +array_api_tests/test_data_type_functions.py::test_finfo[float32] + +# Array methods and attributes not already on np.ndarray cannot be wrapped +array_api_tests/test_has_names.py::test_has_names[array_method-to_device] +array_api_tests/test_has_names.py::test_has_names[array_attribute-device] + +# linalg tests require cleanups +# https://github.com/data-apis/array-api-tests/pull/101 +array_api_tests/test_linalg.py::test_solve + +# NumPy deviates in some special cases for floordiv +array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -infinity and isfinite(x2_i) and x2_i < 0) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[floor_divide(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> -0] +array_api_tests/test_special_cases.py::test_binary[floor_divide(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> -0] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is -infinity and isfinite(x2_i) and x2_i < 0) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> -0] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> -0] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -infinity and isfinite(x2_i) and x2_i < 0) -> +infinity] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> -0] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> -0] + +# https://github.com/numpy/numpy/issues/21213 +array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -infinity and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] +array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -infinity and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +infinity] +array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] +array_api_tests/meta/test_hypothesis_helpers.py::test_symmetric_matrices + +# The test suite is incorrectly checking sums that have loss of significance +# (https://github.com/data-apis/array-api-tests/issues/168) +array_api_tests/test_statistical_functions.py::test_sum + +# fft functions are not yet supported +# (https://github.com/data-apis/array-api-compat/issues/67) +array_api_tests/test_fft.py::test_fft +array_api_tests/test_fft.py::test_ifft +array_api_tests/test_fft.py::test_fftn +array_api_tests/test_fft.py::test_ifftn +array_api_tests/test_fft.py::test_rfft +array_api_tests/test_fft.py::test_irfft +array_api_tests/test_fft.py::test_rfftn +array_api_tests/test_fft.py::test_irfftn +array_api_tests/test_fft.py::test_hfft +array_api_tests/test_fft.py::test_ihfft