Skip to content

Commit a313c3d

Browse files
authored
Merge pull request #80 from honno/ci-profile
Streamline CI workflows with `--ci` option
2 parents dfca243 + e4e900c commit a313c3d

13 files changed

+78
-49
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ issues](https://github.com/data-apis/array-api-tests/issues/) to us.
136136
By default, tests for the optional Array API extensions such as
137137
[`linalg`](https://data-apis.org/array-api/latest/extensions/linear_algebra_functions.html)
138138
will be skipped if not present in the specified array module. You can purposely
139-
skip testing extension(s) via the `--disable-extension` option, and likewise
140-
purposely test them via the `--enable-extension` option.
139+
skip testing extension(s) via the `--disable-extension` option.
141140

142141
The tests make heavy use
143142
[Hypothesis](https://hypothesis.readthedocs.io/en/latest/). You can configure

array_api_tests/test_array_object.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from . import xps
1515
from .typing import DataType, Param, Scalar, ScalarType, Shape
1616

17+
pytestmark = pytest.mark.ci
18+
1719

1820
def scalar_objects(dtype: DataType, shape: Shape) -> st.SearchStrategy[List[Scalar]]:
1921
"""Generates scalars or nested sequences which are valid for xp.asarray()"""

array_api_tests/test_constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from ._array_module import mod as xp
88
from .typing import Array
99

10+
pytestmark = pytest.mark.ci
11+
1012

1113
def assert_scalar_float(name: str, c: Any):
1214
assert isinstance(c, SupportsFloat), f"{name}={c!r} does not look like a float"

array_api_tests/test_creation_functions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import math
2+
import pytest
23
from itertools import count
34
from typing import Iterator, NamedTuple, Union
45

@@ -14,6 +15,8 @@
1415
from . import xps
1516
from .typing import DataType, Scalar
1617

18+
pytestmark = pytest.mark.ci
19+
1720

1821
class frange(NamedTuple):
1922
start: float

array_api_tests/test_linalg.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
from . import _array_module
3636
from ._array_module import linalg
3737

38+
pytestmark = pytest.mark.ci
39+
40+
3841

3942
# Standin strategy for not yet implemented tests
4043
todo = none()

array_api_tests/test_manipulation_functions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from . import xps
1515
from .typing import Array, Shape
1616

17+
pytestmark = pytest.mark.ci
18+
1719
MAX_SIDE = hh.MAX_ARRAY_SIZE // 64
1820
MAX_DIMS = min(hh.MAX_ARRAY_SIZE // MAX_SIDE, 32) # NumPy only supports up to 32 dims
1921

array_api_tests/test_operators_and_elementwise_functions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
from .algos import broadcast_shapes
2929
from .typing import Array, DataType, Param, Scalar
3030

31+
pytestmark = pytest.mark.ci
32+
3133
# When appropiate, this module tests operators alongside their respective
3234
# elementwise methods. We do this by parametrizing a generalised test method
3335
# with every relevant method and operator.

array_api_tests/test_searching_functions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import pytest
12
from hypothesis import given
23
from hypothesis import strategies as st
34

@@ -9,6 +10,8 @@
910
from . import xps
1011
from .algos import broadcast_shapes
1112

13+
pytestmark = pytest.mark.ci
14+
1215

1316
@given(
1417
x=xps.arrays(

array_api_tests/test_set_functions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# TODO: disable if opted out, refactor things
22
import math
3+
import pytest
34
from collections import Counter, defaultdict
45

56
from hypothesis import assume, given
@@ -11,6 +12,8 @@
1112
from . import shape_helpers as sh
1213
from . import xps
1314

15+
pytestmark = pytest.mark.ci
16+
1417

1518
@given(xps.arrays(dtype=xps.scalar_dtypes(), shape=hh.shapes(min_side=1)))
1619
def test_unique_all(x):

array_api_tests/test_sorting_functions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import math
2+
import pytest
23
from typing import Set
34

45
from hypothesis import given
@@ -13,6 +14,8 @@
1314
from . import xps
1415
from .typing import Scalar, Shape
1516

17+
pytestmark = pytest.mark.ci
18+
1619

1720
def assert_scalar_in_set(
1821
func_name: str,

array_api_tests/test_statistical_functions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import math
2+
import pytest
23
from typing import Optional
34

45
from hypothesis import assume, given
@@ -13,6 +14,8 @@
1314
from . import xps
1415
from .typing import DataType
1516

17+
pytestmark = pytest.mark.ci
18+
1619

1720
def kwarg_dtypes(dtype: DataType) -> st.SearchStrategy[Optional[DataType]]:
1821
dtypes = [d2 for d1, d2 in dh.promotion_table if d1 == dtype]

array_api_tests/test_utility_functions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import pytest
12
from hypothesis import given
23
from hypothesis import strategies as st
34

@@ -8,6 +9,8 @@
89
from . import shape_helpers as sh
910
from . import xps
1011

12+
pytestmark = pytest.mark.ci
13+
1114

1215
@given(
1316
x=xps.arrays(dtype=xps.scalar_dtypes(), shape=hh.shapes(min_side=1)),

conftest.py

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,66 @@
11
from functools import lru_cache
22
from pathlib import Path
33

4-
from pytest import mark
54
from hypothesis import settings
5+
from pytest import mark
66

77
from array_api_tests import _array_module as xp
88
from array_api_tests._array_module import _UndefinedStub
99

10-
11-
settings.register_profile('xp_default', deadline=800)
10+
settings.register_profile("xp_default", deadline=800)
1211

1312

1413
def pytest_addoption(parser):
1514
# Hypothesis max examples
1615
# See https://github.com/HypothesisWorks/hypothesis/issues/2434
1716
parser.addoption(
18-
'--hypothesis-max-examples',
19-
'--max-examples',
20-
action='store',
17+
"--hypothesis-max-examples",
18+
"--max-examples",
19+
action="store",
2120
default=None,
22-
help='set the Hypothesis max_examples setting',
21+
help="set the Hypothesis max_examples setting",
2322
)
2423
# Hypothesis deadline
2524
parser.addoption(
26-
'--hypothesis-disable-deadline',
27-
'--disable-deadline',
28-
action='store_true',
29-
help='disable the Hypothesis deadline',
25+
"--hypothesis-disable-deadline",
26+
"--disable-deadline",
27+
action="store_true",
28+
help="disable the Hypothesis deadline",
3029
)
31-
# enable/disable extensions
30+
# disable extensions
3231
parser.addoption(
33-
'--enable-extension',
34-
metavar='ext',
35-
nargs='+',
32+
"--disable-extension",
33+
metavar="ext",
34+
nargs="+",
3635
default=[],
37-
help='enable testing for Array API extension(s)',
36+
help="disable testing for Array API extension(s)",
3837
)
38+
# CI
3939
parser.addoption(
40-
'--disable-extension',
41-
metavar='ext',
42-
nargs='+',
43-
default=[],
44-
help='disable testing for Array API extension(s)',
40+
"--ci",
41+
action="store_true",
42+
help="run just the tests appropiate for CI",
4543
)
4644

4745

4846
def pytest_configure(config):
4947
config.addinivalue_line(
50-
'markers', 'xp_extension(ext): tests an Array API extension'
48+
"markers", "xp_extension(ext): tests an Array API extension"
5149
)
50+
config.addinivalue_line("markers", "primary: primary test")
5251
# Hypothesis
53-
hypothesis_max_examples = config.getoption('--hypothesis-max-examples')
54-
disable_deadline = config.getoption('--hypothesis-disable-deadline')
52+
hypothesis_max_examples = config.getoption("--hypothesis-max-examples")
53+
disable_deadline = config.getoption("--hypothesis-disable-deadline")
5554
profile_settings = {}
5655
if hypothesis_max_examples is not None:
57-
profile_settings['max_examples'] = int(hypothesis_max_examples)
56+
profile_settings["max_examples"] = int(hypothesis_max_examples)
5857
if disable_deadline is not None:
59-
profile_settings['deadline'] = None
58+
profile_settings["deadline"] = None
6059
if profile_settings:
61-
settings.register_profile('xp_override', **profile_settings)
62-
settings.load_profile('xp_override')
60+
settings.register_profile("xp_override", **profile_settings)
61+
settings.load_profile("xp_override")
6362
else:
64-
settings.load_profile('xp_default')
63+
settings.load_profile("xp_default")
6564

6665

6766
@lru_cache
@@ -73,35 +72,37 @@ def xp_has_ext(ext: str) -> bool:
7372

7473

7574
xfail_ids = []
76-
xfails_path = Path(__file__).parent / 'xfails.txt'
75+
xfails_path = Path(__file__).parent / "xfails.txt"
7776
if xfails_path.exists():
7877
with open(xfails_path) as f:
7978
for line in f:
80-
if line.startswith('array_api_tests'):
81-
id_ = line.strip('\n')
79+
if line.startswith("array_api_tests"):
80+
id_ = line.strip("\n")
8281
xfail_ids.append(id_)
8382

8483

8584
def pytest_collection_modifyitems(config, items):
86-
enabled_exts = config.getoption('--enable-extension')
87-
disabled_exts = config.getoption('--disable-extension')
88-
for ext in enabled_exts:
89-
if ext in disabled_exts:
90-
raise ValueError(f'{ext=} both enabled and disabled')
85+
disabled_exts = config.getoption("--disable-extension")
86+
ci = config.getoption("--ci")
9187
for item in items:
92-
# enable/disable extensions
93-
try:
94-
ext_mark = next(m for m in item.iter_markers() if m.name == 'xp_extension')
88+
markers = list(item.iter_markers())
89+
# skip if disabled or non-existent extension
90+
ext_mark = next((m for m in markers if m.name == "xp_extension"), None)
91+
if ext_mark is not None:
9592
ext = ext_mark.args[0]
9693
if ext in disabled_exts:
9794
item.add_marker(
98-
mark.skip(reason=f'{ext} disabled in --disable-extensions')
95+
mark.skip(reason=f"{ext} disabled in --disable-extensions")
9996
)
100-
elif not ext in enabled_exts and not xp_has_ext(ext):
101-
item.add_marker(mark.skip(reason=f'{ext} not found in array module'))
102-
except StopIteration:
103-
pass
104-
# workflow xfail_ids
97+
elif not xp_has_ext(ext):
98+
item.add_marker(mark.skip(reason=f"{ext} not found in array module"))
99+
# xfail if specified in xfails.txt
105100
for id_ in xfail_ids:
106101
if item.nodeid.startswith(id_):
107-
item.add_marker(mark.xfail(reason='xfails.txt'))
102+
item.add_marker(mark.xfail(reason="xfails.txt"))
103+
break
104+
# skip if test not appropiate for CI
105+
if ci:
106+
ci_mark = next((m for m in markers if m.name == "ci"), None)
107+
if ci_mark is None:
108+
item.add_marker(mark.skip(reason="disabled via --ci"))

0 commit comments

Comments
 (0)