Refactored Concept class for better separation of metadata, compiled and values

This commit is contained in:
2020-01-17 17:27:54 +01:00
parent 3789ef25d1
commit a7b239c167
27 changed files with 614 additions and 349 deletions
+63 -62
View File
@@ -5,7 +5,7 @@ import shutil
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept, ConceptAlreadyInSet, \
ParserResultConcept
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property, ConceptParts, DoNotResolve
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property, ConceptParts, DoNotResolve, simplec
from core.sheerka import Sheerka, ExecutionContext
from parsers.PythonParser import PythonNode
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event
@@ -49,8 +49,8 @@ def get_default_concept():
post="isinstance(res, int)",
body="def func(x,y):\n return x+y\nfunc(a,b)",
desc="specific description")
concept.set_prop("a", "value1")
concept.set_prop("b", "value2")
concept.def_prop("a", "value1")
concept.def_prop("b", "value2")
return concept
@@ -238,7 +238,7 @@ def test_i_can_get_the_correct_concept_using_the_id_when_same_key_when_no_cache(
result = sheerka.get(concept1.key, res2.body.body.id)
assert result.name == "a + b"
assert result.body == "a+b"
assert result.metadata.body == "a+b"
def test_i_can_get_the_correct_concept_using_the_id__when_same_key_when_cache():
@@ -254,7 +254,7 @@ def test_i_can_get_the_correct_concept_using_the_id__when_same_key_when_cache():
result = sheerka.get(concept1.key, res2.body.body.id)
assert result.name == "a + b"
assert result.body == "a+b"
assert result.metadata.body == "a+b"
def test_i_cannot_get_the_correct_concept_id_the_id_is_wrong():
@@ -283,11 +283,12 @@ def test_i_cannot_get_when_key_is_none():
def test_unknown_concept_is_return_when_the_concept_is_not_found():
sheerka = get_sheerka()
loaded = sheerka.get("fake_key")
loaded = sheerka.get("concept_that_does_not_exist")
assert loaded is not None
assert sheerka.isinstance(loaded, BuiltinConcepts.UNKNOWN_CONCEPT)
assert loaded.body == "fake_key"
assert loaded.body == "concept_that_does_not_exist"
assert loaded.metadata.is_evaluated
def test_i_can_instantiate_a_builtin_concept_when_it_has_its_own_class():
@@ -335,10 +336,10 @@ def test_i_can_instantiate_with_the_name_and_the_id():
assert len(concepts) == 2
foo1 = sheerka.new(("foo", "1001"))
assert foo1.body == "foo1"
assert foo1.metadata.body == "foo1"
foo2 = sheerka.new(("foo", "1002"))
assert foo2.body == "foo2"
assert foo2.metadata.body == "foo2"
def test_instances_are_different_when_asking_for_new():
@@ -403,7 +404,7 @@ def test_concept_id_is_irrelevant_when_only_one_concept():
new = sheerka.new(("foo", "invalid_id"))
assert sheerka.isinstance(new, "foo")
assert new.body == "foo1"
assert new.metadata.body == "foo1"
def test_i_cannot_instantiate_when_properties_are_not_recognized():
@@ -439,6 +440,12 @@ def test_i_cannot_instantiate_when_properties_are_not_recognized():
def test_i_can_get_value(concept, reduce_simple_list, expected):
sheerka = get_sheerka()
# I use auto_init() instead of evaluate_concept() to be quicker
c = concept
while isinstance(c, Concept):
c.auto_init()
c = c.body
assert sheerka.value(concept, reduce_simple_list) == expected
@@ -462,16 +469,18 @@ def test_list_of_concept_is_sorted_by_id():
def test_i_can_evaluate_a_concept_with_simple_body(body, expected):
sheerka = get_sheerka()
concept = Concept("foo", body=body).init_key()
concept = Concept("foo", body=body)
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body == expected
assert evaluated.metadata.body == body
assert evaluated.metadata.pre is None
assert evaluated.metadata.post is None
assert evaluated.metadata.where is None
assert evaluated.props == {}
assert evaluated.metadata.is_evaluated
assert len(evaluated.values) == 0 if body is None else 1
@pytest.mark.parametrize("expr, expected", [
@@ -493,20 +502,22 @@ def test_i_can_evaluate_the_other_metadata(expr, expected):
sheerka = get_sheerka()
concept = Concept("foo", where=expr).init_key()
concept = Concept("foo", where=expr)
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body is None
assert evaluated.metadata.body is None
assert evaluated.metadata.pre is None
assert evaluated.metadata.post is None
assert evaluated.metadata.where == expected
assert evaluated.metadata.where == expr
assert evaluated.get_metadata_value(ConceptParts.WHERE) == expected
assert evaluated.props == {}
assert evaluated.metadata.is_evaluated
assert len(evaluated.values) == 0 if expr is None else 1
@pytest.mark.parametrize("expr, expected", [
# (None, None),
(None, None),
("", ""),
("1", 1),
("1+1", 2),
@@ -518,11 +529,11 @@ def test_i_can_evaluate_the_other_metadata(expr, expected):
def test_i_can_evaluate_a_concept_with_prop(expr, expected):
sheerka = get_sheerka()
concept = Concept("foo").set_prop("a", expr).init_key()
concept = Concept("foo").def_prop("a", expr)
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body is None
assert evaluated.metadata.pre is None
assert evaluated.metadata.pre is None
assert evaluated.metadata.post is None
assert evaluated.metadata.where is None
@@ -533,7 +544,7 @@ def test_i_can_evaluate_a_concept_with_prop(expr, expected):
def test_i_can_evaluate_metadata_using_do_not_resolve():
sheerka = get_sheerka()
concept = Concept("foo")
concept.cached_asts[ConceptParts.BODY] = DoNotResolve("do not resolve")
concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
@@ -543,8 +554,8 @@ def test_i_can_evaluate_metadata_using_do_not_resolve():
def test_i_can_evaluate_property_using_do_not_resolve():
sheerka = get_sheerka()
concept = Concept("foo").set_prop("a")
concept.cached_asts["a"] = DoNotResolve("do not resolve")
concept = Concept("foo").def_prop("a")
concept.compiled["a"] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
@@ -555,8 +566,8 @@ def test_i_can_evaluate_property_using_do_not_resolve():
def test_original_value_is_overridden_when_using_do_no_resolve():
sheerka = get_sheerka()
concept = Concept("foo", body="original value").set_prop("a", "original value")
concept.cached_asts["a"] = DoNotResolve("do not resolve")
concept.cached_asts[ConceptParts.BODY] = DoNotResolve("do not resolve")
concept.compiled["a"] = DoNotResolve("do not resolve")
concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
@@ -568,7 +579,7 @@ def test_original_value_is_overridden_when_using_do_no_resolve():
def test_props_are_evaluated_before_body():
sheerka = get_sheerka()
concept = Concept("foo", body="a+1").set_prop("a", "10").init_key()
concept = Concept("foo", body="a+1").def_prop("a", "10").init_key()
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
@@ -583,8 +594,7 @@ def test_i_can_evaluate_when_another_concept_is_referenced():
concept = Concept("foo", body="a").init_key()
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert sheerka.isinstance(evaluated.body, concept_a)
assert evaluated == simplec("foo", simplec("a", None))
assert id(evaluated.body) != id(concept_a)
assert evaluated.metadata.is_evaluated
assert evaluated.body.metadata.is_evaluated
@@ -595,11 +605,11 @@ def test_i_can_evaluate_when_the_referenced_concept_has_a_body():
concept_a = Concept("a", body="1")
sheerka.add_in_cache(concept_a)
concept = Concept("foo", body="a").init_key()
concept = Concept("foo", body="a")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body == Concept("a", body=1).init_key()
assert evaluated.body == simplec("a", 1)
assert not concept_a.metadata.is_evaluated
assert evaluated.metadata.is_evaluated
@@ -614,13 +624,8 @@ def test_i_can_evaluate_concept_of_concept_when_the_leaf_has_a_body():
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept_d)
assert evaluated.key == concept_d.key
assert evaluated.body == Concept(
name="c",
body=Concept(
name="b",
body=Concept(
name="a",
body="a").init_key()).init_key()).init_key()
expected = simplec("c", simplec("b", simplec("a", "a")))
assert evaluated.body == expected
assert sheerka.value(evaluated) == 'a'
assert evaluated.metadata.is_evaluated
@@ -635,12 +640,8 @@ def test_i_can_evaluate_concept_of_concept_does_not_have_a_body():
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept_d)
assert evaluated.key == concept_d.key
assert evaluated.body == Concept(
name="c",
body=Concept(
name="b",
body=Concept(
name="a").init_key()).init_key()).init_key()
expected = simplec("c", simplec("b", simplec("a", None)))
assert evaluated.body == expected
assert sheerka.value(evaluated) == Concept(name="a").init_key()
assert evaluated.metadata.is_evaluated
@@ -649,7 +650,7 @@ def test_i_can_evaluate_concept_when_properties_reference_others_concepts():
sheerka = get_sheerka()
concept_a = sheerka.add_in_cache(Concept(name="a").init_key())
concept = Concept("foo", body="a").set_prop("a", "a").init_key()
concept = Concept("foo", body="a").def_prop("a", "a").init_key()
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
# first prop a is evaluated to concept_a
@@ -667,7 +668,7 @@ def test_i_can_evaluate_concept_when_properties_reference_others_concepts_2():
sheerka = get_sheerka()
concept_a = sheerka.add_in_cache(Concept(name="a"))
concept = Concept("foo", body="concept_a").set_prop("concept_a", "a")
concept = Concept("foo", body="concept_a").def_prop("concept_a", "a")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
@@ -679,7 +680,7 @@ def test_i_can_evaluate_concept_when_properties_reference_others_concepts_with_b
sheerka.add_in_cache(Concept(name="a", body="1"))
sheerka.add_in_cache(Concept(name="b", body="2"))
concept = Concept("foo", body="propA + propB").set_prop("propA", "a").set_prop("propB", "b")
concept = Concept("foo", body="propA + propB").def_prop("propA", "a").def_prop("propB", "b")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
@@ -690,24 +691,25 @@ def test_i_can_evaluate_concept_when_properties_is_a_concept():
sheerka = get_sheerka()
concept_a = sheerka.add_in_cache(Concept(name="a", body="'a'").init_key())
concept = Concept("foo").set_prop("a", concept_a)
concept = Concept("foo").def_prop("a")
concept.compiled["a"] = concept_a
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.get_prop("a") == Concept(name="a", body="a").init_key()
assert evaluated.get_prop("a") == simplec("a", "a")
def test_i_can_evaluate_when_property_asts_is_a_list():
sheerka = get_sheerka()
foo = Concept("foo", body="1")
concept = Concept("to_eval").set_prop("prop")
concept.cached_asts["prop"] = [foo, DoNotResolve("1")]
concept = Concept("to_eval").def_prop("prop")
concept.compiled["prop"] = [foo, DoNotResolve("1")]
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
props = evaluated.get_prop("prop")
assert len(props) == 2
assert props[0] == Concept("foo", body=1).init_key()
assert props[0] == simplec("foo", 1)
assert props[1] == "1"
@@ -717,14 +719,14 @@ def test_i_can_evaluate_when_compiled_is_set_up_with_return_value():
python_node = PythonNode("1 +1 ")
parser_result = ParserResultConcept(parser="who", value=python_node)
concept = Concept("to_eval").set_prop("prop")
concept.cached_asts["prop"] = [ReturnValueConcept("who", True, parser_result)]
concept = Concept("to_eval").def_prop("prop")
concept.compiled["prop"] = [ReturnValueConcept("who", True, parser_result)]
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.get_prop("prop") == 2
# also works when only one return value
concept = Concept("to_eval").set_prop("prop")
concept.cached_asts["prop"] = ReturnValueConcept("who", True, parser_result)
concept = Concept("to_eval").def_prop("prop")
concept.compiled["prop"] = ReturnValueConcept("who", True, parser_result)
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.get_prop("prop") == 2
@@ -747,19 +749,19 @@ def test_properties_values_takes_precedence_over_the_outside_world():
concept = Concept("foo", body="a")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body == Concept(name="a", body="concept_a").init_key() # this test was already done
assert evaluated.body == simplec("a", "concept_a") # this test was already done
# so check this one.
concept = Concept("foo", body="a").set_prop("a", "'property_a'")
concept = Concept("foo", body="a").def_prop("a", "'property_a'")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body == 'property_a'
# or this one.
concept = Concept("foo", body="a").set_prop("a", "b")
concept = Concept("foo", body="a").def_prop("a", "b")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body == Concept(name="b", body="concept_b").init_key()
assert evaluated.body == simplec(name="b", body="concept_b")
def test_properties_values_takes_precedence():
@@ -767,7 +769,7 @@ def test_properties_values_takes_precedence():
sheerka.add_in_cache(Concept(name="a", body="'concept_a'"))
sheerka.add_in_cache(Concept(name="b", body="'concept_b'"))
concept = Concept("foo", body="a + b").set_prop("a", "'prop_a'")
concept = Concept("foo", body="a + b").def_prop("a", "'prop_a'")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body == 'prop_aconcept_b'
@@ -775,18 +777,17 @@ def test_properties_values_takes_precedence():
def test_i_can_reference_sub_property_of_a_property():
sheerka = get_sheerka()
sheerka.add_in_cache(Concept(name="concept_a").set_prop("subProp", "'sub_a'"))
sheerka.add_in_cache(Concept(name="concept_a").def_prop("subProp", "'sub_a'"))
concept = Concept("foo", body="a.props['subProp'].value").set_prop("a", "concept_a")
concept = Concept("foo", body="a.props['subProp'].value").def_prop("a", "concept_a")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body == 'sub_a'
assert evaluated == simplec(concept.key, "sub_a")
def test_i_cannot_evaluate_concept_if_property_is_in_error():
sheerka = get_sheerka()
concept = Concept(name="concept_a").set_prop("subProp", "undef_concept")
concept = Concept(name="concept_a").def_prop("subProp", "undef_concept")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)