##// END OF EJS Templates
Merge pull request #6133 from SylvainCorlay/unilink...
Jonathan Frederic -
r17632:ee6e9bbe merge
parent child Browse files
Show More
@@ -19,7 +19,8 b' from IPython.utils.traitlets import ('
19 HasTraits, MetaHasTraits, TraitType, Any, CBytes, Dict,
19 HasTraits, MetaHasTraits, TraitType, Any, CBytes, Dict,
20 Int, Long, Integer, Float, Complex, Bytes, Unicode, TraitError,
20 Int, Long, Integer, Float, Complex, Bytes, Unicode, TraitError,
21 Undefined, Type, This, Instance, TCPAddress, List, Tuple,
21 Undefined, Type, This, Instance, TCPAddress, List, Tuple,
22 ObjectName, DottedObjectName, CRegExp, link, EventfulList, EventfulDict
22 ObjectName, DottedObjectName, CRegExp, link, directional_link,
23 EventfulList, EventfulDict
23 )
24 )
24 from IPython.utils import py3compat
25 from IPython.utils import py3compat
25 from IPython.testing.decorators import skipif
26 from IPython.testing.decorators import skipif
@@ -1147,6 +1148,71 b' class TestLink(TestCase):'
1147 self.assertEqual(''.join(callback_count), 'ab')
1148 self.assertEqual(''.join(callback_count), 'ab')
1148 del callback_count[:]
1149 del callback_count[:]
1149
1150
1151 class TestDirectionalLink(TestCase):
1152 def test_connect_same(self):
1153 """Verify two traitlets of the same type can be linked together using directional_link."""
1154
1155 # Create two simple classes with Int traitlets.
1156 class A(HasTraits):
1157 value = Int()
1158 a = A(value=9)
1159 b = A(value=8)
1160
1161 # Conenct the two classes.
1162 c = directional_link((a, 'value'), (b, 'value'))
1163
1164 # Make sure the values are the same at the point of linking.
1165 self.assertEqual(a.value, b.value)
1166
1167 # Change one the value of the source and check that it synchronizes the target.
1168 a.value = 5
1169 self.assertEqual(b.value, 5)
1170 # Change one the value of the target and check that it has no impact on the source
1171 b.value = 6
1172 self.assertEqual(a.value, 5)
1173
1174 def test_link_different(self):
1175 """Verify two traitlets of different types can be linked together using link."""
1176
1177 # Create two simple classes with Int traitlets.
1178 class A(HasTraits):
1179 value = Int()
1180 class B(HasTraits):
1181 count = Int()
1182 a = A(value=9)
1183 b = B(count=8)
1184
1185 # Conenct the two classes.
1186 c = directional_link((a, 'value'), (b, 'count'))
1187
1188 # Make sure the values are the same at the point of linking.
1189 self.assertEqual(a.value, b.count)
1190
1191 # Change one the value of the source and check that it synchronizes the target.
1192 a.value = 5
1193 self.assertEqual(b.count, 5)
1194 # Change one the value of the target and check that it has no impact on the source
1195 b.value = 6
1196 self.assertEqual(a.value, 5)
1197
1198 def test_unlink(self):
1199 """Verify two linked traitlets can be unlinked."""
1200
1201 # Create two simple classes with Int traitlets.
1202 class A(HasTraits):
1203 value = Int()
1204 a = A(value=9)
1205 b = A(value=8)
1206
1207 # Connect the two classes.
1208 c = directional_link((a, 'value'), (b, 'value'))
1209 a.value = 4
1210 c.unlink()
1211
1212 # Change one of the values to make sure they don't stay in sync.
1213 a.value = 5
1214 self.assertNotEqual(a.value, b.value)
1215
1150 class Pickleable(HasTraits):
1216 class Pickleable(HasTraits):
1151 i = Int()
1217 i = Int()
1152 j = Int()
1218 j = Int()
@@ -227,6 +227,61 b' class link(object):'
227 (obj,attr) = key
227 (obj,attr) = key
228 obj.on_trait_change(callback, attr, remove=True)
228 obj.on_trait_change(callback, attr, remove=True)
229
229
230 @skip_doctest
231 class directional_link(object):
232 """Link the trait of a source object with traits of target objects.
233
234 Parameters
235 ----------
236 source : pair of object, name
237 targets : pairs of objects/attributes
238
239 Examples
240 --------
241
242 >>> c = directional_link((src, 'value'), (tgt1, 'value'), (tgt2, 'value'))
243 >>> src.value = 5 # updates target objects
244 >>> tgt1.value = 6 # does not update other objects
245 """
246 updating = False
247
248 def __init__(self, source, *targets):
249 self.source = source
250 self.targets = targets
251
252 # Update current value
253 src_attr_value = getattr(source[0], source[1])
254 for obj, attr in targets:
255 if getattr(obj, attr) != src_attr_value:
256 setattr(obj, attr, src_attr_value)
257
258 # Wire
259 self.source[0].on_trait_change(self._update, self.source[1])
260
261 @contextlib.contextmanager
262 def _busy_updating(self):
263 self.updating = True
264 try:
265 yield
266 finally:
267 self.updating = False
268
269 def _update(self, name, old, new):
270 if self.updating:
271 return
272 with self._busy_updating():
273 for obj, attr in self.targets:
274 setattr(obj, attr, new)
275
276 def unlink(self):
277 self.source[0].on_trait_change(self._update, self.source[1], remove=True)
278 self.source = None
279 self.targets = []
280
281 def dlink(source, *targets):
282 """Shorter helper function returning a directional_link object"""
283 return directional_link(source, *targets)
284
230 #-----------------------------------------------------------------------------
285 #-----------------------------------------------------------------------------
231 # Base TraitType for all traits
286 # Base TraitType for all traits
232 #-----------------------------------------------------------------------------
287 #-----------------------------------------------------------------------------
General Comments 0
You need to be logged in to leave comments. Login now