From d12e8ff570f8aad64c93d5bf9a5797e03848a2f3 Mon Sep 17 00:00:00 2001 From: "Maarten A. Breddels" Date: Tue, 17 Nov 2020 14:25:30 +0100 Subject: [PATCH 1/2] speed up setting attributes --- traitlets/traitlets.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/traitlets/traitlets.py b/traitlets/traitlets.py index 20355904..e17c992e 100644 --- a/traitlets/traitlets.py +++ b/traitlets/traitlets.py @@ -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_notifiers_found: + obj._magic_trait_notifiers_found[self.name] = hasattr(obj, '_%s_validate' % self.name) + if obj._magic_trait_notifiers_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): @@ -1063,6 +1066,8 @@ 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 = dict() super(HasTraits, self).setup_instance(*args, **kwargs) def __init__(self, *args, **kwargs): @@ -1213,7 +1218,17 @@ 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): + return self.notify_change(Bunch( name=name, old=old_value, @@ -1228,6 +1243,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) From ce95b014595f2ebb8442bdf31125da22d7d4691b Mon Sep 17 00:00:00 2001 From: "Maarten A. Breddels" Date: Wed, 18 Nov 2020 18:10:56 +0100 Subject: [PATCH 2/2] validator != notifier and notify_change can be changed --- traitlets/traitlets.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/traitlets/traitlets.py b/traitlets/traitlets.py index e17c992e..36c3f62d 100644 --- a/traitlets/traitlets.py +++ b/traitlets/traitlets.py @@ -617,9 +617,9 @@ def _cross_validate(self, obj, value): proposal = Bunch({'trait': self, 'value': value, 'owner': obj}) value = obj._trait_validators[self.name](obj, proposal) else: - if self.name not in obj._magic_trait_notifiers_found: - obj._magic_trait_notifiers_found[self.name] = hasattr(obj, '_%s_validate' % self.name) - if obj._magic_trait_notifiers_found[self.name]: + 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, @@ -1067,7 +1067,8 @@ def setup_instance(*args, **kwargs): self._trait_notifiers = {} self._trait_validators = {} # keep track which magic trait notifier is found and not - self._magic_trait_notifiers_found = dict() + self._magic_trait_notifiers_found = {} + self._magic_trait_validator_found = {} super(HasTraits, self).setup_instance(*args, **kwargs) def __init__(self, *args, **kwargs): @@ -1227,7 +1228,9 @@ def _may_have_observer_for_name(self, 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): + 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,