Exemple #1
0
def test_partial_constraint(polar):
    class User:
        pass

    class Post:
        pass

    polar.register_class(User)
    polar.register_class(Post)

    polar.load_str("f(x: User) if x.user = 1;")
    polar.load_str("f(x: Post) if x.post = 1;")

    partial = Partial("x", TypeConstraint("User"))
    results = polar.query_rule("f", partial)

    first = next(results)["bindings"]["x"]
    and_args = unwrap_and(first)

    assert len(and_args) == 2

    assert and_args[0] == Expression("Isa", [Variable("_this"), Pattern("User", {})])

    unify = unwrap_and(and_args[1])
    assert unify == Expression(
        "Unify", [Expression("Dot", [Variable("_this"), "user"]), 1]
    )

    with pytest.raises(StopIteration):
        next(results)
Exemple #2
0
def test_dict_specializers(polar, qvar, qeval, query):
    class Animal:
        def __init__(self, species=None, genus=None, family=None):
            self.genus = genus
            self.species = species

    polar.register_class(Animal)

    rules = """
    what_is(_: {genus: "canis"}, res) if res = "canine";
    what_is(_: {species: "canis lupus", genus: "canis"}, res) if res = "wolf";
    what_is(_: {species: "canis familiaris", genus: "canis"}, res) if res = "dog";
    """
    polar.load_str(rules)

    wolf = 'new Animal(species: "canis lupus", genus: "canis", family: "canidae")'
    dog = 'new Animal(species: "canis familiaris", genus: "canis", family: "canidae")'
    canine = 'new Animal(genus: "canis", family: "canidae")'

    assert len(query(f"what_is({wolf}, res)")) == 2
    assert len(query(f"what_is({dog}, res)")) == 2
    assert len(query(f"what_is({canine}, res)")) == 1

    assert qvar(f"what_is({wolf}, res)", "res") == ["wolf", "canine"]
    assert qvar(f"what_is({dog}, res)", "res") == ["dog", "canine"]
    assert qvar(f"what_is({canine}, res)", "res") == ["canine"]
Exemple #3
0
def test_anything_works(polar, query):
    polar.load_str("f(1);")
    results = query("f(x)")
    assert results[0]["x"] == 1

    results = query("f(y)")
    assert results[0]["y"] == 1
Exemple #4
0
def test_method_with_kwargs(polar, qvar):
    class Test:
        def kwarg_method(self, x=1, y=2):
            self.x = x
            self.y = y
            return True

    polar.register_class(Test)
    rules = """
    defaults(result) if
        test = new Test() and
        test.kwarg_method() and
        result = [test.x, test.y];

    kwargs(result) if
        test = new Test() and
        test.kwarg_method(y: 4, x: 3) and
        result = [test.x, test.y];

    args(result) if
        test = new Test() and
        test.kwarg_method(5, 6) and
        result = [test.x, test.y];

    mixed(result) if
        test = new Test() and
        test.kwarg_method(7, y: 8) and
        result = [test.x, test.y];
    """
    polar.load_str(rules)
    qvar("defaults(result)", "result") == [1, 2]
    qvar("kwargs(result)", "result") == [3, 4]
    qvar("args(result)", "result") == [5, 6]
    qvar("mixed(result)", "result") == [7, 8]
Exemple #5
0
def test_class_specializers(polar, qvar, qeval, query):
    class A:
        def a(self):
            return "A"

        def x(self):
            return "A"

    class B(A):
        def b(self):
            return "B"

        def x(self):
            return "B"

    class C(B):
        def c(self):
            return "C"

        def x(self):
            return "C"

    class X:
        def x(self):
            return "X"

    polar.register_class(A)
    polar.register_class(B)
    polar.register_class(C)
    polar.register_class(X)

    rules = """
    test(_: A);
    test(_: B);

    try(_: B, res) if res = 2;
    try(_: C, res) if res = 3;
    try(_: A, res) if res = 1;
    """
    polar.load_str(rules)

    assert qvar("new A().a() = x", "x", one=True) == "A"
    assert qvar("new A().x() = x", "x", one=True) == "A"
    assert qvar("new B().a() = x", "x", one=True) == "A"
    assert qvar("new B().b() = x", "x", one=True) == "B"
    assert qvar("new B().x() = x", "x", one=True) == "B"
    assert qvar("new C().a() = x", "x", one=True) == "A"
    assert qvar("new C().b() = x", "x", one=True) == "B"
    assert qvar("new C().c() = x", "x", one=True) == "C"
    assert qvar("new C().x() = x", "x", one=True) == "C"
    assert qvar("new X().x() = x", "x", one=True) == "X"

    assert len(query("test(new A())")) == 1
    assert len(query("test(new B())")) == 2

    assert qvar("try(new A(), x)", "x") == [1]
    assert qvar("try(new B(), x)", "x") == [2, 1]
    assert qvar("try(new C(), x)", "x") == [3, 2, 1]
    assert qvar("try(new X(), x)", "x") == []
