def evaluate(self, data): """Evaluate the code needed to compute a given Data object.""" try: inputs = copy.deepcopy(data.input) hydrate_input_references(inputs, data.process.input_schema) hydrate_input_uploads(inputs, data.process.input_schema) # Include special 'proc' variable in the context. inputs["proc"] = { "data_id": data.id, "data_dir": self.manager.get_executor().resolve_data_path(), } # Include special 'requirements' variable in the context. inputs["requirements"] = data.process.requirements # Inject default values and change resources according to # the current Django configuration. inputs["requirements"]["resources"] = data.process.get_resource_limits() script_template = data.process.run.get("program", "") # Get the appropriate expression engine. If none is defined, do not evaluate # any expressions. expression_engine = data.process.requirements.get("expression-engine", None) if not expression_engine: return script_template return self.get_expression_engine(expression_engine).evaluate_block( script_template, inputs, escape=self._escape, safe_wrapper=SafeString, ) except EvaluationError as error: raise ExecutionError("{}".format(error))
def _evaluate_expressions(self, expression_engine, step_id, values, context): """Recursively evaluate expressions in a dictionary of values.""" if expression_engine is None: return values processed = {} for name, value in values.items(): if isinstance(value, str): value = value.strip() try: expression = expression_engine.get_inline_expression(value) if expression is not None: # Inline expression. value = expression_engine.evaluate_inline( expression, context) else: # Block expression. value = expression_engine.evaluate_block( value, context) except EvaluationError as error: raise ExecutionError( 'Error while evaluating expression for step "{}":\n{}'. format(step_id, error)) elif isinstance(value, dict): value = self._evaluate_expressions(expression_engine, step_id, value, context) processed[name] = value return processed
def evaluate(self, data): """Evaluate the code needed to compute a given Data object.""" try: inputs = copy.deepcopy(data.input) hydrate_input_references(inputs, data.process.input_schema) hydrate_input_uploads(inputs, data.process.input_schema) # Include special 'proc' variable in the context. inputs['proc'] = { 'data_id': data.id, 'data_dir': settings.FLOW_EXECUTOR['DATA_DIR'], } # Include special 'requirements' variable in the context. inputs['requirements'] = data.process.requirements script_template = data.process.run.get('program', '') # Get the appropriate expression engine. If none is defined, do not evaluate # any expressions. expression_engine = data.process.requirements.get( 'expression-engine', None) if not expression_engine: return script_template return self.get_expression_engine( expression_engine).evaluate_block( script_template, inputs, escape=self._escape, safe_wrapper=SafeString, ) except EvaluationError as error: raise ExecutionError('{}'.format(error))
def evaluate(self, data): """Evaluate the code needed to compute a given Data object.""" expression_engine = data.process.requirements.get( 'expression-engine', None) if expression_engine is not None: expression_engine = self.get_expression_engine(expression_engine) # Parse steps. steps = data.process.run.get('program', None) if steps is None: return if not isinstance(steps, list): raise ExecutionError('Workflow program must be a list of steps.') # Expression engine evaluation context. context = { 'input': data.input, 'steps': collections.OrderedDict(), } for index, step in enumerate(steps): try: step_id = step['id'] step_slug = step['run'] except KeyError as error: raise ExecutionError( 'Incorrect definition of step "{}", missing property "{}".' .format(step.get('id', index), error)) # Fetch target process. process = Process.objects.filter( slug=step_slug).order_by('-version').first() if not process: raise ExecutionError( 'Incorrect definition of step "{}", invalid process "{}".'. format(step_id, step_slug)) # Process all input variables. step_input = step.get('input', {}) if not isinstance(step_input, dict): raise ExecutionError( 'Incorrect definition of step "{}", input must be a dictionary.' .format(step_id)) data_input = self._evaluate_expressions(expression_engine, step_id, step_input, context) # Create the data object. data_object = Data.objects.create( process=process, contributor=data.contributor, tags=data.tags, input=data_input, collection=data.collection, subprocess_parent=data, ) context['steps'][step_id] = data_object.pk # Immediately set our status to done and output all data object identifiers. data.output = { 'steps': list(context['steps'].values()), } data.status = Data.STATUS_DONE