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 |