From ec7e668255d944b1b861ca689bb1c7ef0dd2fe90 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Thu, 9 Apr 2020 14:31:49 +0200 Subject: [PATCH 1/3] Keep Parameters state on Parameterized --- param/parameterized.py | 73 +++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index 7142e7bd4..1cbcaac23 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1072,16 +1072,43 @@ def __init__(self_, cls, self=None): """ self_.cls = cls self_.self = self - self_._BATCH_WATCH = False # If true, Event and watcher objects are queued. - self_._TRIGGER = False - self_._events = [] # Queue of batched eventd - self_._watchers = [] # Queue of batched watchers + + @property + def _BATCH_WATCH(self_): + return self_.self_or_cls._parameters_state['BATCH_WATCH'] + + @_BATCH_WATCH.setter + def _BATCH_WATCH(self_, value): + self_.self_or_cls._parameters_state['BATCH_WATCH'] = value + + @property + def _TRIGGER(self_): + return self_.self_or_cls._parameters_state['TRIGGER'] + + @_TRIGGER.setter + def _TRIGGER(self_, value): + self_.self_or_cls._parameters_state['TRIGGER'] = value + + @property + def _events(self_): + return self_.self_or_cls._parameters_state['events'] + + @_events.setter + def _events(self_, value): + self_.self_or_cls._parameters_state['events'] = value + + @property + def _watchers(self_): + return self_.self_or_cls._parameters_state['watchers'] + + @_watchers.setter + def _watchers(self_, value): + self_.self_or_cls._parameters_state['watchers'] = value @property def self_or_cls(self_): return self_.cls if self_.self is None else self_.self - def __getitem__(self_, key): """ Returns the class or instance parameter @@ -1872,7 +1899,14 @@ def __init__(mcs,name,bases,dict_): # 'name' to '__name__'?) mcs.name = name - mcs.param = Parameters(mcs) + mcs._parameters_state = { + "BATCH_WATCH": False, # If true, Event and watcher objects are queued. + "TRIGGER": False, + "events": [], # Queue of batched events + "watchers": [] # Queue of batched watchers + } + mcs._param = Parameters(mcs) + # All objects (with their names) of type Parameter that are # defined in this class @@ -1957,7 +1991,10 @@ def __is_abstract(mcs): abstract = property(__is_abstract) + def _get_param(mcs): + return mcs._param + param = property(_get_param) def __setattr__(mcs,attribute_name,value): """ @@ -2309,18 +2346,21 @@ class Foo(Parameterized): see documentation for the 'logging' module. """ - name = String(default=None,constant=True,doc=""" - String identifier for this object.""") + name = String(default=None, constant=True, doc=""" + String identifier for this object.""") - - def __init__(self,**params): + def __init__(self, **params): global object_count # Flag that can be tested to see if e.g. constant Parameters # can still be set - self.initialized=False - # Override class level param namespace with instance namespace - self.param = Parameters(self.__class__, self=self) + self.initialized = False + self._parameters_state = { + "BATCH_WATCH": False, # If true, Event and watcher objects are queued. + "TRIGGER": False, + "events": [], # Queue of batched events + "watchers": [] # Queue of batched watchers + } self._instance__params = {} self._param_watchers = {} @@ -2341,7 +2381,11 @@ def __init__(self,**params): # TODO: can't remember why not just pass m (rather than _m_caller) here (p.inst or p.cls).param.watch(_m_caller(self, n), p.name, p.what, queued=queued) - self.initialized=True + self.initialized = True + + @property + def param(self): + return Parameters(self.__class__, self) # 'Special' methods @@ -2353,7 +2397,6 @@ def __getstate__(self): """ # remind me, why is it a copy? why not just state.update(self.__dict__)? state = self.__dict__.copy() - for slot in get_occupied_slots(self): state[slot] = getattr(self,slot) From ab262c5fe079a074d76d3021d0ac228199dee975 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Thu, 9 Apr 2020 15:48:13 +0200 Subject: [PATCH 2/3] Handle non-initialized Parameterized --- param/parameterized.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index 1cbcaac23..5884c615f 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1116,7 +1116,7 @@ def __getitem__(self_, key): inst = self_.self parameters = self_.objects(False) if inst is None else inst.param.objects(False) p = parameters[key] - if (inst is not None and p.per_instance and + if (inst is not None and getattr(inst, 'initialized', False) and p.per_instance and not getattr(inst, '_disable_instance__params', False)): if key not in inst._instance__params: try: @@ -2385,7 +2385,7 @@ def __init__(self, **params): @property def param(self): - return Parameters(self.__class__, self) + return Parameters(self.__class__, self=self) # 'Special' methods From f639cff6835222fc05bf9ae6d70fad9f3eedda71 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Thu, 9 Apr 2020 19:03:28 +0200 Subject: [PATCH 3/3] Added support for unpickling old Parameters objects --- param/parameterized.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/param/parameterized.py b/param/parameterized.py index 5884c615f..396856bd3 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1109,6 +1109,16 @@ def _watchers(self_, value): def self_or_cls(self_): return self_.cls if self_.self is None else self_.self + def __setstate__(self, state): + # Set old parameters state on Parameterized._parameters_state + self_or_cls = state.get('self', state.get('cls')) + for k in self_or_cls._parameters_state: + key = '_'+k + if key in state: + self_or_cls._parameters_state[k] = state.pop(key) + for k, v in state.items(): + setattr(self, k, v) + def __getitem__(self_, key): """ Returns the class or instance parameter @@ -2421,6 +2431,7 @@ def __setstate__(self, state): state['_instance__params'] = {} if '_param_watchers' not in state: state['_param_watchers'] = {} + state.pop('param', None) for name,value in state.items(): setattr(self,name,value)