ConfigTreeNode.py
changeset 1784 64beb9e9c749
parent 1782 5b6ad7a7fd9d
child 1828 396da88d7b5c
--- a/ConfigTreeNode.py	Mon Aug 21 20:17:19 2017 +0000
+++ b/ConfigTreeNode.py	Mon Aug 21 23:22:58 2017 +0300
@@ -31,7 +31,9 @@
 - ... TODO : document
 """
 
-import os,traceback,types
+import os
+import traceback
+import types
 import shutil
 from lxml import etree
 
@@ -55,6 +57,7 @@
 NameTypeSeparator = '@'
 XSDSchemaErrorMessage = _("{a1} XML file doesn't follow XSD schema at line {a2}:\n{a3}")
 
+
 class ConfigTreeNode:
     """
     This class is the one that define confnodes.
@@ -67,7 +70,7 @@
     LibraryControler = None
     EditorType = ConfTreeNodeEditor
     IconPath = None
-    
+
     def _AddParamsMembers(self):
         self.CTNParams = None
         if self.XSD:
@@ -78,7 +81,7 @@
             setattr(self, name, obj)
 
     def __init__(self):
-        # Create BaseParam 
+        # Create BaseParam
         self.BaseParams = _BaseParamsParser.CreateRoot()
         self.MandatoryParams = ("BaseParams", self.BaseParams)
         self._AddParamsMembers()
@@ -86,39 +89,39 @@
         self._View = None
         # copy ConfNodeMethods so that it can be later customized
         self.ConfNodeMethods = [dic.copy() for dic in self.ConfNodeMethods]
-        
+
     def ConfNodeBaseXmlFilePath(self, CTNName=None):
         return os.path.join(self.CTNPath(CTNName), "baseconfnode.xml")
-    
+
     def ConfNodeXmlFilePath(self, CTNName=None):
         return os.path.join(self.CTNPath(CTNName), "confnode.xml")
 
     def ConfNodePath(self):
         return os.path.join(self.CTNParent.ConfNodePath(), self.CTNType)
 
-    def CTNPath(self,CTNName=None,project_path=None):
+    def CTNPath(self, CTNName=None, project_path=None):
         if not CTNName:
             CTNName = self.CTNName()
         if not project_path:
             project_path = self.CTNParent.CTNPath()
         return os.path.join(project_path,
                             CTNName + NameTypeSeparator + self.CTNType)
-    
+
     def CTNName(self):
         return self.BaseParams.getName()
-    
+
     def CTNEnabled(self):
         return self.BaseParams.getEnabled()
-    
+
     def CTNFullName(self):
         parent = self.CTNParent.CTNFullName()
         if parent != "":
             return parent + "." + self.CTNName()
         return self.BaseParams.getName()
-    
+
     def GetIconName(self):
         return None
-    
+
     def CTNTestModified(self):
         return self.ChangesToSave
 
@@ -134,15 +137,15 @@
                 return True
 
         return False
-    
+
     def RemoteExec(self, script, **kwargs):
         return self.CTNParent.RemoteExec(script, **kwargs)
-    
+
     def OnCTNSave(self, from_project_path=None):
-        #Default, do nothing and return success
+        """Default, do nothing and return success"""
         return True
 
-    def GetParamsAttributes(self, path = None):
+    def GetParamsAttributes(self, path=None):
         if path:
             parts = path.split(".", 1)
             if self.MandatoryParams and parts[0] == self.MandatoryParams[0]:
@@ -154,7 +157,7 @@
             if self.CTNParams:
                 params.append(self.CTNParams[1].getElementInfos(self.CTNParams[0]))
             return params
-        
+
     def SetParamsAttribute(self, path, value):
         self.ChangesToSave = True
         # Filter IEC_Channel and Name, that have specific behavior
@@ -169,7 +172,7 @@
             res = self.FindNewName(value)
             self.CTNRequestSave()
             return res, True
-        
+
         parts = path.split(".", 1)
         if self.MandatoryParams and parts[0] == self.MandatoryParams[0]:
             self.MandatoryParams[1].setElementValue(parts[1], value)
@@ -189,32 +192,32 @@
             if not os.path.isdir(ctnpath):
                 # Create it
                 os.mkdir(ctnpath)
-    
+
             # generate XML for base XML parameters controller of the confnode
             if self.MandatoryParams:
