Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

speed up setting attributes #638

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions traitlets/traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,12 +616,15 @@ def _cross_validate(self, obj, value):
if self.name in obj._trait_validators:
proposal = Bunch({'trait': self, 'value': value, 'owner': obj})
value = obj._trait_validators[self.name](obj, proposal)
elif hasattr(obj, '_%s_validate' % self.name):
meth_name = '_%s_validate' % self.name
cross_validate = getattr(obj, meth_name)
_deprecated_method(cross_validate, obj.__class__, meth_name,
"use @validate decorator instead.")
value = cross_validate(value, self)
else:
if self.name not in obj._magic_trait_validator_found:
obj._magic_trait_validator_found[self.name] = hasattr(obj, '_%s_validate' % self.name)
if obj._magic_trait_validator_found[self.name]:
meth_name = '_%s_validate' % self.name
cross_validate = getattr(obj, meth_name)
_deprecated_method(cross_validate, obj.__class__, meth_name,
"use @validate decorator instead.")
value = cross_validate(value, self)
return value

def __or__(self, other):
Expand Down Expand Up @@ -1063,6 +1066,9 @@ def setup_instance(*args, **kwargs):
self._trait_values = {}
self._trait_notifiers = {}
self._trait_validators = {}
# keep track which magic trait notifier is found and not
self._magic_trait_notifiers_found = {}
self._magic_trait_validator_found = {}
super(HasTraits, self).setup_instance(*args, **kwargs)

def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -1213,7 +1219,19 @@ def hold(change):
for change in changes:
self.notify_change(change)

def _may_have_observer_for_name(self, name):
if self._trait_notifiers:
return True
if name not in self._magic_trait_notifiers_found:
magic_name = '_%s_changed' % name
self._magic_trait_notifiers_found[name] = hasattr(self, magic_name)
return self._magic_trait_notifiers_found[name]

def _notify_trait(self, name, old_value, new_value):
if not self._may_have_observer_for_name(name) and \
self.__class__.notify_change == HasTraits.notify_change and\
"notify_change" not in self.__dict__:
return
self.notify_change(Bunch(
name=name,
old=old_value,
Expand All @@ -1228,6 +1246,12 @@ def notify_change(self, change):

def _notify_observers(self, event):
"""Notify observers of any event"""
if not isinstance(event, Bunch):
name = event['name']
else:
name = event.name
if not self._may_have_observer_for_name(name):
return
if not isinstance(event, Bunch):
# cast to bunch if given a dict
event = Bunch(event)
Expand Down