Skip to content

Commit

Permalink
TST: Make test_partial_iteration_cleanup robust but require leak checker
Browse files Browse the repository at this point in the history
This makes sure the test is not flaky, but the test now requires
a leak checker (both valgrind or reference count based should work
in CPython at least).

Closes gh-21169
  • Loading branch information
seberg authored and charris committed Oct 28, 2022
1 parent e55d2d0 commit e3eb14a
Showing 1 changed file with 9 additions and 13 deletions.
22 changes: 9 additions & 13 deletions numpy/core/tests/test_nditer.py
Expand Up @@ -3130,41 +3130,37 @@ def test_warn_noclose():

@pytest.mark.skipif(sys.version_info[:2] == (3, 9) and sys.platform == "win32",
reason="Errors with Python 3.9 on Windows")
@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
@pytest.mark.parametrize(["in_dtype", "buf_dtype"],
[("i", "O"), ("O", "i"), # most simple cases
("i,O", "O,O"), # structured partially only copying O
("O,i", "i,O"), # structured casting to and from O
])
@pytest.mark.parametrize("steps", [1, 2, 3])
def test_partial_iteration_cleanup(in_dtype, buf_dtype, steps):
value = 123 # relies on python cache (leak-check will still find it)
"""
Checks for reference counting leaks during cleanup. Using explicit
reference counts lead to occasional false positives (at least in parallel
test setups). This test now should still test leaks correctly when
run e.g. with pytest-valgrind or pytest-leaks
"""
value = 2**30 + 1 # just a random value that Python won't intern
arr = np.full(int(np.BUFSIZE * 2.5), value).astype(in_dtype)
count = sys.getrefcount(value)

it = np.nditer(arr, op_dtypes=[np.dtype(buf_dtype)],
flags=["buffered", "external_loop", "refs_ok"], casting="unsafe")
for step in range(steps):
# The iteration finishes in 3 steps, the first two are partial
next(it)

# Note that resetting does not free references
del it
break_cycles()
break_cycles()
assert count == sys.getrefcount(value)
del it # not necessary, but we test the cleanup

# Repeat the test with `iternext`
it = np.nditer(arr, op_dtypes=[np.dtype(buf_dtype)],
flags=["buffered", "external_loop", "refs_ok"], casting="unsafe")
for step in range(steps):
it.iternext()

del it # should ensure cleanup
break_cycles()
break_cycles()
assert count == sys.getrefcount(value)

del it # not necessary, but we test the cleanup

@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
@pytest.mark.parametrize(["in_dtype", "buf_dtype"],
Expand Down

0 comments on commit e3eb14a

Please sign in to comment.