00001
00002 """
00003 class uses functional closure to build and execute function
00004 stores callable functions and arguments to be called
00005 by the run method
00006 """
00007 __copyright__ = """
00008 Copyright 2008 Sean Ross-Ross
00009 """
00010 __license__ = """
00011 This file is part of SLIMpy .
00012
00013 SLIMpy is free software: you can redistribute it and/or modify
00014 it under the terms of the GNU Lesser General Public License as published by
00015 the Free Software Foundation, either version 3 of the License, or
00016 (at your option) any later version.
00017
00018 SLIMpy is distributed in the hope that it will be useful,
00019 but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00021 GNU Lesser General Public License for more details.
00022
00023 You should have received a copy of the GNU Lesser General Public License
00024 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00025 """
00026 from slimpy_base.Core.Interface.node import Source, Target, Node
00027 from itertools import chain
00028 from pdb import set_trace
00029 from slimpy_base.Core.Command.Drivers.Unix_Pipes import gethostname
00030 import re
00031
00032 from slimpy_base.Environment.InstanceManager import InstanceManager
00033
00034 class Command( object ):
00035 """
00036 Base command to be run by a SLIMDataStructure
00037 takes a function to be run, a tuple and a dict object
00038 on the run method being called will run the function with
00039 the given arguments
00040 """
00041 env = InstanceManager()
00042
00043 def __init__( self, tag, adder, *params, **kparams ):
00044 """
00045 function is a given function to be called by run
00046 params and kparams are given to the function at
00047 runtime
00048 """
00049 if isinstance(tag, str):
00050 self.tag = tag
00051 self._func = None
00052 else:
00053 self.tag = str(tag)
00054 self.func = tag
00055
00056 self.params = list( params )
00057 self.kparams = kparams
00058 self._other_dependants = set()
00059 self.__adder = adder
00060 self._is_set = False
00061
00062 self._state = dict()
00063
00064 self.node_name = None
00065 self.tb_info = None
00066 self.runtime_map = None
00067 self.num_proc = 1
00068
00069 def add_node_name_to_targets(self):
00070 """
00071 @todo explain this better
00072 """
00073 if self.command_type == 'multi_process':
00074 for target in self.target_containers:
00075 if hasattr(target, 'add_target_to_current'):
00076 target.add_target_to_current( )
00077 else:
00078 for target in self.target_containers:
00079 target.add_node_name( self.node_name )
00080
00081 return
00082
00083 def copy_sources(self):
00084 if self.command_type == 'multi_process':
00085 for source in self.source_containers:
00086 source.node_copy( gethostname() )
00087 else:
00088 for source in self.source_containers:
00089 source.node_copy( self.node_name )
00090 pass
00091
00092 def _get_cmdtype(self):
00093 return self._state.get('command_type',None)
00094
00095 def _set_cmdtype(self, val):
00096 self._state['command_type'] = val
00097
00098 command_type = property( _get_cmdtype, _set_cmdtype)
00099
00100 def _set_function(self,val):
00101 raise Exception
00102
00103 function = property( fset=_set_function )
00104
00105 def is_set(self):
00106 return self._is_set
00107
00108 def _get_func(self):
00109 if not self.is_set( ):
00110 raise Exception("Function is not set")
00111 return self._func
00112
00113 def _set_func(self,val):
00114 self._is_set = True
00115 self._func = val
00116
00117 func = property( _get_func, _set_func )
00118
00119 def _get_tag(self):
00120 return self._tag
00121 def _set_tag(self,val):
00122 self._tag = val
00123
00124 def _set_runtime_map( self, map_func ):
00125 self._state['runtime_map'] = map_func
00126
00127 def _get_runtime_map(self):
00128 return self._state['runtime_map']
00129
00130 runtime_map = property( _get_runtime_map, _set_runtime_map)
00131
00132 def do_runtime_map(self):
00133 if self.runtime_map is None:
00134 params,kparams = self.params,self.kparams
00135 else:
00136 params,kparams = self.runtime_map( self )
00137
00138 return params,kparams
00139
00140 tag = property( _get_tag , _set_tag )
00141
00142 def get_nodename(self):
00143 return self._state['node_name']
00144
00145 def set_nodename(self,val):
00146
00147 self._state['node_name'] = val
00148
00149 if self.is_set() and hasattr( self.func, "node_name" ):
00150 self.func.node_name = val
00151
00152 node_name = property(get_nodename ,set_nodename )
00153
00154 def _get_tb_info(self):
00155 return self._state['tb_info']
00156
00157 def _set_tb_info(self,val ):
00158 self._state['tb_info'] = val
00159
00160 tb_info = property( _get_tb_info, _set_tb_info )
00161
00162 def __getitem__( self, item ):
00163 """
00164 return an item from kparams
00165
00166 """
00167 return self.kparams[item]
00168
00169 def __setitem__( self, item ,val):
00170 """
00171 return an item from kparams
00172
00173 """
00174 self.kparams[item] = val
00175
00176
00177 def del_kw(self, item):
00178 del self.kparams[item]
00179
00180 def del_par(self,idx):
00181 del self.params[idx]
00182
00183 def pop_kw(self,item,*default):
00184 return self.kparams.pop(item,*default)
00185
00186 def pop_par(self,*index):
00187
00188 return self.params.pop(*index)
00189
00190 def __contains__( self, k ):
00191 """
00192 returns True if the keyword arguments
00193 contain the key k
00194 """
00195 bl = self.kparams.has_key( k )
00196 return bl
00197
00198 def add_other_dep(self,other):
00199 self._other_dependants.add(other)
00200
00201 def has_key( self, key ):
00202 """
00203 returns True if the keyword arguments
00204 contain the key k
00205 """
00206 return self.kparams.has_key( key )
00207
00208 def __repr__( self ):
00209 return self.__str__()
00210
00211 def __str__( self ):
00212 name = self.tag
00213
00214 join = ", ".join
00215 eq = lambda (a, b): '%s=%s' %( a, b )
00216
00217
00218 p_str = join( map(str,self.params) )
00219 k_str = join( map(eq, self.kparams.items() ) )
00220
00221 if p_str:
00222 k_str = join( [p_str,k_str] )
00223
00224 return '<SLIMpy.Command %(name)s %(k_str)s>' % vars()
00225
00226 def _rplace_scalar_str(self, string):
00227 """
00228 replace strings representing scalars with the actual
00229 value
00230 """
00231 re_saclar = re.compile( r'(\$\{SCALAR\[\d*\]\})' )
00232 scalars_map = self.env['table'].scalars_map
00233
00234 all = re_saclar.findall( string )
00235
00236 for scal in all:
00237
00238 if scal in scalars_map:
00239 scalar_val = str( scalars_map[scal] )
00240 string = string.replace(scal, scalar_val )
00241
00242 return string
00243
00244 def _format_params(self):
00245 if not ( self.params or self.kparams):
00246 return ""
00247 else:
00248 is_node = lambda x: isinstance(x, Node)
00249 src_str = lambda nd: is_node(nd) and str(nd.get()) or str(nd)
00250 eq = lambda a,b:"%s=%s" %(a,b)
00251 ksrc_str = lambda (a,nd): eq(a,src_str(nd))
00252
00253 join = ", ".join
00254 p = join( [src_str(p) for p in self.params] )
00255 k = join( [ ksrc_str(key_val) for key_val in self.kparams.iteritems() ] )
00256
00257 res = p and k and p+", "+k or p or k
00258
00259 return "( %s )" %res
00260
00261 def nice_str(self):
00262 re_bound_method = re.compile( "(<bound method type\.(.*) of <class '.*\.(.*)'>>)" )
00263 re_function = re.compile( "(<function (.*) at .*>)" )
00264
00265 if self.is_set( ):
00266 if 'method driver.run' in str( self.func ):
00267 name = 'driver.run'
00268 else:
00269 name = self.func
00270 else:
00271 name = self.tag
00272
00273 string = str(name)
00274 if re_bound_method.match( string ):
00275 old,meth,cls = re_bound_method.findall( string )[0]
00276 new = ".".join([cls,meth])
00277 string = string.replace(old, new)
00278
00279 elif re_function.match( string ):
00280 old,new = re_function.findall( string )[0]
00281 string = string.replace(old,new)
00282
00283 string += self._format_params( )
00284
00285 string = self._rplace_scalar_str(string)
00286
00287 return string
00288
00289 def copy( self ):
00290 """
00291 returns an identical instance
00292 params and kparams are copied as well
00293 """
00294 com = Command( self.tag, self.__adder, *self.params, **self.kparams )
00295
00296 if self.is_set():
00297 com.func =self.func
00298 com._other_dependants = self._other_dependants.copy( )
00299
00300 com._state = self._state.copy( )
00301
00302
00303
00304
00305
00306
00307 return com
00308
00309 def __eq__( self, other ):
00310
00311 if isinstance( other, Command ):
00312 if not self.tag == other.tag:
00313 return False
00314 if not self.is_set() == other.is_set():
00315 return False
00316 if self.is_set():
00317 if not other.func == self.func:
00318 return False
00319 if not other.params == self.params:
00320 return False
00321 if not other.kparams == self.kparams:
00322 return False
00323
00324 return True
00325 else:
00326 return False
00327
00328
00329 def run( self ):
00330 """
00331 runs the function given to the command
00332 with the arguments given
00333 """
00334 return self.func( *self.params, **self.kparams )
00335
00336 def get_all_values(self):
00337
00338 ch = chain( self.params,
00339 self.kparams.values(),
00340 self._other_dependants
00341 )
00342
00343 return ch
00344
00345 all_values = property(get_all_values)
00346
00347
00348 def getTargets(self):
00349 'get all targets in this command'
00350 istarget = lambda args: isinstance( args, Target )
00351 targets = []
00352 push = targets.append
00353
00354 for value in self.all_values:
00355 if istarget( value ):
00356 push( value )
00357 return targets
00358
00359 def getSources(self):
00360 'get all sources in this command'
00361 issource = lambda args: isinstance( args, Source )
00362
00363 sources = []
00364 push = sources.append
00365
00366
00367 for value in self.all_values:
00368
00369 if issource( value ):
00370 push( value )
00371
00372 return sources
00373
00374 def _get_target_cont(self):
00375 table = self.env['table']
00376 tgts = self.getTargets()
00377 return [ table[targ.id] for targ in tgts]
00378
00379 def _get_source_cont(self):
00380 table = self.env['table']
00381 srcs = self.getSources()
00382 return [ table[src.id] for src in srcs]
00383
00384 target_containers = property( _get_target_cont )
00385 source_containers = property( _get_source_cont )
00386
00387
00388 def get_source_spaces(self):
00389 return [cont.params for cont in self.source_containers if hasattr(cont , "params") ]
00390
00391 def get_structure(self, item, default=None):
00392 'get a structure'
00393 if isinstance(item, int):
00394 src = self.params[item]
00395 else:
00396 src = self.kparams[item]
00397
00398 table = self.env['table']
00399 return table[src.id]
00400
00401 def has_unusedtarget( self ):
00402 """
00403 returns true if this command has an
00404 argument that is a Target class
00405 """
00406
00407 all_val = self.get_all_values()
00408
00409 return bool( Target in all_val )
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 def has_unusedsource( self ):
00420 """
00421 returns true if this command has a
00422 argument that is a Target class
00423 """
00424
00425 return bool( Source in self.all_values )
00426
00427
00428 def setunusedtarget( self, target ):
00429 """
00430 if this command contains an un-instanciated target class
00431 then replace it with @parameter: Target
00432 returns True if un-instanciated Source is found and false if not
00433 """
00434
00435
00436 if not isinstance( target, Node ):
00437 target = Target( target )
00438
00439 for i in range( len( self.params ) ):
00440 if self.params[i] == Target:
00441 self.params[i] = target
00442 return
00443
00444 for k in self.kparams.keys():
00445 if self.kparams[k] == Target:
00446 self.kparams[k] = target
00447 return
00448
00449 if Target in self._other_dependants:
00450
00451 self._other_dependants.remove( Target)
00452 self._other_dependants.add( target )
00453 return
00454
00455 raise Exception( 'No target to set' )
00456
00457
00458 def setunusedsource( self, source ):
00459 """
00460 if this command contains an un-instanciated target class
00461 then replace it with @parameter: Target
00462 returns True if un-instanciated Source is found and false if not
00463 """
00464
00465
00466
00467
00468 if not isinstance( source, Node ):
00469 source = Source( source )
00470
00471 for i,val in enumerate(self.params):
00472 if val == Source:
00473 self.params[i] = source
00474 return
00475
00476 if Source in self._other_dependants:
00477 self._other_dependants.remove( Source )
00478 self._other_dependants.add( source )
00479 return
00480
00481 for k,val in self.kparams.iteritems():
00482 if val == Source:
00483 self.kparams[k] = source
00484 return
00485
00486 raise Exception( 'No source to set' )
00487
00488 def getAdder( self ):
00489
00490 return self.__adder
00491
00492
00493 def setAdder( self, adder ):
00494 self.__adder = adder
00495
00496 adder = property( getAdder, setAdder )
00497
00498 def __add__( self, other ):
00499
00500 return self.adder( self, other )
00501
00502
00503 def __radd__( self, other ):
00504
00505 return self.adder( other, self )
00506
00507 def _get_num_proc( self ):
00508
00509 return self._state['num_proc']
00510
00511 def _set_num_proc(self,val):
00512 self._state['num_proc'] = val
00513
00514 num_proc = property( _get_num_proc, _set_num_proc )
00515