Skip to content

Commit 60315b2

Browse files
committed
tests: more xfails, nicer system
1 parent 190436c commit 60315b2

16 files changed

+71
-65
lines changed

tests/conftest.py

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -197,25 +197,40 @@ def pytest_configure():
197197

198198
# Platform Markers
199199

200-
PLAT = sys.platform.lower()
201-
IMPL = platform.python_implementation().lower()
202-
PYMAJ = str(sys.version_info.major)
203-
PYNAME = "py" + PYMAJ
204-
205-
CURRENT = {PLAT, IMPL, PYNAME, IMPL + PYMAJ}
206-
START = {"xfail", "skip"}
200+
PLAT = sys.platform.lower() # linux, osx, or win32
201+
IMPL = platform.python_implementation().lower() # cpython or pypy
207202

208203

209204
def pytest_collection_modifyitems(items):
205+
"""
206+
This will find the markers listed in pytest.ini and add
207+
skip or xfail as needed. The second part can be a platform
208+
marker (linux, osx, or win32), or python, cpython, or pypy.
209+
210+
You can add also add Python version numbers - either 2 or 3.
211+
212+
Keyword arguments are passed on.
213+
214+
# Will skip on Python 2
215+
pytest.mark.skip_python(2)
216+
217+
# Will xfail on pypy as long as TypeError is raised
218+
pytest.mark.xfail_pypy(reason="Not supported", raises=TypeError)
219+
"""
210220
for item in items:
211221
for mark in tuple(item.iter_markers()):
222+
# Check for recognised name
212223
parts = mark.name.split("_")
213-
if len(parts) == 2 and parts[0] in START and parts[1] in CURRENT:
224+
if len(parts) == 2 and parts[0] in {"xfail", "skip"}:
214225
marker = getattr(pytest.mark, parts[0])
215-
reason = "expected to fail on {}".format(parts[1])
216226

217-
item.add_marker(
218-
marker(**mark.kwargs)
219-
if "reason" in mark.kwargs
220-
else marker(reason=reason, **mark.kwargs)
221-
)
227+
if parts[1] in {PLAT, IMPL, "python"}:
228+
# args lets you remove only Py 2 or 3
229+
if mark.args:
230+
(ver,) = mark.args # Only single argument supported
231+
assert isinstance(ver, int), "should be a version number"
232+
if ver == sys.version_info.major:
233+
item.add_marker(marker(**mark.kwargs))
234+
else:
235+
assert parts[1] != "python", "version required (otherwise use mark.skip)"
236+
item.add_marker(marker(**mark.kwargs))

tests/pytest.ini

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ norecursedirs = test_cmake_build test_embed
44
addopts =
55
# show summary of skipped tests
66
-rs
7-
# Report xfails
8-
-rx
7+
# Report xfails (uncomment to use
8+
# -rx
99
# capture only Python print and C++ py::print, but not C output (low-level Python errors)
1010
--capture=sys
1111
# warnings for deprecated features
@@ -26,18 +26,12 @@ markers =
2626
xfail_linux: expected failure on Linux
2727
xfail_darwin: expected failure on MacOS
2828
xfail_win32: expected failure on Windows
29+
xfail_python: expected failure on Python (2 or 3 required)
2930
xfail_cpython: expected failure on CPython
30-
xfail_pypy: expected failure on PyPy (2+3)
31-
xfail_pypy2: expected failure on PyPy 2
32-
xfail_pypy3: expected failure on PyPy 3
33-
xfail_py2: expected failure on Python 2
34-
xfail_py3: expected failure on Python 3
35-
skip_linux: does not run on Linux
36-
skip_darwin: does not run on MacOS
37-
skip_win32: does not run on Windows
38-
skip_cpython: does not run on CPython
39-
skip_pypy: does not run on PyPy (2+3)
40-
skip_pypy2: does not run on PyPy 2
41-
skip_pypy3: does not run on PyPy 3
42-
skip_py2: does not run on Python 2
43-
skip_py3: does not run on Python 3
31+
xfail_pypy: not valid on PyPy (2+3)
32+
skip_linux: not valid on Linux
33+
skip_darwin: not valid on MacOS
34+
skip_win32: not valid on Windows
35+
skip_python: not valid on Python (2 or 3 required)
36+
skip_cpython: not valid on CPython
37+
skip_pypy: not valid on PyPy (2+3)

tests/test_buffers.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ def test_from_python():
3535
assert cstats.move_assignments == 0
3636

3737

38-
# PyPy: Memory leak in the "np.array(m, copy=False)" call
39-
# https://bitbucket.org/pypy/pypy/issues/2444
40-
@pytest.mark.skip_pypy
38+
# https://foss.heptapod.net/pypy/pypy/-/issues/2444
39+
@pytest.mark.xfail_pypy(reason="memory leak in np.array(m, copy=False)")
4140
def test_to_python():
4241
mat = m.Matrix(5, 4)
4342
assert memoryview(mat).shape == (5, 4)
@@ -72,7 +71,7 @@ def test_to_python():
7271
assert cstats.move_assignments == 0
7372

