Skip to content

Commit 69c10da

Browse files
committed
README is more succint and covers more topics
1 parent 41dc5c8 commit 69c10da

File tree

2 files changed

+147
-142
lines changed

2 files changed

+147
-142
lines changed

README.md

Lines changed: 147 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,166 +1,201 @@
1-
# Array API Standard Test Suite
1+
# Test Suite for Array API Compliance
22

3-
This is the test suite for the Python array API standard.
3+
This is the test suite for array libraries adopting the [Python Array API
4+
standard](https://data-apis.org/array-api/).
45

5-
**NOTE: This test suite is still a work in progress.**
6-
7-
Feedback and contributions are welcome, but be aware that this suite is not
8-
yet completed. In particular, there are still many parts of the array API
9-
specification that are not yet tested here.
6+
Note this is still a **work in progress**. Feedback and contributions are
7+
welcome!
108

119
## Running the tests
1210

1311
### Setup
1412

15-
To run the tests, first install the testing dependencies
16-
17-
pip install pytest hypothesis
18-
19-
or
13+
To run the tests, install the testing dependencies
2014

21-
conda install pytest hypothesis
15+
pip install -r requirements
2216

23-
as well as the array libraries that you want to test.
17+
as well as the array libraries that you want to test.
2418

2519
### Specifying the array module
2620

27-
To run the tests, you need to set the array library that is to be tested. There
28-
are two ways to do this. One way is to set the `ARRAY_API_TESTS_MODULE`
29-
environment variable. For example you can set it when running `pytest`
21+
You need to specify the array library to test. It can be specified via the
22+
`XPTESTS_MODULE` environment variable, e.g.
3023

31-
ARRAY_API_TESTS_MODULE=numpy pytest
24+
XPTESTS_MODULE=numpy.array_api pytest xptests/
3225

33-
Alternately, edit the `array_api_tests/_array_module.py` file and change the
26+
Alternately, change the `array_module` variable in `xptests/_array_module.py`
3427
line
3528

36-
```py
37-
array_module = None
29+
```diff
30+
- array_module = None
31+
+ import numpy.array_api as array_module
3832
```
3933

40-
to
34+
### Specifying test cases
4135

42-
```py
43-
import numpy as array_module
44-
```
36+
The suite tries to logically organise its tests so you can utilise a specific
37+
test case for whatever function you are developing.
4538

46-
(replacing `numpy` with the array module namespace to be tested).
39+
pytest xptests/test_creation_functions.py::test_zeros
4740

48-
### Specifying test cases
41+
## What the test suite covers
42+
43+
We are interested in array libraries conforming to the
44+
[spec](https://data-apis.org/array-api/latest/API_specification/index.html).
45+
Ideally this means that if a library has fully adopted the Array API, the test
46+
suite passes. We take great care to _not_ test things which are out-of-scope, so
47+
as to not unexpectedly fail the suite.
48+
49+
### Primary tests
50+
51+
Every function—including array object methods—has a respective test method. We
52+
use [Hypothesis](https://hypothesis.readthedocs.io/en/latest/) to generate a
53+
diverse set of valid inputs. This means array inputs will cover different dtypes
54+
and shapes, as well as contain interesting elements. These examples generate
55+
with interesting arrangements of non-array positional arguments and keyword
56+
arguments.
57+
58+
Each test case will cover the following areas if relevant:
59+
60+
* **Smoking**: We pass our generated examples to all functions. As these
61+
examples solely consist of *valid* inputs, we are testing that functions can
62+
be called using their documented inputs without raising errors.
4963

50-
The test suite tries to logically organise its tests so you can find specific
51-
test cases whilst developing something in particular. So to avoid running the
52-
rather slow complete suite, you can specify particular test cases like any other
53-
test suite.
64+
* **Data type**: For functions returning/modifying arrays, we assert that output
65+
arrays have the correct data types. Most functions
66+
[type-promote](https://data-apis.org/array-api/latest/API_specification/type_promotion.html)
67+
input arrays and some functions have bespoke rules—in both cases we simulate
68+
the correct behaviour to find the expected data types.
5469

55-
pytest array_api_tests/test_creation_functions.py::test_zeros
70+
* **Shape**: For functions returning/modifying arrays, we assert that output
71+
arrays have the correct shape. Most functions
72+
[broadcast](https://data-apis.org/array-api/latest/API_specification/broadcasting.html)
73+
input arrays and some functions have bespoke rules—in both cases we simulate
74+
the correct behaviour to find the expected shapes.
5675

57-
## Notes on Interpreting Errors
76+
* **Values**: We assert output values (including the elements of
77+
returned/modified arrays) are as expected. Except for manipulation functions
78+
or special cases, the spec allows floating-point inputs to have inexact
79+
outputs, so with such examples we only assert values are roughly as expected.
5880

59-
- Some tests cannot be run unless other tests pass first. This is because very
60-
basic APIs such as certain array creation APIs are required for a large
61-
fraction of the tests to run. TODO: Write which tests are required to pass
62-
first here.
81+
### Additional tests
6382

64-
- If an error message involves `_UndefinedStub`, it means some name that is
65-
required for the test to run is not defined in the array library.
83+
In addition to having one test case for each function, we test other properties
84+
of the functions and some miscellaneous things.
6685

67-
- Due to the nature of the array api spec, virtually every array library will
68-
produce a large number of errors from nonconformance. It is still a work in
69-
progress to enable reporting the errors in a way that makes them easy to
70-
understand, even if there are a large number of them.
86+
* **Special cases**: For functions with special case behaviour, we assert that
87+
these functions return the correct values.
7188

72-
- The spec documents are the ground source of truth. If the test suite appears
73-
to be testing something that is different from the spec, or something that
74-
isn't actually mentioned in the spec, this is a bug. [Please report
75-
it](https://github.com/data-apis/array-api-tests/issues/new). Furthermore,
76-
be aware that some aspects of the spec are either impossible or extremely
77-
difficult to actually test, so they are not covered in the test suite (TODO:
78-
list what these are).
89+
* **Signatures**: We assert functions have the correct signatures.
7990

80-
## Configuring Tests
91+
* **Constants**: We assert that
92+
[constants](https://data-apis.org/array-api/latest/API_specification/constants.html)
93+
behave expectedly, are roughly the expected value, and that any related
94+
functions interact with them correctly.
95+
96+
Be aware that some aspects of the spec are impractical or impossible to actually
97+
test, so they are not covered in the suite <!-- TODO: note what these are -->
98+
99+
## Interpreting errors
100+
101+
First and foremost, note that most tests have to assume that certain aspects of
102+
the Array API have been correctly adopted, as fundamental APIs such as array
103+
creation and equalities are hard requirements for many assertions. This means a
104+
test case for one function might fail because another function has bugs or even
105+
no implementation.
106+
107+
This means adopting libraries at first will result in a vast number of errors
108+
due to cascading errors. Generally the nature of the spec means many granular
109+
details such as type promotion is likely going to also fail nearly-conforming
110+
functions.
111+
112+
We hope to improve user experience in regards to "noisy" errors in
113+
[#51](https://github.com/data-apis/array-api-tests/issues/51). For now, if an
114+
error message involves `_UndefinedStub`, it means an attribute of the array
115+
library (including functions) and it's objects (e.g. the array) is missing.
116+
117+
The spec is the suite's source of truth. If the suite appears to assume
118+
behaviour different from the spec, or test something that is not documented,
119+
this is a bug—please [report such
120+
issues](https://github.com/data-apis/array-api-tests/issues/new) to us.
121+
122+
## Configuration
81123

82124
By default, tests for the optional Array API extensions such as
83125
[`linalg`](https://data-apis.org/array-api/latest/extensions/linear_algebra_functions.html)
84126
will be skipped if not present in the specified array module. You can purposely
85127
skip testing extension(s) via the `--disable-extension` option, and likewise
86128
purposely test them via the `--enable-extension` option.
87129

88-
The tests make heavy use of the
89-
[Hypothesis](https://hypothesis.readthedocs.io/en/latest/) testing library.
90-
Hypothesis generates random input values for the tests. You can configure how
91-
many values are generated and run using the `--max-examples` flag. The default
92-
`--max-examples` is 100. For example, `--max-examples 50` will only generate
93-
half as many examples and as a result, the test suite will run in about half
94-
the time. Setting `--max-examples` to a lower value can be useful when you
95-
want to have a faster test run. It can also be useful to set `--max-examples`
96-
to a large value to do a longer, more rigorous run of the tests. For example,
97-
`--max-examples 10000` will do a very rigorous check of the tests, but may
98-
take a few hours to run.
130+
The tests make heavy use
131+
[Hypothesis](https://hypothesis.readthedocs.io/en/latest/). You can configure
132+
how many examples are generated using the `--max-examples` flag, which defaults
133+
to 100. Lower values can be useful for quick checks, and larger values should
134+
result in more rigorous runs. For example, `--max-examples 10000` may find bugs
135+
where default runs don't, but will take a much longer time.
99136

100-
## Contributing
137+
<!-- TODO: howto on CI -->
101138

102-
### Adding Tests
139+
## Contributing guidelines
103140

104-
It is important that every test in the test suite only uses APIs that are part
105-
of the standard. This means that, for instance, when creating test arrays, you
106-
should only use array creation functions that are part of the spec, such as
107-
`ones` or `full`. It also means that many array testing functions that are
108-
built-in to libraries like numpy are reimplemented in the test suite (see
109-
`array_api_tests/pytest_helpers.py`, `array_api_tests/array_helpers.py`, and
110-
`array_api_tests/hypothesis_helpers.py`).
141+
### Remain in-scope
111142

112-
In order to enforce this, the `array_api_tests._array_module` should be used
113-
everywhere in place of the actual array module that is being tested.
143+
It is important that every test only uses APIs that are part of the standard.
144+
For instance, when creating input arrays you should only use the [array creation
145+
functions](https://data-apis.org/array-api/latest/API_specification/creation_functions.html)
146+
that are documented in the spec. The same goes for testing arrays—you'll find
147+
many utilities that parralel NumPy's own test utils in the `*_helpers.py` files.
114148

115-
### Hypothesis
149+
### Tools
116150

117-
The test suite uses [Hypothesis](https://hypothesis.readthedocs.io/en/latest/)
118-
to generate random input data. Any test that should be applied over all
119-
possible array inputs should use hypothesis tests. Custom Hypothesis
120-
strategies are in the `array_api_tests/hypothesis_helpers.py` file.
151+
Hypothesis should always be used for the primary tests, and can be useful
152+
elsewhere. Effort should be made so drawn arguments are labeled with their
153+
respective names. For
154+
[`st.data()`](https://hypothesis.readthedocs.io/en/latest/data.html#hypothesis.strategies.data),
155+
draws should be accompanied with the `label` kwarg e.g. `data.draw(<strategy>,
156+
label=...)`.
121157

122-
### Parameterization
158+
[`pytest.mark.parametrize`](https://docs.pytest.org/en/latest/how-to/parametrize.html)
159+
should be used to run tests over multiple arguments. Parameterization should be
160+
preferred over using Hypothesis when there are a small number of possible
161+
inputs, as this allows better failure reporting. Note using both parametrize and
162+
Hypothesis for a single test method is possible and can be quite useful.
123163

124-
Any test that applies over all functions in a module should use
125-
`pytest.mark.parametrize` to parameterize over them. For example,
164+
### Error messages
126165

127-
```py
128-
from . import function_stubs
166+
Any assertion should be accompanied with a descriptive error message, including
167+
the relevant values. Error messages should be self-explanatory as to why a given
168+
test fails, as one should not need prior knowledge of how the test is
169+
implemented.
129170

130-
@pytest.mark.parametrize('name', function_stubs.__all__)
131-
def test_whatever(name):
132-
...
133-
```
134-
135-
will parameterize `test_whatever` over all the functions stubs generated from
136-
the spec. Parameterization should be preferred over using Hypothesis whenever
137-
there are a finite number of input possibilities, as this will cause pytest to
138-
report failures for all input values separately, as opposed to Hypothesis
139-
which will only report one failure.
140-
141-
### Error Strings
171+
### Generated files
142172

143-
Any assertion or exception should be accompanied with a useful error message.
144-
The test suite is designed to be ran by people who are not familiar with the
145-
test suite code, so the error messages should be self explanatory as to why
146-
the module fails a given test.
173+
Some files in the suite are automatically generated from the spec, and should
174+
not be edited directly. To regenerate these files, run the script
147175

148-
### Meta-errors
176+
./generate_stubs.py path/to/array-api
149177

150-
Any error that indicates a bug in the test suite itself, rather than in the
151-
array module not following the spec, should use `RuntimeError` whenever
152-
possible.
178+
where `path/to/array-api` is the path to a local clone of the [`array-api`
179+
repo](https://github.com/data-apis/array-api/). Edit `generate_stubs.py` to make
180+
changes to the generated files.
153181

154-
(TODO: Update this policy to something better. See [#5](https://github.com/data-apis/array-api-tests/issues/5).)
182+
## Future plans
155183

156-
### Automatically Generated Files
184+
Keeping full coverage of the spec is an on-going priority as the Array API
185+
evolves.
157186

158-
Some files in the test suite are automatically generated from the API spec
159-
files. These files should not be edited directly. To regenerate these files,
160-
run the script
187+
Additionally, we have features and general improvements planned. Work on such
188+
functionality is guided primarily by the concerete needs of developers
189+
implementing and using the Array API—be sure to [let us
190+
know](https://github.com/data-apis/array-api-tests/issues) any limitations you
191+
come across.
161192

162-
./generate_stubs.py path/to/array-api
193+
* A dependency graph for every test case (mentioned in <Interpreting errors>),
194+
which could be used to modify pytest's collection so that low-dependency tests
195+
are run first, and tests with faulty dependencies would skip/xfail.
163196

164-
where `path/to/array-api` is the path to the local clone of the `array-api`
165-
repo. To modify the automatically generated files, edit the code that
166-
generates them in the `generate_stubs.py` script.
197+
* In some tests we've found it difficult to find appropaite assertion parameters
198+
for output values (particularly epsilons for floating-point outputs), so we
199+
need to review these and either implement assertions or properly note the lack
200+
thereof.
201+

tests-coverage.md

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

0 commit comments

Comments
 (0)