Skip to content

Commit b4038ce

Browse files
ev-brCopilot
andauthored
Fix testing on python 3.10 (#398)
Use a python 3.10 compatible workaround for `Exception.add_note`, as suggested in HypothesisWorks/hypothesis#4606 (comment) Commit drafted by GH Copilot, reviewed at #398 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent 8909fbb commit b4038ce

10 files changed

+84
-64
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
strategy:
1010
matrix:
11-
python-version: ["3.12", "3.13", "3.14"]
12-
11+
python-version: ["3.10", "3.12", "3.13", "3.14"]
1312
steps:
1413
- name: Checkout array-api-tests
1514
uses: actions/checkout@v1

array_api_tests/pytest_helpers.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .typing import Array, DataType, Scalar, ScalarType, Shape
1212

1313
__all__ = [
14+
"add_note",
1415
"raises",
1516
"doesnt_raise",
1617
"nargs",
@@ -31,6 +32,26 @@
3132
]
3233

3334

35+
def add_note(exc, note):
36+
"""
37+
Add a note to an exception in a backward-compatible way.
38+
39+
For Python 3.11+, this uses the built-in exc.add_note() method.
40+
For earlier versions, it manually appends to exc.__notes__.
41+
42+
https://github.com/HypothesisWorks/hypothesis/issues/4606#issuecomment-3568140174
43+
"""
44+
try:
45+
exc.add_note(note)
46+
except AttributeError:
47+
if not hasattr(exc, "__notes__"):
48+
try:
49+
exc.__notes__ = []
50+
except AttributeError:
51+
return # give up, might be e.g. a frozen dataclass
52+
exc.__notes__.append(note)
53+
54+
3455
def raises(exceptions, function, message=""):
3556
"""
3657
Like pytest.raises() except it allows custom error messages

array_api_tests/test_array_object.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def test_getitem(shape, dtype, data):
106106
expected = xp.asarray(out_obj, dtype=dtype)
107107
ph.assert_array_elements("__getitem__", out=out, expected=expected)
108108
except Exception as exc:
109-
exc.add_note(repro_snippet)
109+
ph.add_note(exc, repro_snippet)
110110
raise
111111

112112
@pytest.mark.unvectorized

array_api_tests/test_creation_functions.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def test_arange(dtype, data):
196196
out[0], xp.asarray(_start, dtype=out.dtype)
197197
), f"out[0]={out[0]}, but should be {_start} {f_func}"
198198
except Exception as exc:
199-
exc.add_note(repro_snippet)
199+
ph.add_note(exc, repro_snippet)
200200
raise
201201

202202

@@ -257,7 +257,7 @@ def test_asarray_scalars(shape, data):
257257
v = scalar_type(out[idx])
258258
ph.assert_scalar_equals("asarray", type_=scalar_type, idx=idx, out=v, expected=v_expect, kw=kw)
259259
except Exception as exc:
260-
exc.add_note(repro_snippet)
260+
ph.add_note(exc, repro_snippet)
261261
raise
262262

263263
def scalar_eq(s1: Scalar, s2: Scalar) -> bool:
@@ -323,7 +323,7 @@ def test_asarray_arrays(shape, dtypes, data):
323323
new_out_value, value
324324
), f"{f_out}, but should be {value} after x was mutated"
325325
except Exception as exc:
326-
exc.add_note(repro_snippet)
326+
ph.add_note(exc, repro_snippet)
327327
raise
328328

329329

@@ -339,7 +339,7 @@ def test_empty(shape, kw):
339339
ph.assert_kw_dtype("empty", kw_dtype=kw["dtype"], out_dtype=out.dtype)
340340
ph.assert_shape("empty", out_shape=out.shape, expected=shape, kw=dict(shape=shape))
341341
except Exception as exc:
342-
exc.add_note(repro_snippet)
342+
ph.add_note(exc, repro_snippet)
343343
raise
344344

345345

@@ -357,7 +357,7 @@ def test_empty_like(x, kw):
357357
ph.assert_kw_dtype("empty_like", kw_dtype=kw["dtype"], out_dtype=out.dtype)
358358
ph.assert_shape("empty_like", out_shape=out.shape, expected=x.shape)
359359
except Exception as exc:
360-
exc.add_note(repro_snippet)
360+
ph.add_note(exc, repro_snippet)
361361
raise
362362

363363
@given(
@@ -387,7 +387,7 @@ def test_eye(n_rows, n_cols, kw):
387387
expected = xp.reshape(expected, (n_rows, _n_cols))
388388
ph.assert_array_elements("eye", out=out, expected=expected, kw=kw)
389389
except Exception as exc:
390-
exc.add_note(repro_snippet)
390+
ph.add_note(exc, repro_snippet)
391391
raise
392392

393393

@@ -455,7 +455,7 @@ def test_full(shape, fill_value, kw):
455455
ph.assert_shape("full", out_shape=out.shape, expected=shape, kw=dict(shape=shape))
456456
ph.assert_fill("full", fill_value=fill_value, dtype=dtype, out=out, kw=dict(fill_value=fill_value))
457457
except Exception as exc:
458-
exc.add_note(repro_snippet)
458+
ph.add_note(exc, repro_snippet)
459459
raise
460460

461461

@@ -476,7 +476,7 @@ def test_full_like(kw, data):
476476
ph.assert_shape("full_like", out_shape=out.shape, expected=x.shape)
477477
ph.assert_fill("full_like", fill_value=fill_value, dtype=dtype, out=out, kw=dict(fill_value=fill_value))
478478
except Exception as exc:
479-
exc.add_note(repro_snippet)
479+
ph.add_note(exc, repro_snippet)
480480
raise
481481

482482
finite_kw = {"allow_nan": False, "allow_infinity": False}
@@ -534,7 +534,7 @@ def test_linspace(num, dtype, endpoint, data):
534534
expected = expected[:-1]
535535
ph.assert_array_elements("linspace", out=out, expected=expected)
536536
except Exception as exc:
537-
exc.add_note(repro_snippet)
537+
ph.add_note(exc, repro_snippet)
538538
raise
539539

540540

@@ -563,7 +563,7 @@ def test_meshgrid(dtype, data):
563563
for i, x in enumerate(out):
564564
ph.assert_dtype("meshgrid", in_dtype=dtype, out_dtype=x.dtype, repr_name=f"out[{i}].dtype")
565565
except Exception as exc:
566-
exc.add_note(repro_snippet)
566+
ph.add_note(exc, repro_snippet)
567567
raise
568568

569569

@@ -590,7 +590,7 @@ def test_ones(shape, kw):
590590
dtype = kw.get("dtype", None) or dh.default_float
591591
ph.assert_fill("ones", fill_value=make_one(dtype), dtype=dtype, out=out, kw=kw)
592592
except Exception as exc:
593-
exc.add_note(repro_snippet)
593+
ph.add_note(exc, repro_snippet)
594594
raise
595595

596596

@@ -611,7 +611,7 @@ def test_ones_like(x, kw):
611611
ph.assert_fill("ones_like", fill_value=make_one(dtype), dtype=dtype,
612612
out=out, kw=kw)
613613
except Exception as exc:
614-
exc.add_note(repro_snippet)
614+
ph.add_note(exc, repro_snippet)
615615
raise
616616

617617

@@ -638,7 +638,7 @@ def test_zeros(shape, kw):
638638
ph.assert_fill("zeros", fill_value=make_zero(dtype), dtype=dtype, out=out,
639639
kw=kw)
640640
except Exception as exc:
641-
exc.add_note(repro_snippet)
641+
ph.add_note(exc, repro_snippet)
642642
raise
643643

644644

@@ -660,5 +660,5 @@ def test_zeros_like(x, kw):
660660
ph.assert_fill("zeros_like", fill_value=make_zero(dtype), dtype=dtype,
661661
out=out, kw=kw)
662662
except Exception as exc:
663-
exc.add_note(repro_snippet)
663+
ph.add_note(exc, repro_snippet)
664664
raise

array_api_tests/test_data_type_functions.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def test_astype(x_dtype, dtype, kw, data):
9090
# TODO: test values
9191
# TODO: test copy
9292
except Exception as exc:
93-
exc.add_note(repro_snippet)
93+
ph.add_note(exc, repro_snippet)
9494
raise
9595

9696

@@ -124,7 +124,7 @@ def test_broadcast_arrays(shapes, data):
124124
)
125125
# TODO: test values
126126
except Exception as exc:
127-
exc.add_note(repro_snippet)
127+
ph.add_note(exc, repro_snippet)
128128
raise
129129

130130

@@ -145,7 +145,7 @@ def test_broadcast_to(x, data):
145145
ph.assert_shape("broadcast_to", out_shape=out.shape, expected=shape)
146146
# TODO: test values
147147
except Exception as exc:
148-
exc.add_note(repro_snippet)
148+
ph.add_note(exc, repro_snippet)
149149
raise
150150

151151

@@ -168,7 +168,7 @@ def test_can_cast(_from, to):
168168
# check that the array library actually allows such casts.
169169
assert out == expected, f"{out=}, but should be {expected} {f_func}"
170170
except Exception as exc:
171-
exc.add_note(repro_snippet)
171+
ph.add_note(exc, repro_snippet)
172172
raise
173173

174174

@@ -189,7 +189,7 @@ def test_finfo(dtype):
189189
assert isinstance(out.min, float)
190190
assert isinstance(out.smallest_normal, float)
191191
except Exception as exc:
192-
exc.add_note(repro_snippet)
192+
ph.add_note(exc, repro_snippet)
193193
raise
194194

195195
@pytest.mark.min_version("2022.12")
@@ -211,7 +211,7 @@ def test_finfo_dtype(dtype):
211211
assert out.dtype is not float
212212
assert out.dtype is not complex
213213
except Exception as exc:
214-
exc.add_note(repro_snippet)
214+
ph.add_note(exc, repro_snippet)
215215
raise
216216

217217

@@ -230,7 +230,7 @@ def test_iinfo(dtype):
230230
assert isinstance(out.max, int)
231231
assert isinstance(out.min, int)
232232
except Exception as exc:
233-
exc.add_note(repro_snippet)
233+
ph.add_note(exc, repro_snippet)
234234
raise
235235

236236

@@ -245,7 +245,7 @@ def test_iinfo_dtype(dtype):
245245
assert not isinstance(out.dtype, str)
246246
assert out.dtype is not int
247247
except Exception as exc:
248-
exc.add_note(repro_snippet)
248+
ph.add_note(exc, repro_snippet)
249249
raise
250250

251251

@@ -277,7 +277,7 @@ def test_isdtype(dtype, kind):
277277
break
278278
assert out == expected, f"{out=}, but should be {expected} [isdtype()]"
279279
except Exception as exc:
280-
exc.add_note(repro_snippet)
280+
ph.add_note(exc, repro_snippet)
281281
raise
282282

283283

@@ -290,7 +290,7 @@ def test_result_type(self, dtypes):
290290
out = xp.result_type(*dtypes)
291291
ph.assert_dtype("result_type", in_dtype=dtypes, out_dtype=out, repr_name="out")
292292
except Exception as exc:
293-
exc.add_note(repro_snippet)
293+
ph.add_note(exc, repro_snippet)
294294
raise
295295

296296
@given(pair=hh.pair_of_mutually_promotable_dtypes(None))
@@ -312,7 +312,7 @@ def test_arrays_and_dtypes(self, pair, data):
312312
out = xp.result_type(*a_and_dt)
313313
ph.assert_dtype("result_type", in_dtype=s1+s2, out_dtype=out, repr_name="out")
314314
except Exception as exc:
315-
exc.add_note(repro_snippet)
315+
ph.add_note(exc, repro_snippet)
316316
raise
317317

318318
@given(dtypes=hh.mutually_promotable_dtypes(2), data=st.data())
@@ -333,7 +333,7 @@ def test_with_scalars(self, dtypes, data):
333333
else:
334334
raise ValueError(f"unknown dtype {out = }.")
335335
except Exception as exc:
336-
exc.add_note(repro_snippet)
336+
ph.add_note(exc, repro_snippet)
337337
raise
338338

339339
scalar = data.draw(st.sampled_from(scalars))
@@ -344,7 +344,7 @@ def test_with_scalars(self, dtypes, data):
344344
out_scalar = xp.result_type(*inputs)
345345
assert out_scalar == out
346346
except Exception as exc:
347-
exc.add_note(repro_snippet)
347+
ph.add_note(exc, repro_snippet)
348348
raise
349349

350350
# retry with arrays
@@ -356,5 +356,5 @@ def test_with_scalars(self, dtypes, data):
356356
out_scalar = xp.result_type(*inputs)
357357
assert out_scalar == out
358358
except Exception as exc:
359-
exc.add_note(repro_snippet)
359+
ph.add_note(exc, repro_snippet)
360360
raise

0 commit comments

Comments
 (0)