Find circular references in a list of objects. The garbage list contains objects that participate in a cycle, but also the larger set of objects kept alive by that cycle. This function finds subsets of those objects that make up the cycle(s).
(garbage)
| 23 | |
| 24 | |
| 25 | def find_circular_references(garbage): |
| 26 | """Find circular references in a list of objects. |
| 27 | |
| 28 | The garbage list contains objects that participate in a cycle, |
| 29 | but also the larger set of objects kept alive by that cycle. |
| 30 | This function finds subsets of those objects that make up |
| 31 | the cycle(s). |
| 32 | """ |
| 33 | |
| 34 | def inner(level): |
| 35 | for item in level: |
| 36 | item_id = id(item) |
| 37 | if item_id not in garbage_ids: |
| 38 | continue |
| 39 | if item_id in visited_ids: |
| 40 | continue |
| 41 | if item_id in stack_ids: |
| 42 | candidate = stack[stack.index(item) :] |
| 43 | candidate.append(item) |
| 44 | found.append(candidate) |
| 45 | continue |
| 46 | |
| 47 | stack.append(item) |
| 48 | stack_ids.add(item_id) |
| 49 | inner(gc.get_referents(item)) |
| 50 | stack.pop() |
| 51 | stack_ids.remove(item_id) |
| 52 | visited_ids.add(item_id) |
| 53 | |
| 54 | found: typing.List[object] = [] |
| 55 | stack = [] |
| 56 | stack_ids = set() |
| 57 | garbage_ids = set(map(id, garbage)) |
| 58 | visited_ids = set() |
| 59 | |
| 60 | inner(garbage) |
| 61 | return found |
| 62 | |
| 63 | |
| 64 | @contextlib.contextmanager |
no test coverage detected