From ea59221801e0fef332ad4442902fb3496f0922ec Mon Sep 17 00:00:00 2001
From: Daniel Brown <ddb@star.sr.bham.ac.uk>
Date: Tue, 10 Jan 2017 09:43:56 +0000
Subject: [PATCH] tidying up using a decorator instead for freezing objects,
 adding to fsig too

---
 pykat/__init__.py   |  3 +--
 pykat/commands.py   | 13 +++----------
 pykat/components.py | 13 +++----------
 pykat/detectors.py  | 11 ++---------
 pykat/finesse.py    | 34 ++++++++++++++++++++--------------
 5 files changed, 29 insertions(+), 45 deletions(-)

diff --git a/pykat/__init__.py b/pykat/__init__.py
index b256447..b6ec024 100644
--- a/pykat/__init__.py
+++ b/pykat/__init__.py
@@ -20,7 +20,7 @@ except ImportError:
 import pykat.exceptions as pkex
 
 NoGUIException = pkex.BasePyKatException("No PyQt4 module was found so cannot open a GUI")
-
+    
 import pykat.finesse as finesse
 import pykat.components as components
 import pykat.detectors as detectors
@@ -30,4 +30,3 @@ from pykat.optics.gaussian_beams import BeamParam
 
 from pykat.plotting import init_pykat_plotting
 
-
diff --git a/pykat/commands.py b/pykat/commands.py
index e065c57..aefa093 100644
--- a/pykat/commands.py
+++ b/pykat/commands.py
@@ -11,6 +11,7 @@ from __future__ import unicode_literals
 
 import numpy
 import warnings
+import pykat
 import pykat.external.six as six
 import pykat.exceptions as pkex
 
@@ -23,8 +24,9 @@ from numpy import min, max
 from pykat.param import Param, putter
 from collections import namedtuple
 from pykat.optics.gaussian_beams import BeamParam
+from pykat.freeze import canFreeze
 
-
+@canFreeze
 class Command(object):
     __metaclass__ = abc.ABCMeta
     
@@ -54,15 +56,6 @@ class Command(object):
         result._freeze()
         return result
     
-    def _freeze(self): self.__dict__["____FROZEN____"] = True
-    def _unfreeze(self): self.__dict__["____FROZEN____"] = False
-        
-    def __setattr__(self, name, value):
-        if "____FROZEN____" in self.__dict__ and self.__dict__["____FROZEN____"] and not hasattr(self, name):
-            warnings.warn("'%s' does not have attribute called '%s'" % (self.__name, name), stacklevel=2)
-
-        super(Command, self).__setattr__(name, value)
-                       
     def getFinesseText(self):
         """ Base class for individual finesse optical components """
         raise NotImplementedError("This function is not implemented")
diff --git a/pykat/components.py b/pykat/components.py
index 9d014d3..01491be 100644
--- a/pykat/components.py
+++ b/pykat/components.py
@@ -37,6 +37,7 @@ from pykat.param import Param, AttrParam
 import weakref
 import pykat.exceptions as pkex
 from copy import deepcopy
+from pykat.freeze import canFreeze
 
 next_component_id = 1
 
@@ -86,7 +87,8 @@ class NodeGaussSetter(object):
         self.__node().setGauss(self.__comp(), self.qx, complex(value))
         
 id_____pykat_class = 0
-  
+ 
+@canFreeze
 class Component(object):
     __metaclass__ = abc.ABCMeta
 
@@ -121,15 +123,6 @@ class Component(object):
         global next_component_id
         self.__id = next_component_id
         next_component_id += 1    
-     
-    def _freeze(self): self.__dict__["____FROZEN____"] = True
-    def _unfreeze(self): self.__dict__["____FROZEN____"] = False
-        
-    def __setattr__(self, name, value):
-        if "____FROZEN____" in self.__dict__ and self.__dict__["____FROZEN____"] and not hasattr(self, name):
-            warnings.warn("'%s' does not have attribute called '%s'" % (self.__name, name), stacklevel=2)
-
-        super(Component, self).__setattr__(name, value)
          
     def __deepcopy__(self, memo):
         """
diff --git a/pykat/detectors.py b/pykat/detectors.py
index 0258000..62e6938 100644
--- a/pykat/detectors.py
+++ b/pykat/detectors.py
@@ -26,6 +26,7 @@ import warnings
 import copy
 
 from pykat import USE_GUI, NoGUIException
+from pykat.freeze import canFreeze
 
 if USE_GUI:
     import pykat.gui.resources
@@ -33,6 +34,7 @@ if USE_GUI:
 
 id_____pykat_class = 0
 
+@canFreeze
 class BaseDetector(object) :
     """
     This is a base class for all detectors. Classes Detector1 and Detector2 should be used directly.
