1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2006-2021 CEA/DEN, EDF R&D
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 """This module is used to parse a supervision graph Salome (XML) and convert it into
22 YACS calculation schema
24 This parsing is done with SalomeLoader class and its method load.
29 from xml.etree import cElementTree as ElementTree
31 from xml.etree import ElementTree
39 class UnknownKind(Exception):pass
49 """Replace :: in type name by /"""
50 return "/".join(name.split("::"))
54 '1':"CALCIUM_integer",
60 """This class parses a Salome graph (version 3.2.x) and converts it into YACS schema.
62 The loadxml method parses xml file and returns a SalomeProc object
64 The load method calls the loadxml method and creates a YACS object of class Proc
66 def loadxml(self,filename):
68 Parse a XML file from Salome SUPERV and return a list of SalomeProc objects.
70 tree = ElementTree.ElementTree(file=filename)
72 if debug:print("root.tag:",root.tag,root)
75 if root.tag == "dataflow":
78 if debug:print(dataflow)
79 proc=SalomeProc(dataflow)
82 #one or more dataflows. The graph contains macros.
83 #All macros are defined at the same level in the XML file.
84 for dataflow in root.findall("dataflow"):
85 if debug:print(dataflow)
86 proc=SalomeProc(dataflow)
87 if debug:print("dataflow name:",proc.name)
91 def load(self,filename):
92 """Parse a SUPERV XML file (method loadxml) and return a YACS Proc object.
94 global typeMap,_containers,objref,currentProc
100 procs=self.loadxml(filename)
101 #Split the master proc from the possible macros.
105 #Put macros in macro_dict
108 if debug:print("proc_name:",p.name,"coupled_node:",p.coupled_node)
111 if debug:print(filename)
112 yacsproc=ProcNode(proc,macro_dict,filename)
113 return yacsproc.createNode()
116 """Class that defines a Salome Container"""
117 def __init__(self,mach,name):
122 return self.mach+"/"+self.name
124 def getContainer(name):
126 name="localhost/FactoryServer"
127 elif "/" not in name:
128 #no machine name: use localhost
129 name="localhost/"+name
130 return _containers.get(name)
132 def addContainer(name):
136 elif "/" not in name:
137 #no machine name: use localhost for mach
140 mach,name=name.split("/")
141 c=Container(mach,name)
142 _containers[mach+"/"+name]=c
146 """Class for Service properties"""
148 """Class for Parameter properties"""
150 """Class for Link properties"""
152 """Class for Data properties"""
155 """Base class for all nodes """
158 self.links=[] # list to store inputs as links
159 # a link has two attributes : from_node, the starting node
160 # to_node, the end node
162 self.inStreamLinks=[] #list of dataStream links connected to this node (in)
163 self.outStreamLinks=[] #list of dataStream links connected to this node (out)
165 def createNode(self):
166 raise NotImplementedError
167 def getInputPort(self,p):
168 return self.node.getInputPort(".".join(p.split("__")))
169 def getOutputPort(self,p):
172 return self.node.getOutputPort(".".join(p.split("__")))
173 def getInputDataStreamPort(self,p):
174 return self.node.getInputDataStreamPort(p)
175 def getOutputDataStreamPort(self,p):
176 return self.node.getOutputDataStreamPort(p)
178 def initPort(self,l):
180 #double (CORBA::tk_double)
182 self.getInputPort(l.tonodeparam).edInitDbl(l.value)
184 reason="Problem in initialization, not expected type (double): %s %s" % (l.tonodeparam,l.value)
185 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
187 #int (CORBA::tk_long)
189 self.getInputPort(l.tonodeparam).edInitInt(l.value)
191 reason="Problem in initialization, not expected type (int): %s %s" % (l.tonodeparam,l.value)
192 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
194 #objref (CORBA::tk_objref)
196 self.getInputPort(l.tonodeparam).edInitString(l.value)
198 reason="Problem in initialization, not expected type (objref): %s %s" % (l.tonodeparam,l.value)
199 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
201 #string (CORBA::tk_string)
203 self.getInputPort(l.tonodeparam).edInitString(l.value)
205 reason="Problem in initialization, not expected type (string): %s %s" % (l.tonodeparam,l.value)
206 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
208 reason="Problem in initialization, not expected type (%s): %s %s" % (l.type,l.tonodeparam,l.value)
209 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
211 class InlineNode(Node):
212 """Inline Node salome : python function in self.codes[0]"""
216 def createNode(self):
217 r = pilot.getRuntime()
218 if self.fnames[0] == "?":
219 n=r.createScriptNode("",self.name)
221 n=r.createFuncNode("",self.name)
222 n.setFname(self.fnames[0])
223 n.setScript(self.codes[0])
225 for para in self.service.inParameters:
226 if para.type not in typeMap:
227 #create the missing type and add it in type map
228 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
229 if para.type not in currentProc.typeMap:
230 currentProc.typeMap[para.type]=typeMap[para.type]
231 n.edAddInputPort(para.name,typeMap[para.type])
232 for para in self.service.outParameters:
233 if para.type not in typeMap:
234 #create the missing type and add it in type map
235 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
236 if para.type not in currentProc.typeMap:
237 currentProc.typeMap[para.type]=typeMap[para.type]
238 n.edAddOutputPort(para.name,typeMap[para.type])
245 class ComputeNode(Node):
246 """Compute Node Salome execute a component service"""
247 def createNode(self):
251 r = pilot.getRuntime()
252 if self.sComponent in self.container.components:
253 #a node for this component already exists
254 compo_node=self.container.components[self.sComponent]
255 #It's a node associated with another node of the same component instance
256 #It is not sure that the yacs node has been created ????
257 master_node=compo_node.createNode()
258 n=master_node.createNode(self.name)
260 #there is no node for this component. This node is first
261 self.container.components[self.sComponent]=self
262 #There is no component instance for this node
263 n=r.createCompoNode("",self.name)
264 n.setRef(self.sComponent)
266 n.setMethod(self.service.name)
268 #set the container for the node
270 n.getComponent().setContainer(currentProc.containerMap[self.container.getName()])
272 #add dataflow ports in out
273 for para in self.service.inParameters:
274 if para.type not in typeMap:
275 #Create the missing type and adds it into types table
276 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
277 if para.type not in currentProc.typeMap:
278 currentProc.typeMap[para.type]=typeMap[para.type]
279 n.edAddInputPort(para.name,typeMap[para.type])
280 for para in self.service.outParameters:
281 if para.type not in typeMap:
282 #Create the missing type and adds it into types table
283 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
284 if para.type not in currentProc.typeMap:
285 currentProc.typeMap[para.type]=typeMap[para.type]
286 pout=n.edAddOutputPort(para.name,typeMap[para.type])
288 #add datastream ports in and out
289 for para in self.inStreams:
290 if debug:print(para.name,para.type,para.dependency,para.schema, para.interpolation, end=' ')
291 if debug:print(para.extrapolation)
292 pin=n.edAddInputDataStreamPort(para.name,typeMap[streamTypes[para.type]])
293 for para in self.outStreams:
294 if debug:print(para.name,para.type,para.dependency,para.values)
295 pout=n.edAddOutputDataStreamPort(para.name,typeMap[streamTypes[para.type]])
302 class ComposedNode(Node):
303 """Composed Node Salome (base class)"""
305 def reduceLoop(self):
306 """Transform a Salome graph with loops on one level
307 in a hierarchical graph.
309 The initial graph is in self.G. It is transformed in place.
312 if debug:graph.display(G)
317 #Get all loops and their internal nodes
322 loops[n]=graph.reachable(G,n)&graph.reachable(I,n.endloop)
323 n.inner_nodes=loops[n]
324 n.G=graph.InducedSubgraph(loops[n],G)
326 if debug:print("all loops")
327 if debug:print(loops)
329 #Get most external loops
330 outer_loops=list(loops.keys())
332 for ll in outer_loops:
333 if loops[l] < loops[ll]:
335 outer_loops.remove(l)
339 #In the end all remaining loops in outer_loops are the most external
340 if debug:print(outer_loops)
342 #We remove all internal nodes of most external loops
343 for l in outer_loops:
344 #Remove internal nodes
350 #Replace neighbours of loop by those of endloop
353 #Try to transform incoming and outcoming links of endloop in incoming and
354 #outcoming links of internal nodes. Probably not complete.
356 for link in l.endloop.links:
357 if debug:print(link.from_node,link.to_node,link.from_param,link.to_param)
358 inputs[link.to_param]=link.from_node,link.from_param
362 if link.from_node == l.endloop:
363 link.from_node,link.from_param=inputs[link.from_param]
364 if debug:print(link.from_node,link.to_node,link.from_param,link.to_param)
366 if debug:graph.display(G)
368 #Apply the reduction treatment to most external loops (recurse)
369 for l in outer_loops:
372 def connect_macros(self,macro_dict):
373 """This method connects the salome macros in macro_dict to the master YACS Proc.
376 if debug:print("connect_macros",self.node,macro_dict)
378 if isinstance(node,MacroNode):
379 #node is a macro, connect its definition to self.
380 #p is the Salome macro (class SalomeProc)
381 #node is the Salome MacroNode that has the subgraph p
382 #node.node is the YACS Bloc equivalent to node
383 p=macro_dict[node.coupled_node]
385 if debug:print("macronode:",node.name,node.coupled_node,p)
386 #Create a hierarchical graph from the salome graph
390 #create an equivalent YACS node from each salome node
394 #Connect macros to node
395 node.connect_macros(macro_dict)
400 bloc.edAddCFLink(n.node,v.node)
401 #add dataflow links and initializations
405 bloc.edAddLink(l.from_node.getOutputPort(l.from_param),
406 l.to_node.getInputPort(l.to_param))
408 for l in n.outStreamLinks:
409 pout=l.from_node.getOutputDataStreamPort(l.from_param)
410 pin=l.to_node.getInputDataStreamPort(l.to_param)
411 bloc.edAddLink(pout,pin)
415 #double (CORBA::tk_double)
417 n.getInputPort(l.tonodeparam).edInitDbl(l.value)
419 reason="Problem in initialization, not expected type (double): %s %s" % (l.tonodeparam,l.value)
420 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
422 #int (CORBA::tk_long)
424 n.getInputPort(l.tonodeparam).edInitInt(l.value)
426 reason="Problem in initialization, not expected type (int): %s %s" % (l.tonodeparam,l.value)
427 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
429 #objref (CORBA::tk_objref)
431 n.getInputPort(l.tonodeparam).edInitString(l.value)
433 reason="Problem in initialization, not expected type (objref): %s %s" % (l.tonodeparam,l.value)
434 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
436 #string (CORBA::tk_string)
438 n.getInputPort(l.tonodeparam).edInitString(l.value)
440 reason="Problem in initialization, not expected type (string): %s %s" % (l.tonodeparam,l.value)
441 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
443 reason="Problem in initialization, not expected type (%s): %s %s" % (l.type,l.tonodeparam,l.value)
444 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
446 class LoopNode(ComposedNode):
447 """Objet qui simule le comportement d'une boucle Salome."""
449 ComposedNode.__init__(self)
451 #inner_nodes contains internal nodes as in Salome (on one level with endloop nodes)
454 def set_node(self,node):
457 def set_inner(self,loop):
458 for i in self.inner_loops:
459 if loop.inner_nodes < i.inner_nodes:
460 #the loop is contained in i
463 self.inner_loops.append(loop)
465 def createNode(self):
466 """Create the equivalent YACS loop and store it in attribute node
468 A Salome loop has n input ports and output ports with exactly same names.
469 The head of loop has 3 functions : init, next, more which have almost same
470 interface. init and next have same interface : on input, input loop parameters
471 on output, output loop parameters (same as input). more has one more output parameter
472 in first place. This parameter says if the loop must go on or not.
473 The endloop has a function with the same interface as next.
475 To transform this node, create a YACS Bloc. In this bloc put a node for the init function
476 and a While node. In the while put all internal nodes plus 2 nodes for the next and more
480 r = pilot.getRuntime()
481 bloop=r.createBloc(self.name)
484 init=r.createFuncNode("","init")
486 init.setScript(self.codes[0])
487 init.setFname(self.fnames[0])
488 for para in self.service.inParameters:
489 if para.type not in typeMap:
490 #create the missing type and add it in type map
491 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
492 if para.type not in currentProc.typeMap:
493 currentProc.typeMap[para.type]=typeMap[para.type]
494 init.edAddInputPort(para.name,typeMap[para.type])
495 for para in self.service.outParameters:
496 if para.type not in typeMap:
497 #create the missing type and add it in type map
498 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
499 if para.type not in currentProc.typeMap:
500 currentProc.typeMap[para.type]=typeMap[para.type]
501 init.edAddOutputPort(para.name,typeMap[para.type])
502 bloop.edAddChild(init)
505 wh=r.createWhileLoop(self.name)
507 blnode=r.createBloc(self.name)
509 cport=wh.edGetConditionPort()
510 cport.edInitBool(True)
513 next=r.createFuncNode("","next")
515 next.setScript(self.codes[2])
516 next.setFname(self.fnames[2])
517 for para in self.service.inParameters:
518 if para.type not in typeMap:
519 #create the missing type and add it in type map
520 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
521 if para.type not in currentProc.typeMap:
522 currentProc.typeMap[para.type]=typeMap[para.type]
523 next.edAddInputPort(para.name,typeMap[para.type])
524 for para in self.service.outParameters:
525 if para.type not in typeMap:
526 #create the missing type and add it in type map
527 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
528 if para.type not in currentProc.typeMap:
529 currentProc.typeMap[para.type]=typeMap[para.type]
530 next.edAddOutputPort(para.name,typeMap[para.type])
531 blnode.edAddChild(next)
535 more=r.createFuncNode("","more")
537 more.setScript(self.codes[1])
538 more.setFname(self.fnames[1])
539 for para in self.service.inParameters:
540 if para.type not in typeMap:
541 #create the missing type and add it in type map
542 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
543 if para.type not in currentProc.typeMap:
544 currentProc.typeMap[para.type]=typeMap[para.type]
545 more.edAddInputPort(para.name,typeMap[para.type])
546 more.edAddOutputPort("DoLoop",typeMap["int"])
547 for para in self.service.outParameters:
548 if para.type not in typeMap:
549 #create the missing type and add it in type map
550 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
551 if para.type not in currentProc.typeMap:
552 currentProc.typeMap[para.type]=typeMap[para.type]
553 more.edAddOutputPort(para.name,typeMap[para.type])
554 blnode.edAddChild(more)
557 for para in self.service.outParameters:
558 bloop.edAddDFLink(init.getOutputPort(para.name),next.getInputPort(para.name))
560 for para in self.service.outParameters:
561 blnode.edAddDFLink(next.getOutputPort(para.name),more.getInputPort(para.name))
563 wh.edAddLink(more.getOutputPort("DoLoop"),wh.getInputPort("condition"))
565 for para in self.service.outParameters:
566 wh.edAddLink(more.getOutputPort(para.name),next.getInputPort(para.name))
572 blnode.edAddChild(node)
576 blnode.edAddCFLink(n.node,v.node)
581 blnode.edAddDFLink(l.from_node.getOutputPort(l.from_param),
582 l.to_node.getInputPort(l.to_param))
584 reason="Error while connecting output port: "+l.from_param+" from node: "+l.from_node.name
585 reason=reason+" to input port: "+l.to_param+" from node: "+l.to_node.name
586 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
590 def getInputPort(self,p):
591 return self.init.getInputPort(p)
593 def getOutputPort(self,p):
594 return self.more.getOutputPort(p)
596 class Bloc(ComposedNode):
597 """ Composed node containing a set of connected nodes
604 def addLink(self,node1,node2):
605 if node1 not in self.nodes:self.nodes.append(node1)
606 if node2 not in self.nodes:self.nodes.append(node2)
608 class MacroNode(Bloc):
609 """Objet that represents a Salome Macro
611 def createNode(self):
612 """Create a YACS node (Bloc) equivalent to a Salome Macro """
613 r = pilot.getRuntime()
614 macro=r.createBloc(self.name)
619 """Return true if n is a head loop node"""
620 return isinstance(n,LoopNode)
622 class ProcNode(ComposedNode):
623 """Salome proc with its macros
625 The Salome proc is stored in attribute proc
626 The Salome macros are stored in attribute macro_dict ({})
628 def __init__(self,proc,macro_dict,filename):
629 ComposedNode.__init__(self)
631 self.macro_dict=macro_dict
632 self.filename=filename
634 def createNode(self):
635 """Create the YACS node (Proc) equivalent a Salome proc"""
636 global currentProc,objref
637 r = pilot.getRuntime()
639 #create_graph gives a hierarchical graph equivalent to the Salome proc
640 G=self.proc.create_graph()
643 #Create the YACS proc with its elements (types, nodes, containers)
647 p.filename=self.filename
648 typeMap["double"]=p.typeMap["double"]
649 typeMap["float"]=p.typeMap["double"]
650 typeMap["int"]=p.typeMap["int"]
651 typeMap["short"]=p.typeMap["int"]
652 typeMap["long"]=p.typeMap["int"]
653 typeMap["string"]=p.typeMap["string"]
654 typeMap["char"]=p.typeMap["string"]
655 typeMap["boolean"]=p.typeMap["bool"]
656 typeMap["bool"]=p.typeMap["bool"]
658 objref=p.createInterfaceTc("IDL:omg.org/CORBA/Object:1.0","Object",[])
659 typeMap["objref"]=objref
660 typeMap["Unknown"]=p.createInterfaceTc("","Unknown",[])
661 typeMap["GEOM_Object"]=p.createInterfaceTc("IDL:GEOM/GEOM_Object:1.0","GEOM_Object",[objref])
662 typeMap["GEOM_Shape"]=typeMap["GEOM_Object"]
664 typeMap["CALCIUM_integer"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Integer_Port:1.0","CALCIUM_integer",[])
665 typeMap["CALCIUM_real"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Real_Port:1.0","CALCIUM_real",[])
666 typeMap["CALCIUM_double"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Double_Port:1.0","CALCIUM_double",[])
667 typeMap["CALCIUM_string"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_String_Port:1.0","CALCIUM_string",[])
668 typeMap["CALCIUM_boolean"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Logical_Port:1.0","CALCIUM_boolean",[])
670 typeMap["SuperVisionTest::Adder"]=p.createInterfaceTc("","SuperVisionTest/Adder",[objref])
671 typeMap["Adder"]=typeMap["SuperVisionTest::Adder"]
673 currentProc.typeMap["Object"]=typeMap["objref"]
674 currentProc.typeMap["Unknown"]=typeMap["Unknown"]
675 currentProc.typeMap["GEOM_Object"]=typeMap["GEOM_Object"]
676 currentProc.typeMap["GEOM_Shape"]=typeMap["GEOM_Shape"]
677 currentProc.typeMap["CALCIUM_integer"]=typeMap["CALCIUM_integer"]
678 currentProc.typeMap["CALCIUM_real"]=typeMap["CALCIUM_real"]
680 #create all containers
681 for name,container in list(_containers.items()):
682 cont=r.createContainer()
684 cont.setProperty("hostname",container.mach)
685 cont.setProperty("container_name",container.name)
686 currentProc.containerMap[name]=cont
689 #each node in G creates an equivalent YACS node.
693 #Connect Salome macros to nodes of proc p.
694 self.connect_macros(self.macro_dict)
699 p.edAddCFLink(n.node,v.node)
701 #add dataflow links and initializations
706 p.edAddLink(l.from_node.getOutputPort(l.from_param),
707 l.to_node.getInputPort(l.to_param))
709 reason="Error while connecting output port: "+l.from_param+" from node: "+l.from_node.name
710 reason=reason+" to input port: "+l.to_param+" from node: "+l.to_node.name
711 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
714 for l in n.outStreamLinks:
715 pout=l.from_node.getOutputDataStreamPort(l.from_param)
716 pin=l.to_node.getInputDataStreamPort(l.to_param)
717 p.edAddLink(pout,pin)
721 #double (CORBA::tk_double)
723 n.getInputPort(l.tonodeparam).edInitDbl(l.value)
725 reason="Problem in initialization, not expected type (double): %s %s" % (l.tonodeparam,l.value)
726 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
728 #int (CORBA::tk_long)
729 port=n.getInputPort(l.tonodeparam)
731 port.edInitInt(l.value)
733 reason="Problem in initialization, not expected type (int): %s %s" % (l.tonodeparam,l.value)
734 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
736 #objref (CORBA::tk_objref)
738 n.getInputPort(l.tonodeparam).edInitString(l.value)
740 reason="Problem in initialization, not expected type (objref): %s %s" % (l.tonodeparam,l.value)
741 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
743 #string (CORBA::tk_string)
745 n.getInputPort(l.tonodeparam).edInitString(l.value)
747 reason="Problem in initialization, not expected type (string): %s %s" % (l.tonodeparam,l.value)
748 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
750 reason="Problem in initialization, not expected type (%s): %s %s" % (l.type,l.tonodeparam,l.value)
751 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
756 class SalomeProc(ComposedNode):
757 """Salome proc with all its dataflow, datastream and control links
758 The object is built by parsing an XML file.
760 def __init__(self,dataflow):
763 #self.links : list of dataflow links (Link objects)
764 #self.nodes : list of graph nodes
765 #self.node_dict : nodes dict ({name:node})
766 #self.datas : list of graph datas
767 #each node has 2 lists of datastream links (inStreams, outStreams)
769 def parse(self,dataflow):
770 if debug:print("All XML nodes")
771 for node in dataflow:
772 if debug:print(node.tag,node)
774 #Parse dataflow info-list
775 self.dataflow_info=self.parseService(dataflow.find("info-list/node/service"))
776 if debug:print(self.dataflow_info)
777 if debug:print(self.dataflow_info.inParameters)
778 if debug:print(self.dataflow_info.outParameters)
780 for para in self.dataflow_info.inParameters:
781 print("inParam:",para.name,para.name.split("__",1))
783 self.name=dataflow.findtext("info-list/node/node-name")
784 self.coupled_node=dataflow.findtext("info-list/node/coupled-node")
786 if debug:print("All XML nodes dataflow/node-list")
790 for n in dataflow.findall('node-list/node'):
791 #n is a node-list node
792 kind=n.findtext("kind")
793 comp=n.findtext("component-name")
794 name=n.findtext("node-name")
795 coupled_node=n.findtext("coupled-node")
796 interface=n.findtext("interface-name")
797 container=n.findtext("container")
801 #kind=9 : datastream graph ?
809 node.sComponent = comp
810 node.interface=interface
811 node.container= getContainer(container)
812 if not node.container:
813 node.container=addContainer(container)
814 if debug:print("\tcontainer",node.container)
817 #It's a python function
822 for pyfunc in n.findall("PyFunction-list/PyFunction"):
823 fnames.append(pyfunc.findtext("FuncName"))
824 codes.append(self.parsePyFunction(pyfunc))
829 #It's a loop : make a LoopNode
830 #python functions (next, more, init) are found in codes
835 for pyfunc in n.findall("PyFunction-list/PyFunction"):
836 fnames.append(pyfunc.findtext("FuncName"))
837 codes.append(self.parsePyFunction(pyfunc))
842 #End of loop : make an InlineNode
847 for pyfunc in n.findall("PyFunction-list/PyFunction"):
848 fnames.append(pyfunc.findtext("FuncName"))
849 codes.append(self.parsePyFunction(pyfunc))
854 # It's a Macro node : make a MacroNode
858 raise UnknownKind(kind)
862 node.coupled_node=coupled_node
863 #Put nodes in a dict to ease search
864 node_dict[node.name]=node
865 if debug:print("\tnode-name",node.name)
866 if debug:print("\tkind",node.kind,node.__class__.__name__)
870 node.service=self.parseService(s)
873 #Parse datastream ports
874 if debug:print("DataStream ports")
876 for indata in n.findall("DataStream-list/inParameter"):
877 inStreams.append(self.parseInData(indata))
878 node.inStreams=inStreams
881 for outdata in n.findall("DataStream-list/outParameter"):
882 p=self.parseOutData(outdata)
884 outStreams_dict[p.name]=p
885 node.outStreams=outStreams
886 node.outStreams_dict=outStreams_dict
887 if debug:print("\t++++++++++++++++++++++++++++++++++++++++++++")
891 self.node_dict=node_dict
892 #Nodes parsing is finished.
893 #Parse dataflow and datastream links.
896 <fromnode-name>Node_A_1</fromnode-name>
897 <fromserviceparameter-name>a_1</fromserviceparameter-name>
898 <tonode-name>Node_B_1</tonode-name>
899 <toserviceparameter-name>b_1</toserviceparameter-name>
903 if debug:print("All XML nodes dataflow/link-list")
905 if debug:print("\t++++++++++++++++++++++++++++++++++++++++++++")
906 for link in dataflow.findall('link-list/link'):
908 l.from_name=link.findtext("fromnode-name")
909 l.to_name=link.findtext("tonode-name")
910 l.from_param=link.findtext("fromserviceparameter-name")
911 l.to_param=link.findtext("toserviceparameter-name")
913 if debug:print("\tfromnode-name",l.from_name)
914 if debug:print("\tfromserviceparameter-name",l.from_param)
915 if debug:print("\ttonode-name",l.to_name)
916 if debug:print("\ttoserviceparameter-name",l.to_param)
917 if debug:print("\t++++++++++++++++++++++++++++++++++++++++++++")
920 if debug:print("All XML nodes dataflow/data-list")
922 for data in dataflow.findall('data-list/data'):
923 d=self.parseData(data)
925 if debug:print("\ttonode-name",d.tonode)
926 if debug:print("\ttoserviceparameter-name",d.tonodeparam)
927 if debug:print("\tparameter-value",d.value)
928 if debug:print("\tparameter-type",d.type)
929 if debug:print("\t++++++++++++++++++++++++++++++++++++++++++++")
933 def parseService(self,s):
935 service.name=s.findtext("service-name")
936 if debug:print("\tservice-name",service.name)
939 for inParam in s.findall("inParameter-list/inParameter"):
941 p.name=inParam.findtext("inParameter-name")
942 p.type=typeName(inParam.findtext("inParameter-type"))
943 if debug:print("\tinParameter-name",p.name)
944 if debug:print("\tinParameter-type",p.type)
945 inParameters.append(p)
946 service.inParameters=inParameters
947 if debug:print("\t++++++++++++++++++++++++++++++++++++++++++++")
950 for outParam in s.findall("outParameter-list/outParameter"):
952 p.name=outParam.findtext("outParameter-name")
953 p.type=typeName(outParam.findtext("outParameter-type"))
954 if debug:print("\toutParameter-name",p.name)
955 if debug:print("\toutParameter-type",p.type)
956 outParameters.append(p)
957 service.outParameters=outParameters
958 if debug:print("\t++++++++++++++++++++++++++++++++++++++++++++")
961 def parseData(self,d):
963 da.tonode=d.findtext("tonode-name")
964 da.tonodeparam=d.findtext("toserviceparameter-name")
965 da.value=d.findtext("data-value/value")
966 da.type=eval(d.findtext("data-value/value-type"))
968 da.value=eval(da.value)
971 def parsePyFunction(self,pyfunc):
972 if debug:print(pyfunc.tag,":",pyfunc)
973 if debug:print("\tFuncName",pyfunc.findtext("FuncName"))
975 for cdata in pyfunc.findall("PyFunc"):
976 if text:text=text+'\n'
977 if cdata.text != '?':
978 text=text+ cdata.text
981 """<inParameter-type>1</inParameter-type>
982 <inParameter-name>istream</inParameter-name>
983 <inParameter-dependency>2</inParameter-dependency>
984 <inParameter-schema>0</inParameter-schema>
985 <inParameter-interpolation>0</inParameter-interpolation>
986 <inParameter-extrapolation>0</inParameter-extrapolation>
989 <outParameter-type>1</outParameter-type>
990 <outParameter-name>ostream</outParameter-name>
991 <outParameter-dependency>2</outParameter-dependency>
992 <outParameter-values>0</outParameter-values>
996 def parseInData(self,d):
997 if debug:print(d.tag,":",d)
999 p.name=d.findtext("inParameter-name")
1000 p.type=typeName(d.findtext("inParameter-type"))
1001 p.dependency=d.findtext("inParameter-dependency")
1002 p.schema=d.findtext("inParameter-schema")
1003 p.interpolation=d.findtext("inParameter-interpolation")
1004 p.extrapolation=d.findtext("inParameter-extrapolation")
1005 if debug:print("\tinParameter-name",p.name)
1008 def parseOutData(self,d):
1009 if debug:print(d.tag,":",d)
1011 p.name=d.findtext("outParameter-name")
1012 p.type=typeName(d.findtext("outParameter-type"))
1013 p.dependency=d.findtext("outParameter-dependency")
1014 p.values=d.findtext("outParameter-values")
1015 if debug:print("\toutParameter-name",p.name)
1018 def create_graph(self):
1019 #a graph is a dict {node:neighbours}
1020 #neighbours is a Set of neighbour nodes (of course)
1021 #for v in graph (python >= 2.3): iterate through graph nodes
1022 #for v in graph[node] iterate through node neighbours
1024 #create all nodes without neighbours
1025 for n in self.nodes:
1028 #calculate neighbours with links
1029 for link in self.links:
1030 from_node=self.node_dict[link.from_name]
1031 if link.from_param == "Gate" or link.to_param == "Gate":
1032 #control link salome : add to_name node to neighbours
1033 if debug:print("add control link",link.from_name,link.to_name)
1034 G[self.node_dict[link.from_name]].add(self.node_dict[link.to_name])
1036 elif link.from_param in from_node.outStreams_dict:
1038 # 1- add link in link list
1039 # 2- add in link references on from_node and to_node
1040 if debug:print("add stream link",link.from_name,link.to_name)
1041 self.node_dict[link.to_name].inStreamLinks.append(link)
1042 self.node_dict[link.from_name].outStreamLinks.append(link)
1043 link.from_node=self.node_dict[link.from_name]
1044 link.to_node=self.node_dict[link.to_name]
1048 # if link from Loop node to EndOfLoop node, we ignore it
1049 # all others are kept
1050 from_node=self.node_dict[link.from_name]
1051 to_node=self.node_dict[link.to_name]
1052 if isinstance(to_node,LoopNode):
1053 # If it's the link from EndOfLoop to Loop , we ignore it
1054 if to_node.coupled_node == from_node.name:
1055 if debug:print("backlink loop:",from_node,to_node)
1058 if debug:print("add dataflow link",link.from_name,link.to_name)
1059 G[self.node_dict[link.from_name]].add(self.node_dict[link.to_name])
1061 if link.from_param != "DoLoop" and link.to_param != "DoLoop":
1062 #Links on DoLoop are used by Salome supervisor. We ignore them.
1063 #Add in the link references on nodes (from_node and to_node)
1064 #Add this link into the list of links of to_node node.
1065 self.node_dict[link.to_name].links.append(link)
1066 link.from_node=self.node_dict[link.from_name]
1067 link.to_node=self.node_dict[link.to_name]
1069 #In a Salome graph with loops, head node and end node are connected
1070 #with 2 opposite links
1071 #Store the endloop in attribute endloop of head node.
1072 if link.from_param == "DoLoop" and link.to_param == "DoLoop" \
1073 and is_loop(self.node_dict[link.from_name]) \
1074 and isinstance(self.node_dict[link.to_name],InlineNode):
1075 #Store the end loop inline node in attribute endloop
1076 #self.node_dict[link.to_name] is the end node of the head loop node self.node_dict[link.from_name]
1077 if debug:print("add loop",link.from_name,link.to_name)
1078 self.node_dict[link.from_name].endloop=self.node_dict[link.to_name]
1079 self.node_dict[link.to_name].loop=self.node_dict[link.from_name]
1081 for data in self.datas:
1082 if debug:print("datas",data)
1083 self.node_dict[data.tonode].datas.append(data)
1087 #Transform the graph in place
1088 # Transform one level loops in hierarchical graph
1091 #Return the hierarchical graph that can be transform into YACS objects.
1094 def display(self,suivi="sync"):
1095 """Display Salome proc with graphviz (dot file)"""
1096 #to display : dot -Tpng salome.dot |display
1097 f=file("salome.dot", 'w')
1100 cmd="dot -Tpng salome.dot |display" + (suivi == "async" and "&" or "")
1103 def write_dot(self,stream):
1104 """Dump Salome proc into stream with dot format"""
1105 stream.write('digraph %s {\nnode [ style="filled" ]\n' % self.name)
1106 for node in self.nodes:
1107 label = "%s:%s"% (node.name,node.__class__.__name__)
1109 stream.write(' %s [fillcolor="%s" label=< %s >];\n' % (
1110 id(node), color, label
1112 for link in self.links:
1113 from_node=self.node_dict[link.from_name]
1114 to_node=self.node_dict[link.to_name]
1115 stream.write(' %s -> %s;\n' % (id(from_node), id(to_node)))
1121 usage ="""Usage: %s salomeFile convertedFile
1122 where salomeFile is the name of the input schema file (old Salome syntax)
1123 and convertedFile is the name of the output schema file (new YACS syntax)
1126 salomeFile=sys.argv[1]
1127 convertedFile=sys.argv[2]
1129 print(usage%(sys.argv[0]))
1132 SALOMERuntime.RuntimeSALOME_setRuntime()
1133 loader=SalomeLoader()
1136 p= loader.load(salomeFile)
1137 s= pilot.SchemaSave(p)
1138 s.save(convertedFile)
1140 traceback.print_exc(file=sys.stdout)
1141 f=open(convertedFile,'w')
1142 f.write("<proc></proc>\n")
1145 logger=p.getLogger("parser")
1146 if not logger.isEmpty():
1147 print(logger.getStr())
1150 if __name__ == "__main__":