Exemple #6
0
def test_class_specializers(polar, qvar, qeval, query):
    class A:
        def a(self):
            return "A"

        def x(self):
            return "A"

    class B(A):
        def b(self):
            return "B"

        def x(self):
            return "B"

    class C(B):
        def c(self):
            return "C"

        def x(self):
            return "C"

    class X:
        def x(self):
            return "X"

    polar.register_class(A)
    polar.register_class(B)
    polar.register_class(C)
    polar.register_class(X)

    rules = """
    test(_: A{});
    test(_: B{});

    try(_: B{}, res) if res = 2;
    try(_: C{}, res) if res = 3;
    try(_: A{}, res) if res = 1;
    """
    polar.load_str(rules)

    assert qvar("new A{}.a = x", "x", one=True) == "A"
    assert qvar("new A{}.x = x", "x", one=True) == "A"
    assert qvar("new B{}.a = x", "x", one=True) == "A"
    assert qvar("new B{}.b = x", "x", one=True) == "B"
    assert qvar("new B{}.x = x", "x", one=True) == "B"
    assert qvar("new C{}.a = x", "x", one=True) == "A"
    assert qvar("new C{}.b = x", "x", one=True) == "B"
    assert qvar("new C{}.c = x", "x", one=True) == "C"
    assert qvar("new C{}.x = x", "x", one=True) == "C"
    assert qvar("new X{}.x = x", "x", one=True) == "X"

    assert len(query("test(new A{})")) == 1
    assert len(query("test(new B{})")) == 2

    assert qvar("try(new A{}, x)", "x") == [1]
    assert qvar("try(new B{}, x)", "x") == [2, 1]
    assert qvar("try(new C{}, x)", "x") == [3, 2, 1]
    assert qvar("try(new X{}, x)", "x") == []
Exemple #7
0
def test_data_conversions(polar, qvar, query):
    polar.load_str('a(1);b("two");c(true);d([1,"two",true]);')
    assert qvar("a(x)", "x", one=True) == 1
    assert qvar("b(x)", "x", one=True) == "two"
    assert qvar("c(x)", "x", one=True)
    assert qvar("d(x)", "x", one=True) == [1, "two", True]
    y = qvar("x = y", "x", one=True)
    assert str(y) == "Variable('y')"
    assert repr(y) == "Variable('y')"
Exemple #8
0
def test_parser_errors(polar):
    # IntegerOverflow
    rules = """
    f(a) if a = 18446744073709551616;
    """
    with pytest.raises(exceptions.IntegerOverflow) as e:
        polar.load_str(rules)
    assert (
        str(e.value) ==
        "'18446744073709551616' caused an integer overflow at line 2, column 17"
    )

    # InvalidTokenCharacter
    rules = """
    f(a) if a = "this is not
    allowed";
    """
    with pytest.raises(exceptions.InvalidTokenCharacter) as e:
        polar.load_str(rules)
    assert (
        str(e.value) ==
        "'\\n' is not a valid character. Found in this is not at line 2, column 29"
    )

    rules = """
    f(a) if a = "this is not allowed\0
    """

    with pytest.raises(exceptions.InvalidTokenCharacter) as e:
        polar.load_str(rules)
    assert (
        str(e.value) ==
        "'\\u{0}' is not a valid character. Found in this is not allowed at line 2, column 17"
    )

    # InvalidToken -- not sure what causes this

    # UnrecognizedEOF
    rules = """
    f(a)
    """
    with pytest.raises(exceptions.UnrecognizedEOF) as e:
        polar.load_str(rules)
    assert (
        str(e.value) ==
        "hit the end of the file unexpectedly. Did you forget a semi-colon at line 2, column 9"
    )

    # UnrecognizedToken
    rules = """
    1;
    """
    with pytest.raises(exceptions.UnrecognizedToken) as e:
        polar.load_str(rules)
    assert str(
        e.value) == "did not expect to find the token '1' at line 2, column 5"