-                BaseXMLFile = open(self.ConfNodeBaseXmlFilePath(),'w')
+                BaseXMLFile = open(self.ConfNodeBaseXmlFilePath(), 'w')
                 BaseXMLFile.write(etree.tostring(
-                    self.MandatoryParams[1], 
-                    pretty_print=True, 
-                    xml_declaration=True, 
+                    self.MandatoryParams[1],
+                    pretty_print=True,
+                    xml_declaration=True,
                     encoding='utf-8'))
                 BaseXMLFile.close()
-            
+
             # generate XML for XML parameters controller of the confnode
             if self.CTNParams:
-                XMLFile = open(self.ConfNodeXmlFilePath(),'w')
+                XMLFile = open(self.ConfNodeXmlFilePath(), 'w')
                 XMLFile.write(etree.tostring(
-                    self.CTNParams[1], 
-                    pretty_print=True, 
-                    xml_declaration=True, 
+                    self.CTNParams[1],
+                    pretty_print=True,
+                    xml_declaration=True,
                     encoding='utf-8'))
                 XMLFile.close()
-            
+
             # Call the confnode specific OnCTNSave method
             result = self.OnCTNSave(from_project_path)
             if not result:
-                return _("Error while saving \"%s\"\n")%self.CTNPath()
-    
+                return _("Error while saving \"%s\"\n") % self.CTNPath()
+
             # mark confnode as saved
             self.ChangesToSave = False
             # go through all children and do the same
@@ -226,7 +229,7 @@
                 if result:
                     return result
         return None
-    
+
     def CTNImport(self, src_CTNPath):
         shutil.copytree(src_CTNPath, self.CTNPath)
         return True
@@ -236,13 +239,13 @@
         @return: [(instance_name, instance_type),...]
         """
         return []
-    
+
     def _GlobalInstances(self):
         instances = self.CTNGlobalInstances()
         for CTNChild in self.IECSortedChildren():
             instances.extend(CTNChild._GlobalInstances())
         return instances
-    
+
     def CTNGenerate_C(self, buildpath, locations):
         """
         Generate C code
@@ -255,9 +258,9 @@
             }, ...]
         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
         """
-        self.GetCTRoot().logger.write_warning(".".join(map(lambda x:str(x), self.GetCurrentLocation())) + " -> Nothing to do\n")
-        return [],"",False
-    
+        self.GetCTRoot().logger.write_warning(".".join(map(lambda x: str(x), self.GetCurrentLocation())) + " -> Nothing to do\n")
+        return [], "", False
+
     def _Generate_C(self, buildpath, locations):
         # Generate confnodes [(Cfiles, CFLAGS)], LDFLAGS, DoCalls, extra_files
         # extra_files = [(fname,fobject), ...]
@@ -273,46 +276,46 @@
         # confnode asks for some LDFLAGS
         if CTNLDFLAGS:
             # LDFLAGS can be either string
-            if type(CTNLDFLAGS)==type(str()):
-                LDFLAGS=[CTNLDFLAGS]
-            #or list of strings
-            elif type(CTNLDFLAGS)==type(list()):
-                LDFLAGS=CTNLDFLAGS[:]
+            if isinstance(CTNLDFLAGS, str):
+                LDFLAGS = [CTNLDFLAGS]
+            # or list of strings
+            elif isinstance(CTNLDFLAGS, list):
+                LDFLAGS = CTNLDFLAGS[:]
         else:
-            LDFLAGS=[]
-        
+            LDFLAGS = []
+
         # recurse through all children, and stack their results
         for CTNChild in self.IECSortedChildren():
             new_location = CTNChild.GetCurrentLocation()
             # How deep are we in the tree ?
-            depth=len(new_location)
+            depth = len(new_location)
             _LocationCFilesAndCFLAGS, _LDFLAGS, _extra_files = \
                 CTNChild._Generate_C(
-                    #keep the same path
+                    # keep the same path
                     buildpath,
                     # filter locations that start with current IEC location
-                    [loc for loc in locations if loc["LOC"][0:depth] == new_location ])
+                    [loc for loc in locations if loc["LOC"][0:depth] == new_location])
             # stack the result
             LocationCFilesAndCFLAGS += _LocationCFilesAndCFLAGS
             LDFLAGS += _LDFLAGS
             extra_files += _extra_files
-        
+
         return LocationCFilesAndCFLAGS, LDFLAGS, extra_files
 
     def IterChildren(self):
         for CTNType, Children in self.Children.items():
             for CTNInstance in Children:
                 yield CTNInstance
-    
+
     def IECSortedChildren(self):
         # reorder children by IEC_channels
-        ordered = [(chld.BaseParams.getIEC_Channel(),chld) for chld in self.IterChildren()]
+        ordered = [(chld.BaseParams.getIEC_Channel(), chld) for chld in self.IterChildren()]
         if ordered:
             ordered.sort()
             return zip(*ordered)[1]
         else:
             return []
-    
+
     def _GetChildBySomething(self, something, toks):
         for CTNInstance in self.IterChildren():
             # if match component of the name
@@ -320,7 +323,7 @@
                 # if Name have other components
                 if len(toks) >= 2:
                     # Recurse in order to find the latest object
-                    return CTNInstance._GetChildBySomething( something, toks[1:])
+                    return CTNInstance._GetChildBySomething(something, toks[1:])
                 # No sub name -> found
                 return CTNInstance
         # Not found
@@ -338,7 +341,7 @@
             return self._GetChildBySomething("IEC_Channel", Location)
         else:
             return self
-    
+
     def GetCurrentLocation(self):
         """
         @return:  Tupple containing confnode IEC location of current confnode : %I0.0.4.5 => (0,0,4,5)
