ExactConceptParser can now recognize concepts by their names

This commit is contained in:
2020-05-21 16:27:18 +02:00
parent d357329f51
commit 37d3d16e21
17 changed files with 347 additions and 112 deletions
+16
View File
@@ -470,3 +470,19 @@ def remove_from_ret_val(sheerka, return_values, concept_key):
return_values.remove(item)
return return_values
def set_is_evaluated(concepts):
"""
set is_evaluated to True
:param concepts:
:return:
"""
if concepts is None:
return
if hasattr(concepts, "__iter__"):
for c in concepts:
c.metadata.is_evaluated = True
else:
concepts.metadata.is_evaluated = True
+56 -4
View File
@@ -115,10 +115,7 @@ class Concept:
if isinstance(other, simplec):
return self.name == other.name and self.body == other.body
if isinstance(other, CC):
return other == self
if isinstance(other, CB):
if isinstance(other, (CC, CB, CMV)):
return other == self
if not isinstance(other, Concept):
@@ -601,5 +598,60 @@ class CB:
def __hash__(self):
return hash((self.concept, self.body))
def __repr__(self):
return f"CB({self.body})"
class CMV:
"""
Concept with metadata variables
CMV stands for Concept Metadata Variables
Test class that only compare the key and the metadata variables
"""
def __init__(self, concept, **kwargs):
self.concept_key = concept.key if isinstance(concept, Concept) else concept
self.concept = concept if isinstance(concept, Concept) else None
self.variables = kwargs
def __eq__(self, other):
if id(self) == id(other):
return True
if isinstance(other, Concept):
if other.key != self.concept_key:
return False
if len(other.metadata.variables) != len(self.variables):
return False
for name, value in other.metadata.variables:
if self.variables[name] != value:
return False
return True
if not isinstance(other, CMV):
return False
if self.concept_key != other.concept_key:
return False
return self.variables == other.variables
def __hash__(self):
if self.concept:
return hash(self.concept)
return hash(self.concept_key)
def __repr__(self):
if self.concept:
txt = f"CMV(concept='{self.concept}'"
else:
txt = f"CMV(concept_key='{self.concept_key}'"
for k, v in self.variables.items():
txt += f", {k}='{v}'"
return txt + ")"
simplec = namedtuple("concept", "name body") # for simple concept (tests purposes only)
+22 -6
View File
@@ -491,8 +491,14 @@ class Sheerka(Concept):
return self._get_unknown(metadata)
def resolve(self, concept):
def new_instances(concepts):
if hasattr(concepts, "__iter__"):
return [self.new_from_template(c, c.key) for c in concepts]
return self.new_from_template(concepts, concepts.key)
if concept is None:
return concept
return None
# if the entry is a concept token, use its values.
if isinstance(concept, Token):
@@ -500,24 +506,34 @@ class Sheerka(Concept):
return None
concept = concept.value
if isinstance(concept, str) and \
concept.startswith("c:") and \
(tmp := core.utils.unstr_concept(concept)) != (None, None):
concept = tmp
# if the entry is a tuple
# concept[0] is the name
# concept[1] is the id
if isinstance(concept, tuple):
if concept[1]:
if self.is_known(found := self.get_by_id(concept[1])):
return found
instance = self.new_from_template(found, found.key)
instance.metadata.is_evaluated = True
return instance
elif concept[0]:
return found if self.is_known(found := self.get_by_name(concept[0])) else None
if self.is_known(found := self.get_by_name(concept[0])):
instances = new_instances(found)
core.builtin_helpers.set_is_evaluated(instances)
return instances
else:
return None
# otherwise search in db
if isinstance(concept, str):
if self.is_known(found := self.get_by_id(concept)):
return found
if self.is_known(found := self.get_by_name(concept)):
return found
instances = new_instances(found)
core.builtin_helpers.set_is_evaluated(instances)
return instances
return None
@@ -2,6 +2,7 @@ from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import expect_one, only_successful
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved
from core.sheerka.services.sheerka_service import BaseService
from core.utils import unstr_concept
CONCEPT_EVALUATION_STEPS = [
BuiltinConcepts.BEFORE_EVALUATION,
@@ -14,7 +15,7 @@ class SheerkaEvaluateConcept(BaseService):
def __init__(self, sheerka):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self.evaluate_concept)
@@ -73,7 +74,6 @@ class SheerkaEvaluateConcept(BaseService):
Basically, it runs the parsers on all parts
:param concept:
:param context:
:param logger:
:return:
"""
@@ -82,6 +82,11 @@ class SheerkaEvaluateConcept(BaseService):
return context.sheerka.isinstance(r, BuiltinConcepts.RETURN_VALUE) and \
context.sheerka.isinstance(r.body, BuiltinConcepts.ONLY_SUCCESSFUL)
def parse_token_concept(s):
if s.startswith("c:") and (identifier := unstr_concept(s)) != (None, None):
return self.sheerka.resolve(identifier)
return None
steps = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
for part_key in ConceptParts:
if part_key in concept.compiled:
@@ -94,14 +99,19 @@ class SheerkaEvaluateConcept(BaseService):
if source.strip() == "":
concept.compiled[part_key] = DoNotResolve(source)
else:
with context.push(desc=f"Initializing *compiled* for {part_key}") as sub_context:
sub_context.add_inputs(source=source)
to_parse = self.sheerka.ret(context.who, True,
self.sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
res = self.sheerka.execute(sub_context, to_parse, steps)
only_success = only_successful(sub_context, res)
concept.compiled[part_key] = only_success.body.body if is_only_successful(only_success) else res
sub_context.add_values(return_values=res)
# first case, when the metadata references another concept via c:xxx: keyword
if concept_found := parse_token_concept(source):
context.log(f"Recognized concept '{concept_found}'", self.NAME)
concept.compiled[part_key] = concept_found
else:
with context.push(desc=f"Initializing *compiled* for {part_key}") as sub_context:
sub_context.add_inputs(source=source)
to_parse = self.sheerka.ret(context.who, True,
self.sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
res = self.sheerka.execute(sub_context, to_parse, steps)
only_success = only_successful(sub_context, res)
concept.compiled[part_key] = only_success.body.body if is_only_successful(only_success) else res
sub_context.add_values(return_values=res)
for var_name, default_value in concept.metadata.variables:
if var_name in concept.compiled:
@@ -113,14 +123,19 @@ class SheerkaEvaluateConcept(BaseService):
if default_value.strip() == "":
concept.compiled[var_name] = DoNotResolve(default_value)
else:
with context.push(desc=f"Initializing *compiled* for property {var_name}") as sub_context:
sub_context.add_inputs(source=default_value)
to_parse = self.sheerka.ret(context.who, True,
self.sheerka.new(BuiltinConcepts.USER_INPUT, body=default_value))
res = self.sheerka.execute(sub_context, to_parse, steps)
only_success = only_successful(sub_context, res)
concept.compiled[var_name] = only_success.body.body if is_only_successful(only_success) else res
sub_context.add_values(return_values=res)
# first case, when the metadata references another concept via c:xxx: keyword
if concept_found := parse_token_concept(default_value):
context.log(f"Recognized concept '{concept_found}'", self.NAME)
concept.compiled[var_name] = concept_found
else:
with context.push(desc=f"Initializing *compiled* for property {var_name}") as sub_context:
sub_context.add_inputs(source=default_value)
to_parse = self.sheerka.ret(context.who, True,
self.sheerka.new(BuiltinConcepts.USER_INPUT, body=default_value))
res = self.sheerka.execute(sub_context, to_parse, steps)
only_success = only_successful(sub_context, res)
concept.compiled[var_name] = only_success.body.body if is_only_successful(only_success) else res
sub_context.add_values(return_values=res)
# Updates the cache of concepts when possible
if self.sheerka.has_id(concept.id):
+8 -8
View File
@@ -288,7 +288,7 @@ def decode_enum(enum_repr: str):
return None
def str_concept(t, skip_key=None):
def str_concept(t, drop_name=None):
"""
The key,id identifiers of a concept are stored in a tuple
we want to return the key and the id, separated by a pipe
@@ -298,21 +298,21 @@ def str_concept(t, skip_key=None):
>>> assert str_concept((None, "id")) == "c:|id:"
>>> assert str_concept(("key", None)) == "c:key:"
>>> assert str_concept((None, None)) == ""
>>> assert str_concept(Concept(key="foo", id="bar")) == "c:foo|bar:"
>>> assert str_concept(Concept(key="foo", id="bar"), skip_key=True) == "c:|bar:"
>>> assert str_concept(Concept(name="foo", id="bar")) == "c:foo|bar:"
>>> assert str_concept(Concept(name="foo", id="bar"), drop_name=True) == "c:|bar:"
:param t:
:param skip_key: True if we only want the id (and not the key)
:param drop_name: True if we only want the id (and not the key)
:return:
"""
if isinstance(t, tuple):
key, id_ = t[0], t[1]
name, id_ = t[0], t[1]
else:
key, id_ = t.key, t.id
name, id_ = t.key, t.id
if key is None and id_ is None:
if name is None and id_ is None:
return ""
result = 'c:' if (key is None or skip_key) else "c:" + key
result = 'c:' if (name is None or drop_name) else "c:" + name
if id_:
result += "|" + id_
return result + ":"