def get_reference_info(self, strict=True): refs = {} for key, info in self.raw_pool.items(): reference = ConstantTemplate(info['value']).get_reference() formatted_reference = ['${%s}' % ref for ref in reference] ref = [ c for c in formatted_reference if not strict or c in self.raw_pool ] refs[key] = ref return refs
def _resolve(self): maps = {} for key in self._refs: try: ref_val = self._refs[key].value if issubclass(ref_val.__class__, Variable): ref_val = ref_val.get() except exceptions.ReferenceNotExistError: continue maps[key] = ref_val val = ConstantTemplate(self.value).resolve_data(maps) self._value = val
def resolve(self): if self.pool: return refs = self.get_reference_info() nodes = refs.keys() flows = [] for node in nodes: for ref in refs[node]: if ref in nodes: flows.append([node, ref]) graph = Graph(nodes, flows) # circle reference check trace = graph.get_cycle() if trace: raise ConstantReferenceException( 'Exist circle reference between constants: %s' % '->'.join(trace)) # resolve the constants reference pool = {} temp_pool = copy.deepcopy(self.raw_pool) # get those constants which are referenced only(not refer other constants) referenced_only = ConstantPool._get_referenced_only(temp_pool) while temp_pool: for ref in referenced_only: value = temp_pool[ref]['value'] # resolve those constants which reference the 'ref' for key, info in temp_pool.iteritems(): maps = {deformat_constant_key(ref): value} temp_pool[key]['value'] = ConstantTemplate( info['value']).resolve_data(maps) pool[ref] = temp_pool[ref] temp_pool.pop(ref) referenced_only = ConstantPool._get_referenced_only(temp_pool) self.pool = pool
def _determine_next_flow_with_boolrule(self, data): """ 根据当前传入的数据判断下一个应该流向的 flow ( 不使用 eval 的版本) :param data: :return: """ for condition in self.conditions: deformatted_data = {deformat_constant_key(key): value for key, value in data.items()} try: resolved_evaluate = ConstantTemplate(condition.evaluate).resolve_data(deformatted_data) result = BoolRule(resolved_evaluate).test(data) except Exception as e: raise EvaluationException( 'evaluate[%s] fail with data[%s] message: %s' % ( condition.evaluate, json.dumps(deformatted_data), e.message ) ) if result: return condition.sequence_flow return None
def calculate_constants_type(to_calculate, calculated): """ @summary: @param to_calculate: 待计算的变量 @param calculated: 变量类型确定的,直接放入结果 @return: """ data = copy.deepcopy(calculated) for key, info in to_calculate.items(): ref = ConstantTemplate(info['value']).get_reference() if ref: constant_type = 'splice' elif info.get('type', 'plain') != 'plain': constant_type = info['type'] else: constant_type = 'plain' data.setdefault(key, { 'type': constant_type, 'value': info['value'], 'is_param': info.get('is_param', False) }) return data
def targets_meet_condition(self, data): targets = [] for condition in self.conditions: deformatted_data = {deformat_constant_key(key): value for key, value in data.items()} try: resolved_evaluate = ConstantTemplate(condition.evaluate).resolve_data(deformatted_data) result = BoolRule(resolved_evaluate).test(data) except Exception as e: raise EvaluationException( 'evaluate[%s] fail with data[%s] message: %s' % ( condition.evaluate, json.dumps(deformatted_data), e.message ) ) if result: targets.append(condition.sequence_flow.target) if not targets: raise ConditionExhaustedException('all conditions of branches are False') return targets
def format_web_data_to_pipeline(web_pipeline, is_subprocess=False): """ @summary: @param web_pipeline: @return: """ pipeline_tree = copy.deepcopy(web_pipeline) constants = pipeline_tree.pop('constants') classification = classify_constants(constants, is_subprocess) # 解析隐藏全局变量互引用 pool_obj = ConstantPool(classification['constant_pool']) pre_resolved_constants = pool_obj.pool classification['data_inputs'] = calculate_constants_type( pre_resolved_constants, classification['data_inputs']) classification['data_inputs'] = calculate_constants_type( classification['params'], classification['data_inputs']) pipeline_tree['data'] = { 'inputs': classification['data_inputs'], 'outputs': [key for key in pipeline_tree.pop('outputs')], } for act_id, act in pipeline_tree['activities'].items(): if act['type'] == 'ServiceActivity': act_data = act['component'].pop('data') # for key, info in act_data.items(): # info['value'] = pool_obj.resolve_value(info['value']) all_inputs = calculate_constants_type( act_data, classification['data_inputs']) act['component']['inputs'] = { key: value for key, value in all_inputs.items() if key in act_data } act['component']['global_outputs'] = classification[ 'acts_outputs'].get(act_id, {}) elif act['type'] == 'SubProcess': parent_params = {} act_constants = {} for key, info in act['pipeline']['constants'].items(): act_constants[key] = info if info['show_type'] == 'show': references = ConstantTemplate( info['value']).get_reference() for ref_key in references: formatted_key = format_constant_key(ref_key) if formatted_key in classification['data_inputs']: parent_params[formatted_key] = classification[ 'data_inputs'][formatted_key] act['params'] = parent_params act['pipeline'] = format_web_data_to_pipeline(act['pipeline'], is_subprocess=True) else: raise exceptions.FlowTypeError(u"Unknown Activity type: %s" % act['type']) for act in pipeline_tree['activities'].values(): format_node_io_to_list(act, o=False) for gateway in pipeline_tree['gateways'].values(): format_node_io_to_list(gateway, o=False) format_node_io_to_list(pipeline_tree['end_event'], o=False) return pipeline_tree
def _build_reference(self, context): keys = ConstantTemplate(self.value).get_reference() refs = {} for key in keys: refs[key] = OutputRef(format_constant_key(key), context) self._refs = refs
def classify_constants(constants, is_subprocess): # pipeline tree inputs data_inputs = {} # pipeline act outputs acts_outputs = {} for key, info in list(constants.items()): # 显示的变量可以引用父流程 context,通过 param 传参 if info["show_type"] == "show": info["is_param"] = True else: info["is_param"] = False if info["custom_type"]: var_cls = library.VariableLibrary.get_var_class( info["custom_type"]) # 输出参数 if info["source_type"] == "component_outputs": if info["source_info"].values(): source_key = list(info["source_info"].values())[0][0] source_step = list(info["source_info"].keys())[0] # 生成 pipeline 层需要的 pipeline input data_inputs[key] = { "type": "splice", "source_act": source_step, "source_key": source_key, "value": info["value"], "is_param": info["is_param"], } # 生成 pipeline 层需要的 acts_output acts_outputs.setdefault(source_step, {}).update({source_key: key}) # 自定义的Lazy类型变量 elif info["custom_type"] and var_cls and issubclass( var_cls, var.LazyVariable): if (var_cls.type == "meta" and hasattr(var_cls, "process_meta_avalue") and callable(var_cls.process_meta_avalue)): value = var_cls.process_meta_avalue(info["meta"], info["value"]) else: value = info["value"] data_inputs[key] = { "type": "lazy", "source_tag": info["source_tag"], "custom_type": info["custom_type"], "value": value, "is_param": info["is_param"], } else: ref = ConstantTemplate(info["value"]).get_reference() constant_type = "splice" if ref else "plain" is_param = info["show_type"] == "show" and is_subprocess data_inputs[key] = { "type": constant_type, "value": info["value"], "is_param": is_param } result = {"data_inputs": data_inputs, "acts_outputs": acts_outputs} return result