import ast import pytest from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts from core.concept import VARIABLE_PREFIX, ConceptParts, Concept from core.sheerka import Sheerka, ExecutionContext from core.tokenizer import Tokenizer from evaluators.AddConceptEvaluator import AddConceptEvaluator from parsers.BaseParser import BaseParser from parsers.ConceptLexerParser import Sequence, StrMatch, ZeroOrMore, ConceptExpression from parsers.BnfParser import BnfParser from parsers.DefaultParser import DefConceptNode, NameNode from parsers.PythonParser import PythonNode, PythonParser from sdp.sheerkaDataProvider import Event def get_context(): sheerka = Sheerka(skip_builtins_in_db=True) sheerka.initialize("mem://") return ExecutionContext("test", Event(), sheerka) def get_def_concept(name, where=None, pre=None, post=None, body=None, definition=None): concept = DefConceptNode([], name=NameNode(list(Tokenizer(name)))) if body: concept.body = get_concept_part(body) if where: concept.where = get_concept_part(where) if pre: concept.pre = get_concept_part(pre) if post: concept.post = get_concept_part(post) if definition: concept.definition = definition return ReturnValueConcept(BaseParser.PREFIX + "some_name", True, ParserResultConcept(value=concept)) def get_concept_part(part): if isinstance(part, str): node = PythonNode(part, ast.parse(part, mode="eval")) return ReturnValueConcept( who="parsers.Default", status=True, value=ParserResultConcept( source=part, parser=PythonParser(), value=node)) if isinstance(part, PythonNode): return ReturnValueConcept( who="parsers.Default", status=True, value=ParserResultConcept( source=part.source, parser=PythonParser(), value=part)) if isinstance(part, ReturnValueConcept): return part def get_concept_definition(source, parsing_expression): return ReturnValueConcept( who="Parsers:RegexParser", status=True, value=ParserResultConcept( source=source, parser=BnfParser(), value=parsing_expression ) ) @pytest.mark.parametrize("ret_val, expected", [ (ReturnValueConcept(BaseParser.PREFIX + "some_name", True, ParserResultConcept(value=DefConceptNode([]))), True), (ReturnValueConcept(BaseParser.PREFIX + "some_name", False, ParserResultConcept(value=DefConceptNode([]))), False), (ReturnValueConcept(BaseParser.PREFIX + "some_name", True, "not a ParserResultConcept"), False), (ReturnValueConcept(BaseParser.PREFIX + "some_name", True, ParserResultConcept()), False), ]) def test_i_can_match(ret_val, expected): context = get_context() assert AddConceptEvaluator().matches(context, ret_val) == expected def test_that_the_source_is_correctly_set(): context = get_context() def_concept_return_value = get_def_concept( name="hello a", definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))), where="isinstance(a, str )", pre="a is not None", body="print('hello' + a)") evaluated = AddConceptEvaluator().eval(context, def_concept_return_value) assert evaluated.status assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT) created_concept = evaluated.body.body assert created_concept.metadata.name == "hello a" assert created_concept.metadata.where == "isinstance(a, str )" assert created_concept.metadata.pre == "a is not None" assert created_concept.metadata.post is None assert created_concept.metadata.body == "print('hello' + a)" assert created_concept.metadata.definition == "hello a" # def test_that_the_ast_is_correctly_initialized(): # """ # When I parse the definition of a concept, I evaluate the metadata (like the body) # I wanted to keep in cache these evaluation for further utilisation but I have # a serialization issue. # So I had to comment concept.add_codes(def_concept_node.get_asts()) around line 85 # So this test is now irrelevant # :return: # """ # context = get_context() # def_concept_return_value = get_concept( # name="hello a", # definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))), # where="isinstance(a, str )", # pre="a is not None", # body="print('hello' + a)") # # evaluated = AddConceptEvaluator().eval(context, def_concept_return_value) # # assert evaluated.status # assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT) # # created_concept = evaluated.body.body # # assert ConceptParts.WHERE in created_concept.compiled # assert ConceptParts.PRE in created_concept.compiled # assert ConceptParts.BODY in created_concept.compiled # assert ConceptParts.POST not in created_concept.compiled def test_that_the_new_concept_is_correctly_saved_in_db(): context = get_context() def_concept_return_value = get_def_concept( name="hello a", definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))), where="isinstance(a, str )", pre="a is not None", body="print('hello' + a)") # sanity. Make sure that the concept does not already exist from_db = context.sheerka.get("hello " + VARIABLE_PREFIX + "0") assert context.sheerka.isinstance(from_db, BuiltinConcepts.UNKNOWN_CONCEPT) AddConceptEvaluator().eval(context, def_concept_return_value) context.sheerka.concepts_cache = {} # reset cache from_db = context.sheerka.get("hello " + VARIABLE_PREFIX + "0") assert from_db.metadata.key == f"hello {VARIABLE_PREFIX}0" assert from_db.metadata.name == "hello a" assert from_db.metadata.where == "isinstance(a, str )" assert from_db.metadata.pre == "a is not None" assert from_db.metadata.post is None assert from_db.metadata.body == "print('hello' + a)" assert from_db.metadata.definition == "hello a" assert len(from_db.metadata.props) == 1 assert from_db.metadata.props[0] == ("a", None) assert "a" in from_db.props assert from_db.compiled == {} # ast is not saved in db def test_i_can_get_props_from_python_node(): ret_val = get_concept_part("isinstance(a, str)") context = get_context() assert AddConceptEvaluator.get_props(context.sheerka, ret_val, ["a"]) == ["a"] def test_i_can_get_props_from_another_concept(): concept = Concept("hello").def_prop("a").def_prop("b") ret_val = ReturnValueConcept(who="some_parser", status=True, value=ParserResultConcept(value=concept)) assert AddConceptEvaluator.get_props(get_context(), ret_val, []) == ["a", "b"] def test_i_can_get_props_from_definition(): parsing_expression = Sequence(ConceptExpression('mult'), ZeroOrMore(Sequence(StrMatch("+"), ConceptExpression("add")))) ret_val = get_concept_definition("mult (('+'|'-') add)?", parsing_expression) assert AddConceptEvaluator.get_props(get_context(), ret_val, []) == ["add", "mult"]