@@ -100,15 +102,6 @@ class BaseDetector(object) :
             else:
                 raise pkex.BasePyKatException("Nodes should be a list or tuple of node names or a singular node name as a string.")
     
-    def _freeze(self): self.__dict__["____FROZEN____"] = True
-    def _unfreeze(self): self.__dict__["____FROZEN____"] = False
-        
-    def __setattr__(self, name, value):
-        if "____FROZEN____" in self.__dict__ and self.__dict__["____FROZEN____"] and not hasattr(self, name):
-            warnings.warn("'%s' does not have attribute called '%s'" % (self.__name, name), stacklevel=2)
-
-        super(BaseDetector, self).__setattr__(name, value)
-    
     def __deepcopy__(self, memo):
         """
         When deep copying a kat object we need to take into account
diff --git a/pykat/finesse.py b/pykat/finesse.py
index a524485..98a5036 100644
--- a/pykat/finesse.py
+++ b/pykat/finesse.py
@@ -87,14 +87,13 @@ from pykat.commands import Command, xaxis
 from pykat.SIfloat import *
 from pykat.param import Param, AttrParam
 from pykat.external import progressbar
-
+from pykat.freeze import canFreeze
 import pykat.external.six as six
 
 import pykat.exceptions as pkex
 
 from pykat import USE_GUI, HAS_OPTIVIS, NoGUIException
 
-    
 if HAS_OPTIVIS:
     from optivis.bench.labels import Label as optivis_label
     from optivis.geometry import Coordinates as optivis_coord
@@ -342,18 +341,24 @@ def GUILength(L):
     Should scale the lengths in some way to handle km and mm for time being
     """
     return L # * ( 40 * erfc(L/400.0) + 0.01)
-            
+
+@canFreeze
 class KatRun(object):
     def __init__(self):
+        self._unfreeze()
         self.runtime = None
         self.StartDateTime = datetime.datetime.now()
         self.x = None
+        self.stdout = None
+        self.stderr = None
+        self.runDateTime = None
         self.y = None
         self.xlabel = None
         self.ylabels = None
         self.katScript = None
         self.katVersion = None
         self.yaxis = None
+        self._freeze()
         
     def info(self):
         
@@ -635,9 +640,11 @@ class KatRun(object):
                 return out.squeeze()
         else:
             raise  pkex.BasePyKatException("No output by the name '{0}' found in the output".format(str(value)))
-      
+            
+@canFreeze 
 class KatRun2D(object):
     def __init__(self):
+        self._unfreeze()
         self.runtime = None
         self.startDateTime = datetime.datetime.now()
         self.x = None
@@ -650,6 +657,7 @@ class KatRun2D(object):
         self.katVersion = None
         self.stderr = None
         self.stdout = None
+        self._freeze()
         
     def saveKatRun(self, filename):
         with open(filename,'w') as outfile:
@@ -670,10 +678,13 @@ class KatRun2D(object):
         else:
             raise  pkex.BasePyKatException("No output by the name {0} found".format(str(value)))
     
-        
+@canFreeze    
 class Signals(object):
+    
+    @canFreeze 
     class fsig(object):
         def __init__(self, param, name, amplitude, phase, signal):
+            self._unfreeze()
             self._params = []
             self.__target = param
             self.__name = name
@@ -681,6 +692,7 @@ class Signals(object):
             self.__phase = Param("phase", self, SIfloat(phase))
             self.__removed = False
             self.__signal = signal
+            self._freeze()
             
             # unfortunatenly the target names for fsig are not the same as the
             # various parameter names of the components, e.g. mirror xbeta is x 
@@ -766,11 +778,13 @@ class Signals(object):
         self.__f.value = SIfloat(value)
     
     def __init__(self, kat):
+        self._unfreeze()
         self._default_name = "fsignal"
         self.targets = []
         self._params = []
         self.__f = Param("f", self, None)
         self._kat = kat
+        self._freeze()
         
     def _register_param(self, param):
         self._params.append(param)
@@ -823,6 +837,7 @@ Constant = namedtuple('Constant', 'name, value, usedBy')
 
 id___ = 0
 
+@canFreeze
 class kat(object):  
 
     def __new__(cls, *args, **kwargs):
@@ -891,15 +906,6 @@ class kat(object):
     
         self._freeze()
         
-    def _freeze(self): self.__dict__["____FROZEN____"] = True
-    def _unfreeze(self): self.__dict__["____FROZEN____"] = False
-        
-    def __setattr__(self, name, value):
-        if "____FROZEN____" in self.__dict__ and self.__dict__["____FROZEN____"] and not hasattr(self, name):
-            warnings.warn("'%s' does not have attribute called '%s'" % (self.__class__.__name__, name), stacklevel=2)
-
-        super(kat, self).__setattr__(name, value)
-        
     def deepcopy(self):
         return copy.deepcopy(self)
     
-- 
GitLab