1 # -*- coding: iso-8859-1 -*-
2 """This module is used to parse a supervision graph Salome (XML) and convert it into
3 YACS calculation schema
5 This parsing is done with SalomeLoader class and its method load.
10 import cElementTree as ElementTree
19 class UnknownKind(Exception):pass
26 """Replace :: in type name by /"""
27 return "/".join(name.split("::"))
31 '1':"CALCIUM_integer",
38 """This class parses a Salome graph (version 3.2.x) and converts it into YACS schema.
40 The loadxml method parses xml file and returns a SalomeProc object
42 The load method calls the loadxml method and creates a YACS object of class Proc
45 def loadxml(self,filename):
47 Parse a XML file from Salome SUPERV and return a list of SalomeProc objects.
49 tree = ElementTree.ElementTree(file=filename)
51 if debug:print "root.tag:",root.tag,root
54 if root.tag == "dataflow":
57 if debug:print dataflow
58 proc=SalomeProc(dataflow)
61 #one or more dataflows. The graph contains macros.
62 #All macros are defined at the same level in the XML file.
63 for dataflow in root.findall("dataflow"):
64 if debug:print dataflow
65 proc=SalomeProc(dataflow)
66 if debug:print "dataflow name:",proc.name
70 def load(self,filename):
71 """Parse a SUPERV XML file (method loadxml) and return a YACS Proc object.
74 procs=self.loadxml(filename)
75 #Split the master proc from the possible macros.
79 #Put macros in macro_dict
82 if debug:print "proc_name:",p.name,"coupled_node:",p.coupled_node
85 if debug:print filename
86 yacsproc=ProcNode(proc,macro_dict,filename)
87 return yacsproc.createNode()
90 """Class that defines a Salome Container"""
91 def __init__(self,mach,name):
96 return self.mach+"/"+self.name
99 def getContainer(name):
101 name="localhost/FactoryServer"
102 elif "/" not in name:
103 #no machine name: use localhost
104 name="localhost/"+name
105 return _containers.get(name)
107 def addContainer(name):
111 elif "/" not in name:
112 #no machine name: use localhost for mach
115 mach,name=name.split("/")
116 c=Container(mach,name)
117 _containers[mach+"/"+name]=c
121 """Class for Service properties"""
123 """Class for Parameter properties"""
125 """Class for Link properties"""
127 """Class for Data properties"""
130 """Base class for all nodes """
133 self.links=[] # list to store inputs as links
134 # a link has two attributes : from_node, the starting node
135 # to_node, the end node
137 self.inStreamLinks=[] #list of dataStream links connected to this node (in)
138 self.outStreamLinks=[] #list of dataStream links connected to this node (out)
140 def createNode(self):
141 raise NotImplementedError
142 def getInputPort(self,p):
143 return self.node.getInputPort(".".join(p.split("__")))
144 def getOutputPort(self,p):
147 return self.node.getOutputPort(".".join(p.split("__")))
148 def getInputDataStreamPort(self,p):
149 return self.node.getInputDataStreamPort(p)
150 def getOutputDataStreamPort(self,p):
151 return self.node.getOutputDataStreamPort(p)
153 def initPort(self,l):
155 #double (CORBA::tk_double)
157 self.getInputPort(l.tonodeparam).edInitDbl(l.value)
159 reason="Problem in initialization, not expected type (double): %s %s" % (l.tonodeparam,l.value)
160 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
162 #int (CORBA::tk_long)
164 self.getInputPort(l.tonodeparam).edInitInt(l.value)
166 reason="Problem in initialization, not expected type (int): %s %s" % (l.tonodeparam,l.value)
167 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
169 #objref (CORBA::tk_objref)
171 self.getInputPort(l.tonodeparam).edInitString(l.value)
173 reason="Problem in initialization, not expected type (objref): %s %s" % (l.tonodeparam,l.value)
174 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
176 #string (CORBA::tk_string)
178 self.getInputPort(l.tonodeparam).edInitString(l.value)
180 reason="Problem in initialization, not expected type (string): %s %s" % (l.tonodeparam,l.value)
181 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
183 reason="Problem in initialization, not expected type (%s): %s %s" % (l.type,l.tonodeparam,l.value)
184 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
186 class InlineNode(Node):
187 """Inline Node salome : python function in self.codes[0]"""
191 def createNode(self):
192 r = pilot.getRuntime()
193 if self.fnames[0] == "?":
194 n=r.createScriptNode("",self.name)
196 n=r.createFuncNode("",self.name)
197 n.setFname(self.fnames[0])
198 n.setScript(self.codes[0])
200 for para in self.service.inParameters:
201 if not typeMap.has_key(para.type):
202 #create the missing type and add it in type map
203 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
204 if not currentProc.typeMap.has_key(para.type):
205 currentProc.typeMap[para.type]=typeMap[para.type]
206 n.edAddInputPort(para.name,typeMap[para.type])
207 for para in self.service.outParameters:
208 if not typeMap.has_key(para.type):
209 #create the missing type and add it in type map
210 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
211 if not currentProc.typeMap.has_key(para.type):
212 currentProc.typeMap[para.type]=typeMap[para.type]
213 n.edAddOutputPort(para.name,typeMap[para.type])
220 class ComputeNode(Node):
221 """Compute Node Salome execute a component service"""
222 def createNode(self):
226 r = pilot.getRuntime()
227 if self.container.components.has_key(self.sComponent):
228 #a node for this component already exists
229 compo_node=self.container.components[self.sComponent]
230 #It's a node associated with another node of the same component instance
231 #It is not sure that the yacs node has been created ????
232 master_node=compo_node.createNode()
233 n=master_node.createNode(self.name)
235 #there is no node for this component. This node is first
236 self.container.components[self.sComponent]=self
237 #There is no component instance for this node
238 n=r.createCompoNode("",self.name)
239 n.setRef(self.sComponent)
241 n.setMethod(self.service.name)
243 #set the container for the node
245 n.getComponent().setContainer(currentProc.containerMap[self.container.getName()])
247 #add dataflow ports in out
248 for para in self.service.inParameters:
249 if not typeMap.has_key(para.type):
250 #Create the missing type and adds it into types table
251 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
252 if not currentProc.typeMap.has_key(para.type):
253 currentProc.typeMap[para.type]=typeMap[para.type]
254 n.edAddInputPort(para.name,typeMap[para.type])
255 for para in self.service.outParameters:
256 if not typeMap.has_key(para.type):
257 #Create the missing type and adds it into types table
258 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
259 if not currentProc.typeMap.has_key(para.type):
260 currentProc.typeMap[para.type]=typeMap[para.type]
261 pout=n.edAddOutputPort(para.name,typeMap[para.type])
263 #add datastream ports in and out
264 for para in self.inStreams:
265 if debug:print para.name,para.type,para.dependency,para.schema, para.interpolation,
266 if debug:print para.extrapolation
267 pin=n.edAddInputDataStreamPort(para.name,typeMap[streamTypes[para.type]])
268 for para in self.outStreams:
269 if debug:print para.name,para.type,para.dependency,para.values
270 pout=n.edAddOutputDataStreamPort(para.name,typeMap[streamTypes[para.type]])
277 class ComposedNode(Node):
278 """Composed Node Salome (base class)"""
280 def reduceLoop(self):
281 """Transform a Salome graph with loops on one level
282 in a hierarchical graph.
284 The initial graph is in self.G. It is transformed in place.
287 if debug:graph.display(G)
292 #Get all loops and their internal nodes
297 loops[n]=graph.reachable(G,n)&graph.reachable(I,n.endloop)
298 n.inner_nodes=loops[n]
299 n.G=graph.InducedSubgraph(loops[n],G)
301 if debug:print "all loops"
304 #Get most external loops
305 outer_loops=loops.keys()
307 for ll in outer_loops:
308 if loops[l] < loops[ll]:
310 outer_loops.remove(l)
314 #In the end all remaining loops in outer_loops are the most external
315 if debug:print outer_loops
317 #We remove all internal nodes of most external loops
318 for l in outer_loops:
319 #Remove internal nodes
325 #Replace neighbours of loop by those of endloop
328 #Try to transform incoming and outcoming links of endloop in incoming and
329 #outcoming links of internal nodes. Probably not complete.
331 for link in l.endloop.links:
332 if debug:print link.from_node,link.to_node,link.from_param,link.to_param
333 inputs[link.to_param]=link.from_node,link.from_param
337 if link.from_node == l.endloop:
338 link.from_node,link.from_param=inputs[link.from_param]
339 if debug:print link.from_node,link.to_node,link.from_param,link.to_param
341 if debug:graph.display(G)
343 #Apply the reduction treatment to most external loops (recurse)
344 for l in outer_loops:
347 def connect_macros(self,macro_dict):
348 """This method connects the salome macros in macro_dict to the master YACS Proc.
351 if debug:print "connect_macros",self.node,macro_dict
353 if isinstance(node,MacroNode):
354 #node is a macro, connect its definition to self.
355 #p is the Salome macro (class SalomeProc)
356 #node is the Salome MacroNode that has the subgraph p
357 #node.node is the YACS Bloc equivalent to node
358 p=macro_dict[node.coupled_node]
360 if debug:print "macronode:",node.name,node.coupled_node,p
361 #Create a hierarchical graph from the salome graph
365 #create an equivalent YACS node from each salome node
369 #Connect macros to node
370 node.connect_macros(macro_dict)
375 bloc.edAddCFLink(n.node,v.node)
376 #add dataflow links and initializations
380 bloc.edAddLink(l.from_node.getOutputPort(l.from_param),
381 l.to_node.getInputPort(l.to_param))
383 for l in n.outStreamLinks:
384 pout=l.from_node.getOutputDataStreamPort(l.from_param)
385 pin=l.to_node.getInputDataStreamPort(l.to_param)
386 bloc.edAddLink(pout,pin)
390 #double (CORBA::tk_double)
392 n.getInputPort(l.tonodeparam).edInitDbl(l.value)
394 reason="Problem in initialization, not expected type (double): %s %s" % (l.tonodeparam,l.value)
395 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
397 #int (CORBA::tk_long)
399 n.getInputPort(l.tonodeparam).edInitInt(l.value)
401 reason="Problem in initialization, not expected type (int): %s %s" % (l.tonodeparam,l.value)
402 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
404 #objref (CORBA::tk_objref)
406 n.getInputPort(l.tonodeparam).edInitString(l.value)
408 reason="Problem in initialization, not expected type (objref): %s %s" % (l.tonodeparam,l.value)
409 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
411 #string (CORBA::tk_string)
413 n.getInputPort(l.tonodeparam).edInitString(l.value)
415 reason="Problem in initialization, not expected type (string): %s %s" % (l.tonodeparam,l.value)
416 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
418 reason="Problem in initialization, not expected type (%s): %s %s" % (l.type,l.tonodeparam,l.value)
419 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
421 class LoopNode(ComposedNode):
422 """Objet qui simule le comportement d'une boucle Salome."""
424 ComposedNode.__init__(self)
426 #inner_nodes contains internal nodes as in Salome (on one level with endloop nodes)
429 def set_node(self,node):
432 def set_inner(self,loop):
433 for i in self.inner_loops:
434 if loop.inner_nodes < i.inner_nodes:
435 #the loop is contained in i
438 self.inner_loops.append(loop)
440 def createNode(self):
441 """Create the equivalent YACS loop and store it in attribute node
443 A Salome loop has n input ports and output ports with exactly same names.
444 The head of loop has 3 functions : init, next, more which have almost same
445 interface. init and next have same interface : on input, input loop parameters
446 on output, output loop parameters (same as input). more has one more output parameter
447 in first place. This parameter says if the loop must go on or not.
448 The endloop has a function with the same interface as next.
450 To transform this node, create a YACS Bloc. In this bloc put a node for the init function
451 and a While node. In the while put all internal nodes plus 2 nodes for the next and more
455 r = pilot.getRuntime()
456 bloop=r.createBloc(self.name)
459 init=r.createFuncNode("","init")
461 init.setScript(self.codes[0])
462 init.setFname(self.fnames[0])
463 for para in self.service.inParameters:
464 if not typeMap.has_key(para.type):
465 #create the missing type and add it in type map
466 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
467 if not currentProc.typeMap.has_key(para.type):
468 currentProc.typeMap[para.type]=typeMap[para.type]
469 init.edAddInputPort(para.name,typeMap[para.type])
470 for para in self.service.outParameters:
471 if not typeMap.has_key(para.type):
472 #create the missing type and add it in type map
473 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
474 if not currentProc.typeMap.has_key(para.type):
475 currentProc.typeMap[para.type]=typeMap[para.type]
476 init.edAddOutputPort(para.name,typeMap[para.type])
477 bloop.edAddChild(init)
480 wh=r.createWhileLoop(self.name)
482 blnode=r.createBloc(self.name)
484 cport=wh.edGetConditionPort()
485 cport.edInitBool(True)
488 next=r.createFuncNode("","next")
490 next.setScript(self.codes[2])
491 next.setFname(self.fnames[2])
492 for para in self.service.inParameters:
493 if not typeMap.has_key(para.type):
494 #create the missing type and add it in type map
495 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
496 if not currentProc.typeMap.has_key(para.type):
497 currentProc.typeMap[para.type]=typeMap[para.type]
498 next.edAddInputPort(para.name,typeMap[para.type])
499 for para in self.service.outParameters:
500 if not typeMap.has_key(para.type):
501 #create the missing type and add it in type map
502 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
503 if not currentProc.typeMap.has_key(para.type):
504 currentProc.typeMap[para.type]=typeMap[para.type]
505 next.edAddOutputPort(para.name,typeMap[para.type])
506 blnode.edAddChild(next)
510 more=r.createFuncNode("","more")
512 more.setScript(self.codes[1])
513 more.setFname(self.fnames[1])
514 for para in self.service.inParameters:
515 if not typeMap.has_key(para.type):
516 #create the missing type and add it in type map
517 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
518 if not currentProc.typeMap.has_key(para.type):
519 currentProc.typeMap[para.type]=typeMap[para.type]
520 more.edAddInputPort(para.name,typeMap[para.type])
521 more.edAddOutputPort("DoLoop",typeMap["int"])
522 for para in self.service.outParameters:
523 if not typeMap.has_key(para.type):
524 #create the missing type and add it in type map
525 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
526 if not currentProc.typeMap.has_key(para.type):
527 currentProc.typeMap[para.type]=typeMap[para.type]
528 more.edAddOutputPort(para.name,typeMap[para.type])
529 blnode.edAddChild(more)
532 for para in self.service.outParameters:
533 bloop.edAddDFLink(init.getOutputPort(para.name),next.getInputPort(para.name))
535 for para in self.service.outParameters:
536 blnode.edAddDFLink(next.getOutputPort(para.name),more.getInputPort(para.name))
538 wh.edAddLink(more.getOutputPort("DoLoop"),wh.getInputPort("condition"))
540 for para in self.service.outParameters:
541 wh.edAddLink(more.getOutputPort(para.name),next.getInputPort(para.name))
547 blnode.edAddChild(node)
551 blnode.edAddCFLink(n.node,v.node)
556 blnode.edAddDFLink(l.from_node.getOutputPort(l.from_param),
557 l.to_node.getInputPort(l.to_param))
559 reason="Error while connecting output port: "+l.from_param+" from node: "+l.from_node.name
560 reason=reason+" to input port: "+l.to_param+" from node: "+l.to_node.name
561 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
565 def getInputPort(self,p):
566 return self.init.getInputPort(p)
568 def getOutputPort(self,p):
569 return self.more.getOutputPort(p)
571 class Bloc(ComposedNode):
572 """ Composed node containing a set of connected nodes
579 def addLink(self,node1,node2):
580 if node1 not in self.nodes:self.nodes.append(node1)
581 if node2 not in self.nodes:self.nodes.append(node2)
583 class MacroNode(Bloc):
584 """Objet that represents a Salome Macro
586 def createNode(self):
587 """Create a YACS node (Bloc) equivalent to a Salome Macro """
588 r = pilot.getRuntime()
589 macro=r.createBloc(self.name)
594 """Return true if n is a head loop node"""
595 return isinstance(n,LoopNode)
597 class ProcNode(ComposedNode):
598 """Salome proc with its macros
600 The Salome proc is stored in attribute proc
601 The Salome macros are stored in attribute macro_dict ({})
603 def __init__(self,proc,macro_dict,filename):
604 ComposedNode.__init__(self)
606 self.macro_dict=macro_dict
607 self.filename=filename
609 def createNode(self):
610 """Create the YACS node (Proc) equivalent a Salome proc"""
611 global currentProc,objref
612 r = pilot.getRuntime()
614 #create_graph gives a hierarchical graph equivalent to the Salome proc
615 G=self.proc.create_graph()
618 #Create the YACS proc with its elements (types, nodes, containers)
622 p.filename=self.filename
623 typeMap["double"]=p.typeMap["double"]
624 typeMap["float"]=p.typeMap["double"]
625 typeMap["int"]=p.typeMap["int"]
626 typeMap["short"]=p.typeMap["int"]
627 typeMap["long"]=p.typeMap["int"]
628 typeMap["string"]=p.typeMap["string"]
629 typeMap["char"]=p.typeMap["string"]
630 typeMap["boolean"]=p.typeMap["bool"]
631 typeMap["bool"]=p.typeMap["bool"]
633 objref=p.createInterfaceTc("IDL:omg.org/CORBA/Object:1.0","Object",[])
634 typeMap["objref"]=objref
635 typeMap["Unknown"]=p.createInterfaceTc("","Unknown",[])
636 typeMap["GEOM_Object"]=p.createInterfaceTc("IDL:GEOM/GEOM_Object:1.0","GEOM_Object",[objref])
637 typeMap["GEOM_Shape"]=typeMap["GEOM_Object"]
639 typeMap["CALCIUM_integer"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Integer_Port:1.0","CALCIUM_integer",[])
640 typeMap["CALCIUM_real"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Real_Port:1.0","CALCIUM_real",[])
641 typeMap["CALCIUM_double"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Double_Port:1.0","CALCIUM_double",[])
642 typeMap["CALCIUM_string"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_String_Port:1.0","CALCIUM_string",[])
643 typeMap["CALCIUM_boolean"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Logical_Port:1.0","CALCIUM_boolean",[])
645 typeMap["SuperVisionTest::Adder"]=p.createInterfaceTc("","SuperVisionTest/Adder",[objref])
646 typeMap["Adder"]=typeMap["SuperVisionTest::Adder"]
648 currentProc.typeMap["Object"]=typeMap["objref"]
649 currentProc.typeMap["Unknown"]=typeMap["Unknown"]
650 currentProc.typeMap["GEOM_Object"]=typeMap["GEOM_Object"]
651 currentProc.typeMap["GEOM_Shape"]=typeMap["GEOM_Shape"]
652 currentProc.typeMap["CALCIUM_integer"]=typeMap["CALCIUM_integer"]
653 currentProc.typeMap["CALCIUM_real"]=typeMap["CALCIUM_real"]
655 #create all containers
656 for name,container in _containers.items():
657 cont=r.createContainer()
659 cont.setProperty("hostname",container.mach)
660 cont.setProperty("container_name",container.name)
661 currentProc.containerMap[name]=cont
664 #each node in G creates an equivalent YACS node.
668 #Connect Salome macros to nodes of proc p.
669 self.connect_macros(self.macro_dict)
674 p.edAddCFLink(n.node,v.node)
676 #add dataflow links and initializations
681 p.edAddLink(l.from_node.getOutputPort(l.from_param),
682 l.to_node.getInputPort(l.to_param))
684 reason="Error while connecting output port: "+l.from_param+" from node: "+l.from_node.name
685 reason=reason+" to input port: "+l.to_param+" from node: "+l.to_node.name
686 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
689 for l in n.outStreamLinks:
690 pout=l.from_node.getOutputDataStreamPort(l.from_param)
691 pin=l.to_node.getInputDataStreamPort(l.to_param)
692 p.edAddLink(pout,pin)
696 #double (CORBA::tk_double)
698 n.getInputPort(l.tonodeparam).edInitDbl(l.value)
700 reason="Problem in initialization, not expected type (double): %s %s" % (l.tonodeparam,l.value)
701 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
703 #int (CORBA::tk_long)
704 port=n.getInputPort(l.tonodeparam)
706 port.edInitInt(l.value)
708 reason="Problem in initialization, not expected type (int): %s %s" % (l.tonodeparam,l.value)
709 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
711 #objref (CORBA::tk_objref)
713 n.getInputPort(l.tonodeparam).edInitString(l.value)
715 reason="Problem in initialization, not expected type (objref): %s %s" % (l.tonodeparam,l.value)
716 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
718 #string (CORBA::tk_string)
720 n.getInputPort(l.tonodeparam).edInitString(l.value)
722 reason="Problem in initialization, not expected type (string): %s %s" % (l.tonodeparam,l.value)
723 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
725 reason="Problem in initialization, not expected type (%s): %s %s" % (l.type,l.tonodeparam,l.value)
726 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
731 class SalomeProc(ComposedNode):
732 """Salome proc with all its dataflow, datastream and control links
733 The object is built by parsing an XML file.
735 def __init__(self,dataflow):
738 #self.links : list of dataflow links (Link objects)
739 #self.nodes : list of graph nodes
740 #self.node_dict : nodes dict ({name:node})
741 #self.datas : list of graph datas
742 #each node has 2 lists of datastream links (inStreams, outStreams)
744 def parse(self,dataflow):
745 if debug:print "All XML nodes"
746 for node in dataflow:
747 if debug:print node.tag,node
749 #Parse dataflow info-list
750 self.dataflow_info=self.parseService(dataflow.find("info-list/node/service"))
751 if debug:print self.dataflow_info
752 if debug:print self.dataflow_info.inParameters
753 if debug:print self.dataflow_info.outParameters
755 for para in self.dataflow_info.inParameters:
756 print "inParam:",para.name,para.name.split("__",1)
758 self.name=dataflow.findtext("info-list/node/node-name")
759 self.coupled_node=dataflow.findtext("info-list/node/coupled-node")
761 if debug:print "All XML nodes dataflow/node-list"
765 for n in dataflow.findall('node-list/node'):
766 #n is a node-list node
767 kind=n.findtext("kind")
768 comp=n.findtext("component-name")
769 name=n.findtext("node-name")
770 coupled_node=n.findtext("coupled-node")
771 interface=n.findtext("interface-name")
772 container=n.findtext("container")
776 #kind=9 : datastream graph ?
784 node.sComponent = comp
785 node.interface=interface
786 node.container= getContainer(container)
787 if not node.container:
788 node.container=addContainer(container)
789 if debug:print "\tcontainer",node.container
792 #It's a python function
797 for pyfunc in n.findall("PyFunction-list/PyFunction"):
798 fnames.append(pyfunc.findtext("FuncName"))
799 codes.append(self.parsePyFunction(pyfunc))
804 #It's a loop : make a LoopNode
805 #python functions (next, more, init) are found in codes
810 for pyfunc in n.findall("PyFunction-list/PyFunction"):
811 fnames.append(pyfunc.findtext("FuncName"))
812 codes.append(self.parsePyFunction(pyfunc))
817 #End of loop : make an InlineNode
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 Macro node : make a MacroNode
833 raise UnknownKind,kind
837 node.coupled_node=coupled_node
838 #Put nodes in a dict to ease search
839 node_dict[node.name]=node
840 if debug:print "\tnode-name",node.name
841 if debug:print "\tkind",node.kind,node.__class__.__name__
845 node.service=self.parseService(s)
848 #Parse datastream ports
849 if debug:print "DataStream ports"
851 for indata in n.findall("DataStream-list/inParameter"):
852 inStreams.append(self.parseInData(indata))
853 node.inStreams=inStreams
856 for outdata in n.findall("DataStream-list/outParameter"):
857 p=self.parseOutData(outdata)
859 outStreams_dict[p.name]=p
860 node.outStreams=outStreams
861 node.outStreams_dict=outStreams_dict
862 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
866 self.node_dict=node_dict
867 #Nodes parsing is finished.
868 #Parse dataflow and datastream links.
871 <fromnode-name>Node_A_1</fromnode-name>
872 <fromserviceparameter-name>a_1</fromserviceparameter-name>
873 <tonode-name>Node_B_1</tonode-name>
874 <toserviceparameter-name>b_1</toserviceparameter-name>
878 if debug:print "All XML nodes dataflow/link-list"
880 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
881 for link in dataflow.findall('link-list/link'):
883 l.from_name=link.findtext("fromnode-name")
884 l.to_name=link.findtext("tonode-name")
885 l.from_param=link.findtext("fromserviceparameter-name")
886 l.to_param=link.findtext("toserviceparameter-name")
888 if debug:print "\tfromnode-name",l.from_name
889 if debug:print "\tfromserviceparameter-name",l.from_param
890 if debug:print "\ttonode-name",l.to_name
891 if debug:print "\ttoserviceparameter-name",l.to_param
892 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
895 if debug:print "All XML nodes dataflow/data-list"
897 for data in dataflow.findall('data-list/data'):
898 d=self.parseData(data)
900 if debug:print "\ttonode-name",d.tonode
901 if debug:print "\ttoserviceparameter-name",d.tonodeparam
902 if debug:print "\tparameter-value",d.value
903 if debug:print "\tparameter-type",d.type
904 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
908 def parseService(self,s):
910 service.name=s.findtext("service-name")
911 if debug:print "\tservice-name",service.name
914 for inParam in s.findall("inParameter-list/inParameter"):
916 p.name=inParam.findtext("inParameter-name")
917 p.type=typeName(inParam.findtext("inParameter-type"))
918 if debug:print "\tinParameter-name",p.name
919 if debug:print "\tinParameter-type",p.type
920 inParameters.append(p)
921 service.inParameters=inParameters
922 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
925 for outParam in s.findall("outParameter-list/outParameter"):
927 p.name=outParam.findtext("outParameter-name")
928 p.type=typeName(outParam.findtext("outParameter-type"))
929 if debug:print "\toutParameter-name",p.name
930 if debug:print "\toutParameter-type",p.type
931 outParameters.append(p)
932 service.outParameters=outParameters
933 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
936 def parseData(self,d):
938 da.tonode=d.findtext("tonode-name")
939 da.tonodeparam=d.findtext("toserviceparameter-name")
940 da.value=d.findtext("data-value/value")
941 da.type=eval(d.findtext("data-value/value-type"))
943 da.value=eval(da.value)
946 def parsePyFunction(self,pyfunc):
947 if debug:print pyfunc.tag,":",pyfunc
948 if debug:print "\tFuncName",pyfunc.findtext("FuncName")
950 for cdata in pyfunc.findall("PyFunc"):
951 if text:text=text+'\n'
952 if cdata.text != '?':
953 text=text+ cdata.text
956 """<inParameter-type>1</inParameter-type>
957 <inParameter-name>istream</inParameter-name>
958 <inParameter-dependency>2</inParameter-dependency>
959 <inParameter-schema>0</inParameter-schema>
960 <inParameter-interpolation>0</inParameter-interpolation>
961 <inParameter-extrapolation>0</inParameter-extrapolation>
964 <outParameter-type>1</outParameter-type>
965 <outParameter-name>ostream</outParameter-name>
966 <outParameter-dependency>2</outParameter-dependency>
967 <outParameter-values>0</outParameter-values>
971 def parseInData(self,d):
972 if debug:print d.tag,":",d
974 p.name=d.findtext("inParameter-name")
975 p.type=typeName(d.findtext("inParameter-type"))
976 p.dependency=d.findtext("inParameter-dependency")
977 p.schema=d.findtext("inParameter-schema")
978 p.interpolation=d.findtext("inParameter-interpolation")
979 p.extrapolation=d.findtext("inParameter-extrapolation")
980 if debug:print "\tinParameter-name",p.name
983 def parseOutData(self,d):
984 if debug:print d.tag,":",d
986 p.name=d.findtext("outParameter-name")
987 p.type=typeName(d.findtext("outParameter-type"))
988 p.dependency=d.findtext("outParameter-dependency")
989 p.values=d.findtext("outParameter-values")
990 if debug:print "\toutParameter-name",p.name
993 def create_graph(self):
994 #a graph is a dict {node:neighbours}
995 #neighbours is a Set of neighbour nodes (of course)
996 #for v in graph (python >= 2.3): iterate through graph nodes
997 #for v in graph[node] iterate through node neighbours
999 #create all nodes without neighbours
1000 for n in self.nodes:
1003 #calculate neighbours with links
1004 for link in self.links:
1005 from_node=self.node_dict[link.from_name]
1006 if link.from_param == "Gate" or link.to_param == "Gate":
1007 #control link salome : add to_name node to neighbours
1008 if debug:print "add control link",link.from_name,link.to_name
1009 G[self.node_dict[link.from_name]].add(self.node_dict[link.to_name])
1011 elif from_node.outStreams_dict.has_key(link.from_param):
1013 # 1- add link in link list
1014 # 2- add in link references on from_node and to_node
1015 if debug:print "add stream link",link.from_name,link.to_name
1016 self.node_dict[link.to_name].inStreamLinks.append(link)
1017 self.node_dict[link.from_name].outStreamLinks.append(link)
1018 link.from_node=self.node_dict[link.from_name]
1019 link.to_node=self.node_dict[link.to_name]
1023 # if link from Loop node to EndOfLoop node, we ignore it
1024 # all others are kept
1025 from_node=self.node_dict[link.from_name]
1026 to_node=self.node_dict[link.to_name]
1027 if isinstance(to_node,LoopNode):
1028 # If it's the link from EndOfLoop to Loop , we ignore it
1029 if to_node.coupled_node == from_node.name:
1030 if debug:print "backlink loop:",from_node,to_node
1033 if debug:print "add dataflow link",link.from_name,link.to_name
1034 G[self.node_dict[link.from_name]].add(self.node_dict[link.to_name])
1036 if link.from_param != "DoLoop" and link.to_param != "DoLoop":
1037 #Links on DoLoop are used by Salome supervisor. We ignore them.
1038 #Add in the link references on nodes (from_node and to_node)
1039 #Add this link into the list of links of to_node node.
1040 self.node_dict[link.to_name].links.append(link)
1041 link.from_node=self.node_dict[link.from_name]
1042 link.to_node=self.node_dict[link.to_name]
1044 #In a Salome graph with loops, head node and end node are connected
1045 #with 2 opposite links
1046 #Store the endloop in attribute endloop of head node.
1047 if link.from_param == "DoLoop" and link.to_param == "DoLoop" \
1048 and is_loop(self.node_dict[link.from_name]) \
1049 and isinstance(self.node_dict[link.to_name],InlineNode):
1050 #Store the end loop inline node in attribute endloop
1051 #self.node_dict[link.to_name] is the end node of the head loop node self.node_dict[link.from_name]
1052 if debug:print "add loop",link.from_name,link.to_name
1053 self.node_dict[link.from_name].endloop=self.node_dict[link.to_name]
1054 self.node_dict[link.to_name].loop=self.node_dict[link.from_name]
1056 for data in self.datas:
1057 if debug:print "datas",data
1058 self.node_dict[data.tonode].datas.append(data)
1062 #Transform the graph in place
1063 # Transform one level loops in hierarchical graph
1066 #Return the hierarchical graph that can be transform into YACS objects.
1069 def display(self,suivi="sync"):
1070 """Display Salome proc with graphviz (dot file)"""
1071 #to display : dot -Tpng salome.dot |display
1072 f=file("salome.dot", 'w')
1075 cmd="dot -Tpng salome.dot |display" + (suivi == "async" and "&" or "")
1078 def write_dot(self,stream):
1079 """Dump Salome proc into stream with dot format"""
1080 stream.write('digraph %s {\nnode [ style="filled" ]\n' % self.name)
1081 for node in self.nodes:
1082 label = "%s:%s"% (node.name,node.__class__.__name__)
1084 stream.write(' %s [fillcolor="%s" label=< %s >];\n' % (
1085 id(node), color, label
1087 for link in self.links:
1088 from_node=self.node_dict[link.from_name]
1089 to_node=self.node_dict[link.to_name]
1090 stream.write(' %s -> %s;\n' % (id(from_node), id(to_node)))
1096 usage ="""Usage: %s salomeFile convertedFile
1097 where salomeFile is the name of the input schema file (old Salome syntax)
1098 and convertedFile is the name of the output schema file (new YACS syntax)
1101 salomeFile=sys.argv[1]
1102 convertedFile=sys.argv[2]
1104 print usage%(sys.argv[0])
1107 SALOMERuntime.RuntimeSALOME_setRuntime()
1108 loader=SalomeLoader()
1111 p= loader.load(salomeFile)
1112 s= pilot.SchemaSave(p)
1113 s.save(convertedFile)
1115 traceback.print_exc(file=sys.stdout)
1116 f=open(convertedFile,'w')
1117 f.write("<proc></proc>\n")
1120 logger=p.getLogger("parser")
1121 if not logger.isEmpty():
1122 print logger.getStr()
1125 if __name__ == "__main__":