def _topological_sort(dependencies): seen = set() order = [] explored = set() for v in dependencies.keys(): # process all vertices if v in explored: continue fringe = [v] # nodes yet to look at while fringe: w = fringe[-1] # depth first search if w in explored: # already looked down this branch fringe.pop() continue seen.add(w) # mark as seen # Check successors for cycles and for new nodes new_nodes = [] for n in dependencies[w]: if n not in explored: if n in seen: #CYCLE !! raise RuleEngineError( "Dependencies graph contains a cycle, cannot set salience automatically." ) new_nodes.append(n) if new_nodes: # Add new_nodes to fringe fringe.extend(new_nodes) else: # No new nodes so w is fully explored explored.add(w) order.append(w) fringe.pop() # done considering this node return list(reversed(order))
def get_type(self): lhs_type, rhs_type = [arg.get_type() for arg in self.args] if lhs_type in (Integer, Number) and rhs_type in (Integer, Number): return Integer if lhs_type is Integer and rhs_type is Integer else Number else: raise RuleEngineError('Illegal operator "{}" on {} and {}'.format( self.op.__name__, self.lhs.get_type(), self.rhs.get_type()))
def __init__(self, expr): expr = normalize_expr(expr) super(Condition, self).__init__(all_fields=expr.all_fields) if expr.get_type() is not Boolean: raise RuleEngineError( 'Condition must be of boolean type. Got "{}", which is {}'. format(expr, expr.get_type())) self.expr = expr
def set_target_fields(self, **fields): if self.target is not None: raise RuleEngineError('Target already set') self.target_fields = { key: FieldExpr(_type=TYPE_MAP.get(_type, _type)) for key, _type in fields.iteritems() } self.target = make_slotted_type(Fact, self.name, **self.target_fields)
def __init__(self, *args): self.args = map(normalize_expr, args) types = {arg.get_type() for arg in self.args[1:3]} if len(types) != 1: raise RuleEngineError("Different return types: {}".format(types)) self.return_type = types.pop() all_fields = reduce(set.union, (arg.all_fields for arg in self.args), set()) super(ConditionalExpr, self).__init__(all_fields=all_fields)
def normalize_expr(expr): if isinstance(expr, BaseExpr): return expr elif isinstance(expr, ConvertibleToExpr): return expr._to_expr() else: try: return PrimitiveExpr(expr) except TypeError: raise RuleEngineError('Expected primitive or expression, found {}'.format(expr))
def __init__(self, **kwargs): if self._clips_type is None: raise RuleEngineError('Class {} is not bound to a rule engine and cannot be instantiated'.format(type(self))) existing_clips_obj = kwargs.get('_clips_obj') if existing_clips_obj is None: self._clips_obj = self._create_clips_obj() self._clips_obj.AssignSlotDefaults() for key, value in kwargs.iteritems(): field = self._fields.get(key) if field is None: raise RuleEngineError('Field {} does not exist in {}'.format(key, self._name)) if not field.get_type()._isinstance(value): raise RuleEngineError('In {}: expected {} should be of type {}, got {}.'. format(self._name, key, field.get_type(), value)) if isinstance(value, HasSlots): value = value._clips_obj self._clips_obj.Slots[key] = field._type._to_clips_value(value) else: self._clips_obj = self._copy_clips_obj(existing_clips_obj) self._data = tuple(self._fields[key]._type._from_clips_value(self._clips_obj.Slots[key]) for key in self._ordered_fields)
def _init_target(self, engine): target_name = self.get_target_name() if target_name is None: raise RuleEngineError( 'Cannot build rule, target name not set or multiple targets have the same name' ) if self.name is None: self.name = target_name if self.target._name is None: self.target._name = target_name if target_name not in engine.clips_types: self.target._build(engine)
def load(self, filename): """ Load facts and class instances from a text file in CLIPS format (as written by the save() method) """ try: self.logger.debug('Loading facts from {}'.format(filename)) self.environment.LoadFacts(filename) instance_filename = _get_instance_filename(filename) if os.path.exists(instance_filename): self.environment.LoadInstances(instance_filename) except IOError: raise RuleEngineError( 'Error while loading {}.\n Error log:\n{}'.format( filename, clips.ErrorStream.Read()))
def export_facts_to_xls(facts_filename, out_filename, max_rows_in_sheet=10000): workbook = xlwt.Workbook() writers = {} _logger.info('Exporting facts to {}.'.format(out_filename)) for template_name, fact in read_fact_file(facts_filename): writer = writers.get(template_name) if writer is None: writer = ExportSheetWriter(workbook, template_name, max_rows_in_sheet=max_rows_in_sheet) writers[template_name] = writer writer.write_fact(fact) if not writers: raise RuleEngineError('No facts found, cannot export to Excel') workbook.save(out_filename)
def prepare_rule(self, rule): if self.rule is not None: raise RuleEngineError( '"Assert" instance may only be used in a single rule.') self.rule = rule # Deduce fields for rule target if rule.target_fields is None: implied_fields = { key: value.get_type() for key, value in self.data.iteritems() } rule.set_target_fields(**implied_fields) # Fields of input facts cannot be used directly in the Assert() clause. # They must be bound to variables. for key, value in self.data.iteritems(): for field in value.all_fields: rule.add_variable(field)
def get_type(self): raise RuleEngineError('Cannot infer type for {}'.format(self))
def process_one(self, **kwargs): if self.finalized: raise RuleEngineError('Aggregation failed') key = tuple(key(**kwargs) for key in keys) value = kwargs.values()[0] if len(kwargs) == 1 else Bunch(kwargs) self.data[key].append(value)
def _build(cls, engine): if not cls._fields: raise RuleEngineError('{} has no fields'.format(cls._name)) logger.getChild('slots').debug('Building: %s, slots: %s', cls._name, cls._slots) cls._environment = engine.environment engine.register_clips_type(cls)
def set_name(self, name): if self.name not in (None, name): raise RuleEngineError( 'Tried to set target name to "{}", but it is already "{}"'. format(name, self.name)) self.name = name
def set_target(self, target=None): if self.target_fields is not None: raise RuleEngineError( 'Cannot set both target template and target fields') self.target = target self.target_fields = target._fields