plcopen/plcopen.py
changeset 1305 714f1381a09a
parent 1302 7856cd7767d6
child 1307 26e8b99bc2c3
equal deleted inserted replaced
1304:6be6c1e0e4d0 1305:714f1381a09a
   122         test_result.append((start, end, "\n".join(lines[start[0]:end[0] + 1])))
   122         test_result.append((start, end, "\n".join(lines[start[0]:end[0] + 1])))
   123         result = criteria["pattern"].search(text, result.end())
   123         result = criteria["pattern"].search(text, result.end())
   124     return test_result
   124     return test_result
   125 
   125 
   126 PLCOpenParser = GenerateParserFromXSD(os.path.join(os.path.split(__file__)[0], "tc6_xml_v201.xsd"))
   126 PLCOpenParser = GenerateParserFromXSD(os.path.join(os.path.split(__file__)[0], "tc6_xml_v201.xsd"))
       
   127 PLCOpen_XPath = lambda xpath: etree.XPath(xpath, namespaces=PLCOpenParser.NSMAP)
   127 
   128 
   128 LOAD_POU_PROJECT_TEMPLATE = """
   129 LOAD_POU_PROJECT_TEMPLATE = """
   129 <project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" 
   130 <project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" 
   130          xmlns:xhtml="http://www.w3.org/1999/xhtml" 
   131          xmlns:xhtml="http://www.w3.org/1999/xhtml" 
   131          xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   132          xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   168         project_xml = cre.sub(repl, project_xml)
   169         project_xml = cre.sub(repl, project_xml)
   169     project_file.close()
   170     project_file.close()
   170     
   171     
   171     return etree.fromstring(project_xml, PLCOpenParser)
   172     return etree.fromstring(project_xml, PLCOpenParser)
   172 
   173 
       
   174 project_pou_xpath = PLCOpen_XPath("/ppx:project/ppx:types/ppx:pous/ppx:pou")
   173 def LoadPou(xml_string):
   175 def LoadPou(xml_string):
   174     root = etree.fromstring(
   176     root = etree.fromstring(
   175         LOAD_POU_PROJECT_TEMPLATE % xml_string, 
   177         LOAD_POU_PROJECT_TEMPLATE % xml_string, 
   176         PLCOpenParser)
   178         PLCOpenParser)
   177     return root.xpath(
   179     return project_pou_xpath(root)[0]
   178         "/ppx:project/ppx:types/ppx:pous/ppx:pou",
   180 
   179         namespaces=PLCOpenParser.NSMAP)[0]
   181 project_pou_instances_xpath = {
   180 
   182     body_type: PLCOpen_XPath(
       
   183         "/ppx:project/ppx:types/ppx:pous/ppx:pou[@name='paste_pou']/ppx:body/ppx:%s/*" % body_type)
       
   184     for body_type in ["FBD", "LD", "SFC"]}
   181 def LoadPouInstances(xml_string, body_type):
   185 def LoadPouInstances(xml_string, body_type):
   182     root = etree.fromstring(
   186     root = etree.fromstring(
   183         LOAD_POU_INSTANCES_PROJECT_TEMPLATE(body_type) % xml_string, 
   187         LOAD_POU_INSTANCES_PROJECT_TEMPLATE(body_type) % xml_string, 
   184         PLCOpenParser)
   188         PLCOpenParser)
   185     return root.xpath(
   189     return project_pou_instances_xpath[body_type](root)
   186         "/ppx:project/ppx:types/ppx:pous/ppx:pou[@name='paste_pou']/ppx:body/ppx:%s/*" % body_type,
       
   187         namespaces=PLCOpenParser.NSMAP)
       
   188 
   190 
   189 def SaveProject(project, filepath):
   191 def SaveProject(project, filepath):
   190     project_file = open(filepath, 'w')
   192     project_file = open(filepath, 'w')
   191     project_file.write(etree.tostring(
   193     project_file.write(etree.tostring(
   192         project, 
   194         project, 
   301                 contentheader_obj.setscaling(contentheader["scaling"])
   303                 contentheader_obj.setscaling(contentheader["scaling"])
   302             else:
   304             else:
   303                 setattr(contentheader_obj, attr, value)
   305                 setattr(contentheader_obj, attr, value)
   304     setattr(cls, "setcontentHeader", setcontentHeader)
   306     setattr(cls, "setcontentHeader", setcontentHeader)
   305     
   307     
   306     def gettypeElement(self, element_type, name):
   308     def gettypeElementFunc(element_type):
   307         elements = self.xpath(
   309         elements_xpath = PLCOpen_XPath(
   308             "ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s[@name='%(name)s']" % locals(),
   310             "ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s[@name=$name]" % locals())
   309             namespaces=PLCOpenParser.NSMAP)
   311         def gettypeElement(self, name):
   310         if name is None:
   312             elements = elements_xpath(self, name=name)
   311             return elements
   313             if len(elements) == 1:
   312         elif len(elements) == 1:
   314                 return elements[0]
   313             return elements[0]
   315             return None
   314         return None
   316         return gettypeElement
   315     setattr(cls, "gettypeElement", gettypeElement)
   317     
   316     
   318     datatypes_xpath = PLCOpen_XPath("ppx:types/ppx:dataTypes/ppx:dataType")
       
   319     filtered_datatypes_xpath = PLCOpen_XPath(
       
   320         "ppx:types/ppx:dataTypes/ppx:dataType[@name!=$exclude]")
   317     def getdataTypes(self, exclude=None):
   321     def getdataTypes(self, exclude=None):
   318         return self.xpath(
   322         if exclude is not None:
   319             "ppx:types/ppx:dataTypes/ppx:dataType%s" % 
   323             return filtered_datatypes_xpath(self, exclude=exclude)
   320                 ("[@name!='%s']" % exclude if exclude is not None else ""),
   324         return datatypes_xpath(self)
   321             namespaces=PLCOpenParser.NSMAP)
       
   322     setattr(cls, "getdataTypes", getdataTypes)
   325     setattr(cls, "getdataTypes", getdataTypes)
   323     
   326     
   324     def getdataType(self, name):
   327     setattr(cls, "getdataType", gettypeElementFunc("dataType"))
   325         return self.gettypeElement("dataType", name)
       
   326     setattr(cls, "getdataType", getdataType)
       
   327     
   328     
   328     def appenddataType(self, name):
   329     def appenddataType(self, name):
   329         if self.getdataType(name) is not None:
   330         if self.getdataType(name) is not None:
   330             raise ValueError, "\"%s\" Data Type already exists !!!"%name
   331             raise ValueError, "\"%s\" Data Type already exists !!!"%name
   331         self.types.appenddataTypeElement(name)
   332         self.types.appenddataTypeElement(name)
   337     
   338     
   338     def removedataType(self, name):
   339     def removedataType(self, name):
   339         self.types.removedataTypeElement(name)
   340         self.types.removedataTypeElement(name)
   340     setattr(cls, "removedataType", removedataType)
   341     setattr(cls, "removedataType", removedataType)
   341     
   342     
   342     def getpous(self, exclude=None, filter=None):
   343     def getpous(self, exclude=None, filter=[]):
   343         return self.xpath(
   344         return self.xpath(
   344             "ppx:types/ppx:pous/ppx:pou%s%s" % 
   345             "ppx:types/ppx:pous/ppx:pou%s%s" % 
   345                 (("[@name!='%s']" % exclude) if exclude is not None else '',
   346                 (("[@name!='%s']" % exclude) if exclude is not None else '',
   346                  ("[%s]" % " or ".join(
   347                  ("[%s]" % " or ".join(
   347                     map(lambda x: "@pouType='%s'" % x, filter)))
   348                     map(lambda x: "@pouType='%s'" % x, filter)))
   348                  if filter is not None else ""),
   349                  if len(filter) > 0 else ""),
   349             namespaces=PLCOpenParser.NSMAP)
   350             namespaces=PLCOpenParser.NSMAP)
   350     setattr(cls, "getpous", getpous)
   351     setattr(cls, "getpous", getpous)
   351     
   352     
   352     def getpou(self, name):
   353     setattr(cls, "getpou", gettypeElementFunc("pou"))
   353         return self.gettypeElement("pou", name)
       
   354     setattr(cls, "getpou", getpou)
       
   355     
   354     
   356     def appendpou(self, name, pou_type, body_type):
   355     def appendpou(self, name, pou_type, body_type):
   357         self.types.appendpouElement(name, pou_type, body_type)
   356         self.types.appendpouElement(name, pou_type, body_type)
   358     setattr(cls, "appendpou", appendpou)
   357     setattr(cls, "appendpou", appendpou)
   359         
   358         
   363     
   362     
   364     def removepou(self, name):
   363     def removepou(self, name):
   365         self.types.removepouElement(name)
   364         self.types.removepouElement(name)
   366     setattr(cls, "removepou", removepou)
   365     setattr(cls, "removepou", removepou)
   367 
   366 
       
   367     configurations_xpath = PLCOpen_XPath(
       
   368         "ppx:instances/ppx:configurations/ppx:configuration")
   368     def getconfigurations(self):
   369     def getconfigurations(self):
   369         return self.getconfiguration()
   370         return configurations_xpath(self)
   370     setattr(cls, "getconfigurations", getconfigurations)
   371     setattr(cls, "getconfigurations", getconfigurations)
   371 
   372 
   372     def getconfiguration(self, name=None):
   373     configuration_xpath = PLCOpen_XPath(
   373         configurations = self.xpath(
   374         "ppx:instances/ppx:configurations/ppx:configuration[@name=$name]")
   374             "ppx:instances/ppx:configurations/ppx:configuration%s" %
   375     def getconfiguration(self, name):
   375                 ("[@name='%s']" % name if name is not None else ""),
   376         configurations = configuration_xpath(self, name=name)
   376             namespaces=PLCOpenParser.NSMAP)
   377         if len(configurations) == 1:
   377         if name is None:
       
   378             return configurations
       
   379         elif len(configurations) == 1:
       
   380             return configurations[0]
   378             return configurations[0]
   381         return None
   379         return None
   382     setattr(cls, "getconfiguration", getconfiguration)
   380     setattr(cls, "getconfiguration", getconfiguration)
   383 
   381 
   384     def addconfiguration(self, name):
   382     def addconfiguration(self, name):
   393         configuration = self.getconfiguration(name)
   391         configuration = self.getconfiguration(name)
   394         if configuration is None:
   392         if configuration is None:
   395             raise ValueError, ("\"%s\" configuration doesn't exist !!!") % name
   393             raise ValueError, ("\"%s\" configuration doesn't exist !!!") % name
   396         self.instances.configurations.remove(configuration)
   394         self.instances.configurations.remove(configuration)
   397     setattr(cls, "removeconfiguration", removeconfiguration)
   395     setattr(cls, "removeconfiguration", removeconfiguration)
   398 
   396     
       
   397     resources_xpath = PLCOpen_XPath(
       
   398         "ppx:instances/ppx:configurations/ppx:configuration[@name=$configname]/ppx:resource[@name=$name]")
   399     def getconfigurationResource(self, config_name, name):
   399     def getconfigurationResource(self, config_name, name):
   400         resources = self.xpath(
   400         resources = resources_xpath(self, configname=config_name, name=name)
   401             "ppx:instances/ppx:configurations/ppx:configuration[@name='%s']/ppx:resource[@name='%s']" % 
       
   402             (config_name, name),
       
   403             namespaces=PLCOpenParser.NSMAP)
       
   404         if len(resources) == 1:
   401         if len(resources) == 1:
   405             return resources[0]
   402             return resources[0]
   406         return None
   403         return None
   407     setattr(cls, "getconfigurationResource", getconfigurationResource)
   404     setattr(cls, "getconfigurationResource", getconfigurationResource)
   408 
   405 
   458             pou.removeVariableByFilter(address_model)
   455             pou.removeVariableByFilter(address_model)
   459         for configuration in self.getconfigurations():
   456         for configuration in self.getconfigurations():
   460             configuration.removeVariableByFilter(address_model)
   457             configuration.removeVariableByFilter(address_model)
   461     setattr(cls, "removeVariableByFilter", removeVariableByFilter)
   458     setattr(cls, "removeVariableByFilter", removeVariableByFilter)
   462 
   459 
       
   460     enumerated_values_xpath = PLCOpen_XPath(
       
   461         "ppx:types/ppx:dataTypes/ppx:dataType/ppx:baseType/ppx:enum/ppx:values/ppx:value")
   463     def GetEnumeratedDataTypeValues(self):
   462     def GetEnumeratedDataTypeValues(self):
   464         return [
   463         return [value.getname() for value in enumerated_values_xpath(self)]
   465             value.getname() 
       
   466             for value in self.xpath(
       
   467                 "ppx:types/ppx:dataTypes/ppx:dataType/ppx:baseType/ppx:enum/ppx:values/ppx:value",
       
   468                 namespaces=PLCOpenParser.NSMAP)]
       
   469     setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues)
   464     setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues)
   470 
   465 
   471     def Search(self, criteria, parent_infos=[]):
   466     def Search(self, criteria, parent_infos=[]):
   472         result = self.types.Search(criteria, parent_infos)
   467         result = self.types.Search(criteria, parent_infos)
   473         for configuration in self.instances.configurations.getconfiguration():
   468         for configuration in self.instances.configurations.getconfiguration():
   980     
   975     
   981     def updateElementName(self, old_name, new_name):
   976     def updateElementName(self, old_name, new_name):
   982         pass
   977         pass
   983     setattr(cls, "updateElementName", updateElementName)
   978     setattr(cls, "updateElementName", updateElementName)
   984     
   979     
       
   980     enumerated_datatype_values_xpath = PLCOpen_XPath("ppx:values/ppx:value")
   985     def Search(self, criteria, parent_infos=[]):
   981     def Search(self, criteria, parent_infos=[]):
   986         search_result = []
   982         search_result = []
   987         for i, value in enumerate(self.xpath("ppx:values/ppx:value", namespaces=PLCOpenParser.NSMAP)):
   983         for i, value in enumerate(enumerated_datatype_values_xpath(self)):
   988             for result in TestTextElement(value.getname(), criteria):
   984             for result in TestTextElement(value.getname(), criteria):
   989                 search_result.append((tuple(parent_infos + ["value", i]),) + result)
   985                 search_result.append((tuple(parent_infos + ["value", i]),) + result)
   990         return search_result
   986         return search_result
   991     setattr(cls, "Search", Search)
   987     setattr(cls, "Search", Search)
   992 
   988 
   998     return type_content_type.upper()
   994     return type_content_type.upper()
   999     
   995     
  1000 cls = PLCOpenParser.GetElementClass("pou", "pous")
   996 cls = PLCOpenParser.GetElementClass("pou", "pous")
  1001 if cls:
   997 if cls:
  1002     
   998     
       
   999     block_inputs_xpath = PLCOpen_XPath(
       
  1000         "ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars]/ppx:variable")
       
  1001     block_outputs_xpath = PLCOpen_XPath(
       
  1002         "ppx:interface/*[self::ppx:outputVars or self::ppx:inOutVars]/ppx:variable")
  1003     def getblockInfos(self): 
  1003     def getblockInfos(self): 
  1004         block_infos = {
  1004         block_infos = {
  1005             "name" : self.getname(), 
  1005             "name" : self.getname(), 
  1006             "type" : self.getpouType(), 
  1006             "type" : self.getpouType(), 
  1007             "extensible" : False,
  1007             "extensible" : False,
  1013         if self.interface is not None:
  1013         if self.interface is not None:
  1014             return_type = self.interface.getreturnType()
  1014             return_type = self.interface.getreturnType()
  1015             if return_type is not None:
  1015             if return_type is not None:
  1016                 block_infos["outputs"].append(
  1016                 block_infos["outputs"].append(
  1017                     ("OUT", _getvariableTypeinfos(return_type), "none"))
  1017                     ("OUT", _getvariableTypeinfos(return_type), "none"))
  1018             for var in self.xpath(
  1018             block_infos["inputs"].extend(
  1019                 "ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars]/ppx:variable",
  1019                 [(var.getname(), _getvariableTypeinfos(var.type), "none")
  1020                 namespaces=PLCOpenParser.NSMAP):
  1020                  for var in block_inputs_xpath(self)])
  1021                 block_infos["inputs"].append(
  1021             block_infos["outputs"].extend(
  1022                     (var.getname(), _getvariableTypeinfos(var.type), "none"))
  1022                 [(var.getname(), _getvariableTypeinfos(var.type), "none")
  1023             for var in self.xpath(
  1023                  for var in block_outputs_xpath(self)])
  1024                 "ppx:interface/*[self::ppx:outputVars or self::ppx:inOutVars]/ppx:variable",
       
  1025                 namespaces=PLCOpenParser.NSMAP):
       
  1026                 block_infos["outputs"].append(
       
  1027                     (var.getname(), _getvariableTypeinfos(var.type), "none"))
       
  1028             
  1024             
  1029         block_infos["usage"] = ("\n (%s) => (%s)" % 
  1025         block_infos["usage"] = ("\n (%s) => (%s)" % 
  1030             (", ".join(["%s:%s" % (input[1], input[0]) 
  1026             (", ".join(["%s:%s" % (input[1], input[0]) 
  1031                         for input in block_infos["inputs"]]),
  1027                         for input in block_infos["inputs"]]),
  1032              ", ".join(["%s:%s" % (output[1], output[0]) 
  1028              ", ".join(["%s:%s" % (output[1], output[0]) 
  1608         if self.content.getLocalTag() in ["LD","FBD","SFC"]:
  1604         if self.content.getLocalTag() in ["LD","FBD","SFC"]:
  1609             return self.content.getcontent()
  1605             return self.content.getcontent()
  1610         else:
  1606         else:
  1611             raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
  1607             raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
  1612     setattr(cls, "getcontentInstances", getcontentInstances)
  1608     setattr(cls, "getcontentInstances", getcontentInstances)
  1613 
  1609     
       
  1610     instance_by_id_xpath = PLCOpen_XPath("*[@localId=$localId]")
       
  1611     instance_by_name_xpath = PLCOpen_XPath("ppx:block[@instanceName=$name]")
  1614     def getcontentInstance(self, local_id):
  1612     def getcontentInstance(self, local_id):
  1615         if self.content.getLocalTag() in ["LD","FBD","SFC"]:
  1613         if self.content.getLocalTag() in ["LD","FBD","SFC"]:
  1616             instance = self.content.xpath("*[@localId=%d]" % local_id)
  1614             instance = instance_by_id_xpath(self.content, localId=local_id)
  1617             if len(instance) > 0:
  1615             if len(instance) > 0:
  1618                 return instance[0]
  1616                 return instance[0]
  1619             return None
  1617             return None
  1620         else:
  1618         else:
  1621             raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
  1619             raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
  1634             raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
  1632             raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
  1635     setattr(cls, "getcontentRandomInstance", getcontentRandomInstance)
  1633     setattr(cls, "getcontentRandomInstance", getcontentRandomInstance)
  1636     
  1634     
  1637     def getcontentInstanceByName(self, name):
  1635     def getcontentInstanceByName(self, name):
  1638         if self.content.getLocalTag() in ["LD","FBD","SFC"]:
  1636         if self.content.getLocalTag() in ["LD","FBD","SFC"]:
  1639             instance = self.content.xpath("ppx:block[@instanceName=%s]" % name, namespaces=PLCOpenParser.NSMAP)
  1637             instance = instance_by_name_xpath(self.content)
  1640             if len(instance) > 0:
  1638             if len(instance) > 0:
  1641                 return instance[0]
  1639                 return instance[0]
  1642             return None
  1640             return None
  1643         else:
  1641         else:
  1644             raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
  1642             raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
  1645     setattr(cls, "getcontentInstanceByName", getcontentInstanceByName)
  1643     setattr(cls, "getcontentInstanceByName", getcontentInstanceByName)
  1646     
  1644     
  1647     def removecontentInstance(self, local_id):
  1645     def removecontentInstance(self, local_id):
  1648         if self.content.getLocalTag() in ["LD","FBD","SFC"]:
  1646         if self.content.getLocalTag() in ["LD","FBD","SFC"]:
  1649             instance = self.content.xpath("*[@localId=%d]" % local_id)
  1647             instance = instance_by_id_xpath(self.content)
  1650             if len(instance) > 0:
  1648             if len(instance) > 0:
  1651                 self.content.remove(instance[0])
  1649                 self.content.remove(instance[0])
  1652             else:
  1650             else:
  1653                 raise ValueError, _("Instance with id %d doesn't exist!")%id
  1651                 raise ValueError, _("Instance with id %d doesn't exist!")%id
  1654         else:
  1652         else:
  2531 
  2529 
  2532     def removeconnections(self):
  2530     def removeconnections(self):
  2533         self.content = None
  2531         self.content = None
  2534     setattr(cls, "removeconnections", removeconnections)
  2532     setattr(cls, "removeconnections", removeconnections)
  2535     
  2533     
       
  2534     connection_xpath = PLCOpen_XPath("ppx:connection")
       
  2535     connection_by_position_xpath = PLCOpen_XPath("ppx:connection[position()=$pos]")
  2536     def getconnections(self):
  2536     def getconnections(self):
  2537         return self.xpath("ppx:connection", namespaces=PLCOpenParser.NSMAP)
  2537         return connection_xpath(self)
  2538     setattr(cls, "getconnections", getconnections)
  2538     setattr(cls, "getconnections", getconnections)
  2539     
  2539     
  2540     def getconnection(self, idx):
  2540     def getconnection(self, idx):
  2541         connection = self.xpath("ppx:connection[position()=%d]" % (idx + 1), 
  2541         connection = connection_by_position_xpath(self, pos=idx+1)
  2542                                 namespaces=PLCOpenParser.NSMAP)
       
  2543         if len(connection) > 0:
  2542         if len(connection) > 0:
  2544             return connection[0]
  2543             return connection[0]
  2545         return None
  2544         return None
  2546     setattr(cls, "getconnection", getconnection)
  2545     setattr(cls, "getconnection", getconnection)
  2547     
  2546