def test_or_and_fact_inside_or(): from pyknow import Fact, OR, Rule from pyknow.matchers.rete.dnf import dnf input_ = Rule(OR(Fact(a=1), OR(Fact(a=2), Fact(a=3)))) output = Rule(OR(Fact(a=1), Fact(a=2), Fact(a=3))) assert dnf(input_) == output
def test_or_inside_and(): from pyknow import Fact, Rule, AND, OR from pyknow.matchers.rete.dnf import dnf input_ = Rule(AND(Fact(a=1), OR(Fact(a=2), Fact(a=3)))) output = Rule(OR(AND(Fact(a=1), Fact(a=2)), AND(Fact(a=1), Fact(a=3)))) assert dnf(input_[0]) == output[0]
def test_and_inside_rule(): from pyknow import Fact, Rule, AND from pyknow.matchers.rete.dnf import dnf input_ = Rule(Fact(a=1), AND(Fact(b=2), Fact(c=3))) output = Rule(Fact(a=1), Fact(b=2), Fact(c=3)) result = dnf(input_) assert result == output
def test_double_not_inside_fact(): from pyknow import Fact, OR, Rule, L from pyknow.matchers.rete.dnf import dnf input_ = Rule(Fact(a=~~L(1))) output = Rule(Fact(a=L(1))) result = dnf(input_) assert result == output
def test_not_and_inside_fact(): from pyknow import Fact, OR, Rule, L from pyknow.matchers.rete.dnf import dnf input_ = Rule(Fact(a=~(L(1) & L(2)))) output = Rule(OR(Fact(a=~L(1)), Fact(a=~L(2)))) result = dnf(input_) assert result == output
def test_or_inside_or_inside_and(): from pyknow import Fact, OR, AND, Rule from pyknow.matchers.rete.dnf import dnf input_ = Rule(AND(Fact(b=1), OR(Fact(a=1), OR(Fact(a=3), Fact(a=4))))) output = Rule(OR(AND(Fact(b=1), Fact(a=1)), AND(Fact(b=1), Fact(a=3)), AND(Fact(b=1), Fact(a=4)))) result = dnf(input_) assert result == output
def test_and_inside_and_inside_fact(): from pyknow import Fact, OR, Rule, L from pyknow.fieldconstraint import ANDFC from pyknow.matchers.rete.dnf import dnf input_ = Rule(Fact(a=L(1) & (L(2) & L(3)))) output = Rule(Fact(a=ANDFC(L(1), L(2), L(3)))) result = dnf(input_) assert result == output
def test_or_inside_fact(): from pyknow import Fact, OR, Rule, L from pyknow.matchers.rete.dnf import dnf input_ = Rule(Fact(a=L(1) | L(2), b=3)) output = Rule(OR(Fact(a=L(1), b=3), Fact(a=L(2), b=3))) result = dnf(input_) assert set(result[0]) == set(output[0])
def test_not_or_inside_fact(): from pyknow import Fact, OR, Rule, L from pyknow.fieldconstraint import ANDFC, NOTFC from pyknow.matchers.rete.dnf import dnf input_ = Rule(Fact(a=~(L(1) | L(2)))) output = Rule(Fact(a=ANDFC(NOTFC(L(1)), NOTFC(L(2))))) result = dnf(input_) assert result == output
def test_or_inside_or_inside_fact(): from pyknow import Fact, OR, Rule, L from pyknow.matchers.rete.dnf import dnf input_ = Rule(Fact(a=L(1) | (L(2) | L(3)))) output = Rule(OR(Fact(a=L(1)), Fact(a=L(2)), Fact(a=L(3)))) result = dnf(input_) assert result == output
def test_activation_facts_only_iterable(): """ Check if activation facts are required to be a tuple """ from pyknow.activation import Activation from pyknow import Rule import pytest # SHOULD NOT RAISE Activation(rule=Rule(), facts=tuple()) Activation(rule=Rule(), facts=list()) Activation(rule=Rule(), facts=dict()) with pytest.raises(TypeError): Activation(rule=Rule(), facts=None)
def test_multiple_or_inside_rule(): from pyknow import Fact, OR, Rule, AND from pyknow.matchers.rete.dnf import dnf input_ = Rule(Fact(a=1), OR(Fact(b=1), Fact(b=2)), OR(Fact(c=1), Fact(c=2))) output_ = Rule(OR(AND(Fact(a=1), Fact(b=1), Fact(c=1)), AND(Fact(a=1), Fact(b=1), Fact(c=2)), AND(Fact(a=1), Fact(b=2), Fact(c=1)), AND(Fact(a=1), Fact(b=2), Fact(c=2)))) result = dnf(input_) assert result == output_
def test_prepare_rule__or_starting_with_not(): from pyknow import Rule, InitialFact, NOT, Fact, OR, AND rule = Rule(OR(NOT(Fact(1)), NOT(Fact(2))))(lambda: None) assert list(utils.prepare_rule(rule)) == [ OR(AND(InitialFact(), NOT(Fact(1))), AND(InitialFact(), NOT(Fact(2)))) ]
def set_sensor_value(context: dict, sensor: str, value: bool = False) -> None: """Set a sensor to a specific value.""" assert False rules = context.rules.copy() context.rules.clear() context.final_rules.append( Rule(AND(*rules))(lambda engine: engine.results.__setitem__( sensor.replace(' ', '_'), from_state(value))))
def test_Rule_is_iterable(): from pyknow import Rule from pyknow import Fact rule_ = iter(Rule(Fact(a=1), Fact(a=2))) assert next(rule_) == Fact(a=1) assert next(rule_) == Fact(a=2) with pytest.raises(StopIteration): assert next(rule_)
def test_DepthStrategy_update_agenda_asertion_order_affects_agenda_order_3(): """ From Clips docs on Depth Strategy:: Newly activated rules are placed above all rules of the same salience. For example, given that facta activates rule1 and rule2 and factb activates rule3 and rule4, then if facta is asserted before factb, rule3 and rule4 will be above rule1 and rule2 on the agenda. However, the position of rule1 relative to rule2 and rule3 relative to rule4 will be arbitrary. """ from pyknow.strategies import DepthStrategy from pyknow.activation import Activation from pyknow import Rule from pyknow.agenda import Agenda from pyknow import Fact from pyknow.factlist import FactList fl = FactList() f1 = Fact(1) fl.declare(f1) f2 = Fact(2) fl.declare(f2) act1 = Activation(rule=Rule(), facts=(f1, )) act2 = Activation(rule=Rule(), facts=(f1, )) act3 = Activation(rule=Rule(), facts=(f2, )) act4 = Activation(rule=Rule(), facts=(f2, )) a = Agenda() st = DepthStrategy() st.update_agenda(a, [act1, act2, act3, act4], []) order = list(a.activations) assert (order.index(act4) > order.index(act1) and order.index(act4) > order.index(act2)) assert (order.index(act3) > order.index(act1) and order.index(act3) > order.index(act2))
def test_prepare_rule_is_dnf(): from pyknow import Rule, NOT, AND, OR, Fact from pyknow.matchers.rete.dnf import dnf rule = Rule(AND(Fact(0), NOT(OR(Fact(1), Fact(2)))))(lambda: None) assert list( utils.prepare_rule(rule)) == [Fact(0), NOT(Fact(1)), NOT(Fact(2))]
def test_DepthStrategy_update_agenda_different_salience(): from random import shuffle from pyknow.strategies import DepthStrategy from pyknow.activation import Activation from pyknow import Rule from pyknow import Fact from pyknow.agenda import Agenda from pyknow.factlist import FactList flist = FactList() f1 = Fact(1) flist.declare(f1) f2 = Fact(2) flist.declare(f2) f3 = Fact(3) flist.declare(f3) f4 = Fact(4) flist.declare(f4) act1 = Activation(rule=Rule(salience=1), facts=(f1, )) act2 = Activation(rule=Rule(salience=2), facts=(f2, )) act3 = Activation(rule=Rule(salience=3), facts=(f3, )) act4 = Activation(rule=Rule(salience=4), facts=(f4, )) acts = [act1, act2, act3, act4] shuffle(acts) st = DepthStrategy() a = Agenda() for act in acts: st.update_agenda(a, acts, []) order = list(a.activations) assert (order.index(act4) < order.index(act3) < order.index(act2) < order.index(act1))
def test_DepthStrategy_update_agenda_assertion_order_affects_agenda_order_1(): from pyknow.strategies import DepthStrategy from pyknow.activation import Activation from pyknow import Rule from pyknow.agenda import Agenda from pyknow import Fact from pyknow.factlist import FactList fl = FactList() f1 = Fact(1) fl.declare(f1) f2 = Fact(2) fl.declare(f2) f3 = Fact(3) fl.declare(f3) f4 = Fact(4) fl.declare(f4) act1 = Activation(rule=Rule(), facts=(f1, )) act2 = Activation(rule=Rule(), facts=(f2, )) first = [act1, act2] act3 = Activation(rule=Rule(), facts=(f3, )) act4 = Activation(rule=Rule(), facts=(f4, )) second = [act3, act4] a = Agenda() st = DepthStrategy() oldact = a.activations st.update_agenda(a, first, []) assert list(a.activations) == list(reversed(first)) st.update_agenda(a, second, first) assert list(a.activations) == list(reversed(second))
def test_DepthStrategy_update_agenda_activations_to_agenda(): from pyknow.strategies import DepthStrategy from pyknow.activation import Activation from pyknow import Rule from pyknow.agenda import Agenda from pyknow import Fact from pyknow.factlist import FactList fl = FactList() f1 = Fact(1) fl.declare(f1) f2 = Fact(2) fl.declare(f2) act1 = Activation(rule=Rule(), facts=(f1, )) act2 = Activation(rule=Rule(), facts=(f2, )) a = Agenda() st = DepthStrategy() st.update_agenda(a, [act1, act2], []) assert act1 in a.activations assert act2 in a.activations
def build(cls, setname, spec): """ Rule struct example {'rulename1': {'lhs': [Vector(_type="ip", ip=MATCH.pollas)))], 'command': "run_nmap.py"}} """ def _create_rhs(command): def _rhs(self, **context): idxs = sorted([int(k.split('_')[2]) for k in context.keys() if k.startswith('_elem_')], reverse=True) lineages = list() for idx in idxs: lineages.extend(context[f'_lineage_{idx}']) elem = context[f'_elem_{idx}'].as_dict() del elem['_lineage'] lineages.append(elem) stdin = {k: v for k, v in context.items() if not k.startswith("_")} self.declare(TaskRequest(command=command, stdin=stdin, lineages=lineages)) return _rhs rules = {} for rulename, body in spec.items(): comps = list() for idx, comp in enumerate(body['lhs']): comp["_lineage"] = W(f"_lineage_{idx}") f"_elem_{idx}" << comp comps.append(comp) lhs = Rule(*comps, TEST(_shared_lineage)) rhs = _create_rhs(body['command']) rhs.__name__ = f"{setname}__{rulename}" rules[rulename] = lhs(rhs) return type(setname, (cls,), rules)
def test_pyknowdecoder(fakeexecutor): import operator from pyknow_rt import JsonEngine from pyknow_rt.utils import FactTypes from pyknow import Rule, TEST, MATCH executor = fakeexecutor() extra = { 'Rule': [{ 'Number': { 'a': { 'MATCH': 'a' } } }, { 'Number': { 'b': { 'MATCH': 'b' } } }, { 'TEST': ['gt'] }, { 'Number': { 'c': { 'MATCH': 'c' } } }, { 'TEST': ['gt'] }] } engine = type("engine", (JsonEngine, ), {"executor": executor})() res = engine.lhs_from_json(extra) Number = FactTypes.get('Number') expected = Rule(Number(a=MATCH.a), Number(b=MATCH.b), TEST(operator.gt), Number(c=MATCH.c), TEST(operator.gt)) assert res == expected
def test_prepare_rule__and_inside_rule(): from pyknow import Rule, AND, Fact rule = Rule(AND(Fact(1), Fact(2)))(lambda: None) assert list(utils.prepare_rule(rule)) == [Fact(1), Fact(2)]
def test_prepare_rule_empty(): from pyknow import Rule, InitialFact rule = Rule()(lambda: None) assert list(utils.prepare_rule(rule)) == [InitialFact()]
def test_activation_has_facts(): """ Check if activation has facts property """ from pyknow.activation import Activation from pyknow import Rule assert hasattr(Activation(rule=Rule(), facts=[]), 'facts')
def test_prepare_rule__rule_starting_with_not(): from pyknow import Rule, InitialFact, NOT, Fact rule = Rule(NOT(Fact(1)))(lambda: None) assert list(utils.prepare_rule(rule)) == [InitialFact(), NOT(Fact(1))]
def test_Rule_decorator_raise_AttributeError_if_called_without_function(): from pyknow import Rule with pytest.raises(AttributeError): Rule()()
def test_extract_facts(): from pyknow import Rule, NOT, AND, OR, Fact rule = Rule(OR(AND(Fact(1), NOT(Fact(2))), Fact(3))) assert utils.extract_facts(rule) == {Fact(1), Fact(2), Fact(3)}