Skip to content

Commit 0b3e170

Browse files
committed
Merge branch 'master' into more-linalg2
2 parents 9cb58a1 + d0d9696 commit 0b3e170

39 files changed

+2373
-1468
lines changed

.github/workflows/numpy.yml

Lines changed: 3 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
strategy:
1010
matrix:
11-
python-version: [3.8, 3.9]
11+
python-version: ["3.10", "3.11"]
1212

1313
steps:
1414
- name: Checkout array-api-tests
@@ -22,60 +22,10 @@ jobs:
2222
- name: Install dependencies
2323
run: |
2424
python -m pip install --upgrade pip
25-
python -m pip install numpy==1.22.1
25+
python -m pip install numpy==1.26.2
2626
python -m pip install -r requirements.txt
2727
- name: Run the test suite
2828
env:
2929
ARRAY_API_TESTS_MODULE: numpy.array_api
3030
run: |
31-
# Skip testing functions with known issues
32-
cat << EOF >> skips.txt
33-
34-
# copy not implemented
35-
array_api_tests/test_creation_functions.py::test_asarray_arrays
36-
# https://github.com/numpy/numpy/issues/20870
37-
array_api_tests/test_data_type_functions.py::test_can_cast
38-
# The return dtype for trace is not consistent in the spec
39-
# https://github.com/data-apis/array-api/issues/202#issuecomment-952529197
40-
array_api_tests/test_linalg.py::test_trace
41-
# Various fixes to vector_norm are in
42-
# https://github.com/numpy/numpy/pull/21084.
43-
array_api_tests/test_linalg.py::test_vector_norm
44-
# waiting on NumPy to allow/revert distinct NaNs for np.unique
45-
# https://github.com/numpy/numpy/issues/20326#issuecomment-1012380448
46-
array_api_tests/test_set_functions.py
47-
48-
# https://github.com/numpy/numpy/issues/21373
49-
array_api_tests/test_array_object.py::test_getitem
50-
51-
# missing copy arg
52-
array_api_tests/test_signatures.py::test_func_signature[reshape]
53-
54-
# https://github.com/numpy/numpy/issues/21211
55-
array_api_tests/test_special_cases.py::test_iop[__iadd__(x1_i is -0 and x2_i is -0) -> -0]
56-
# https://github.com/numpy/numpy/issues/21213
57-
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]
58-
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]
59-
# noted diversions from spec
60-
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity]
61-
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity]
62-
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity]
63-
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -infinity and isfinite(x2_i) and x2_i < 0) -> +infinity]
64-
array_api_tests/test_special_cases.py::test_binary[floor_divide(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> -0]
65-
array_api_tests/test_special_cases.py::test_binary[floor_divide(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> -0]
66-
array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity]
67-
array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity]
68-
array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity]
69-
array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is -infinity and isfinite(x2_i) and x2_i < 0) -> +infinity]
70-
array_api_tests/test_special_cases.py::test_binary[__floordiv__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> -0]
71-
array_api_tests/test_special_cases.py::test_binary[__floordiv__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> -0]
72-
array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity]
73-
array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity]
74-
array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity]
75-
array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -infinity and isfinite(x2_i) and x2_i < 0) -> +infinity]
76-
array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> -0]
77-
array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> -0]
78-
79-
EOF
80-
81-
pytest -v -rxXfE --ci
31+
pytest -v -rxXfE --ci --skips-file numpy-skips.txt

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ venv.bak/
117117
# Rope project settings
118118
.ropeproject
119119

120+
# IDE
121+
.idea/
122+
.vscode/
123+
120124
# mkdocs documentation
121125
/site
122126

README.md

Lines changed: 84 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,7 @@ You need to specify the array library to test. It can be specified via the
3636
$ export ARRAY_API_TESTS_MODULE=numpy.array_api
3737
```
3838

39-
Alternately, change the `array_module` variable in `array_api_tests/_array_module.py`
40-
line, e.g.
41-
42-
```diff
43-
- array_module = None
44-
+ import numpy.array_api as array_module
45-
```
39+
Alternately, import/define the `xp` variable in `array_api_tests/__init__.py`.
4640

4741
### Run the suite
4842

@@ -160,6 +154,13 @@ library to fail.
160154

161155
### Configuration
162156

157+
#### API version
158+
159+
You can specify the API version to use when testing via the
160+
`ARRAY_API_TESTS_VERSION` environment variable. Currently this defaults to the
161+
array module's `__array_api_version__` value, and if that attribute doesn't
162+
exist then we fallback to `"2021.12"`.
163+
163164
#### CI flag
164165

165166
Use the `--ci` flag to run only the primary and special cases tests. You can
@@ -178,13 +179,22 @@ By default, tests for the optional Array API extensions such as
178179
will be skipped if not present in the specified array module. You can purposely
179180
skip testing extension(s) via the `--disable-extension` option.
180181

181-
#### Skip test cases
182+
#### Skip or XFAIL test cases
183+
184+
Test cases you want to skip can be specified in a skips or XFAILS file. The
185+
difference between skip and XFAIL is that XFAIL tests are still run and
186+
reported as XPASS if they pass.
187+
188+
By default, the skips and xfails files are `skips.txt` and `fails.txt` in the root
189+
of this repository, but any file can be specified with the `--skips-file` and
190+
`--xfails-file` command line flags.
182191

183-
Test cases you want to skip can be specified in a `skips.txt` file in the root
184-
of this repository, e.g.:
192+
The files should list the test ids to be skipped/xfailed. Empty lines and
193+
lines starting with `#` are ignored. The test id can be any substring of the
194+
test ids to skip/xfail.
185195

