def wrapped_f(*args, **kwargs): # args - <Tuple> - Contains the objects that the function has been called with (positional). # kwargs - <Dictionary> - Contains the named objects that the function has been called with. is_replicated = self.kwargs['isReplicated'] is_distributed = self.kwargs['isDistributed'] # By default, each task is set to use one core. computingNodes = 1 if 'computingNodes' in kwargs: # There is a @mpi decorator over task that overrides the # default value of computing nodes computingNodes = kwargs['computingNodes'] del kwargs['computingNodes'] # Check if this call is nested using the launch_pycompss_module # function from launch.py. is_nested = False istack = inspect.stack() for i_s in istack: if i_s[3] == 'launch_pycompss_module': is_nested = True if i_s[3] == 'launch_pycompss_application': is_nested = True if not i_am_at_master() and (not is_nested): # Task decorator worker body code. newTypes, newValues = self.worker_code(f, args, kwargs) return newTypes, newValues else: # Task decorator master body code. # Returns the future object that will be used instead of the # actual function return. fo = self.master_code(f, is_replicated, is_distributed, computingNodes, args, kwargs) return fo
def __call__(self, func): """ Parse and set the mpi parameters within the task core element. :param func: Function to decorate :return: Decorated function. """ if not self.scope: # from pycompss.api.dummy.mpi import mpi as dummy_mpi # d_m = dummy_mpi(self.args, self.kwargs) # return d_m.__call__(func) raise Exception( "The mpi decorator only works within PyCOMPSs framework.") if i_am_at_master(): # master code from pycompss.runtime.binding import register_ce mod = inspect.getmodule(func) self.module = mod.__name__ # not func.__module__ if (self.module == '__main__' or self.module == 'pycompss.runtime.launch'): # The module where the function is defined was run as __main__, # we need to find out the real module name. # path=mod.__file__ # dirs=mod.__file__.split(os.sep) # file_name=os.path.splitext(os.path.basename(mod.__file__))[0] # Get the real module name from our launch.py variable path = getattr(mod, "app_path") dirs = path.split(os.path.sep) file_name = os.path.splitext(os.path.basename(path))[0] mod_name = file_name i = len(dirs) - 1 while i > 0: new_l = len(path) - (len(dirs[i]) + 1) path = path[0:new_l] if "__init__.py" in os.listdir(path): # directory is a package i -= 1 mod_name = dirs[i] + '.' + mod_name else: break self.module = mod_name # Include the registering info related to @MPI # Retrieve the base coreElement established at @task decorator coreElement = func.__to_register__ # Update the core element information with the mpi information coreElement.set_implType("MPI") binary = self.kwargs['binary'] if 'workingDir' in self.kwargs: workingDir = self.kwargs['workingDir'] else: workingDir = '[unassigned]' # Empty or '[unassigned]' runner = self.kwargs['runner'] implSignature = 'MPI.' + binary coreElement.set_implSignature(implSignature) implArgs = [binary, workingDir, runner] coreElement.set_implTypeArgs(implArgs) func.__to_register__ = coreElement # Do the task register if I am the top decorator if func.__who_registers__ == __name__: if __debug__: logger.debug( "[@MPI] I have to do the register of function %s in module %s" % (func.__name__, self.module)) register_ce(coreElement) else: # worker code pass @wraps(func) def mpi_f(*args, **kwargs): # This is executed only when called. if __debug__: logger.debug("Executing mpi_f wrapper.") # Set the computingNodes variable in kwargs for its usage # in @task decorator kwargs['computingNodes'] = self.kwargs['computingNodes'] if len(args) > 0: # The 'self' for a method function is passed as args[0] slf = args[0] # Replace and store the attributes saved = {} for k, v in self.kwargs.items(): if hasattr(slf, k): saved[k] = getattr(slf, k) setattr(slf, k, v) # Call the method ret = func(*args, **kwargs) if len(args) > 0: # Put things back for k, v in saved.items(): setattr(slf, k, v) return ret mpi_f.__doc__ = func.__doc__ return mpi_f
def __call__(self, func): if i_am_at_master(): # master code mod = inspect.getmodule(func) self.module = mod.__name__ # not func.__module__ if(self.module == '__main__' or self.module == 'pycompss.runtime.launch'): # The module where the function is defined was run as __main__, # we need to find out the real module name. # path=mod.__file__ # dirs=mod.__file__.split(os.sep) # file_name=os.path.splitext(os.path.basename(mod.__file__))[0] # Get the real module name from our launch.py variable path = getattr(mod, "app_path") dirs = path.split(os.path.sep) file_name = os.path.splitext(os.path.basename(path))[0] mod_name = file_name i = len(dirs) - 1 while i > 0: new_l = len(path) - (len(dirs[i]) + 1) path = path[0:new_l] if "__init__.py" in os.listdir(path): # directory is a package i -= 1 mod_name = dirs[i] + '.' + mod_name else: break self.module = mod_name # Include the registering info related to @constraint # Retrieve the base coreElement established at @task decorator coreElement = func.__to_register__ # Update the core element information with the constraints coreElement.set_implConstraints(self.kwargs) func.__to_register__ = coreElement # Do the task register if I am the top decorator if func.__who_registers__ == __name__: logger.debug("[@CONSTRAINT] I have to do the register of function %s in module %s" % (func.__name__, self.module)) register_ce(coreElement) else: # worker code pass @wraps(func) def constrained_f(*args, **kwargs): # This is executed only when called. logger.debug("Executing constrained_f wrapper.") if len(args) > 0: # The 'self' for a method function is passed as args[0] slf = args[0] # Replace and store the attributes saved = {} for k, v in self.kwargs.items(): if hasattr(slf, k): saved[k] = getattr(slf, k) setattr(slf, k, v) # Call the method ret = func(*args, **kwargs) if len(args) > 0: # Put things back for k, v in saved.items(): setattr(slf, k, v) return ret constrained_f.__doc__ = func.__doc__ return constrained_f
def __init__(self, *args, **kwargs): """ If there are decorator arguments, the function to be decorated is not passed to the constructor! """ logger.debug("Init @task decorator...") # Defaults self.args = args # Not used self.kwargs = kwargs # The only ones actually used: (decorators) self.is_instance = False # Pre-process decorator arguments from pycompss.api.parameter import Parameter from pycompss.api.parameter import IN from pycompss.api.parameter import TYPE from pycompss.api.parameter import DIRECTION # Reserved PyCOMPSs keywords and default values reserved_keywords = { 'isModifier': True, 'returns': False, 'priority': False, 'isReplicated': False, 'isDistributed': False, 'varargsType': IN } for (reserved_keyword, default_value) in reserved_keywords.items(): if reserved_keyword not in self.kwargs: self.kwargs[reserved_keyword] = default_value # Remove old args for old_vararg in [ x for x in self.kwargs.keys() if x.startswith('*args') ]: self.kwargs.pop(old_vararg) import copy if i_am_at_master(): for arg_name in self.kwargs.keys(): if arg_name not in [ 'isModifier', 'returns', 'priority', 'isReplicated', 'isDistributed' ]: # Prevent p.value from being overwritten later by ensuring # each Parameter is a separate object p = self.kwargs[arg_name] pcopy = copy.copy(p) # shallow copy self.kwargs[arg_name] = pcopy if self.kwargs['isModifier']: direction = DIRECTION.INOUT else: direction = DIRECTION.IN # Add callee object parameter self.kwargs['self'] = Parameter(p_type=TYPE.OBJECT, p_direction=direction) # Check the return type: if self.kwargs['returns']: # This condition is interesting, because a user can write # returns=list # However, lists have the attribute __len__ but raise an exception. # Since the user does not indicate the length, it will be managed # as a single return. # When the user specifies the length, it is possible to manage the # elements independently. if not hasattr(self.kwargs['returns'], '__len__') or type(self.kwargs['returns']) is type: # Simple return retType = getCOMPSsType(self.kwargs['returns']) self.kwargs['compss_retvalue'] = Parameter( p_type=retType, p_direction=DIRECTION.OUT) else: # Multi return i = 0 returns = [] for r in self.kwargs['returns']: # This adds only one? - yep retType = getCOMPSsType(r) returns.append( Parameter(p_type=retType, p_direction=DIRECTION.OUT)) self.kwargs['compss_retvalue'] = tuple(returns) logger.debug("Init @task decorator finished.")
def __call__(self, f): """ If there are decorator arguments, __call__() is only called once, as part of the decoration process! You can only give it a single argument, which is the function object. """ # Assume it is an instance method if the first parameter of the # function is called 'self' # "I would rely on the convention that functions that will become # methods have a first argument named self, and other functions don't. # Fragile, but then, there's no really solid way." self.spec_args = inspect.getargspec(f) # Set default booleans self.is_instance = False self.is_classmethod = False # not used currently in this scope, only when registering the task self.has_varargs = False self.has_keywords = False self.has_defaults = False self.has_return = False # Question: Will the first condition evaluate to false? spec_args will # always be a named tuple, so it will always return true if evaluated # as a bool # Answer: The first condition evaluates if args exists (a list) and is # not empty in the spec_args. The second checks if the first argument # in that list is 'self'. In case that the args list exists and its # first element is self, then the function is considered as an instance # function (task defined within a class). if self.spec_args.args and self.spec_args.args[0] == 'self': self.is_instance = True # Check if contains *args if self.spec_args.varargs is not None: self.has_varargs = True # Check if contains **kwargs if self.spec_args.keywords is not None: self.has_keywords = True # Check if has default values if self.spec_args.defaults is not None: self.has_defaults = True # Check if the keyword returns has been specified by the user. if self.kwargs['returns']: self.has_return = True self.spec_args.args.append('compss_retvalue') # Get module (for invocation purposes in the worker) mod = inspect.getmodule(f) self.module = mod.__name__ if (self.module == '__main__' or self.module == 'pycompss.runtime.launch'): # the module where the function is defined was run as __main__, # we need to find out the real module name # Get the real module name from our launch.py app_path global variable try: path = getattr(mod, "app_path") except AttributeError: # This exception is raised when the runtime is not running and # the @task decorator is used. print( "ERROR!!! The runtime has not been started yet. The function will be ignored." ) print( "Please, start the runtime before using task decorated functions in order to avoid this error." ) print( "Suggestion: Use the 'runcompss' command or the 'start' function from pycompss.interactive module depending on your needs." ) return # Get the file name file_name = os.path.splitext(os.path.basename(path))[0] # Do any necessary preprocessing action before executing any code if file_name.startswith('InteractiveMode'): # If the file_name starts with 'InteractiveMode' means that # the user is using PyCOMPSs from jupyter-notebook. # Convention between this file and interactive.py # In this case it is necessary to do a pre-processing step # that consists of putting all user code that may be executed # in the worker on a file. # This file has to be visible for all workers. updateTasksCodeFile(f, path) else: # work as always pass # Get the module self.module = getModuleName(path, file_name) # The registration needs to be done only in the master node if i_am_at_master(): registerTask(f, self.module, self.is_instance) # Modified variables until now that will be used later: # - self.spec_args : Function argspect (Named tuple) # e.g. ArgSpec(args=['a', 'b', 'compss_retvalue'], varargs=None, keywords=None, defaults=None) # - self.is_instance : Boolean - if the function is an instance (contains self in the spec_args) # - self.has_varargs : Boolean - if the function has *args # - self.has_keywords : Boolean - if the function has **kwargs # - self.has_defaults : Boolean - if the function has default values # - self.has_return : Boolean - if the function has return # - self.module : module as string (e.g. test.kmeans) # - is_replicated : Boolean - if the task is replicated # - is_distributed : Boolean - if the task is distributed # Other variables that will be used: # - f : Decorated function # - self.args : Decorator args tuple (usually empty) # - self.kwargs : Decorator keywords dictionary. # e.g. {'priority': True, 'isModifier': True, 'returns': <type 'dict'>, # 'self': <pycompss.api.parameter.Parameter instance at 0xXXXXXXXXX>, # 'compss_retvalue': <pycompss.api.parameter.Parameter instance at 0xXXXXXXXX>} @wraps(f) def wrapped_f(*args, **kwargs): # args - <Tuple> - Contains the objects that the function has been called with (positional). # kwargs - <Dictionary> - Contains the named objects that the function has been called with. is_replicated = self.kwargs['isReplicated'] is_distributed = self.kwargs['isDistributed'] computingNodes = 1 if 'computingNodes' in kwargs: # There is a @mpi decorator over task that overrides the # default value of computing nodes computingNodes = kwargs['computingNodes'] del kwargs['computingNodes'] # Check if this call is nested using the launch_pycompss_module # function from launch.py. is_nested = False istack = inspect.stack() for i_s in istack: if i_s[3] == 'launch_pycompss_module': is_nested = True if i_s[3] == 'launch_pycompss_application': is_nested = True if not i_am_at_master() and (not is_nested): # Task decorator worker body code. newTypes, newValues = workerCode(f, self.is_instance, self.has_varargs, self.has_keywords, self.has_defaults, self.has_return, args, kwargs, self.kwargs, self.spec_args) return newTypes, newValues else: # Task decorator master body code. # Returns the future object that will be used instead of the # actual function return. fo = masterCode(f, self.module, self.is_instance, self.has_varargs, self.has_keywords, self.has_defaults, self.has_return, is_replicated, is_distributed, computingNodes, args, self.args, kwargs, self.kwargs, self.spec_args) return fo return wrapped_f
def __init__(self, *args, **kwargs): """ If there are decorator arguments, the function to be decorated is not passed to the constructor! """ from pycompss.util.location import i_am_within_scope # Check if under the PyCOMPSs scope if i_am_within_scope(): from pycompss.util.location import i_am_at_master from pycompss.api.parameter import IN self.scope = True if __debug__: logger.debug("Init @task decorator...") # Defaults self.args = args # Not used self.kwargs = kwargs # The only ones actually used: (decorators) # Pre-process decorator arguments # Reserved PyCOMPSs keywords and default values reserved_keywords = { 'isModifier': True, 'returns': False, 'priority': False, 'isReplicated': False, 'isDistributed': False, 'varargsType': IN } # Set reserved keyword default values in self.kwargs for (reserved_keyword, default_value) in reserved_keywords.items(): if reserved_keyword not in self.kwargs: self.kwargs[reserved_keyword] = default_value # Remove old args for old_vararg in [ x for x in self.kwargs.keys() if x.startswith('*args') ]: self.kwargs.pop(old_vararg) if i_am_at_master(): for arg_name in self.kwargs.keys(): if arg_name not in reserved_keywords.keys(): # Prevent p.value from being overwritten later by ensuring # each Parameter is a separate object p = self.kwargs[arg_name] pcopy = copy.copy(p) # shallow copy self.kwargs[arg_name] = pcopy if __debug__: logger.debug("Init @task decorator finished.") else: # Not under the PyCOMPSs scope self.scope = False # Defaults self.args = args self.kwargs = kwargs
def __call__(self, f): """ If there are decorator arguments, __call__() is only called once, as part of the decoration process! You can only give it a single argument, which is the function object. """ # Check if under the PyCOMPSs scope if not self.scope: return self.__not_under_pycompss_scope(f) # Imports from pycompss.api.parameter import Parameter from pycompss.api.parameter import TYPE from pycompss.api.parameter import DIRECTION from pycompss.util.interactive_helpers import updateTasksCodeFile from pycompss.util.location import i_am_at_master if __debug__: logger.debug("Call in @task decorator...") # Assume it is an instance method if the first parameter of the # function is called 'self' # "I would rely on the convention that functions that will become # methods have a first argument named self, and other functions don't. # Fragile, but then, there's no really solid way." self.f_argspec = inspect.getargspec(f) # Set default booleans self.is_instance = False self.is_classmethod = False self.has_varargs = False self.has_keywords = False self.has_defaults = False self.has_return = False self.has_multireturn = False # Step 1.- Check if it is an instance method. # Question: Will the first condition evaluate to false? spec_args will # always be a named tuple, so it will always return true if evaluated # as a bool # Answer: The first condition evaluates if args exists (a list) and is # not empty in the spec_args. The second checks if the first argument # in that list is 'self'. In case that the args list exists and its # first element is self, then the function is considered as an instance # function (task defined within a class). if self.f_argspec.args and self.f_argspec.args[0] == 'self': self.is_instance = True if self.kwargs['isModifier']: direction = DIRECTION.INOUT else: direction = DIRECTION.IN # Add callee object parameter self.kwargs['self'] = Parameter(p_type=TYPE.OBJECT, p_direction=direction) # Step 2.- Check if it is a class method. # The check of 'cls' may be weak but it is PEP8 style agreements. if self.f_argspec.args and self.f_argspec.args[0] == 'cls': self.is_classmethod = True # Add class object parameter self.kwargs['self'] = Parameter(p_type=TYPE.OBJECT, p_direction=DIRECTION.IN) # Step 3.- Check if it has varargs (contains *args?) # Check if contains *args if self.f_argspec.varargs is not None: self.has_varargs = True # Step 4.- Check if it has keyword arguments (contains **kwargs?) # Check if contains **kwargs if self.f_argspec.keywords is not None: self.has_keywords = True # Step 5.- Check if it has default values # Check if has default values if self.f_argspec.defaults is not None: self.has_defaults = True # Step 6.- Check if the keyword returns has been specified by the user. # Check if the keyword returns has been specified by the user. if self.kwargs['returns']: self.has_return = True self.f_argspec.args.append( 'compss_retvalue' ) # TODO: WHY THIS VARIABLE? THE INFORMATION IS IN SELF.KWARGS['COMPSS_RETVALUE'] self.__update_return_type() else: # If no returns statement found, double check to see if the user has specified a return statement. self.__update_return_if_no_returns(f) # Get module (for invocation purposes in the worker) mod = inspect.getmodule(f) self.module = mod.__name__ if self.module == '__main__' or self.module == 'pycompss.runtime.launch': # the module where the function is defined was run as __main__, # we need to find out the real module name # Get the real module name from our launch.py app_path global variable try: path = getattr(mod, "app_path") except AttributeError: # This exception is raised when the runtime is not running and the @task decorator is used. # The runtime has not been started yet. return self.__not_under_pycompss_scope(f) # Get the file name file_name = os.path.splitext(os.path.basename(path))[0] # Do any necessary preprocessing action before executing any code if file_name.startswith('InteractiveMode'): # If the file_name starts with 'InteractiveMode' means that # the user is using PyCOMPSs from jupyter-notebook. # Convention between this file and interactive.py # In this case it is necessary to do a pre-processing step # that consists of putting all user code that may be executed # in the worker on a file. # This file has to be visible for all workers. updateTasksCodeFile(f, path) else: # work as always pass # Get the module self.module = get_module_name(path, file_name) # The registration needs to be done only in the master node if i_am_at_master(): self.__register_task(f) # Modified variables until now that will be used later: # - self.f_argspec : Function argspect (Named tuple) # e.g. ArgSpec(args=['a', 'b', 'compss_retvalue'], varargs=None, keywords=None, defaults=None) # - self.is_instance : Boolean - if the function is an instance (contains self in the f_argspec) # - self.is_classmethod : Boolean - if the function is a classmethod (contains cls in the f_argspec) # - self.has_varargs : Boolean - if the function has *args # - self.has_keywords : Boolean - if the function has **kwargs # - self.has_defaults : Boolean - if the function has default values # - self.has_return : Boolean - if the function has return # - self.has_multireturn : Boolean - if the function has multireturn # - self.module_name : String - Module name (e.g. test.kmeans) # - is_replicated : Boolean - if the task is replicated # - is_distributed : Boolean - if the task is distributed # Other variables that will be used: # - f : Decorated function # - self.args : Decorator args tuple (usually empty) # - self.kwargs : Decorator keywords dictionary. # e.g. {'priority': True, 'isModifier': True, 'returns': <type 'dict'>, # 'self': <pycompss.api.parameter.Parameter instance at 0xXXXXXXXXX>, # 'compss_retvalue': <pycompss.api.parameter.Parameter instance at 0xXXXXXXXX>} if __debug__: logger.debug("Call in @task decorator finished.") @wraps(f) def wrapped_f(*args, **kwargs): # args - <Tuple> - Contains the objects that the function has been called with (positional). # kwargs - <Dictionary> - Contains the named objects that the function has been called with. is_replicated = self.kwargs['isReplicated'] is_distributed = self.kwargs['isDistributed'] # By default, each task is set to use one core. computingNodes = 1 if 'computingNodes' in kwargs: # There is a @mpi decorator over task that overrides the # default value of computing nodes computingNodes = kwargs['computingNodes'] del kwargs['computingNodes'] # Check if this call is nested using the launch_pycompss_module # function from launch.py. is_nested = False istack = inspect.stack() for i_s in istack: if i_s[3] == 'launch_pycompss_module': is_nested = True if i_s[3] == 'launch_pycompss_application': is_nested = True if not i_am_at_master() and (not is_nested): # Task decorator worker body code. newTypes, newValues = self.worker_code(f, args, kwargs) return newTypes, newValues else: # Task decorator master body code. # Returns the future object that will be used instead of the # actual function return. fo = self.master_code(f, is_replicated, is_distributed, computingNodes, args, kwargs) return fo return wrapped_f
def __call__(self, func): """ Parse and set the implementation parameters within the task core element. :param func: Function to decorate :return: Decorated function. """ if not self.scope: # from pycompss.api.dummy.implement import implement as dummy_implement # d_i = dummy_implement(self.args, self.kwargs) # return d_i.__call__(func) raise Exception("The implement decorator only works within PyCOMPSs framework.") if i_am_at_master(): # master code from pycompss.runtime.binding import register_ce mod = inspect.getmodule(func) self.module = mod.__name__ # not func.__module__ if(self.module == '__main__' or self.module == 'pycompss.runtime.launch'): # The module where the function is defined was run as __main__, # we need to find out the real module name. # path=mod.__file__ # dirs=mod.__file__.split(os.sep) # file_name=os.path.splitext(os.path.basename(mod.__file__))[0] # Get the real module name from our launch.py variable path = getattr(mod, "app_path") dirs = path.split(os.path.sep) file_name = os.path.splitext(os.path.basename(path))[0] mod_name = file_name i = len(dirs) - 1 while i > 0: new_l = len(path) - (len(dirs[i]) + 1) path = path[0:new_l] if "__init__.py" in os.listdir(path): # directory is a package i -= 1 mod_name = dirs[i] + '.' + mod_name else: break self.module = mod_name # Include the registering info related to @MPI # Retrieve the base coreElement established at @task decorator coreElement = func.__to_register__ # Update the core element information with the mpi information ce_signature = coreElement.get_ce_signature() implSignature = ce_signature coreElement.set_implSignature(implSignature) anotherClass = self.kwargs['source_class'] anotherMethod = self.kwargs['method'] ce_signature = anotherClass + '.' + anotherMethod coreElement.set_ce_signature(ce_signature) # This is not needed since the arguments are already set by the # task decorator. # implArgs = [anotherClass, anotherMethod] # coreElement.set_implTypeArgs(implArgs) coreElement.set_implType("METHOD") func.__to_register__ = coreElement # Do the task register if I am the top decorator if func.__who_registers__ == __name__: if __debug__: logger.debug("[@IMPLEMENT] I have to do the register of function %s in module %s" % (func.__name__, self.module)) register_ce(coreElement) else: # worker code pass @wraps(func) def implement_f(*args, **kwargs): # This is executed only when called. if __debug__: logger.debug("Executing implement_f wrapper.") # The 'self' for a method function is passed as args[0] slf = args[0] # Replace and store the attributes saved = {} for k, v in self.kwargs.items(): if hasattr(slf, k): saved[k] = getattr(slf, k) setattr(slf, k, v) # Call the method ret = func(*args, **kwargs) # Put things back for k, v in saved.items(): setattr(slf, k, v) return ret implement_f.__doc__ = func.__doc__ return implement_f
def __call__(self, func): if i_am_at_master(): # master code mod = inspect.getmodule(func) self.module = mod.__name__ # not func.__module__ if (self.module == '__main__' or self.module == 'pycompss.runtime.launch'): # The module where the function is defined was run as __main__, # we need to find out the real module name. # path=mod.__file__ # dirs=mod.__file__.split(os.sep) # file_name=os.path.splitext(os.path.basename(mod.__file__))[0] # Get the real module name from our launch.py variable path = getattr(mod, "app_path") dirs = path.split(os.path.sep) file_name = os.path.splitext(os.path.basename(path))[0] mod_name = file_name i = len(dirs) - 1 while i > 0: new_l = len(path) - (len(dirs[i]) + 1) path = path[0:new_l] if "__init__.py" in os.listdir(path): # directory is a package i -= 1 mod_name = dirs[i] + '.' + mod_name else: break self.module = mod_name # Include the registering info related to @MPI # Retrieve the base coreElement established at @task decorator coreElement = func.__to_register__ # Update the core element information with the mpi information coreElement.set_implType("DECAF") if 'workingDir' in self.kwargs: workingDir = self.kwargs['workingDir'] else: workingDir = '[unassigned]' # Empty or '[unassigned]' if 'mpiRunner' in self.kwargs: runner = self.kwargs['mpiRunner'] else: runner = 'mpirun' dfScript = self.kwargs['dfScript'] if 'dfExecutor' in self.kwargs: dfExecutor = self.kwargs['dfExecutor'] else: dfExecutor = '[unassigned]' # Empty or '[unassigned]' if 'dfLib' in self.kwargs: dfLib = self.kwargs['dfLib'] else: dfLib = '[unassigned]' # Empty or '[unassigned]' implSignature = 'DECAF.' + dfScript coreElement.set_implSignature(implSignature) implArgs = [dfScript, dfExecutor, dfLib, workingDir, runner] coreElement.set_implTypeArgs(implArgs) func.__to_register__ = coreElement # Do the task register if I am the top decorator if func.__who_registers__ == __name__: logger.debug( "[@DECAF] I have to do the register of function %s in module %s" % (func.__name__, self.module)) register_ce(coreElement) else: # worker code pass @wraps(func) def decaf_f(*args, **kwargs): # This is executed only when called. logger.debug("Executing decaf_f wrapper.") # Set the computingNodes variable in kwargs for its usage in @task decorator kwargs['computingNodes'] = self.kwargs['computingNodes'] if len(args) > 0: # The 'self' for a method function is passed as args[0] slf = args[0] # Replace and store the attributes saved = {} for k, v in self.kwargs.items(): if hasattr(slf, k): saved[k] = getattr(slf, k) setattr(slf, k, v) # Call the method ret = func(*args, **kwargs) if len(args) > 0: # Put things back for k, v in saved.items(): setattr(slf, k, v) return ret decaf_f.__doc__ = func.__doc__ return decaf_f