Skip to content

Commit 26fb918

Browse files
committed
Tweak test
1 parent d3dc220 commit 26fb918

File tree

1 file changed

+17
-19
lines changed

1 file changed

+17
-19
lines changed

hypothesis-python/tests/nocover/test_recursive.py

+17-19
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,9 @@ def test_gc_hooks_do_not_cause_unraisable_recursionerror():
197197
# constant. Regardless, if the test passes just once that's sufficient proof that
198198
# it's not the GC (or accounting of it) that is at fault.
199199

200-
NUM_CYCLES = 10_000
200+
# The number of cycles sufficient to reliably trigger a GC cycle, experimentally
201+
# found to be a few hundred on CPython. Multiply by 10 for safety margin.
202+
NUM_CYCLES = 5_000
201203

202204
def probe_depth():
203205
try:
@@ -213,11 +215,7 @@ def at_depth(depth, fn):
213215
return at_depth(depth - 1, fn)
214216

215217
def gen_cycles():
216-
# We may be at the recursion limit, no free stack frames. Generate lots
217-
# of reference cycles, to trigger GC (if enabled). Beware: there may not
218-
# even be room for raising new exceptions here, anything will end up as
219-
# a RecursionError.
220-
for _ in range(NUM_CYCLES):
218+
for i in range(NUM_CYCLES):
221219
a = [None]
222220
b = [a]
223221
a[0] = b
@@ -228,37 +226,37 @@ def gen_cycles_at_depth(depth, *, gc_disable):
228226
gc.disable()
229227
at_depth(depth, gen_cycles)
230228
dead_objects = gc.collect()
231-
if dead_objects is not None: # == None on PyPy
229+
if dead_objects is not None: # is None on PyPy
232230
if gc_disable:
233231
assert dead_objects >= 2 * NUM_CYCLES
234232
else:
235-
assert dead_objects < 2 * NUM_CYCLES # collection was triggered
233+
# collection was triggered
234+
assert dead_objects < 2 * NUM_CYCLES
236235
finally:
237236
gc.enable()
238237

238+
# Warmup to de-flake PyPy (the first run has much lower effective limits)
239+
probe_depth()
240+
239241
@given(st.booleans())
240242
def inner_test(_):
241243
max_depth = probe_depth()
242-
max_depth = probe_depth() # Executing probe twice de-flakes PyPy
243244

245+
# Lower the limit to where we can successfully generate cycles
246+
# when no gc is performed
244247
while True:
245-
# Lower the limit to where we can successfully generate cycles
246248
try:
247249
gen_cycles_at_depth(max_depth, gc_disable=True)
248250
except RecursionError:
249251
max_depth -= 1
250252
else:
251253
break
254+
# Note that PyPy is a bit weird, in that it raises RecursionError at
255+
# (maxdepth - n) for small positive n, but not at exactly (maxdepth).
256+
# In general, it is really finicky to get the details right in this
257+
# test, so be careful.
252258

253-
# Verify limits w/o any gc interfering
254-
255-
# gen_cycles_at_depth(max_depth - 1, gc_disable=True) # RecursionError on PyPy (!)
256-
gen_cycles_at_depth(max_depth, gc_disable=True)
257-
with pytest.raises(RecursionError):
258-
gen_cycles_at_depth(max_depth + 1, gc_disable=True)
259-
260-
# Check that the limit is unchanged with gc enabled
261-
259+
# Now check that the limit is unchanged with gc enabled
262260
gen_cycles_at_depth(max_depth, gc_disable=False)
263261
with pytest.raises(RecursionError):
264262
gen_cycles_at_depth(max_depth + 1, gc_disable=False)

0 commit comments

Comments
 (0)