(name=None)
| 2579 | |
| 2580 | @contextlib.contextmanager |
| 2581 | def _assert_no_gc_cycles_context(name=None): |
| 2582 | __tracebackhide__ = True # Hide traceback for py.test |
| 2583 | |
| 2584 | # not meaningful to test if there is no refcounting |
| 2585 | if not HAS_REFCOUNT: |
| 2586 | yield |
| 2587 | return |
| 2588 | |
| 2589 | assert_(gc.isenabled()) |
| 2590 | gc.disable() |
| 2591 | gc_debug = gc.get_debug() |
| 2592 | try: |
| 2593 | for i in range(100): |
| 2594 | if gc.collect() == 0: |
| 2595 | break |
| 2596 | else: |
| 2597 | raise RuntimeError( |
| 2598 | "Unable to fully collect garbage - perhaps a __del__ method " |
| 2599 | "is creating more reference cycles?") |
| 2600 | |
| 2601 | gc.set_debug(gc.DEBUG_SAVEALL) |
| 2602 | yield |
| 2603 | # gc.collect returns the number of unreachable objects in cycles that |
| 2604 | # were found -- we are checking that no cycles were created in the context |
| 2605 | n_objects_in_cycles = gc.collect() |
| 2606 | objects_in_cycles = gc.garbage[:] |
| 2607 | finally: |
| 2608 | del gc.garbage[:] |
| 2609 | gc.set_debug(gc_debug) |
| 2610 | gc.enable() |
| 2611 | |
| 2612 | if n_objects_in_cycles: |
| 2613 | name_str = f' when calling {name}' if name is not None else '' |
| 2614 | raise AssertionError( |
| 2615 | "Reference cycles were found{}: {} objects were collected, " |
| 2616 | "of which {} are shown below:{}" |
| 2617 | .format( |
| 2618 | name_str, |
| 2619 | n_objects_in_cycles, |
| 2620 | len(objects_in_cycles), |
| 2621 | ''.join( |
| 2622 | "\n {} object with id={}:\n {}".format( |
| 2623 | type(o).__name__, |
| 2624 | id(o), |
| 2625 | pprint.pformat(o).replace('\n', '\n ') |
| 2626 | ) for o in objects_in_cycles |
| 2627 | ) |
| 2628 | ) |
| 2629 | ) |
| 2630 | |
| 2631 | |
| 2632 | def assert_no_gc_cycles(*args, **kwargs): |
no test coverage detected
searching dependent graphs…