186196
```
187-
# ./skips.txt
197+
# skips.txt or xfails.txt
188198
# Line comments can be denoted with the hash symbol (#)
189199
190200
# Skip specific test case, e.g. when argsort() does not respect relative order
@@ -200,39 +210,81 @@ array_api_tests/test_add[__iadd__(x, s)]
200210
array_api_tests/test_set_functions.py
201211
```
202212

203-
For GitHub Actions, you might like to keep everything in the workflow config
204-
instead of having a seperate `skips.txt` file, e.g.:
213+
Here is an example GitHub Actions workflow file, where the xfails are stored
214+
in `array-api-tests.xfails.txt` in the base of the `your-array-library` repo.
215+
216+
If you want, you can use `-o xfail_strict=True`, which causes XPASS tests (XFAIL
217+
tests that actually pass) to fail the test suite. However, be aware that
218+
XFAILures can be flaky (see below, so this may not be a good idea unless you
219+
use some other mitigation of such flakyness).
220+
221+
If you don't want this behavior, you can remove it, or use `--skips-file`
222+
instead of `--xfails-file`.
205223

206224
```yaml
207225
# ./.github/workflows/array_api.yml
208-
...
209-
...
210-
- name: Run the test suite
226+
jobs:
227+
tests:
228+
runs-on: ubuntu-latest
229+
strategy:
230+
matrix:
231+
python-version: ['3.8', '3.9', '3.10', '3.11']
232+
233+
steps:
234+
- name: Checkout <your array library>
235+
uses: actions/checkout@v3
236+
with:
237+
path: your-array-library
238+
239+
- name: Checkout array-api-tests
240+
uses: actions/checkout@v3
241+
with:
242+
repository: data-apis/array-api-tests
243+
submodules: 'true'
244+
path: array-api-tests
245+
246+
- name: Run the array API test suite
211247
env:
212248
ARRAY_API_TESTS_MODULE: your.array.api.namespace
213249
run: |
214-
# Skip test cases with known issues
215-
cat << EOF >> skips.txt
216-
217-
# Comments can still work here
218-
array_api_tests/test_sorting_functions.py::test_argsort
219-
array_api_tests/test_add[__iadd__(x1, x2)]
220-
array_api_tests/test_add[__iadd__(x, s)]
221-
array_api_tests/test_set_functions.py
222-
223-
EOF
224-
225-
pytest -v -rxXfE --ci
250+
export PYTHONPATH="${GITHUB_WORKSPACE}/your-array-library"
251+
cd ${GITHUB_WORKSPACE}/array-api-tests
252+
pytest -v -rxXfE --ci --xfails-file ${GITHUB_WORKSPACE}/your-array-library/array-api-tests-xfails.txt array_api_tests/
226253
```
227254
255+
> **Warning**
256+
>
257+
> XFAIL tests that use Hypothesis (basically every test in the test suite except
258+
> those in test_has_names.py) can be flaky, due to the fact that Hypothesis
259+
> might not always run the test with an input that causes the test to fail.
260+
> There are several ways to avoid this problem:
261+
>
262+
> - Increase the maximum number of examples, e.g., by adding `--max-examples
263+
> 200` to the test command (the default is `100`, see below). This will
264+
> make it more likely that the failing case will be found, but it will also
265+
> make the tests take longer to run.
266+
> - Don't use `-o xfail_strict=True`. This will make it so that if an XFAIL
267+
> test passes, it will alert you in the test summary but will not cause the
268+
> test run to register as failed.
269+
> - Use skips instead of XFAILS. The difference between XFAIL and skip is that
270+
> a skipped test is never run at all, whereas an XFAIL test is always run
271+
> but ignored if it fails.
272+
> - Save the [Hypothesis examples
273+
> database](https://hypothesis.readthedocs.io/en/latest/database.html)
274+
> persistently on CI. That way as soon as a run finds one failing example,
275+
> it will always re-run future runs with that example. But note that the
276+
> Hypothesis examples database may be cleared when a new version of
277+
> Hypothesis or the test suite is released.
278+
228279
#### Max examples
229280

230281
The tests make heavy use
231282
[Hypothesis](https://hypothesis.readthedocs.io/en/latest/). You can configure
232-
how many examples are generated using the `--max-examples` flag, which defaults
233-
to 100. Lower values can be useful for quick checks, and larger values should
234-
result in more rigorous runs. For example, `--max-examples 10_000` may find bugs
235-
where default runs don't but will take much longer to run.
283+
how many examples are generated using the `--max-examples` flag, which
284+
defaults to `100`. Lower values can be useful for quick checks, and larger
285+
values should result in more rigorous runs. For example, `--max-examples
286+
10_000` may find bugs where default runs don't but will take much longer to
287+
run.
236288

237289

238290
## Contributing

array-api

Submodule array-api updated 211 files

array_api_tests/__init__.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,36 @@
1+
import os
12
from functools import wraps
3+
from importlib import import_module
24

35
from hypothesis import strategies as st
46
from hypothesis.extra import array_api
57

6-
from ._array_module import mod as _xp
8+
from . import _version
79

8-
__all__ = ["xps"]
10+
__all__ = ["xp", "api_version", "xps"]
11+
12+
13+
# You can comment the following out and instead import the specific array module
14+
# you want to test, e.g. `import numpy.array_api as xp`.
15+
if "ARRAY_API_TESTS_MODULE" in os.environ:
16+
xp_name = os.environ["ARRAY_API_TESTS_MODULE"]
17+
_module, _sub = xp_name, None
18+
if "." in xp_name:
19+
_module, _sub = xp_name.split(".", 1)
20+
xp = import_module(_module)
21+
if _sub:
22+
try:
23+
xp = getattr(xp, _sub)
24+
except AttributeError:
25+
# _sub may be a submodule that needs to be imported. WE can't
26+
# do this in every case because some array modules are not
27+
# submodules that can be imported (like mxnet.nd).
28+
xp = import_module(xp_name)
29+
else:
30+
raise RuntimeError(
31+
"No array module specified - either edit __init__.py or set the "
32+
"ARRAY_API_TESTS_MODULE environment variable."
33+
)
934

1035

1136
# We monkey patch floats() to always disable subnormals as they are out-of-scope
@@ -41,9 +66,9 @@ def _from_dtype(*a, **kw):
4166
pass
4267

4368

44-
xps = array_api.make_strategies_namespace(_xp, api_version="2021.12")
45-
46-
47-
from . import _version
69+
api_version = os.getenv(
70+
"ARRAY_API_TESTS_VERSION", getattr(xp, "__array_api_version__", "2021.12")
71+
)
72+
xps = array_api.make_strategies_namespace(xp, api_version=api_version)
4873

4974
__version__ = _version.get_versions()["version"]

array_api_tests/_array_module.py

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,5 @@
1-
import os
2-
from importlib import import_module
1+
from . import stubs, xp
32

4-
from . import stubs
5-
6-
# Replace this with a specific array module to test it, for example,
7-
#
8-
# import numpy as array_module
9-
array_module = None
10-
11-
if array_module is None:
12-
if 'ARRAY_API_TESTS_MODULE' in os.environ:
13-
mod_name = os.environ['ARRAY_API_TESTS_MODULE']
14-
_module, _sub = mod_name, None
15-
if '.' in mod_name:
16-
_module, _sub = mod_name.split('.', 1)
17-
mod = import_module(_module)
18-
if _sub:
19-
try:
20-
mod = getattr(mod, _sub)
21-
except AttributeError:
22-
# _sub may be a submodule that needs to be imported. WE can't
23-
# do this in every case because some array modules are not
24-
# submodules that can be imported (like mxnet.nd).
25-
mod = import_module(mod_name)
26-
else:
27-
raise RuntimeError("No array module specified. Either edit _array_module.py or set the ARRAY_API_TESTS_MODULE environment variable")
28-
else:
29-
mod = array_module
30-
mod_name = mod.__name__
31-
# Names from the spec. This is what should actually be imported from this
32-
# file.
333

344
class _UndefinedStub:
355
"""
@@ -45,7 +15,7 @@ def __init__(self, name):
4515
self.name = name
4616

4717
def _raise(self, *args, **kwargs):
48-
raise AssertionError(f"{self.name} is not defined in {mod_name}")
18+
raise AssertionError(f"{self.name} is not defined in {xp.__name__}")
4919

5020
def __repr__(self):
5121
return f"<undefined stub for {self.name!r}>"
@@ -58,13 +28,15 @@ def __repr__(self):
5828
"uint8", "uint16", "uint32", "uint64",
5929
"int8", "int16", "int32", "int64",
6030
"float32", "float64",
31+
"complex64", "complex128",
6132
]
6233
_constants = ["e", "inf", "nan", "pi"]
6334
_funcs = [f.__name__ for funcs in stubs.category_to_funcs.values() for f in funcs]
64-
_top_level_attrs = _dtypes + _constants + _funcs + stubs.EXTENSIONS
35+
_funcs += ["take", "isdtype", "conj", "imag", "real"] # TODO: bump spec and update array-api-tests to new spec layout
36+
_top_level_attrs = _dtypes + _constants + _funcs + stubs.EXTENSIONS + ["fft"]
6537

6638
for attr in _top_level_attrs:
6739
try:
68-
globals()[attr] = getattr(mod, attr)
40+
globals()[attr] = getattr(xp, attr)
6941
except AttributeError:
7042
globals()[attr] = _UndefinedStub(attr)

array_api_tests/conftest.py

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)