Exemple #9
0
def test_clear_rules(polar, query):
    class Test:
        pass

    polar.register_class(Test)
    polar.load_str("f(x) if x = 1;")
    assert len(query("f(1)")) == 1
    assert len(query("x = new Test()")) == 1
    polar.clear_rules()
    assert len(query("f(1)")) == 0
    assert len(query("x = new Test()")) == 1
Exemple #10
0
def test_unbound_variable(polar, query):
    """Test that unbound variable is returned."""
    polar.load_str("rule(x, y) if y = 1;")

    first = query("rule(x, y)")[0]

    # y will be bound to 1
    first["y"] = 1

    # x should be unbound
    assert isinstance(first["x"], Variable)
Exemple #11
0
def test_return_list(polar, query):
    class User:
        def groups(self):
            return ["engineering", "social", "admin"]

    polar.register_class(User)

    # for testing lists
    polar.load_str('allow(actor: User, "join", "party") if "social" in actor.groups();')

    assert query(Predicate(name="allow", args=[User(), "join", "party"]))
Exemple #12
0
def test_static_method(polar, qeval):
    class Foo(list):
        @staticmethod
        def plus_one(x):
            return x + 1

        def map(self, f):
            return [f(x) for x in self]

    polar.register_class(Foo)
    polar.load_str("f(x: Foo) if x.map(Foo.plus_one) = [2, 3, 4];")
    assert next(polar.query_rule("f", Foo([1, 2, 3])))
Exemple #13
0
def test_datetime(polar, query):
    # test datetime comparison
    t1 = datetime(2020, 5, 25)
    t2 = datetime.now()
    t3 = datetime(2030, 5, 25)
    t4 = datetime(2020, 5, 26)

    polar.load_str("lt(a, b) if a < b;")
    assert query(Predicate("lt", [t1, t2]))
    assert not query(Predicate("lt", [t2, t1]))

    # test creating datetime from polar
    polar.load_str("dt(x) if x = new Datetime(year: 2020, month: 5, day: 25);")
    assert query(Predicate("dt", [Variable("x")])) == [{
        "x":
        datetime(2020, 5, 25)
    }]
    polar.load_str("ltnow(x) if x < Datetime.now();")
    assert query(Predicate("ltnow", [t1]))
    assert not query(Predicate("ltnow", [t3]))

    polar.load_str(
        "timedelta(a: Datetime, b: Datetime) if a.__sub__(b) == new Timedelta(days: 1);"
    )
    assert query(Predicate("timedelta", [t4, t1]))
Exemple #14
0
def test_unify(polar, qeval):
    class Foo:
        def __init__(self, foo):
            self.foo = foo

        def __eq__(self, other):
            if isinstance(other, Foo):
                return self.foo == other.foo
            return False

    polar.register_class(Foo)

    polar.load_str("foo() if new Foo(foo: 1) = new Foo(foo: 1);")
    assert qeval("foo()")
Exemple #15
0
def test_runtime_errors(polar, query):
    rules = """
    foo(a,b) if a in b;
    """
    polar.load_str(rules)
    with pytest.raises(exceptions.PolarRuntimeException) as e:
        query("foo(1,2)")
    assert (str(e.value) == """trace (most recent evaluation last):
  in query at line 1, column 1
    foo(1,2)
  in rule foo at line 2, column 17
    a in b
Type error: can only use `in` on a list, this is Variable(Symbol("_a_3")) at line 2, column 17"""
            )
