(name=None)
| 2281 | |
| 2282 | @contextlib.contextmanager |
| 2283 | def _assert_no_gc_cycles_context(name=None): |
| 2284 | __tracebackhide__ = True # Hide traceback for py.test |
| 2285 | |
| 2286 | # not meaningful to test if there is no refcounting |
| 2287 | if not HAS_REFCOUNT: |
| 2288 | yield |
| 2289 | return |
| 2290 | |
| 2291 | assert_(gc.isenabled()) |
| 2292 | gc.disable() |
| 2293 | gc_debug = gc.get_debug() |
| 2294 | try: |
| 2295 | for i in range(100): |
| 2296 | if gc.collect() == 0: |
| 2297 | break |
| 2298 | else: |
| 2299 | raise RuntimeError( |
| 2300 | "Unable to fully collect garbage - perhaps a __del__ method " |
| 2301 | "is creating more reference cycles?") |
| 2302 | |
| 2303 | gc.set_debug(gc.DEBUG_SAVEALL) |
| 2304 | yield |
| 2305 | # gc.collect returns the number of unreachable objects in cycles that |
| 2306 | # were found -- we are checking that no cycles were created in the context |
| 2307 | n_objects_in_cycles = gc.collect() |
| 2308 | objects_in_cycles = gc.garbage[:] |
| 2309 | finally: |
| 2310 | del gc.garbage[:] |
| 2311 | gc.set_debug(gc_debug) |
| 2312 | gc.enable() |
| 2313 | |
| 2314 | if n_objects_in_cycles: |
| 2315 | name_str = f' when calling {name}' if name is not None else '' |
| 2316 | raise AssertionError( |
| 2317 | "Reference cycles were found{}: {} objects were collected, " |
| 2318 | "of which {} are shown below:{}" |
| 2319 | .format( |
| 2320 | name_str, |
| 2321 | n_objects_in_cycles, |
| 2322 | len(objects_in_cycles), |
| 2323 | ''.join( |
| 2324 | "\n {} object with id={}:\n {}".format( |
| 2325 | type(o).__name__, |
| 2326 | id(o), |
| 2327 | pprint.pformat(o).replace('\n', '\n ') |
| 2328 | ) for o in objects_in_cycles |
| 2329 | ) |
| 2330 | ) |
| 2331 | ) |
| 2332 | |
| 2333 | |
| 2334 | def assert_no_gc_cycles(*args, **kwargs): |
no test coverage detected