From c708e9f57b44f564b6b26acc10c035ac2a10d560 Mon Sep 17 00:00:00 2001
From: Daniel Brown <ddb@star.sr.bham.ac.uk>
Date: Tue, 16 Aug 2016 19:33:28 -0700
Subject: [PATCH] Cleaning up removing of components/commands/detectors and
 loose references. Fixing block remove

---
 pykat/commands.py   | 21 +++++++++++++++++----
 pykat/components.py | 24 ++++++++++++++----------
 pykat/detectors.py  |  3 +++
 pykat/finesse.py    |  7 +++++--
 pykat/param.py      | 45 +++++++++++++++++++++++++++++----------------
 5 files changed, 68 insertions(+), 32 deletions(-)

diff --git a/pykat/commands.py b/pykat/commands.py
index 5df7a6b..83aa6f0 100644
--- a/pykat/commands.py
+++ b/pykat/commands.py
@@ -53,12 +53,25 @@ class Command(object):
         for _ in self._putters_to_register:
             kat.registerVariable(_.name, _)
 
-    def remove(self):
-        self._kat.remove(self)
+    def _on_kat_remove(self):
         self.__removed = True
         
-        for _ in self._putters_to_register:
-            kat.unregisterVariable(_.name)
+        for i in range(len(self._putters_to_register)):
+            _ = self._putters_to_register[i]
+            
+            self._kat.unregisterVariable(_.name)
+            _.clearPuts()
+            
+            del self._putters_to_register[i]
+            
+        del self._putters_to_register[:]
+        
+        
+    def remove(self):
+        if self.__removed:
+            raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
+        else:
+            self._kat.remove(self)
     
     @property
     def name(self): return self.__name
diff --git a/pykat/components.py b/pykat/components.py
index da2aca3..345e60c 100644
--- a/pykat/components.py
+++ b/pykat/components.py
@@ -162,7 +162,17 @@ class Component(object):
         self._kat = kat
         
         kat.nodes.registerComponentNodes(self, self._requested_node_names, self.__on_node_change)
+     
+    def _on_kat_remove(self):
+        # inform all parameters that we have removed its owner
+        # so that it can then warn about any puts/vars/xaxis
+        for p in self._params:
+            p._onOwnerRemoved()
         
+        del self._params[:]
+
+        self.__removed = True
+          
     def __on_node_change(self):
         # need to update the node gauss parameter setter members 
         self.__update_node_setters()
@@ -237,16 +247,10 @@ class Component(object):
     def __str__(self): return self.name
     
     def remove(self):
-        self._kat.remove(self)
-        
-        # inform all parameters that we have removed its owner
-        # so that it can then warn about any puts/vars/xaxis
-        for p in self._params:
-            p._onOwnerRemoved()
-        
-        del self._params[:]
-
-        self.__removed = True
+        if self.__removed:
+            raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
+        else:
+            self._kat.remove(self)
     
     def getOptivisParameterDict(self):
         if len(self._params) == 0:
diff --git a/pykat/detectors.py b/pykat/detectors.py
index 4b1b7db..757494a 100644
--- a/pykat/detectors.py
+++ b/pykat/detectors.py
@@ -120,6 +120,9 @@ class BaseDetector(object) :
             if rn != None:
                 self._nodes.append(kat.nodes.createNode(rn))
     
+    def _on_kat_remove(self):
+        self.__removed = True
+        
     def remove(self):
         if self.__removed:
             raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
diff --git a/pykat/finesse.py b/pykat/finesse.py
index 94403c9..3f9971f 100644
--- a/pykat/finesse.py
+++ b/pykat/finesse.py
@@ -997,8 +997,8 @@ class kat(object):
                 sys.exit(1)
             else:
                 return
-                
-        for o in self.__blocks[name].contents:
+        
+        for o in self.__blocks[name].contents.copy():
             self.remove(o)
         
         del self.__blocks[name]
@@ -1810,6 +1810,9 @@ class kat(object):
     
             del nodes
         
+            if hasattr(obj, "_on_kat_remove"):
+                obj._on_kat_remove()
+            
             #import gc
             #print (gc.get_referrers(obj))
             
diff --git a/pykat/param.py b/pykat/param.py
index 72740a8..440473c 100644
--- a/pykat/param.py
+++ b/pykat/param.py
@@ -27,29 +27,30 @@ class putable(object):
     @property
     def isPutable(self): return self._isPutable
     
-    def put(self, var, alt):
-        if not isinstance(var, putter):
+    def put(self, var, alt=False):
+        if var is not None and not isinstance(var, putter):
             raise pkex.BasePyKatException("`%s` was not something that can be `put` to a parameter" % str(var))
         
-        if self._putter is not None:
-            self._putter.put_count -= 1
-            self._putter.putees.remove(self)
+        # Remove existing puts
+        if self._putter is not None: self._putter().unregister(self)
         
-        self._putter = var
+        if var is not None:
+            self._putter = weakref.ref(var)
+        else:
+            self._putter = None
+            
         self._alt = alt
         
-        if var is not None:
-            self._putter.put_count += 1
-            self._putter.putees.append(self)
+        if var is not None: self._putter().register(self)
         
     def _getPutFinesseText(self):
         rtn = []
         
-        if self._putter is not None:
+        if self._putter is not None and self._putter() is not None:
             putter_enabled = True
             
-            if hasattr(self._putter.owner, 'enabled'):
-                putter_enabled = self._putter.owner.enabled
+            if hasattr(self._putter().owner, 'enabled'):
+                putter_enabled = self._putter().owner.enabled
                                 
             if putter_enabled:
                 if self._alt:
@@ -58,7 +59,7 @@ class putable(object):
                     alt = ''
     
                 # if something is being put to this 
-                rtn.append("put{alt} {comp} {param} ${value}".format(alt=alt, comp=self._component_name, param=self._parameter_name, value=self._putter.put_name()))
+                rtn.append("put{alt} {comp} {param} ${value}".format(alt=alt, comp=self._component_name, param=self._parameter_name, value=self._putter().put_name()))
         
         return rtn
             
@@ -73,11 +74,23 @@ class putter(object):
         self.put_count = 0
         self._isPutter = isPutter
         self.putees = [] # list of params that this puts to
-        self.__owner = owner
+        self.__owner = weakref.ref(owner)
         assert(owner is not None)
     
+    def clearPuts(self):
+        for _ in self.putees:
+            _.put(None)
+    
+    def register(self, toput):
+        self.put_count += 1
+        self.putees.append(toput)
+    
+    def unregister(self, item):
+        self.put_count -= 1
+        self.putees.remove(item)
+        
     @property
-    def owner(self): return self.__owner
+    def owner(self): return self.__owner()
     
     @property
     def name(self): return self._put_name
@@ -114,7 +127,7 @@ class Param(putable, putter):
             if var_name is None:
                 var_name = "var_{0}_{1}".format(owner.name, name)
                 
-        putter.__init__(self, var_name, isPutter)
+        putter.__init__(self, var_name, owner, isPutter)
             
         putable.__init__(self, owner.name, name, isPutable)
 
-- 
GitLab