Exemple #16
0
def test_class_field_specializers(polar, qvar, qeval, query):
    class Animal:
        def __init__(self, species=None, genus=None, family=None):
            self.genus = genus
            self.species = species
            self.family = family

    polar.register_class(Animal)

    rules = """
    what_is(_: Animal, res) if res = "animal";
    what_is(_: Animal{genus: "canis"}, res) if res = "canine";
    what_is(_: Animal{family: "canidae"}, res) if res = "canid";
    what_is(_: Animal{species: "canis lupus", genus: "canis"}, res) if res = "wolf";
    what_is(_: Animal{species: "canis familiaris", genus: "canis"}, res) if res = "dog";
    what_is(_: Animal{species: s, genus: "canis"}, res) if res = s;
    """
    polar.load_str(rules)

    wolf = 'new Animal(species: "canis lupus", genus: "canis", family: "canidae")'
    dog = 'new Animal(species: "canis familiaris", genus: "canis", family: "canidae")'
    canine = 'new Animal(genus: "canis", family: "canidae")'
    canid = 'new Animal(family: "canidae")'
    animal = "new Animal()"

    assert len(query(f"what_is({wolf}, res)")) == 5
    assert len(query(f"what_is({dog}, res)")) == 5
    assert len(query(f"what_is({canine}, res)")) == 4
    assert len(query(f"what_is({canid}, res)")) == 2
    assert len(query(f"what_is({animal}, res)")) == 1

    assert qvar(f"what_is({wolf}, res)", "res") == [
        "wolf",
        "canis lupus",
        "canine",
        "canid",
        "animal",
    ]
    assert qvar(f"what_is({dog}, res)", "res") == [
        "dog",
        "canis familiaris",
        "canine",
        "canid",
        "animal",
    ]
    assert qvar(f"what_is({canine}, res)",
                "res") == [None, "canine", "canid", "animal"]
    assert qvar(f"what_is({canid}, res)", "res") == ["canid", "animal"]
    assert qvar(f"what_is({animal}, res)", "res") == ["animal"]
Exemple #17
0
def test_return_none(polar, qeval):
    class Foo:
        def this_is_none(self):
            return None

    polar.register_class(Foo)
    polar.load_str("f(x) if x.this_is_none = 1;")
    assert not list(polar.query_rule("f", Foo()))

    polar.load_str("f(x) if x.this_is_none.bad_call = 1;")

    with pytest.raises(exceptions.PolarRuntimeException) as e:
        list(polar.query_rule("f", Foo()))
    assert str(e.value).find(
        "Application error: 'NoneType' object has no attribute 'bad_call'")
Exemple #18
0
def test_instance_cache(polar, qeval, query):
    class Counter:
        count = 0

        def __init__(self):
            self.__class__.count += 1

    polar.register_class(Counter)
    polar.load_str("f(c: Counter) if c.count > 0;")

    assert Counter.count == 0
    c = Counter()
    assert Counter.count == 1
    assert query(Predicate(name="f", args=[c]))
    assert Counter.count == 1
    assert c not in polar.host.instances.values()
Exemple #19
0
def test_runtime_errors(polar, query):
    rules = """
    foo(a,b) if a in b;
    """
    polar.load_str(rules)
    with pytest.raises(exceptions.PolarRuntimeError) as e:
        query("foo(1,2)")
    assert (
        str(e.value)
        == """trace (most recent evaluation last):
  in query at line 1, column 1
    foo(1,2)
  in rule foo at line 2, column 17
    a in b
Type error: can only use `in` on an iterable value, this is Number(Integer(2)) at line 1, column 7"""
    )
Exemple #20
0
def test_partial(polar):
    polar.load_str("f(1);")
    polar.load_str("f(x) if x = 1 and x = 2;")

    results = polar.query_rule("f", Partial("x"))
    first = next(results)

    x = first["bindings"]["x"]
    assert unwrap_and(x) == Expression("Unify", [Variable("_this"), 1])

    second = next(results)
    x = second["bindings"]["x"]

    # Top level should be and
    and_args = unwrap_and(x)
    assert and_args[0] == Expression("Unify", [Variable("_this"), 1])

    polar.load_str("g(x) if x.bar = 1 and x.baz = 2;")

    results = polar.query_rule("g", Partial("x"))
    first = next(results)

    x = first["bindings"]["x"]
    and_args = unwrap_and(x)
    assert len(and_args) == 2
    assert unwrap_and(and_args[0]) == Expression(
        "Unify", [Expression("Dot", [Variable("_this"), "bar"]), 1]
    )
    assert unwrap_and(and_args[1]) == Expression(
        "Unify", [Expression("Dot", [Variable("_this"), "baz"]), 2]
    )