@@ -349,13 +352,13 @@
         """
         @return:  String "ParentParentName.ParentName.Name"
         """
-        return  self.CTNParent._GetCurrentName() + self.BaseParams.getName()
+        return self.CTNParent._GetCurrentName() + self.BaseParams.getName()
 
     def _GetCurrentName(self):
         """
         @return:  String "ParentParentName.ParentName.Name."
         """
-        return  self.CTNParent._GetCurrentName() + self.BaseParams.getName() + "."
+        return self.CTNParent._GetCurrentName() + self.BaseParams.getName() + "."
 
     def GetCTRoot(self):
         return self.CTNParent.GetCTRoot()
@@ -372,7 +375,7 @@
         This function is meant to be overridden by confnodes.
 
         It should returns an list of dictionaries
-        
+
         - IEC_type is an IEC type like BOOL/BYTE/SINT/...
         - location is a string of this variable's location, like "%IX0.0.0"
         '''
@@ -392,9 +395,9 @@
         # Get Current Name
         CurrentName = self.BaseParams.getName()
         # Do nothing if no change
-        #if CurrentName == DesiredName: return CurrentName
+        # if CurrentName == DesiredName: return CurrentName
         # Build a list of used Name out of parent's Children
-        AllNames=[]
+        AllNames = []
         for CTNInstance in self.CTNParent.IterChildren():
             if CTNInstance != self:
                 AllNames.append(CTNInstance.BaseParams.getName())
@@ -407,9 +410,9 @@
             BaseDesiredName = DesiredName
         suffix = 1
         while res in AllNames:
-            res = "%s_%d"%(BaseDesiredName, suffix)
+            res = "%s_%d" % (BaseDesiredName, suffix)
             suffix += 1
-        
+
         # Get old path
         oldname = self.CTNPath()
         # Check previous confnode existance
@@ -421,12 +424,12 @@
             shutil.move(oldname, self.CTNPath())
         # warn user he has two left hands
         if DesiredName != res:
-            msg = _("A child named \"{a1}\" already exists -> \"{a2}\"\n").format(a1 = DesiredName, a2 = res)
+            msg = _("A child named \"{a1}\" already exists -> \"{a2}\"\n").format(a1=DesiredName, a2=res)
             self.GetCTRoot().logger.write_warning(msg)
         return res
 
     def GetAllChannels(self):
-        AllChannels=[]
+        AllChannels = []
         for CTNInstance in self.CTNParent.IterChildren():
             if CTNInstance != self:
                 AllChannels.append(CTNInstance.BaseParams.getIEC_Channel())
@@ -441,20 +444,20 @@
         # Get Current IEC channel
         CurrentChannel = self.BaseParams.getIEC_Channel()
         # Do nothing if no change
-        #if CurrentChannel == DesiredChannel: return CurrentChannel
+        # if CurrentChannel == DesiredChannel: return CurrentChannel
         # Build a list of used Channels out of parent's Children
         AllChannels = self.GetAllChannels()
-        
+
         # Now, try to guess the nearest available channel
         res = DesiredChannel
-        while res in AllChannels: # While channel not free
-            if res < CurrentChannel: # Want to go down ?
-                res -=  1 # Test for n-1
-                if res < 0 :
-                    self.GetCTRoot().logger.write_warning(_("Cannot find lower free IEC channel than %d\n")%CurrentChannel)
-                    return CurrentChannel # Can't go bellow 0, do nothing
-            else : # Want to go up ?
-                res +=  1 # Test for n-1
+        while res in AllChannels:  # While channel not free
+            if res < CurrentChannel:  # Want to go down ?
+                res -= 1  # Test for n-1
+                if res < 0:
+                    self.GetCTRoot().logger.write_warning(_("Cannot find lower free IEC channel than %d\n") % CurrentChannel)
+                    return CurrentChannel  # Can't go bellow 0, do nothing
+            else:  # Want to go up ?
+                res += 1  # Test for n-1
         # Finally set IEC Channel
         self.BaseParams.setIEC_Channel(res)
         return res
@@ -466,14 +469,14 @@
         if self.EditorType is not None:
             app_frame = self.GetCTRoot().AppFrame
             if self._View is None and not onlyopened:
-                
+
                 self._View = self.EditorType(app_frame.TabsOpened, self, app_frame)
-            
+
             if self._View is not None:
                 if name is None:
                     name = self.CTNFullName()
                 app_frame.EditProjectElement(self._View, name)
-            
+
             return self._View
         return None
 
@@ -508,7 +511,7 @@
 
     def CTNRemove(self):
         # Fetch the confnode
-        #CTNInstance = self.GetChildByName(CTNName)
+        # CTNInstance = self.GetChildByName(CTNName)
         # Ask to his parent to remove it
         self.CTNParent._doRemoveChild(self)
 
@@ -521,29 +524,31 @@
         # reorganize self.CTNChildrenTypes tuples from (name, CTNClass, Help)
         # to ( name, (CTNClass, Help)), an make a dict
         transpose = zip(*self.CTNChildrenTypes)
-        CTNChildrenTypes = dict(zip(transpose[0],zip(transpose[1],transpose[2])))
+        CTNChildrenTypes = dict(zip(transpose[0], zip(transpose[1], transpose[2])))
         # Check that adding this confnode is allowed
         try:
             CTNClass, CTNHelp = CTNChildrenTypes[CTNType]
         except KeyError:
-            raise Exception, _("Cannot create child {a1} of type {a2} ").format(a1 = CTNName, a2 = CTNType)
-        
+            raise Exception(_("Cannot create child {a1} of type {a2} ").
+                            format(a1=CTNName, a2=CTNType))
+
         # if CTNClass is a class factory, call it. (prevent unneeded imports)
-        if type(CTNClass) == types.FunctionType:
+        if isinstance(CTNClass, types.FunctionType):
             CTNClass = CTNClass()
-        
+
         # Eventualy Initialize child instance list for this class of confnode
         ChildrenWithSameClass = self.Children.setdefault(CTNType, list())
         # Check count
         if getattr(CTNClass, "CTNMaxCount", None) and len(ChildrenWithSameClass) >= CTNClass.CTNMaxCount:
-            msg = _("Max count ({a1}) reached for this confnode of type {a2} ").format(a1 = CTNClass.CTNMaxCount, a2 = CTNType)
-            raise Exception, msg
-        
+            raise Exception(
+                _("Max count ({a1}) reached for this confnode of type {a2} ").
+                format(a1=CTNClass.CTNMaxCount, a2=CTNType))
+
         # create the final class, derived of provided confnode and template
         class FinalCTNClass(CTNClass, ConfigTreeNode):
             """
             ConfNode class is derivated into FinalCTNClass before being instanciated
-            This way __init__ is overloaded to ensure ConfigTreeNode.__init__ is called 
+            This way __init__ is overloaded to ensure ConfigTreeNode.__init__ is called
             before CTNClass.__init__, and to do the file related stuff.
             """
             def __init__(_self):
@@ -558,25 +563,25 @@
                 # check name is unique
                 NewCTNName = _self.FindNewName(CTNName)
                 # If dir have already be made, and file exist
-                if os.path.isdir(_self.CTNPath(NewCTNName)): #and os.path.isfile(_self.ConfNodeXmlFilePath(CTNName)):
-                    #Load the confnode.xml file into parameters members
+                if os.path.isdir(_self.CTNPath(NewCTNName)):  # and os.path.isfile(_self.ConfNodeXmlFilePath(CTNName)):
+                    # Load the confnode.xml file into parameters members
                     _self.LoadXMLParams(NewCTNName)
                     # Basic check. Better to fail immediately.
                     if (_self.BaseParams.getName() != NewCTNName):
-                        msg = _("Project tree layout do not match confnode.xml {a1}!={a2} ").\
-                              format(a1 = NewCTNName, a2 = _self.BaseParams.getName())
-                        raise Exception, msg
+                        raise Exception(
+                            _("Project tree layout do not match confnode.xml {a1}!={a2} ").
+                            format(a1=NewCTNName, a2=_self.BaseParams.getName()))
 
                     # Now, self.CTNPath() should be OK
-                    
+
                     # Check that IEC_Channel is not already in use.
                     _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel())
                     # Call the confnode real __init__
                     if getattr(CTNClass, "__init__", None):
                         CTNClass.__init__(_self)
-                    #Load and init all the children
+                    # Load and init all the children
                     _self.LoadChildren()
-                    #just loaded, nothing to saved
+                    # just loaded, nothing to saved
                     _self.ChangesToSave = False
                 else:
                     # If confnode do not have corresponding file/dirs - they will be created on Save
@@ -587,31 +592,31 @@
                     if getattr(CTNClass, "__init__", None):
                         CTNClass.__init__(_self)
                     _self.CTNRequestSave()
-                    #just created, must be saved
+                    # just created, must be saved
                     _self.ChangesToSave = True
-                
+
             def _getBuildPath(_self):
                 return self._getBuildPath()
-            
+
         # Create the object out of the resulting class
         newConfNodeOpj = FinalCTNClass()
         # Store it in CTNgedChils
         ChildrenWithSameClass.append(newConfNodeOpj)
-        
+
         return newConfNodeOpj
-    
+
     def ClearChildren(self):
         for child in self.IterChildren():
             child.ClearChildren()
         self.Children = {}
-    
-    def LoadXMLParams(self, CTNName = None):
+
+    def LoadXMLParams(self, CTNName=None):
         methode_name = os.path.join(self.CTNPath(CTNName), "methods.py")
         if os.path.isfile(methode_name):
             execfile(methode_name)
-        
+
         ConfNodeName = CTNName if CTNName is not None else self.CTNName()
-        
+
         # Get the base xml tree
         if self.MandatoryParams:
             try:
@@ -619,14 +624,14 @@
                 self.BaseParams, error = _BaseParamsParser.LoadXMLString(basexmlfile.read())
                 if error is not None:
                     (fname, lnum, src) = ((ConfNodeName + " BaseParams",) + error)
-                    self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1 = fname, a2 = lnum, a3 = src))
+                    self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1=fname, a2=lnum, a3=src))
                 self.MandatoryParams = ("BaseParams", self.BaseParams)
                 basexmlfile.close()
             except Exception, exc:
-                msg = _("Couldn't load confnode base parameters {a1} :\n {a2}").format(a1 =  ConfNodeName, a2 = unicode(exc))
+                msg = _("Couldn't load confnode base parameters {a1} :\n {a2}").format(a1=ConfNodeName, a2=unicode(exc))
                 self.GetCTRoot().logger.write_error(msg)
                 self.GetCTRoot().logger.write_error(traceback.format_exc())
-        
+
         # Get the xml tree
         if self.CTNParams:
             try:
@@ -634,16 +639,16 @@
                 obj, error = self.Parser.LoadXMLString(xmlfile.read())
                 if error is not None:
                     (fname, lnum, src) = ((ConfNodeName,) + error)
-                    self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1 = fname, a2 = lnum, a3 = src))
+                    self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1=fname, a2=lnum, a3=src))
                 name = obj.getLocalTag()
                 setattr(self, name, obj)
                 self.CTNParams = (name, obj)
                 xmlfile.close()
             except Exception, exc:
-                msg = _("Couldn't load confnode parameters {a1} :\n {a2}").format(a1 = ConfNodeName, a2 = unicode(exc))
+                msg = _("Couldn't load confnode parameters {a1} :\n {a2}").format(a1=ConfNodeName, a2=unicode(exc))
                 self.GetCTRoot().logger.write_error(msg)
                 self.GetCTRoot().logger.write_error(traceback.format_exc())
-        
+
     def LoadChildren(self):
         # Iterate over all CTNName@CTNType in confnode directory, and try to open them
         for CTNDir in os.listdir(self.CTNPath()):
@@ -653,7 +658,6 @@
                 try:
                     self.CTNAddChild(pname, ptype)
                 except Exception, exc:
-                    msg = _("Could not add child \"{a1}\", type {a2} :\n{a3}\n").format(a1 = pname, a2 = ptype, a3 = unicode(exc))
+                    msg = _("Could not add child \"{a1}\", type {a2} :\n{a3}\n").format(a1=pname, a2=ptype, a3=unicode(exc))
                     self.GetCTRoot().logger.write_error(msg)
                     self.GetCTRoot().logger.write_error(traceback.format_exc())
-