Fixed #131 : Implement ExprToConditions

Fixed #130 : ArithmeticOperatorParser
Fixed #129 : python_wrapper : create_namespace
Fixed #128 : ExpressionParser: Cannot parse func(x) infixed concept 'xxx'
This commit is contained in:
2021-10-13 16:06:57 +02:00
parent a61a1c0d2b
commit 89e1f20975
76 changed files with 5867 additions and 3206 deletions
@@ -0,0 +1,500 @@
import ast
from dataclasses import dataclass
import pytest
from core.builtin_concepts_ids import BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules
from core.sheerka.services.SheerkaExecute import ParserInput
from core.sheerka.services.SheerkaRuleManager import CompiledCondition
from evaluators.PythonEvaluator import PythonEvaluator
from parsers.BaseParser import ErrorSink
from parsers.ExpressionParser import ExpressionParser
from parsers.PythonParser import PythonNode
from sheerkapython.ExprToConditions import ExprToConditionsVisitor
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.core.test_SheerkaRuleManager import PYTHON_EVALUATOR_NAME
@dataclass
class Obj:
value: object
def __eq__(self, other):
return isinstance(other, Obj) and self.value == other.value
def __hash__(self):
return hash(self.value)
cmap = {
"one": Concept("one", body="1"),
"two": Concept("two", body="2"),
"three": Concept("three", body="3"),
"twenties": Concept("twenties", definition="'twenty' (one|two)=unit", body="20 + unit").def_var("unit"),
"equals": Concept("x equals y", pre="is_question()", body="x == y").def_var("x").def_var("y"),
"isa1": Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
"isa2": Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
"isan1": Concept("x is an y", pre="is_question()", body="isa(x , y)").def_var("x").def_var("y"),
"isan2": Concept("x is an y", body="set_isa(x, y)").def_var("x").def_var("y"),
"foo": Concept("foo"),
"bar": Concept("bar"),
"baz": Concept("baz"),
}
class TestExprToConditionsVisitor(TestUsingMemoryBasedSheerka):
shared_ontology = None
@classmethod
def setup_class(cls):
instance = cls()
init_test_helper = instance.init_test(cache_only=False, ontology="#TestExprToConditionsVisitor#")
sheerka, context, *updated = init_test_helper.with_concepts(*cmap.values(), create_new=True).unpack()
for i, concept_name in enumerate(cmap):
cmap[concept_name] = updated[i]
global_context = instance.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_context, cmap["baz"], cmap["foo"])
cls.shared_ontology = sheerka.get_ontology(context)
sheerka.pop_ontology(context)
def initialize_test(self, concepts_map=None):
if concepts_map is None:
sheerka, context = self.init_test().unpack()
sheerka.add_ontology(context, self.shared_ontology)
else:
sheerka, context, *updated = super().init_test().with_concepts(*concepts_map.values(),
create_new=True).unpack()
for i, concept_name in enumerate(concepts_map):
concepts_map[concept_name] = updated[i]
return sheerka, context
@staticmethod
def evaluate_conditions(context, conditions, namespace):
with context.push(BuiltinConcepts.EXEC_CODE, None) as sub_context:
sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
sub_context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
sub_context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
sub_context.deactivate_push()
evaluation_service = sub_context.sheerka.services[SheerkaEvaluateRules.NAME]
return evaluation_service.evaluate_conditions(sub_context, conditions, namespace)
@staticmethod
def get_conditions_from_expression(context, expression, parser=None):
parser = parser or ExpressionParser(old_style=False)
error_sink = ErrorSink()
parser_input = ParserInput(expression)
parser.reset_parser_input(parser_input, error_sink)
parsed = parser.parse_input(context, parser_input, error_sink)
assert not error_sink.has_error
known_variables = parser.known_variables if hasattr(parser, "known_variables") else None
visitor = ExprToConditionsVisitor(context, known_variables=known_variables)
conditions = visitor.get_conditions(parsed)
return conditions
@staticmethod
def validate_condition(context, expression, condition, e_code, e_objects, e_variables, e_not_variables):
sheerka = context.sheerka
# check what was compiled
if e_code is None:
# manage cases where we only check for variable existence
assert condition.evaluator_type is None
assert condition.return_value is None
else:
ast_ = ast.parse(e_code, "<source>", 'exec' if "\n" in e_code else 'eval')
expected_python_node = PythonNode(e_code, ast_, expression)
assert condition.evaluator_type == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(condition.return_value, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(condition.return_value) == expected_python_node
# check the objects
if e_objects is not None:
resolved_objects = {k: v.id for k, v in condition.objects.items()}
resolved_expected_objects = {k: cmap[v].id for k, v in e_objects.items()}
assert resolved_objects == resolved_expected_objects
# check that variables detected
if e_variables is not None:
assert condition.variables == e_variables
if e_not_variables is not None:
assert condition.not_variables == e_not_variables
def run_test_cases(self, context, conditions, test_suite):
sheerka = context.sheerka
for test_data in test_suite:
namespace, expected_value = test_data
for k, v in namespace.items():
if isinstance(v, str):
try:
namespace[k] = self.evaluate_from_source(context, v)
except:
pass
res = self.evaluate_conditions(context, conditions, namespace)
value = sheerka.objvalue(res[0].body) if res else False
assert value == expected_value
@staticmethod
def evaluate_condition(context, expression, condition, objects):
with context.push("Testing conditions SheerkaRuleManagerRulesCompilation", expression) as sub_context:
sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
sub_context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
sub_context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
sub_context.sheerka.add_many_to_short_term_memory(sub_context, objects)
evaluator = PythonEvaluator()
for c in condition.concepts_to_reset:
c.get_hints().is_evaluated = False
return evaluator.eval(sub_context, condition.return_value)
@pytest.mark.parametrize("expression, e_code, e_variables, e_not_variables, test_suite", [
("var", None, {"var"}, set(), [({"var": "value"}, True), ({}, False)]),
("True", "True", set(), set(), []),
("var.value", None, {"var.value"}, set(), []),
("not var", None, set(), {"var"}, [({"var": "value"}, False), ({}, True)]),
("not not var", None, {"var"}, set(), []),
("var and var2 and not var3", None, {"var", "var2"}, {"var3"}, []),
("var and var.value == 3", "var.value == 3", {"var"}, set(), [({"var": Obj(3)}, True)]),
("not v2 and v1.value == 3", "v1.value == 3", {"v1"}, {"v2"}, [({"v1": Obj(3)}, True), ({"v2": 0}, False)]),
("func(var)", "func(var)", {"var"}, set(), []),
("var in []", "var in []", {"var"}, set(), []),
("a + b", "a + b", {"a", "b"}, set(), []),
("foo x", "__o_00__", set(), set(), []), # foo is not a variable
("foo y", "evaluate_question(__o_00__, x=y)", {"y"}, set(), []), # foo is not a variable
("bar y", "call_concept(__o_00__, x=y)", {"y"}, set(), []), # bar is not a variable
])
def test_i_can_parse_and_manage_exists(self, expression, e_code, e_variables, e_not_variables, test_suite):
sheerka, context, foo, bar = self.init_test().with_concepts(
Concept("foo x", pre="is_question()").def_var("x"),
Concept("bar x").def_var("x"),
).unpack()
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 1
assert isinstance(conditions[0], CompiledCondition)
condition = conditions[0]
self.validate_condition(context, expression, condition, e_code, None, e_variables, e_not_variables)
self.run_test_cases(context, conditions, test_suite)
@pytest.mark.parametrize("expression, e_code, e_objects, e_variables, test_suite", [
# Concept
("1 equals 1", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, True)]),
("1 equals 2", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, False)]),
("one equals one", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, True)]),
("one equals two", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, False)]),
("one equals twenty one", "evaluate_question(__o_00__)", {"__o_00__": "equals"}, set(), [({}, False)]),
("self equals 1", "evaluate_question(__o_00__, x=self)", {"__o_00__": "equals"}, {"self"}, [
({"self": 1}, True),
({"self": 2}, False)]),
("x equals 1", "evaluate_question(__o_00__, x=x)", {"__o_00__": "equals"}, {"x"}, [
({"x": 1}, True),
({"x": 2}, False)]),
("one equals self", "evaluate_question(__o_00__, y=self)", {"__o_00__": "equals"}, {"self"}, [
({"self": "one"}, True),
({"self": "two"}, False)]),
("self equals twenty two", "evaluate_question(__o_00__, x=self)", {"__o_00__": "equals"}, {"self"}, [
({"self": "twenty two"}, True),
({"self": "two"}, False)]
),
("x equals 1 and y equals 2",
"evaluate_question(__o_00__, x=x) and evaluate_question(__o_01__, x=y)",
{"__o_00__": "equals", "__o_01__": "equals"},
{"x", "y"},
[({"x": 1, "y": 2}, True), ({"x": "0", "y": "0"}, False)]
),
("x equals y", "__o_00__", {"__o_00__": "equals"}, set(), []),
("func(self) equals twenty one",
"evaluate_question(__o_00__, x=func(self))",
{"__o_00__": "equals"},
{"self"},
[({"self": "twenty one", "func": lambda x: x}, True)]),
("func(self) equals twenty one + 1",
"evaluate_question(__o_01__, x=func(self), y=__o_00__ + 1)",
{"__o_01__": "equals", "__o_00__": "twenties"},
{"self"},
[({"self": "22", "func": lambda x: x}, True)]),
# equality
("a == 10", "a == 10", {}, {"a"}, [({"a": 10}, True), ({"a": 20}, False), ({}, False)]),
("__ret.status == True", "__ret.status == True", {}, {"__ret"}, []),
("self == sheerka", "is_sheerka(self)", {}, {"self"}, [
({"self": "sheerka"}, True),
({"self": "other"}, False),
]),
("self == BuiltinConcepts.TO_DICT", "self == BuiltinConcepts.TO_DICT", {}, {"self"}, [
({"self": "BuiltinConcepts.TO_DICT"}, True),
({"self": "other"}, False),
]),
# other Comparisons
("a + self > 10", "a + self > 10", {}, {"a", "self"}, [
({"a": 10, "self": 1}, True),
({"a": 10, "self": 0}, False),
]),
("10 < one + self", "10 < __o_00__ + self", {"__o_00__": "one"}, {"self"}, [
({"self": 10}, True),
({"self": 1}, False),
]),
("23 < twenty one + self", "23 < __o_00__ + self", {"__o_00__": "twenties"}, {"self"}, [
({"self": 10}, True),
({"self": 1}, False),
]),
("a equals b and c equals d",
"evaluate_question(__o_00__, x=a, y=b) and evaluate_question(__o_01__, x=c, y=d)",
{"__o_00__": "equals", "__o_01__": "equals"},
{"a", "b", "c", "d"},
[]),
# simple expressions
("True", "True", {}, set(), [({}, True)]),
("False", "False", {}, set(), [({}, False)]),
("10 + 5", "10 + 5", {}, set(), [({}, 15)]),
("a + self", "a + self", {}, {"a", "self"}, [({"a": 10, "self": 5}, 15)]),
("a + twenty one", "a + __o_00__", {"__o_00__": "twenties"}, {"a"}, [({"a": 10}, 31)]),
# functions
("isinstance('hello', str)", "isinstance('hello', str)", {}, set(), [({}, True)]),
("isinstance(a, str)", "isinstance(a, str)", {}, {"a"}, [({"a": "an_str"}, True), ({"a": 1}, False)]),
("f(BuiltinConcepts.TO_DICT)", "f(BuiltinConcepts.TO_DICT)", {}, set(), [({"f": lambda x: x}, "__TO_DICT")])
])
def test_i_can_parse(self, expression, e_code, e_objects, e_variables, test_suite):
sheerka, context = self.initialize_test()
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 1
assert isinstance(conditions[0], CompiledCondition)
condition = conditions[0]
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
self.run_test_cases(context, conditions, test_suite)
def test_i_can_force_variable(self):
sheerka, context = self.initialize_test()
parser = ExpressionParser(known_variables={"one"})
conditions = self.get_conditions_from_expression(context, "one < two", parser)
python_source = conditions[0].return_value.body.body.source
assert python_source == "one < __o_00__"
resolved_objects = {k: v.id for k, v in conditions[0].objects.items()}
resolved_expected_objects = {k: cmap[v].id for k, v in {"__o_00__": "two"}.items()}
assert resolved_objects == resolved_expected_objects
def test_i_can_parse_when_variables_are_missing(self):
sheerka, context = self.initialize_test()
expression = "x equals 1"
e_code = "evaluate_question(__o_00__, x=x)"
e_objects = {"__o_00__": "equals"}
e_variables = {"x"}
test_suite = [({}, False), ({"y": 1}, False)]
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 1
assert isinstance(conditions[0], CompiledCondition)
condition = conditions[0]
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
self.run_test_cases(context, conditions, test_suite)
def test_question_concept_is_chosen_other_non_question_concept(self):
sheerka, context = self.initialize_test()
expression = "a is an b"
e_code = "evaluate_question(__o_00__, x=a, y=b)"
e_objects = {"__o_00__": "isan1"}
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 1
assert isinstance(conditions[0], CompiledCondition)
condition = conditions[0]
self.validate_condition(context, expression, condition, e_code, e_objects, None, None)
def test_i_can_manage_when_multiple_concepts(self):
sheerka, context = self.initialize_test()
expression = "a is a b"
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 2
condition = conditions[0]
assert isinstance(condition, CompiledCondition)
e_code = "evaluate_question(__o_00__, x=a, y=b)"
e_objects = {"__o_00__": "isa1"}
e_variables = {"a", "b"}
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
condition = conditions[1]
assert isinstance(condition, CompiledCondition)
e_code = "evaluate_question(__o_01__, x=a, y=b)"
e_objects = {"__o_01__": "isa2"}
e_variables = {"a", "b"}
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
# testing
namespace = {"a": sheerka.new("foo"), "b": sheerka.new("bar")}
res = self.evaluate_conditions(context, conditions, namespace)
assert len(res) == 2
assert isinstance(res[0].value, bool) and not res[0].value
assert isinstance(res[1].value, bool) and not res[1].value
namespace = {"a": sheerka.new("foo"), "b": sheerka.new("foo")}
res = self.evaluate_conditions(context, conditions, namespace)
assert len(res) == 1
assert isinstance(res[0].value, bool) and res[0].value
namespace = {"a": sheerka.new("baz"), "b": sheerka.new("foo")}
res = self.evaluate_conditions(context, conditions, namespace)
assert len(res) == 1
assert isinstance(res[0].value, bool) and res[0].value
def test_i_can_manage_or_expressions(self):
sheerka, context = self.initialize_test()
expression = "isinstance(self, foo) or self is a bar"
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 3
condition = conditions[0]
assert isinstance(condition, CompiledCondition)
e_code = "isinstance(self, __o_00__)"
e_objects = {"__o_00__": "foo"}
e_variables = {"self"}
self.validate_condition(context, "isinstance(self, foo)", condition, e_code, e_objects, e_variables, None)
condition = conditions[1]
assert isinstance(condition, CompiledCondition)
e_code = "evaluate_question(__o_01__, x=self)"
e_objects = {"__o_01__": "isa1"}
e_variables = {"self"}
self.validate_condition(context, "self is a bar", condition, e_code, e_objects, e_variables, None)
condition = conditions[2]
assert isinstance(condition, CompiledCondition)
e_code = "evaluate_question(__o_02__, x=self)"
e_objects = {"__o_02__": "isa2"}
e_variables = {"self"}
self.validate_condition(context, "self is a bar", condition, e_code, e_objects, e_variables, None)
def test_i_can_manage_multiple_concepts_melt_with_and_expressions(self):
sheerka, context = self.initialize_test()
expression = "isinstance(self, foo) and self is a bar"
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 2
condition = conditions[0]
assert isinstance(condition, CompiledCondition)
e_code = "isinstance(self, __o_00__) and evaluate_question(__o_01__, x=self)"
e_objects = {"__o_00__": "foo", "__o_01__": "isa1"}
e_variables = {"self"}
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
condition = conditions[1]
assert isinstance(condition, CompiledCondition)
e_code = "isinstance(self, __o_00__) and evaluate_question(__o_02__, x=self)"
e_objects = {"__o_00__": "foo", "__o_02__": "isa2"}
e_variables = {"self"}
self.validate_condition(context, expression, condition, e_code, e_objects, e_variables, None)
@pytest.mark.parametrize("expression, expected", [
("self is a 'foo'", {"x is a y"}),
("set self is a 'foo'", set()),
])
def test_i_can_get_concept_to_reset(self, expression, expected):
"""
When compiled conditions, sometimes there are concepts to reset between two usages
:param expression:
:param expected:
:return:
"""
concepts_map = {
"isa": Concept("x is a y", pre="is_question()").def_var("x").def_var("y"),
"set_isa": Concept("set x is a y").def_var("x").def_var("y"),
}
sheerka, context = self.initialize_test(concepts_map)
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 1
assert {c.name for c in conditions[0].concepts_to_reset} == expected
def test_i_can_reset_concepts_when_multiple_levels(self):
"""
When compiled conditions, sometimes there are concepts to reset between two usages
:return:
"""
sheerka, context, is_instance, is_int, is_integer = self.init_concepts(
Concept("x is an instance of y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("x is a int", pre="is_question()", body="x is an instance of int").def_var("x"),
Concept("x is an integer", pre="is_question()", body="x is a int").def_var("x"),
)
expression = "self is an integer"
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 1
assert {c.name for c in conditions[0].concepts_to_reset} == {"x is an instance of y",
"x is a int",
"x is an integer"}
# So I can evaluate multiple times
res = self.evaluate_condition(context, expression, conditions[0], {'self': 10})
assert res.status
assert sheerka.objvalue(res.body)
res = self.evaluate_condition(context, expression, conditions[0], {'self': "string"})
assert res.status
assert not sheerka.objvalue(res.body)
def test_i_can_reset_concepts_when_multiple_levels_and_concept_node(self):
"""
When compiled conditions, sometimes there are concepts to reset between two usages
:return:
"""
# in this example, x + 2 is an int won't be parsed as an ExactNodeConcept, but as a ConceptNode
sheerka, context, is_int, is_integer = self.init_concepts(
Concept("x is a int", pre="is_question()", body="isinstance(x, int)").def_var("x"),
Concept("x is an integer", pre="is_question()", body="x + 2 is a int").def_var("x"),
create_new=True
)
expression = "self is an integer"
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 1
assert set(c.name for c in conditions[0].concepts_to_reset) == {"x is a int",
"x is an integer"}
# So I can evaluate multiple times
res = self.evaluate_condition(context, expression, conditions[0], {'self': 10})
assert res.status
assert sheerka.objvalue(res.body)
res = self.evaluate_condition(context, expression, conditions[0], {'self': "string"})
assert not res.status
def test_long_name_concepts_are_not_considered_as_variables(self):
sheerka, context, one, number = self.init_concepts(
"one",
"all numbers",
)
sheerka.set_isa(context, one, number)
expression = "all numbers < 5"
conditions = self.get_conditions_from_expression(context, expression)
assert len(conditions) == 1
assert conditions[0].return_value.body.body.source == '__o_00__ < 5'
@@ -1,23 +1,23 @@
import pytest
from core.builtin_concepts_ids import BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.SheerkaEvaluateConcept import EvaluationHints
from core.concept import Concept, DEFINITION_TYPE_DEF
from core.sheerka.services.SheerkaExecute import ParserInput
from evaluators.PythonEvaluator import PythonEvaluator
from parsers.BaseParser import ErrorSink
from parsers.ExpressionParser import ExpressionParser
from parsers.FunctionParser import FunctionParser
from parsers.ListComprehensionParser import ListComprehensionParser
from parsers.PythonParser import PythonNode
from sheerkapython.ExprToPython import PythonExprVisitor
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestExprToPython(TestUsingMemoryBasedSheerka):
class TestPythonExprVisitor(TestUsingMemoryBasedSheerka):
@staticmethod
def get_expr_node(context, expression, parser=None):
parser = parser or ExpressionParser()
parser = parser or ExpressionParser(old_style=False)
error_sink = ErrorSink()
parser_input = ParserInput(expression)
parser.reset_parser_input(parser_input, error_sink)
@@ -37,6 +37,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
context.add_to_short_term_memory(k, v)
res = evaluator.eval(context, return_value)
assert res.status
return res.body
@@ -49,25 +50,63 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
("foo a or bar b",
"call_concept(__o_00__, x=a) or call_concept(__o_01__, y=b)",
{"__o_00__": "foo", "__o_01__": "bar"}),
("not foo w", "not call_concept(__o_00__, x=w)", {"__o_00__": "foo"}),
("not foo w", "not (call_concept(__o_00__, x=w))", {"__o_00__": "foo"}),
("foo a >= bar b",
"call_concept(__o_00__, x=a) >= call_concept(__o_01__, y=b)",
{"__o_00__": "foo", "__o_01__": "bar"}),
("function(foo a, bar b)",
"function(call_concept(__o_00__, x=a), call_concept(__o_01__, y=b))",
{"__o_00__": "foo", "__o_01__": "bar"})
{"__o_00__": "foo", "__o_01__": "bar"}),
("set_isa(one, number)", "set_isa(__o_00__, __o_01__)", {"__o_00__": "one", "__o_01__": "number"}),
("set_isa(twenty two, number)", "set_isa(__o_00__, __o_01__)", {"__o_00__": "twenties", "__o_01__": "number"}),
("foo and twenty one", "__o_00__ and __o_01__", {"__o_00__": "foo", "__o_01__": "twenties"}),
("func(z) is a 'foo'", "call_concept(__o_00__, x=func(z))", {"__o_00__": "isa"}),
("isinstance('hello', str)", "isinstance('hello', str)", {}),
("not (a and b)", "not (a and b)", {}),
("twenty one is a number", "__o_00__", {"__o_00__": "isa"}),
("x is a number", "call_concept(__o_00__, x=x)", {"__o_00__": "isa"}),
("y is a number", "call_concept(__o_00__, x=y)", {"__o_00__": "isa"}),
("number is a x", "call_concept(__o_00__, y=x)", {"__o_00__": "isa"}),
("number is a y", "call_concept(__o_00__, y=y)", {"__o_00__": "isa"}),
("x is a y", "__o_00__", {"__o_00__": "isa"}),
("foo x + 1", "call_concept(__o_00__, x=x + 1)", {"__o_00__": "foo"}),
("twenty two + 3", "__o_00__ + 3", {"__o_00__": "twenties"}),
("twenty two * 2 - 1", "__o_00__ * 2 - 1", {"__o_00__": "twenties"}),
("x * bar a + 2", "x * call_concept(__o_00__, y=a + 2)", {"__o_00__": "bar"}),
("foo x * bar a + 2",
"call_concept(__o_01__, x=x * call_concept(__o_00__, y=a + 2))",
{"__o_00__": "bar", "__o_01__": "foo"}),
("(foo y) * (bar a) + 2",
"call_concept(__o_00__, x=y) * call_concept(__o_01__, y=a) + 2",
{"__o_00__": "foo", "__o_01__": "bar"}),
("func([one, two])", "func([__o_00__, __o_01__])", {"__o_00__": "one", "__o_01__": "two"}),
("func([twenty one, two])", "func([__o_00__, __o_01__])", {"__o_00__": "twenties", "__o_01__": "two"}),
("func((twenty one, two))", "func((__o_00__, __o_01__))", {"__o_00__": "twenties", "__o_01__": "two"}),
("func({twenty one, two})", "func({__o_00__, __o_01__})", {"__o_00__": "twenties", "__o_01__": "two"}),
("foo twenty one + self",
"call_concept(__o_01__, x=__o_00__ + self)",
{"__o_01__": "foo", "__o_00__": "twenties"}),
])
def test_i_can_compile_concept_when_is_question_is_false(self, expression, source, objects):
sheerka, context, foo, bar = self.init_test().with_concepts(
Concept("foo x", body="x").def_var("x"),
sheerka, context, foo, bar, isa, one, two, twenties, number = self.init_test().with_concepts(
Concept("foo", definition="foo x", definition_type=DEFINITION_TYPE_DEF, body="x").def_var("x"),
Concept("bar y", body="y").def_var("y"),
Concept("x is a y").def_var("x").def_var("y"),
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenties", definition="'twenty' (one|two)=unit").def_var("unit"),
Concept("number"),
create_new=True
).unpack()
concepts = {
"foo": foo,
"bar": bar
"bar": bar,
"isa": isa,
"one": one,
"two": two,
"twenties": twenties,
"number": number
}
node = self.get_expr_node(context, expression)
@@ -80,6 +119,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
assert python_node.original_source == expression
assert python_node.source == source
assert len(objects) == len(python_node.objects)
for obj_name, obj_value in objects.items():
assert obj_name in python_node.objects
@@ -87,7 +127,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
if isinstance(obj, Concept):
assert sheerka.isinstance(obj, concepts[obj_value])
assert obj.get_hints().use_copy
assert obj.get_hints().is_evaluated
# assert obj.get_hints().is_evaluated
else:
assert False
@@ -106,8 +146,9 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
}
node = self.get_expr_node(context, expression)
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
visitor = PythonExprVisitor(context)
ret = visitor.compile(node, EvaluationHints(eval_body=True, eval_question=True))
ret = visitor.compile(node)
assert len(ret) == 1
python_node = ret[0].body.body
@@ -125,6 +166,61 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
else:
assert False
@pytest.mark.parametrize("expression, expected", [
("foo w", [
("call_concept(__o_00__, x=w)", {"__o_00__": "foo1"}),
("call_concept(__o_01__, y=w)", {"__o_01__": "foo2"})
]),
("foo z + 2", [
("call_concept(__o_00__, x=z + 2)", {"__o_00__": "foo1"}),
("call_concept(__o_01__, y=z + 2)", {"__o_01__": "foo2"}),
]),
("foo bar a + 2", [
("call_concept(__o_00__, x=call_concept(__o_01__, x=a + 2))", {"__o_00__": "foo1", "__o_01__": "bar1"}),
("call_concept(__o_02__, y=call_concept(__o_03__, x=a + 2))", {"__o_02__": "foo2", "__o_03__": "bar1"}),
("call_concept(__o_04__, y=call_concept(__o_05__, y=a + 2))", {"__o_04__": "foo2", "__o_05__": "bar2"}),
("call_concept(__o_06__, x=call_concept(__o_07__, y=a + 2))", {"__o_06__": "foo1", "__o_07__": "bar2"}),
]),
])
def test_i_can_compile_when_multiple_concept_are_possible(self, expression, expected):
sheerka, context, foo1, foo2, bar1, bar2, = self.init_test().with_concepts(
Concept("foo x", body="x").def_var("x"),
Concept("foo y", body="y").def_var("y"),
Concept("bar x", body="x").def_var("x"),
Concept("bar y", body="y").def_var("y"),
create_new=True
).unpack()
concepts = {
"foo1": foo1,
"foo2": foo2,
"bar1": bar1,
"bar2": bar2
}
node = self.get_expr_node(context, expression)
visitor = PythonExprVisitor(context)
ret = visitor.compile(node)
assert len(ret) == len(expected)
for ret, (source, objects) in zip(ret, expected):
python_node = ret.body.body
assert python_node.original_source == expression
assert python_node.source == source
for obj_name, obj_value in objects.items():
assert obj_name in python_node.objects
obj = python_node.objects[obj_name]
if isinstance(obj, Concept):
assert sheerka.isinstance(obj, concepts[obj_value])
assert obj.get_hints().use_copy
assert obj.get_hints().is_evaluated
else:
assert False
def test_i_can_compile_simple_list_comprehension(self):
sheerka, context = self.init_test().unpack()
@@ -193,6 +289,39 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
assert self.eval(context, ret[0]) == ["a", "b"]
def test_i_can_compile_list_comprehension_when_element_is_a_concept_using_bnf(self):
sheerka, context, one, two, twenties, foo = self.init_test().with_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenties", definition="'twenty' (one|two)=unit").def_var("unit"),
Concept("foo x y", body="{x, y}").def_var("x").def_var("y"),
create_new=True,
).unpack()
expression = "[ foo x twenty one for x in ['a', 'b'] ]"
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
visitor = PythonExprVisitor(context)
ret = visitor.compile(node)
assert len(ret) == 1
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
assert isinstance(ret[0].body.body, PythonNode)
python_node = ret[0].body.body
assert python_node.original_source == expression
assert python_node.source == "[ call_concept(__o_00__, x=x) for x in ['a', 'b'] ]"
assert "__o_00__" in python_node.objects
concept = python_node.objects["__o_00__"]
assert sheerka.isinstance(concept, foo)
assert concept.get_hints().use_copy
assert concept.get_hints().is_evaluated
twenty_one = self.evaluate_from_source(context, "twenty one")
assert self.eval(context, ret[0]) == [{"a", twenty_one}, {"b", twenty_one}]
def test_i_can_compile_list_comprehension_when_concept_with_complex_parameter(self):
sheerka, context, foo = self.init_test().with_concepts(
Concept("foo x", body="x").def_var("x"),
@@ -242,19 +371,56 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
python_node = ret[0].body.body
assert python_node.original_source == expression
assert python_node.source == "[ call_concept(__o_00__, x=x) for x in call_concept(__o_01__) ]"
assert python_node.source == "[ call_concept(__o_01__, x=x) for x in __o_00__ ]"
assert "__o_00__" in python_node.objects
assert "__o_01__" in python_node.objects
concept0 = python_node.objects["__o_00__"]
concept0 = python_node.objects["__o_01__"]
assert sheerka.isinstance(concept0, foo)
assert concept0.get_hints().use_copy
assert concept0.get_hints().is_evaluated
concept1 = python_node.objects["__o_01__"]
concept1 = python_node.objects["__o_00__"]
assert sheerka.isinstance(concept1, "colors")
assert set(self.eval(context, ret[0])) == {red, blue}
def test_i_can_compile_list_comprehension_when_target_is_the_name_of_a_concept_concept(self):
sheerka, context, red, blue, color, foo = self.init_test().with_concepts(
"red",
"blue",
"color",
Concept("foo x", body="x").def_var("x")
).unpack()
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, red, color)
sheerka.set_isa(global_truth_context, blue, color)
expression = "[ foo color for color in colors ]"
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
visitor = PythonExprVisitor(context)
ret = visitor.compile(node)
assert len(ret) == 1
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
assert isinstance(ret[0].body.body, PythonNode)
python_node = ret[0].body.body
assert python_node.original_source == expression
assert python_node.source == "[ call_concept(__o_01__, x=color) for color in __o_00__ ]"
assert "__o_00__" in python_node.objects
assert "__o_01__" in python_node.objects
concept0 = python_node.objects["__o_01__"]
assert sheerka.isinstance(concept0, foo)
assert concept0.get_hints().use_copy
assert concept0.get_hints().is_evaluated
concept1 = python_node.objects["__o_00__"]
assert sheerka.isinstance(concept1, "colors")
assert concept1.get_hints().use_copy
assert concept1.get_hints().is_evaluated
assert set(self.eval(context, ret[0])) == {red, blue}
@@ -264,7 +430,8 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
"blue",
"color",
Concept("foo x", body="x").def_var("x"),
Concept("x starts with y", body="x.name.startswith(y)", pre="is_question()").def_var("x").def_var("y")
Concept("x starts with y", body="x.name.startswith(y)", pre="is_question()").def_var("x").def_var("y"),
create_new=True
).unpack()
global_truth_context = self.get_context(sheerka, global_truth=True)
sheerka.set_isa(global_truth_context, red, color)
@@ -284,7 +451,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
python_node = ret[0].body.body
assert python_node.original_source == expression
assert python_node.source == "[ call_concept(__o_00__, x=x) for x in call_concept(__o_01__) if evaluate_question(__o_02__, x=x, y='b') ]"
assert python_node.source == "[ call_concept(__o_02__, x=x) for x in __o_00__ if evaluate_question(__o_01__, x=x) ]"
assert "__o_00__" in python_node.objects
assert "__o_01__" in python_node.objects
assert "__o_02__" in python_node.objects
@@ -312,15 +479,15 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
assert len(ret) == 8
python_node = ret[0].body.body
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
assert python_node.source == '[ call_concept(__o_00__, x=a) for a in call_concept(__o_02__) if evaluate_question(__o_04__, x=a) ]'
assert object_to_compare == {"__o_00__": "foo x", "__o_02__": "colors", "__o_04__": "bar x"}
assert python_node.source == '[ call_concept(__o_04__, x=a) for a in __o_00__ if evaluate_question(__o_02__, x=a) ]'
assert object_to_compare == {"__o_04__": "foo x", "__o_00__": "colors", "__o_02__": "bar x"}
# ...
python_node = ret[7].body.body
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
assert python_node.source == '[ call_concept(__o_01__, y=a) for a in call_concept(__o_03__) if evaluate_question(__o_05__, y=a) ]'
assert object_to_compare == {"__o_01__": "foo y", "__o_03__": "colors", "__o_05__": "bar y"}
assert python_node.source == '[ call_concept(__o_05__, y=a) for a in __o_01__ if evaluate_question(__o_03__, y=a) ]'
assert object_to_compare == {"__o_05__": "foo y", "__o_01__": "colors", "__o_03__": "bar y"}
def test_i_can_compile_list_comprehension_when_missing_concept_parameter(self):
sheerka, context, foo = self.init_test().with_concepts(
@@ -339,7 +506,7 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
assert python_node.source == "[ call_concept(__o_00__, x=x, y=k) for x in ['a', 'b'] ]"
assert object_to_compare == {"__o_00__": "foo x y"}
def test_i_can_compile_simple_list_comprehension_when_multiple_for(self):
def test_i_can_compile_list_comprehension_when_multiple_for(self):
sheerka, context = self.init_test().unpack()
expression = "[ (x, y) for x in ['a', 'b'] if x == 'a' for y in ['c', 'd'] if y == 'c' ]"
@@ -359,7 +526,66 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
assert self.eval(context, ret[0]) == [("a", "c")]
def test_i_can_compile_and_when_multiple_results(self):
def test_i_can_compile_list_comprehension_when_element_is_missing_its_parenthesis(self):
sheerka, context, foo = self.init_test().with_concepts(
Concept("foo x", body="x").def_var("x")
).unpack()
expression = "[ w, foo w for w in ['a', 'b'] ]"
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
visitor = PythonExprVisitor(context)
ret = visitor.compile(node)
assert len(ret) == 1
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
assert isinstance(ret[0].body.body, PythonNode)
python_node = ret[0].body.body
assert python_node.original_source == expression
assert python_node.source == "[ (w, call_concept(__o_00__, x=w)) for w in ['a', 'b'] ]"
assert "__o_00__" in python_node.objects
concept = python_node.objects["__o_00__"]
assert sheerka.isinstance(concept, foo)
assert concept.get_hints().use_copy
assert concept.get_hints().is_evaluated
assert self.eval(context, ret[0]) == [("a", "a"), ("b", "b")]
def test_i_can_compile_list_comprehension_when_multiple_targets(self):
sheerka, context, foo = self.init_test().with_concepts(
Concept("foo x y", body="(x, y)").def_var("x").def_var("y")
).unpack()
items = {"one": 1, "two": 2}
sheerka.add_to_short_term_memory(None, "items", items)
expression = "[ foo x y for x, y in items.items() ]"
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
visitor = PythonExprVisitor(context)
ret = visitor.compile(node)
assert len(ret) == 1
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
assert isinstance(ret[0].body.body, PythonNode)
python_node = ret[0].body.body
assert python_node.original_source == expression
assert python_node.source == "[ call_concept(__o_00__, x=x, y=y) for x, y in items.items() ]"
assert "__o_00__" in python_node.objects
concept0 = python_node.objects["__o_00__"]
assert sheerka.isinstance(concept0, foo)
assert concept0.get_hints().use_copy
assert concept0.get_hints().is_evaluated
assert self.eval(context, ret[0]) == [("one", 1), ("two", 2)]
def test_i_can_compile_when_multiple_results(self):
sheerka, context, foo, foo2, bar, bar2 = self.init_test().with_concepts(
Concept("foo x", body="x").def_var("x"),
Concept("foo y", body="y").def_var("y"),
@@ -393,30 +619,118 @@ class TestExprToPython(TestUsingMemoryBasedSheerka):
assert python_node.source == 'call_concept(__o_01__, y=a) and call_concept(__o_03__, y=b)'
assert object_to_compare == {"__o_01__": "foo y", "__o_03__": "bar y"}
def test_i_can_compile_when_element_is_missing_its_parenthesis(self):
sheerka, context, foo = self.init_test().with_concepts(
Concept("foo x", body="x").def_var("x")
def test_i_can_compile_function_of_function(self):
sheerka, context, one, two = self.init_test().with_concepts(
Concept("one"),
Concept("two"),
).unpack()
expression = "[ w, foo w for w in ['a', 'b'] ]"
node = self.get_expr_node(context, expression, parser=ListComprehensionParser())
expression = "func(func1(func2(one, two)), 'foo')"
node = self.get_expr_node(context, expression)
visitor = PythonExprVisitor(context)
ret = visitor.compile(node)
assert len(ret) == 1
assert sheerka.isinstance(ret[0], BuiltinConcepts.RETURN_VALUE)
assert sheerka.isinstance(ret[0].body, BuiltinConcepts.PARSER_RESULT)
assert isinstance(ret[0].body.body, PythonNode)
python_node = ret[0].body.body
assert python_node.original_source == expression
assert python_node.source == "[ (w, call_concept(__o_00__, x=w)) for w in ['a', 'b'] ]"
assert "__o_00__" in python_node.objects
assert python_node.source == "func(func1(func2(__o_00__, __o_01__)), 'foo')"
concept = python_node.objects["__o_00__"]
assert sheerka.isinstance(concept, foo)
assert concept.get_hints().use_copy
assert concept.get_hints().is_evaluated
def test_i_can_compile_function_when_keyword_parameters(self):
sheerka, context, foo = self.init_test().with_concepts(
Concept("foo x", body="x").def_var("x")).unpack()
assert self.eval(context, ret[0]) == [("a", "a"), ("b", "b")]
def func(**kwargs):
# Uncomment to test that PythonEvalutor tests until success
# if not isinstance(kwargs["y"], str):
# raise Exception()
return kwargs
sheerka.add_to_short_term_memory(None, "func", func)
expression = "func(x=5, y=foo 'a')"
node = self.get_expr_node(context, expression)
visitor = PythonExprVisitor(context)
ret = visitor.compile(node)
assert len(ret) == 1
python_node = ret[0].body.body
assert python_node.original_source == expression
assert python_node.source == "func(x=5, y=__o_00__)"
assert python_node.objects["__o_00__"].name == "foo x"
res = self.eval(context, ret[0])
assert res["x"] == 5
assert sheerka.isinstance(res["y"], foo)
assert res["y"].body == "a"
def test_i_can_compile_function_when_keyword_parameters_and_multiple_results(self):
sheerka, context, foo, foo2, bar, bar2 = self.init_test().with_concepts(
Concept("foo x", body="x").def_var("x"),
Concept("foo y", body="y").def_var("y"),
Concept("bar x", body="x").def_var("x"),
Concept("bar y", body="y").def_var("y"),
create_new=True
).unpack()
def func(**kwargs):
return kwargs
sheerka.add_to_short_term_memory(None, "func", func)
expression = "func(foo 'a', y=bar 'b')"
node = self.get_expr_node(context, expression)
visitor = PythonExprVisitor(context)
ret = visitor.compile(node)
assert len(ret) == 4
python_node = ret[0].body.body
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
assert python_node.source == "func(__o_00__, y=__o_02__)"
assert object_to_compare == {"__o_00__": "foo x", "__o_02__": "bar x"}
# ...
python_node = ret[3].body.body
object_to_compare = {k: v.name for k, v in python_node.objects.items()}
assert python_node.source == "func(__o_01__, y=__o_03__)"
assert object_to_compare == {"__o_01__": "foo y", "__o_03__": "bar y"}
def test_i_can_compile_sequence_with_function_call(self):
sheerka, context, foo, bar = self.init_test().with_concepts(
Concept("foo x", body="f'x={x}'").def_var("x"),
Concept("x bar", body="x").def_var("x"),
create_new=True
).unpack()
def func(x):
return x + 1
sheerka.add_to_short_term_memory(None, "func", func)
expression = "foo func(self)"
node = self.get_expr_node(context, expression, parser=FunctionParser(strict=False))
visitor = PythonExprVisitor(context)
ret = visitor.compile(node)
assert len(ret) == 1
python_node = ret[0].body.body
assert python_node.original_source == expression
assert python_node.source == "call_concept(__o_00__, x=func(self))"
assert python_node.objects["__o_00__"].name == "foo x"
assert self.eval(context, ret[0], {"self": 1}) == "x=2"
def test_i_cannot_compile_function_when_invalid_keyword_parameters(self):
sheerka, context = self.init_test().unpack()
expression = "func(x=5=2)"
node = self.get_expr_node(context, expression)
visitor = PythonExprVisitor(context)
with pytest.raises(SyntaxError):
visitor.compile(node)
+49 -2
View File
@@ -1,12 +1,13 @@
import pytest
from core.builtin_concepts_ids import BuiltinConcepts
from core.builtin_helpers import ensure_asts
from core.concept import Concept
from core.global_symbols import SyaAssociativity
from core.sheerka.ExecutionContext import ExecutionContext
from core.sheerka.services.SheerkaAdmin import SheerkaAdmin
from sheerkapython.python_wrapper import Expando, create_namespace, inject_context, get_sheerka_method, Pipe, \
MethodAccessError
from sheerkapython.python_wrapper import Expando, MethodAccessError, Pipe, create_namespace, get_sheerka_method, \
get_variables_from_concept_asts, inject_context
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -135,6 +136,27 @@ class TestPythonWrapper(TestUsingMemoryBasedSheerka):
res = create_namespace(context, "TestPythonWrapper", ["foo"], None, objects, False)
assert res == {"foo": objects["foo"]}
def test_external_value_takes_precedence_over_concept_parameter(self):
"""
To manage :
Concept("x is a y").def_var("x").def_var("y"),
"y is a number" -> "call_concept(__o_00__, x=y)"
If 'y' is not given, it will use the concept parameter 'y'
But if y is given (as a short term memory) it must be prioritized
:return:
"""
sheerka, context = self.init_test().unpack()
obj = Concept("x is a y").def_var("x").def_var("y", "concept value").auto_init()
context.obj = obj
objects = {"y": "object value"}
res = create_namespace(context, "TestPythonWrapper", ["y"], None, objects, False)
assert res == {'y': 'concept value'}
context.add_to_short_term_memory("y", "stm value")
res = create_namespace(context, "TestPythonWrapper", ["y"], None, objects, False)
assert res == {'y': 'stm value'}
def test_i_can_get_sheerka_method(self):
context = self.get_context()
@@ -167,3 +189,28 @@ class TestPythonWrapper(TestUsingMemoryBasedSheerka):
res = get_sheerka_method(context, "TestPythonWrapper", "where", True)
assert isinstance(res, Pipe)
@pytest.mark.parametrize("concept, known_variables, expected", [
(Concept("foo").def_var("x", "True"), set(), {}),
(Concept("foo").def_var("x"), set(), {}),
(Concept("foo").def_var("x", "self"), set(), {"x": {"self"}}),
(Concept("foo").def_var("x", "self + a"), set(), {"x": {"self", "a"}}),
(Concept("foo").def_var("x", "self + a").def_var("y", "b"), set(), {'x': {'a', 'self'}, 'y': {'b'}}),
(Concept("foo", body="x").def_var("x"), set(), {}), # 'x' is a concept var, so it can be resolved
(Concept("foo", body="x").def_var("x", "x"), set(), {'x': {'x'}}),
(Concept("foo").def_var("x", "func(y)"), set(), {"x": {"y"}}),
(Concept("foo").def_var("x", "x"), set(), {'x': {'x'}}),
(Concept("foo").def_var("x", "y"), set(), {'x': {'y'}}),
(Concept("foo").def_var("x", "x"), {"x"}, {"x": {"x"}}),
(Concept("foo").def_var("x"), {"x"}, {}), # var x has no value, there no way to link the two 'x's
(Concept("foo", body="x").def_var("x"), {"x"}, {"#body#": {"x"}}),
(Concept("foo").def_var("x", "bar"), set(), {}),
(Concept("foo").def_var("x", "bar"), {"bar"}, {"x": {"bar"}}),
])
def test_get_variables_from_concept_asts(self, concept, known_variables, expected):
sheerka, context, foo, bar = self.init_concepts(concept, "bar")
ensure_asts(context, concept)
variables = get_variables_from_concept_asts(context, concept, known_variables, parameters_only=False)
assert variables == expected