Exemple #21
0
def test_external_op(polar, query):
    class A:
        def __init__(self, a):
            self.a = a

        def __gt__(self, other):
            return self.a > other.a

        def __lt__(self, other):
            return self.a < other.a

        def __eq__(self, other):
            return self.a == other.a

    polar.register_class(A)

    a1 = A(1)
    a2 = A(2)

    polar.load_str("lt(a, b) if a < b;")
    polar.load_str("gt(a, b) if a > b;")
    assert query(Predicate("lt", [a1, a2]))
    assert not query(Predicate("lt", [a2, a1]))
    assert query(Predicate("gt", [a2, a1]))
Exemple #22
0
def test_specializers_mixed(polar, qvar, qeval, query):
    class Animal:
        def __init__(self, species=None, genus=None, family=None):
            self.genus = genus
            self.species = species
            self.family = family

    polar.register_class(Animal)

    # load rules
    rules = """
    what_is(_: Animal, res) if res = "animal_class";
    what_is(_: Animal{genus: "canis"}, res) if res = "canine_class";
    what_is(_: {genus: "canis"}, res) if res = "canine_dict";
    what_is(_: Animal{family: "canidae"}, res) if res = "canid_class";
    what_is(_: {species: "canis lupus", genus: "canis"}, res) if res = "wolf_dict";
    what_is(_: {species: "canis familiaris", genus: "canis"}, res) if res = "dog_dict";
    what_is(_: Animal{species: "canis lupus", genus: "canis"}, res) if res = "wolf_class";
    what_is(_: Animal{species: "canis familiaris", genus: "canis"}, res) if res = "dog_class";
    """
    polar.load_str(rules)

    wolf = 'new Animal(species: "canis lupus", genus: "canis", family: "canidae")'
    dog = 'new Animal(species: "canis familiaris", genus: "canis", family: "canidae")'
    canine = 'new Animal(genus: "canis", family: "canidae")'

    wolf_dict = '{species: "canis lupus", genus: "canis", family: "canidae"}'
    dog_dict = '{species: "canis familiaris", genus: "canis", family: "canidae"}'
    canine_dict = '{genus: "canis", family: "canidae"}'

    # test number of results
    assert len(query(f"what_is({wolf}, res)")) == 6
    assert len(query(f"what_is({dog}, res)")) == 6
    assert len(query(f"what_is({canine}, res)")) == 4
    assert len(query(f"what_is({wolf_dict}, res)")) == 2
    assert len(query(f"what_is({dog_dict}, res)")) == 2
    assert len(query(f"what_is({canine_dict}, res)")) == 1

    # test rule ordering for instances
    assert qvar(f"what_is({wolf}, res)", "res") == [
        "wolf_class",
        "canine_class",
        "canid_class",
        "animal_class",
        "wolf_dict",
        "canine_dict",
    ]
    assert qvar(f"what_is({dog}, res)", "res") == [
        "dog_class",
        "canine_class",
        "canid_class",
        "animal_class",
        "dog_dict",
        "canine_dict",
    ]
    assert qvar(f"what_is({canine}, res)", "res") == [
        "canine_class",
        "canid_class",
        "animal_class",
        "canine_dict",
    ]

    # test rule ordering for dicts
    assert qvar(f"what_is({wolf_dict}, res)",
                "res") == ["wolf_dict", "canine_dict"]
    assert qvar(f"what_is({dog_dict}, res)",
                "res") == ["dog_dict", "canine_dict"]
    assert qvar(f"what_is({canine_dict}, res)", "res") == ["canine_dict"]
Exemple #23
0
def test_nil(polar, query, qvar):
    """Test that nil is pre-registered as None."""
    polar.load_str("null(nil);")
    assert qvar("null(x)", "x") == [None]
    assert query(Predicate("null", [None])) == [{}]
    assert not query(Predicate("null", [[]]))
Exemple #24
0
def test_in(polar, qeval):
    polar.load_str("g(x, y) if not x in y;")
    polar.load_str("f(x) if not (x=1 or x=2);")
    assert not qeval("f(1)")
    assert qeval("g(4, [1,2,3])")
    assert not qeval("g(1, [1,1,1])")
Exemple #25
0
def test_predicate(polar, qvar, query):
    """Test that predicates can be converted to and from python."""
    polar.load_str("f(x) if x = pred(1, 2);")
    assert qvar("f(x)", "x") == [Predicate("pred", [1, 2])]

    assert query(Predicate(name="f", args=[Predicate("pred", [1, 2])])) == [{}]