| Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf-8 -*-
2 """general methods and classes """
3 __docformat__ = "restructuredtext"
4
5 from mrv.dge import PlugAlreadyConnected
6 import logging
7 log = logging.getLogger("mrv.automation.base")
8
9 #{ Edit
10
12 for cls in [ int, float, str ]:
13 try:
14 return cls( stringtype )
15 except ValueError:
16 pass
17 # END for each simple type
18 raise ValueError( "Could not convert %r to any simple type" % stringtype )
19
21 """:return: ( nodename, args, kwargs ) - all arguments have been parsed"""
22 args = [ node.get_name().strip('"') ]
23 nodeattrs = node.get_attributes()
24 tl = nodeattrs.get('toplabel', '').strip('"')
25 if tl:
26 args.extend( [ _toSimpleType( a ) for a in tl.split(',') ] )
27 # END if args are set
28
29 kwargs = dict()
30 bl = nodeattrs.get('bottomlabel', '').strip('"')
31 if bl:
32 for kwa in bl.split(','):
33 k,v = tuple(kwa.split('='))
34 kwargs[ k ] = _toSimpleType( v )
35 # END for each kw value
36 # END if bottom label is set
37
38 # convert name such that if one can write nodename(args,kwargs), without
39 # destroing the original node name
40 typename = node.get_label()
41 if typename:
42 typename = typename.strip('"').split( "(" )[0]
43
44 return ( typename, args,kwargs )
45
47 """Create a graph from the given dotfile and create a workflow from it.
48 The workflow will be fully intiialized with connected process instances.
49 The all compatible plugs will automatically be connected for all processes
50 connected in the dot file
51
52 :param workflowcls: if not None, a dgengine.Graph compatible class to be used
53 for workflow creation. Defaults to automation.workflow.Workflow.
54 :return: List of initialized workflow classes - as they can be nested, the
55 creation of one workflow can actually create several of them"""
56 import pydot
57 import processes
58 from workflow import Workflow
59 wflclass = workflowcls or Workflow
60 dotgraph = pydot.graph_from_dot_file( dotfile )
61
62 if not dotgraph:
63 raise AssertionError( "Returned graph from file %r was None" % dotfile )
64
65
66 # use the filename as name
67 edge_lut = {} # string -> processinst
68 wfl = wflclass( name=dotfile.namebase() )
69
70
71 for node in dotgraph.get_node_list():
72 # can have initializers
73 nodeid = node.get_name().strip( '"' )
74 # ignore default node
75 if nodeid == "node":
76 continue
77 processname,args,kwargs = _getNodeInfo( node )
78
79 # skip nodes with incorrect label - the parser returns one node each time it appears
80 # in the file, although its mentioned in connections, at least if labels are used
81 if not isinstance( processname, basestring ):
82 continue
83
84 # GET PROCESS CLASS
85 try:
86 processcls = getattr( processes, processname )
87 except AttributeError:
88 raise TypeError( "Process '%s' not found in 'processes' module" % processname )
89
90 # create instance and add to workflow
91 try:
92 processinst = processcls( *args, **kwargs )
93 except TypeError:
94 log.error( "Process %r could not be created as it required a different init call" % processcls )
95 raise
96 else:
97 edge_lut[ nodeid ] = processinst
98 wfl.addNode( processinst )
99 # END for each node in graph
100
101
102 # ADD EDGES
103 #############
104 # create most suitable plug connections
105 for edge in dotgraph.get_edge_list():
106 snode = edge_lut[ edge.get_source().strip('"') ]
107 dnode = edge_lut[ edge.get_destination().strip('"') ]
108 destplugs = dnode.inputPlugs( )
109
110 numConnections = 0
111 for sourceplug in snode.outputPlugs():
112 try:
113 # first is best
114 targetcandidates = snode.filterCompatiblePlugs( destplugs, sourceplug.attr, raise_on_ambiguity = 0, attr_affinity = False, attr_as_source = True )
115 except ( TypeError,IndexError ),e: # could have no compatible plugs or is ambigous
116 log.debug(str(e.args)) # debug
117 continue
118 else:
119 # if a plug is already connected, try another one
120 blockedDestinationShells = list()
121 numplugconnections = 0
122 for rate,targetplug in targetcandidates:
123 try:
124 sshell = snode.toShell( sourceplug )
125 dshell = dnode.toShell( targetplug )
126 sshell.connect( dshell )
127
128 numConnections += 1
129 numplugconnections += 1
130 except PlugAlreadyConnected:
131 # remember the connected d-shell - we might disconnect it later
132 blockedDestinationShells.append( dnode.toShell( targetplug ) )
133 else:
134 pass # allow several connections ( if no other claims one ... )
135 # END for each candidate
136
137 # if we have no connecitons, and one node already connected has at least two from
138 # the same plug disconnect the node in question
139 # Dont do anything if we are connected or have less than 2 blocked
140 if numplugconnections > 0 or len( blockedDestinationShells ) < 2:
141 continue
142
143 # count connections by sourceshell
144 sourcemap = dict() # source->list( edge( s->d ) ... )
145 for shell in blockedDestinationShells:
146 inshell = dshell.input()
147 sourcemap.setdefault( inshell, list() ).append( ( inshell,dshell ) )
148
149 # find multiple edges
150 for sourceshell, edgelist in sourcemap.iteritems():
151 if len( edgelist ) < 2:
152 continue
153 sshell = snode.toShell( sourceplug )
154 dshell = edgelist[-1][1] # take the last edge as it possibly has lowest connection priority
155 sshell.connect( dshell, force = 1 ) # connect breaking existing ones
156
157 numConnections += 1
158 break
159 # END for each sourceshell record
160
161 # END try connecting plugs
162 # END for each output plug on snode
163
164 # assure we have a connection
165 if numConnections == 0:
166 raise AssertionError( "Found no compatible connection from %s to %s in workflow %s - check your processes" % ( snode, dnode, wfl ) )
167 # END for each edge
168
169 return wfl
170
171
173 """Create workflows from a list of dot-files and add them to the module
174
175 :param workflowcls: see `loadWorkflowFromDotFile`
176 :return: list of workflow instances created from the given files"""
177 outwfls = list()
178 for dotfile in dotfiles:
179 wflname = dotfile.namebase()
180 # it can be that a previous nested workflow already created the workflow
181 # in which case we do not want to recreate it
182 if hasattr( module, wflname ):
183 continue
184
185 wflinst = loadWorkflowFromDotFile( dotfile, workflowcls = workflowcls )
186 setattr( module, wflname , wflinst )
187 outwfls.append( wflinst )
188
189 return outwfls
190
191 #} END interface
192
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Tue Apr 19 18:00:22 2011 | http://epydoc.sourceforge.net |