From fec780c98e73c744e1453c6175dc44959dcc9831 Mon Sep 17 00:00:00 2001 From: Stephan Steinbach Date: Fri, 9 Nov 2018 13:35:33 -0800 Subject: [PATCH] Use a weakref for _parent to prevent cycles. (#364) --- opentimelineio/core/composable.py | 16 +++++++++------- opentimelineio/core/composition.py | 2 +- opentimelineio/core/item.py | 4 ++-- tests/test_composable.py | 4 ++-- tests/test_composition.py | 4 ++-- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/opentimelineio/core/composable.py b/opentimelineio/core/composable.py index 35576cb9b..eb2e75cc6 100644 --- a/opentimelineio/core/composable.py +++ b/opentimelineio/core/composable.py @@ -27,6 +27,8 @@ An object that can be composed by tracks. """ +import weakref + from . import serializable_object from . import type_registry @@ -81,28 +83,28 @@ def _root_parent(self): def _ancestors(self): ancestors = [] seqi = self - while seqi._parent is not None: - seqi = seqi._parent + while seqi.parent() is not None: + seqi = seqi.parent() ancestors.append(seqi) return ancestors def parent(self): """Return the parent Composable, or None if self has no parent.""" - return self._parent + return self._parent() if self._parent is not None else None def _set_parent(self, new_parent): - self._parent = new_parent + self._parent = weakref.ref(new_parent) if new_parent is not None else None def is_parent_of(self, other): """Returns true if self is a parent or ancestor of other.""" visited = set([]) - while other._parent is not None and other._parent not in visited: - if other._parent is self: + while other.parent() is not None and other.parent() not in visited: + if other.parent() is self: return True visited.add(other) - other = other._parent + other = other.parent() return False diff --git a/opentimelineio/core/composition.py b/opentimelineio/core/composition.py index 32c0555a3..8bbc8f4d9 100644 --- a/opentimelineio/core/composition.py +++ b/opentimelineio/core/composition.py @@ -225,7 +225,7 @@ def _path_to_child(self, child): while(current is not self): try: - current = current._parent + current = current.parent() except AttributeError: raise exceptions.NotAChildError( "Item '{}' is not a child of '{}'.".format(child, self) diff --git a/opentimelineio/core/item.py b/opentimelineio/core/item.py index befcc7d41..162007cfc 100644 --- a/opentimelineio/core/item.py +++ b/opentimelineio/core/item.py @@ -159,7 +159,7 @@ def transformed_time(self, t, to_item): item = self while item != root and item != to_item: - parent = item._parent + parent = item.parent() result -= item.trimmed_range().start_time result += parent.range_of_child(item).start_time @@ -171,7 +171,7 @@ def transformed_time(self, t, to_item): item = to_item while item != root and item != ancestor: - parent = item._parent + parent = item.parent() result += item.trimmed_range().start_time result -= parent.range_of_child(item).start_time diff --git a/tests/test_composable.py b/tests/test_composable.py index 16616a6e0..b76f7d2b5 100644 --- a/tests/test_composable.py +++ b/tests/test_composable.py @@ -85,9 +85,9 @@ def test_set_parent(self): # set seqi from none seqi_2._set_parent(seqi) - self.assertEqual(seqi, seqi_2._parent) + self.assertEqual(seqi, seqi_2.parent()) # change seqi seqi_3 = otio.core.Composable() seqi_2._set_parent(seqi_3) - self.assertEqual(seqi_3, seqi_2._parent) + self.assertEqual(seqi_3, seqi_2.parent()) diff --git a/tests/test_composition.py b/tests/test_composition.py index 1e4fc85a7..dc973d282 100755 --- a/tests/test_composition.py +++ b/tests/test_composition.py @@ -120,7 +120,7 @@ def test_replacing_children(self): def test_parent_manip(self): it = otio.core.Item() co = otio.core.Composition(children=[it]) - self.assertIs(it._parent, co) + self.assertIs(it.parent(), co) def test_each_child_recursion(self): tl = otio.schema.Timeline(name="TL") @@ -203,7 +203,7 @@ def test_serialize(self): decoded = otio.adapters.otio_json.read_from_string(encoded) self.assertIsOTIOEquivalentTo(st, decoded) - self.assertIsNotNone(decoded[0]._parent) + self.assertIsNotNone(decoded[0].parent()) def test_str(self): st = otio.schema.Stack(name="foo", children=[])