7473

75-
@pytest.mark.skip_pypy
74+
@pytest.mark.xfail_pypy
7675
def test_inherited_protocol():
7776
"""SquareMatrix is derived from Matrix and inherits the buffer protocol"""
7877

@@ -81,7 +80,7 @@ def test_inherited_protocol():
8180
assert np.asarray(matrix).shape == (5, 5)
8281

8382

84-
@pytest.mark.skip_pypy
83+
@pytest.mark.xfail_pypy
8584
def test_pointer_to_member_fn():
8685
for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:
8786
buf = cls()
@@ -90,15 +89,15 @@ def test_pointer_to_member_fn():
9089
assert value == 0x12345678
9190

9291

93-
@pytest.mark.skip_pypy
92+
@pytest.mark.xfail_pypy
9493
def test_readonly_buffer():
9594
buf = m.BufferReadOnly(0x64)
9695
view = memoryview(buf)
9796
assert view[0] == b'd' if six.PY2 else 0x64
9897
assert view.readonly
9998

10099

101-
@pytest.mark.skip_pypy
100+
@pytest.mark.xfail_pypy
102101
def test_selective_readonly_buffer():
103102
buf = m.BufferReadOnlySelect()
104103

tests/test_call_policies.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ def test_keep_alive_return_value(capture):
7070
"""
7171

7272

73-
# https://bitbucket.org/pypy/pypy/issues/2447
74-
@pytest.mark.skip_pypy
73+
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
74+
@pytest.mark.xfail_pypy(reason="_PyObject_GetDictPtr is unimplemented")
7575
def test_alive_gc(capture):
7676
n_inst = ConstructorStats.detail_reg_inst()
7777
p = m.ParentGC()

tests/test_class.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ def test_brace_initialization():
261261
assert b.vec == [123, 456]
262262

263263

264-
@pytest.mark.skip_pypy
264+
@pytest.mark.xfail_pypy
265265
def test_class_refcount():
266266
"""Instances must correctly increase/decrease the reference count of their types (#1029)"""
267267
from sys import getrefcount
@@ -307,17 +307,17 @@ def test_aligned():
307307
assert p % 1024 == 0
308308

309309

310-
# https://bitbucket.org/pypy/pypy/issues/2742
311-
@pytest.mark.skip_pypy
310+
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
311+
@pytest.mark.xfail_pypy
312312
def test_final():
313313
with pytest.raises(TypeError) as exc_info:
314314
class PyFinalChild(m.IsFinal):
315315
pass
316316
assert str(exc_info.value).endswith("is not an acceptable base type")
317317

318318

319-
# https://bitbucket.org/pypy/pypy/issues/2742
320-
@pytest.mark.skip_pypy
319+
# https://foss.heptapod.net/pypy/pypy/-/issues/2742
320+
@pytest.mark.xfail_pypy
321321
def test_non_final_final():
322322
with pytest.raises(TypeError) as exc_info:
323323
class PyNonFinalFinalChild(m.IsNonFinalFinal):

tests/test_eval.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def test_evals(capture):
1515
assert m.test_eval_failure()
1616

1717

18-
@pytest.mark.xfail_pypy3(raises=RuntimeError)
18+
@pytest.mark.xfail_pypy(3, raises=RuntimeError)
1919
def test_eval_file():
2020
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
2121
assert m.test_eval_file(filename)

tests/test_factory_constructors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ def test_reallocations(capture, msg):
418418
""")
419419

420420

421-
@pytest.mark.skip_py2
421+
@pytest.mark.skip_python(2)
422422
def test_invalid_self():
423423
"""Tests invocation of the pybind-registered base class with an invalid `self` argument. You
424424
can only actually do this on Python 3: Python 2 raises an exception itself if you try."""

tests/test_kwargs_and_defaults.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,7 @@ def test_keyword_only_args(msg):
146146
"""
147147

148148

149-
# PyPy2 doesn't seem to double count
150-
@pytest.mark.xfail_pypy2
149+
@pytest.mark.xfail_pypy(2, reason="PyPy2 doesn't seem to double count")
151150
def test_args_refcount():
152151
"""Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular
153152
arguments"""

tests/test_methods_and_attributes.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def test_property_rvalue_policy():
258258

259259

260260
# https://bitbucket.org/pypy/pypy/issues/2447
261-
@pytest.mark.skip_pypy
261+
@pytest.mark.xfail_pypy
262262
def test_dynamic_attributes():
263263
instance = m.DynamicClass()
264264
assert not hasattr(instance, "foo")
@@ -299,8 +299,8 @@ class PythonDerivedDynamicClass(m.DynamicClass):
299299
assert cstats.alive() == 0
300300

301301

302-
# https://bitbucket.org/pypy/pypy/issues/2447
303-
@pytest.mark.skip_pypy
302+
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
303+
@pytest.mark.xfail_pypy
304304
def test_cyclic_gc():
305305
# One object references itself
306306
instance = m.DynamicClass()

tests/test_multiple_inheritance.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ def test_multiple_inheritance_cpp():
1111
assert mt.bar() == 4
1212

1313

14-
@pytest.mark.skip_pypy2
15-
@pytest.mark.xfail_pypy3
14+
@pytest.mark.skip_pypy(2)
15+
@pytest.mark.xfail_pypy(3)
1616
def test_multiple_inheritance_mix1():
1717
class Base1:
1818
def __init__(self, i):
@@ -51,8 +51,8 @@ def __init__(self, i, j):
5151
assert mt.bar() == 4
5252

5353

54-
@pytest.mark.skip_pypy2
55-
@pytest.mark.xfail_pypy3
54+
@pytest.mark.skip_pypy(2)
55+
@pytest.mark.xfail_pypy(3)
5656
def test_multiple_inheritance_python():
5757

5858
class MI1(m.Base1, m.Base2):

tests/test_numpy_array.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ def test_numpy_view(capture):
240240
"""
241241

242242

243-
@pytest.mark.skip_pypy
243+
@pytest.mark.xfail_pypy
244244
def test_cast_numpy_int64_to_uint64():
245245
m.function_taking_uint64(123)
246246
m.function_taking_uint64(np.uint64(123))
@@ -421,7 +421,7 @@ def test_array_resize(msg):
421421
assert(b.shape == (8, 8))
422422

423423

424-
@pytest.mark.skip_pypy
424+
@pytest.mark.xfail_pypy
425425
def test_array_create_and_resize(msg):
426426
a = m.create_and_resize(2)
427427
assert(a.size == 4)
@@ -433,7 +433,7 @@ def test_index_using_ellipsis():
433433
assert a.shape == (6,)
434434

435435

436-
@pytest.mark.skip_pypy
436+
@pytest.mark.xfail_pypy
437437
def test_dtype_refcount_leak():
438438
from sys import getrefcount
439439
dtype = np.dtype(np.float_)

tests/test_numpy_dtypes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ def test_register_dtype():
291291
assert 'dtype is already registered' in str(excinfo.value)
292292

293293

294-
@pytest.mark.skip_pypy
294+
@pytest.mark.xfail_pypy
295295
def test_str_leak():
296296
from sys import getrefcount
297297
fmt = "f4"

tests/test_pickling.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def test_roundtrip(cls_name):
2222
assert p2.extra2() == p.extra2()
2323

2424

25-
@pytest.mark.skip_pypy
25+
@pytest.mark.xfail_pypy
2626
@pytest.mark.parametrize("cls_name", ["PickleableWithDict", "PickleableWithDictNew"])
2727
def test_roundtrip_with_dict(cls_name):
2828
cls = getattr(m, cls_name)

tests/test_pytypes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ def test_test_memoryview_from_buffer_nullptr():
373373
m.test_memoryview_from_buffer_nullptr()
374374

375375

376-
@pytest.mark.skip_py2
376+
@pytest.mark.skip_python(2)
377377
def test_memoryview_from_memory():
378378
view = m.test_memoryview_from_memory()
379379
assert isinstance(view, memoryview)

tests/test_stl_binders.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ def test_vector_int():
6868
assert len(v_int2) == 0
6969

7070

71-
# related to the PyPy's buffer protocol.
72-
@pytest.mark.skip_pypy
71+
# Older PyPy's failed here, related to the PyPy's buffer protocol.
7372
def test_vector_buffer():
7473
b = bytearray([1, 2, 3, 4])
7574
v = m.VectorUChar(b)
@@ -94,7 +93,7 @@ def test_vector_buffer():
9493
assert "NumPy type info missing for " in str(excinfo.value)
9594

9695

97-
@pytest.mark.skip_pypy
96+
@pytest.mark.xfail_pypy
9897
def test_vector_buffer_numpy():
9998
np = pytest.importorskip("numpy")
10099
a = np.array([1, 2, 3, 4], dtype=np.int32)

tests/test_virtual_functions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def f(self):
160160

161161
# PyPy: Reference count > 1 causes call with noncopyable instance
162162
# to fail in ncv1.print_nc()
163-
@pytest.mark.skip_pypy
163+
@pytest.mark.xfail_pypy
164164
@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC")
165165
def test_move_support():
166166
class NCVirtExt(m.NCVirt):

0 commit comments

Comments
 (0)