HasTraits.trait_set does not properly handle recursion
- Dominant language
- Python
- Stars
- 462
- Forks
- 90
- PR merge metrics
- No merged PRs in 30d
Description
The current body of `HasTraits.trait_set` looks like this:
``` python
def trait_set ( self, trait_change_notify = True, **traits ):
if not trait_change_notify:
self._trait_change_notify( False )
try:
for name, value in traits.items():
setattr( self, name, value )
finally:
self._trait_change_notify( True )
else:
for name, value in traits.items():
setattr( self, name, value )
return self
```
The problem with this is that if `trait_change_notify` is `False`, and the call to `setattr(...)` somehow triggers another call to `trait_set` with `trait_change_notify = False` (like through a property), then `_trait_change_notify( True )` will be called by the recursive path, incorrectly turning on notifications for the first `setattr(...)` call. This happens because `_trait_change_notify` just sets a bit flag on the HasTraits object at the C level; it does not keep a stack context.
I've got a workaround that overrides trait_set with the following:
``` python
_trait_change_notify_flag = Bool(True)
def trait_set(self, trait_change_notify=True, **traits):
last = self._trait_change_notify_flag
self._trait_change_notify_flag = trait_change_notify
self._trait_change_notify(trait_change_notify)
try:
for name, value in traits.iteritems():
setattr(self, name, value)
finally:
self._trait_change_notify_flag = last
self._trait_change_notify(last)
return self
```
This works, but it's not ideal. It would be better if the C api exposed the flag as read-write instead of write-only.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.