Logger is now an attribute of the execution context

This commit is contained in:
2020-02-18 16:31:55 +01:00
parent 86c2ff58d4
commit 87f232b527
27 changed files with 213 additions and 243 deletions
+7 -8
View File
@@ -32,13 +32,12 @@ def is_same_success(sheerka, return_values):
return True return True
def expect_one(context, return_values, logger=None): def expect_one(context, return_values):
""" """
Checks if there is at least one success return value Checks if there is at least one success return value
If there is more than one, check if it's the same value If there is more than one, check if it's the same value
:param context: :param context:
:param return_values: :param return_values:
:param logger:
:return: :return:
""" """
@@ -75,10 +74,10 @@ def expect_one(context, return_values, logger=None):
successful_results[0].value, successful_results[0].value,
parents=return_values) parents=return_values)
else: else:
if logger and logger.isEnabledFor(logging.DEBUG): if context.logger and context.logger.isEnabledFor(logging.DEBUG):
context.log(logger, f"Too many successful results found by expect_one()", context.who) context.log(f"Too many successful results found by expect_one()", context.who)
for s in successful_results: for s in successful_results:
context.log(logger, f"-> {s}", context.who) context.log(f"-> {s}", context.who)
return sheerka.ret( return sheerka.ret(
context.who, context.who,
False, False,
@@ -86,10 +85,10 @@ def expect_one(context, return_values, logger=None):
parents=return_values) parents=return_values)
# only errors, i cannot help you # only errors, i cannot help you
if logger and logger.isEnabledFor(logging.DEBUG): if context.logger and context.logger.isEnabledFor(logging.DEBUG):
context.log(logger, f"Too many errors found by expect_one()", context.who) context.log(f"Too many errors found by expect_one()", context.who)
for s in successful_results: for s in successful_results:
context.log(logger, f"-> {s}", context.who) context.log(f"-> {s}", context.who)
if len(return_values) == 1: if len(return_values) == 1:
return sheerka.ret( return sheerka.ret(
+33 -12
View File
@@ -3,8 +3,8 @@ import time
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept from core.concept import Concept
from core.sheerka_logger import get_logger
from sdp.sheerkaDataProvider import Event from sdp.sheerkaDataProvider import Event
from sheerkapickle.SheerkaPickler import SheerkaPickler
DEBUG_TAB_SIZE = 4 DEBUG_TAB_SIZE = 4
@@ -21,6 +21,8 @@ PROPERTIES_TO_SERIALIZE = ("_id",
"concepts") "concepts")
class ExecutionContext: class ExecutionContext:
""" """
To keep track of the execution of a request To keep track of the execution of a request
@@ -41,6 +43,7 @@ class ExecutionContext:
event: Event, event: Event,
sheerka, sheerka,
desc: str = None, desc: str = None,
logger=None,
**kwargs): **kwargs):
self._parent = None self._parent = None
@@ -56,6 +59,7 @@ class ExecutionContext:
self.desc = desc # human description of what is going on self.desc = desc # human description of what is going on
self.children = [] self.children = []
self.preprocess = None self.preprocess = None
self.logger = logger
self.inputs = {} # what was the parameters of the execution context self.inputs = {} # what was the parameters of the execution context
self.values = {} # what was produced by the execution context self.values = {} # what was produced by the execution context
@@ -66,6 +70,9 @@ class ExecutionContext:
for k, v in kwargs.items(): for k, v in kwargs.items():
self._bag[k] = v self._bag[k] = v
self.stat_log = get_logger("stats")
self.show_stats = False
@property @property
def elapsed(self): def elapsed(self):
if self._start == 0: if self._start == 0:
@@ -91,10 +98,13 @@ class ExecutionContext:
def __enter__(self): def __enter__(self):
self._start = time.time_ns() self._start = time.time_ns()
self.log_new()
return self return self
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):
self._stop = time.time_ns() self._stop = time.time_ns()
if self.show_stats:
self.stat_log.debug(f"[{self._id:2}]" + self._tab + "Execution time: " + self.elapsed_str)
def __repr__(self): def __repr__(self):
msg = f"ExecutionContext(who={self.who}, id={self._id}" msg = f"ExecutionContext(who={self.who}, id={self._id}"
@@ -103,6 +113,11 @@ class ExecutionContext:
msg += ")" msg += ")"
return msg return msg
def __str__(self):
msg = self.desc or "New Context"
msg += f", who={self.who}, id={self.id}"
return msg
def __eq__(self, other): def __eq__(self, other):
if id(self) == id(other): if id(self) == id(other):
return True return True
@@ -183,8 +198,9 @@ class ExecutionContext:
return self.sheerka.new(key, **kwargs) return self.sheerka.new(key, **kwargs)
def push(self, who=None, desc=None, **kwargs): def push(self, who=None, desc=None, logger=None, **kwargs):
who = who or self.who who = who or self.who
logger = logger or self.logger
_kwargs = {"obj": self.obj, "concepts": self.concepts} _kwargs = {"obj": self.obj, "concepts": self.concepts}
_kwargs.update(self._bag) _kwargs.update(self._bag)
_kwargs.update(kwargs) _kwargs.update(kwargs)
@@ -193,6 +209,7 @@ class ExecutionContext:
self.event, self.event,
self.sheerka, self.sheerka,
desc, desc,
logger,
**_kwargs, **_kwargs,
) )
new._parent = self new._parent = self
@@ -202,25 +219,29 @@ class ExecutionContext:
self.children.append(new) self.children.append(new)
return new return new
def log_new(self, logger): def log_new(self):
logger.debug(f"[{self._id:2}]" + self._tab + str(self)) if self.logger and not self.logger.disabled:
self.logger.debug(f"[{self._id:2}]" + self._tab + str(self))
self.show_stats = True
def log(self, logger, message, who=None): def log(self, message, who=None):
logger.debug(f"[{self._id:2}]" + self._tab + (f"[{who}] " if who else "") + str(message)) if self.logger and not self.logger.disabled:
self.logger.debug(f"[{self._id:2}]" + self._tab + (f"[{who}] " if who else "") + str(message))
def log_error(self, logger, message, who=None): def log_error(self, message, who=None):
logger.exception(f"[{self._id:2}]" + self._tab + (f"[{who}] " if who else "") + str(message)) if self.logger and not self.logger.disabled:
self.logger.exception(f"[{self._id:2}]" + self._tab + (f"[{who}] " if who else "") + str(message))
def log_result(self, logger, return_values): def log_result(self, return_values):
if not logger.isEnabledFor(logging.DEBUG): if not self.logger or not self.logger.isEnabledFor(logging.DEBUG):
return return
if len(return_values) == 0: if len(return_values) == 0:
logger.debug(self._tab + "No return value") self.logger.debug(self._tab + "No return value")
for r in return_values: for r in return_values:
to_str = self.return_value_to_str(r) to_str = self.return_value_to_str(r)
logger.debug(f"[{self._id:2}]" + self._tab + "-> " + to_str) self.logger.debug(f"[{self._id:2}]" + self._tab + "-> " + to_str)
def get_parent(self): def get_parent(self):
return self._parent return self._parent
@@ -14,7 +14,7 @@ class SheerkaCreateNewConcept:
self.sheerka = sheerka self.sheerka = sheerka
self.logger_name = self.create_new_concept.__name__ self.logger_name = self.create_new_concept.__name__
def create_new_concept(self, context, concept: Concept, logger=None): def create_new_concept(self, context, concept: Concept):
""" """
Adds a new concept to the system Adds a new concept to the system
:param context: :param context:
@@ -23,8 +23,6 @@ class SheerkaCreateNewConcept:
:return: digest of the new concept :return: digest of the new concept
""" """
logger = logger or self.sheerka.log
concept.init_key() concept.init_key()
concepts_definitions = None concepts_definitions = None
init_ret_value = None init_ret_value = None
@@ -52,7 +50,6 @@ class SheerkaCreateNewConcept:
concept_lexer_parser = self.sheerka.parsers[CONCEPT_LEXER_PARSER_CLASS]() concept_lexer_parser = self.sheerka.parsers[CONCEPT_LEXER_PARSER_CLASS]()
with context.push(self.sheerka.name, desc=f"Initializing concept definition for {concept}") as sub_context: with context.push(self.sheerka.name, desc=f"Initializing concept definition for {concept}") as sub_context:
sub_context.concepts[concept.key] = concept # the concept is not in the real cache yet sub_context.concepts[concept.key] = concept # the concept is not in the real cache yet
sub_context.log_new(logger)
init_ret_value = concept_lexer_parser.initialize(sub_context, concepts_definitions) init_ret_value = concept_lexer_parser.initialize(sub_context, concepts_definitions)
sub_context.add_values(return_values=init_ret_value) sub_context.add_values(return_values=init_ret_value)
if not init_ret_value.status: if not init_ret_value.status:
@@ -83,7 +80,7 @@ class SheerkaCreateNewConcept:
use_ref=True) use_ref=True)
self.sheerka.concepts_definitions_cache = None # invalidate cache self.sheerka.concepts_definitions_cache = None # invalidate cache
except SheerkaDataProviderDuplicateKeyError as error: except SheerkaDataProviderDuplicateKeyError as error:
context.log_error(logger, "Failed to create a new concept.", who=self.logger_name) context.log_error("Failed to create a new concept.", who=self.logger_name)
return self.sheerka.ret( return self.sheerka.ret(
self.logger_name, self.logger_name,
False, False,
+5
View File
@@ -58,6 +58,11 @@ class SheerkaDump:
self.sheerka.log.info(f"body : {c.metadata.body}") self.sheerka.log.info(f"body : {c.metadata.body}")
if eval: if eval:
self.sheerka.log.info(f"value : {value}") self.sheerka.log.info(f"value : {value}")
for p in c.props:
self.sheerka.log.info(f"{p}: {c.get_prop(p)}")
else:
self.sheerka.log.info("No property")
self.sheerka.log.info(f"digest : {c.get_digest()}") self.sheerka.log.info(f"digest : {c.get_digest()}")
if self.sheerka.isaset(context, c): if self.sheerka.isaset(context, c):
@@ -62,7 +62,7 @@ class SheerkaEvaluateConcept:
False, False,
self.sheerka.new(BuiltinConcepts.CHICKEN_AND_EGG, body=concepts_found)) self.sheerka.new(BuiltinConcepts.CHICKEN_AND_EGG, body=concepts_found))
def initialize_concept_asts(self, context, concept: Concept, logger=None): def initialize_concept_asts(self, context, concept: Concept):
""" """
Updates the codes of the newly created concept Updates the codes of the newly created concept
Basically, it runs the parsers on all parts Basically, it runs the parsers on all parts
@@ -84,11 +84,10 @@ class SheerkaEvaluateConcept:
concept.compiled[part_key] = DoNotResolve(source) concept.compiled[part_key] = DoNotResolve(source)
else: else:
with context.push(desc=f"Initializing compiled for {part_key}") as sub_context: with context.push(desc=f"Initializing compiled for {part_key}") as sub_context:
sub_context.log_new(logger)
sub_context.add_inputs(source=source) sub_context.add_inputs(source=source)
to_parse = self.sheerka.ret(context.who, True, to_parse = self.sheerka.ret(context.who, True,
self.sheerka.new(BuiltinConcepts.USER_INPUT, body=source)) self.sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
res = self.sheerka.execute(sub_context, to_parse, steps, logger) res = self.sheerka.execute(sub_context, to_parse, steps)
concept.compiled[part_key] = res concept.compiled[part_key] = res
sub_context.add_values(return_values=res) sub_context.add_values(return_values=res)
@@ -103,7 +102,6 @@ class SheerkaEvaluateConcept:
concept.compiled[prop] = DoNotResolve(default_value) concept.compiled[prop] = DoNotResolve(default_value)
else: else:
with context.push(desc=f"Initializing AST for property {prop}") as sub_context: with context.push(desc=f"Initializing AST for property {prop}") as sub_context:
sub_context.log_new(logger)
sub_context.add_inputs(source=default_value) sub_context.add_inputs(source=default_value)
to_parse = self.sheerka.ret(context.who, True, to_parse = self.sheerka.ret(context.who, True,
self.sheerka.new(BuiltinConcepts.USER_INPUT, body=default_value)) self.sheerka.new(BuiltinConcepts.USER_INPUT, body=default_value))
@@ -120,7 +118,7 @@ class SheerkaEvaluateConcept:
else: else:
self.sheerka.cache_by_key[concept.key].compiled = concept.compiled self.sheerka.cache_by_key[concept.key].compiled = concept.compiled
def resolve(self, context, to_resolve, current_prop, current_concept, logger): def resolve(self, context, to_resolve, current_prop, current_concept):
if isinstance(to_resolve, DoNotResolve): if isinstance(to_resolve, DoNotResolve):
return to_resolve.value return to_resolve.value
@@ -128,20 +126,18 @@ class SheerkaEvaluateConcept:
if self.infinite_recursion_detected(context, current_concept): if self.infinite_recursion_detected(context, current_concept):
with context.push(desc="Infinite recursion detected", obj=current_concept) as sub_context: with context.push(desc="Infinite recursion detected", obj=current_concept) as sub_context:
# I create a sub context in order to log what happened # I create a sub context in order to log what happened
sub_context.log_new(logger)
ret_val = self.manage_infinite_recursion(context) ret_val = self.manage_infinite_recursion(context)
sub_context.add_values(return_values=ret_val) sub_context.add_values(return_values=ret_val)
return ret_val.body return ret_val.body
desc = f"Evaluating {current_prop} (concept={current_concept})" desc = f"Evaluating {current_prop} (concept={current_concept})"
context.log(logger, desc, self.logger_name) context.log(desc, self.logger_name)
with context.push(desc=desc, obj=current_concept) as sub_context: with context.push(desc=desc, obj=current_concept) as sub_context:
sub_context.log_new(logger)
# when it's a concept, evaluate it # when it's a concept, evaluate it
if isinstance(to_resolve, Concept) and \ if isinstance(to_resolve, Concept) and \
not context.sheerka.isinstance(to_resolve, BuiltinConcepts.RETURN_VALUE): not context.sheerka.isinstance(to_resolve, BuiltinConcepts.RETURN_VALUE):
evaluated = self.evaluate_concept(sub_context, to_resolve, logger) evaluated = self.evaluate_concept(sub_context, to_resolve)
sub_context.add_values(return_values=evaluated) sub_context.add_values(return_values=evaluated)
if evaluated.key == to_resolve.key: if evaluated.key == to_resolve.key:
return evaluated return evaluated
@@ -151,7 +147,7 @@ class SheerkaEvaluateConcept:
# otherwise, execute all return values to find out what is the value # otherwise, execute all return values to find out what is the value
else: else:
use_copy = [r for r in to_resolve] if hasattr(to_resolve, "__iter__") else to_resolve use_copy = [r for r in to_resolve] if hasattr(to_resolve, "__iter__") else to_resolve
r = self.sheerka.execute(sub_context, use_copy, CONCEPT_EVALUATION_STEPS, logger) r = self.sheerka.execute(sub_context, use_copy, CONCEPT_EVALUATION_STEPS)
one_r = core.builtin_helpers.expect_one(context, r) one_r = core.builtin_helpers.expect_one(context, r)
sub_context.add_values(return_values=one_r) sub_context.add_values(return_values=one_r)
if one_r.status: if one_r.status:
@@ -165,7 +161,7 @@ class SheerkaEvaluateConcept:
concept=current_concept, concept=current_concept,
property_name=current_prop) property_name=current_prop)
def resolve_list(self, context, list_to_resolve, current_prop, current_concept, logger): def resolve_list(self, context, list_to_resolve, current_prop, current_concept):
"""When dealing with a list, there are two possibilities""" """When dealing with a list, there are two possibilities"""
# It may be a list of ReturnValueConcept to execute (always the case for metadata) # It may be a list of ReturnValueConcept to execute (always the case for metadata)
# or a list of single values (may be the case for properties) # or a list of single values (may be the case for properties)
@@ -174,7 +170,7 @@ class SheerkaEvaluateConcept:
return [] return []
if self.sheerka.isinstance(list_to_resolve[0], BuiltinConcepts.RETURN_VALUE): if self.sheerka.isinstance(list_to_resolve[0], BuiltinConcepts.RETURN_VALUE):
return self.resolve(context, list_to_resolve, current_prop, current_concept, logger) return self.resolve(context, list_to_resolve, current_prop, current_concept)
res = [] res = []
for to_resolve in list_to_resolve: for to_resolve in list_to_resolve:
@@ -185,14 +181,14 @@ class SheerkaEvaluateConcept:
concept=current_concept, concept=current_concept,
property_name=current_prop) property_name=current_prop)
r = self.resolve(context, to_resolve, current_prop, current_concept, logger) r = self.resolve(context, to_resolve, current_prop, current_concept)
if self.sheerka.isinstance(r, BuiltinConcepts.CONCEPT_EVAL_ERROR): if self.sheerka.isinstance(r, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return r return r
res.append(r) res.append(r)
return res return res
def evaluate_concept(self, context, concept: Concept, logger=None): def evaluate_concept(self, context, concept: Concept):
""" """
Evaluation a concept Evaluation a concept
It means that if the where clause is True, will evaluate the body It means that if the where clause is True, will evaluate the body
@@ -202,8 +198,6 @@ class SheerkaEvaluateConcept:
:return: value of the evaluation or error :return: value of the evaluation or error
""" """
logger = logger or self.sheerka.log
if concept.metadata.is_evaluated: if concept.metadata.is_evaluated:
return concept return concept
@@ -211,7 +205,7 @@ class SheerkaEvaluateConcept:
# TODO : Validate the PRE condition # TODO : Validate the PRE condition
# #
self.initialize_concept_asts(context, concept, logger) self.initialize_concept_asts(context, concept)
# to make sure of the order, it don't use ConceptParts.get_parts() # to make sure of the order, it don't use ConceptParts.get_parts()
# props must be evaluated first, body must be evaluated before where # props must be evaluated first, body must be evaluated before where
@@ -224,10 +218,10 @@ class SheerkaEvaluateConcept:
if isinstance(prop_ast, list): if isinstance(prop_ast, list):
# Do not send the current concept for the properties # Do not send the current concept for the properties
resolved = self.resolve_list(context, prop_ast, prop_name, None, logger) resolved = self.resolve_list(context, prop_ast, prop_name, None)
else: else:
# Do not send the current concept for the properties # Do not send the current concept for the properties
resolved = self.resolve(context, prop_ast, prop_name, None, logger) resolved = self.resolve(context, prop_ast, prop_name, None)
if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved): if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved):
resolved.set_prop("concept", concept) # since current concept was not sent resolved.set_prop("concept", concept) # since current concept was not sent
return resolved return resolved
@@ -243,7 +237,7 @@ class SheerkaEvaluateConcept:
if part_key in concept.compiled and concept.compiled[part_key] is not None: if part_key in concept.compiled and concept.compiled[part_key] is not None:
metadata_ast = concept.compiled[part_key] metadata_ast = concept.compiled[part_key]
resolved = self.resolve(context, metadata_ast, part_key, concept, logger) resolved = self.resolve(context, metadata_ast, part_key, concept)
if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved): if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved):
return resolved return resolved
else: else:
+9 -15
View File
@@ -10,7 +10,7 @@ class SheerkaExecute:
def __init__(self, sheerka): def __init__(self, sheerka):
self.sheerka = sheerka self.sheerka = sheerka
def call_parsers(self, execution_context, return_values, logger=None): def call_parsers(self, execution_context, return_values):
# return_values must be a list # return_values must be a list
if not isinstance(return_values, list): if not isinstance(return_values, list):
@@ -35,8 +35,6 @@ class SheerkaExecute:
instantiated_parsers = [parser(sheerka=self.sheerka) for parser in self.sheerka.parsers.values()] instantiated_parsers = [parser(sheerka=self.sheerka) for parser in self.sheerka.parsers.values()]
grouped_parsers = {} grouped_parsers = {}
for parser in [p for p in instantiated_parsers if p.enabled]: for parser in [p for p in instantiated_parsers if p.enabled]:
if logger:
parser.log = logger
grouped_parsers.setdefault(parser.priority, []).append(parser) grouped_parsers.setdefault(parser.priority, []).append(parser)
sorted_priorities = sorted(grouped_parsers.keys(), reverse=True) sorted_priorities = sorted(grouped_parsers.keys(), reverse=True)
@@ -56,9 +54,9 @@ class SheerkaExecute:
# if self.sheerka.log.isEnabledFor(logging.DEBUG): # if self.sheerka.log.isEnabledFor(logging.DEBUG):
# debug_text = "'" + to_parse + "'" if isinstance(to_parse, str) \ # debug_text = "'" + to_parse + "'" if isinstance(to_parse, str) \
# else "'" + BaseParser.get_text_from_tokens(to_parse) + "' as tokens" # else "'" + BaseParser.get_text_from_tokens(to_parse) + "' as tokens"
# execution_context.log(logger or self.sheerka.log, f"Parsing {debug_text}") # execution_context.log(f"Parsing {debug_text}")
with execution_context.push(desc=f"Parsing using {parser.name}") as sub_context: with execution_context.push(desc=f"Parsing using {parser.name}", logger=parser.verbose_log) as sub_context:
sub_context.add_inputs(to_parse=to_parse) sub_context.add_inputs(to_parse=to_parse)
res = parser.parse(sub_context, to_parse) res = parser.parse(sub_context, to_parse)
if res is not None: if res is not None:
@@ -92,7 +90,7 @@ class SheerkaExecute:
result = core.utils.remove_list_from_list(result, user_inputs) result = core.utils.remove_list_from_list(result, user_inputs)
return result return result
def call_evaluators(self, execution_context, return_values, process_step, evaluation_context=None, logger=None): def call_evaluators(self, execution_context, return_values, process_step, evaluation_context=None):
# return_values must be a list # return_values must be a list
if not isinstance(return_values, list): if not isinstance(return_values, list):
@@ -122,8 +120,6 @@ class SheerkaExecute:
instantiated_evaluators = self._preprocess_evaluators(execution_context, instantiated_evaluators) instantiated_evaluators = self._preprocess_evaluators(execution_context, instantiated_evaluators)
for evaluator in [e for e in instantiated_evaluators if e.enabled and process_step in e.steps]: for evaluator in [e for e in instantiated_evaluators if e.enabled and process_step in e.steps]:
if logger:
evaluator.log = logger
grouped_evaluators.setdefault(evaluator.priority, []).append(evaluator) grouped_evaluators.setdefault(evaluator.priority, []).append(evaluator)
# order the groups by priority, the higher first # order the groups by priority, the higher first
@@ -145,7 +141,7 @@ class SheerkaExecute:
evaluator = self._preprocess_evaluators(execution_context, evaluator.__class__()) # fresh copy evaluator = self._preprocess_evaluators(execution_context, evaluator.__class__()) # fresh copy
sub_context_desc = f"Evaluating using {evaluator.name} ({priority=})" sub_context_desc = f"Evaluating using {evaluator.name} ({priority=})"
with iteration_context.push(desc=sub_context_desc) as sub_context: with iteration_context.push(desc=sub_context_desc, logger=evaluator.verbose_log) as sub_context:
sub_context.add_inputs(return_values=original_items) sub_context.add_inputs(return_values=original_items)
# process evaluators that work on one simple return value at the time # process evaluators that work on one simple return value at the time
@@ -206,28 +202,26 @@ class SheerkaExecute:
return_values = core.utils.remove_list_from_list(return_values, evaluation_return_values) return_values = core.utils.remove_list_from_list(return_values, evaluation_return_values)
return return_values return return_values
def execute(self, execution_context, return_values, execution_steps, logger=None): def execute(self, execution_context, return_values, execution_steps):
""" """
Executes process for all initial contexts Executes process for all initial contexts
:param execution_context: :param execution_context:
:param return_values: :param return_values:
:param execution_steps: :param execution_steps:
:param logger: logger to use (if not directly called by sheerka)
:return: :return:
""" """
for step in execution_steps: for step in execution_steps:
copy = return_values[:] if hasattr(return_values, "__iter__") else [return_values] copy = return_values[:] if hasattr(return_values, "__iter__") else [return_values]
with execution_context.push(step=step, iteration=0, desc=f"{step=}") as sub_context: with execution_context.push(step=step, iteration=0, desc=f"{step=}") as sub_context:
sub_context.log(logger or self.sheerka.log, f"{step=}, context='{sub_context}'")
if step == BuiltinConcepts.PARSING: if step == BuiltinConcepts.PARSING:
return_values = self.call_parsers(sub_context, return_values, logger) return_values = self.call_parsers(sub_context, return_values)
else: else:
return_values = self.call_evaluators(sub_context, return_values, step, None, logger) return_values = self.call_evaluators(sub_context, return_values, step, None)
if copy != return_values: if copy != return_values:
sub_context.log_result(logger or self.sheerka.log, return_values) sub_context.log_result(return_values)
sub_context.add_values(return_values=return_values) sub_context.add_values(return_values=return_values)
@@ -6,8 +6,7 @@ class SheerkaModifyConcept:
self.sheerka = sheerka self.sheerka = sheerka
self.logger_name = self.modify_concept.__name__ self.logger_name = self.modify_concept.__name__
def modify_concept(self, context, concept, logger=None): def modify_concept(self, context, concept):
logger = logger or self.sheerka.log
self.sheerka.sdp.modify(context.event.get_digest(), self.sheerka.CONCEPTS_ENTRY, concept.key, concept) self.sheerka.sdp.modify(context.event.get_digest(), self.sheerka.CONCEPTS_ENTRY, concept.key, concept)
+18 -29
View File
@@ -11,42 +11,38 @@ class SheerkaSetsManager:
self.sheerka = sheerka self.sheerka = sheerka
self.logger_name = self.add_concept_to_set.__name__ self.logger_name = self.add_concept_to_set.__name__
def set_isa(self, context, concept, concept_set, logger=None): def set_isa(self, context, concept, concept_set):
""" """
Defines that concept a is b is another concept Defines that concept a is b is another concept
:param context: :param context:
:param concept: :param concept:
:param concept_set: :param concept_set:
:param logger:
:return: :return:
""" """
logger = logger or self.sheerka.log context.log(f"Setting that concept {concept} is a {concept_set}", who=self.logger_name)
context.log(logger, f"Setting that concept {concept} is a {concept_set}", who=self.logger_name)
isa = [] if BuiltinConcepts.ISA not in concept.props else concept.get_prop(BuiltinConcepts.ISA) isa = [] if BuiltinConcepts.ISA not in concept.props else concept.get_prop(BuiltinConcepts.ISA)
if concept_set not in isa: if concept_set not in isa:
isa.append(concept_set) isa.append(concept_set)
concept.set_prop(BuiltinConcepts.ISA, isa) concept.set_prop(BuiltinConcepts.ISA, isa)
res = self.sheerka.modify_concept(context, concept, logger) res = self.sheerka.modify_concept(context, concept)
if not res.status: if not res.status:
return res return res
return self.add_concept_to_set(context, concept, concept_set, logger) return self.add_concept_to_set(context, concept, concept_set)
def add_concept_to_set(self, context, concept, concept_set, logger=None): def add_concept_to_set(self, context, concept, concept_set):
""" """
Add an entry in sdp to tell that concept isa concept_set Add an entry in sdp to tell that concept isa concept_set
:param context: :param context:
:param concept: :param concept:
:param concept_set: :param concept_set:
:param logger:
:return: :return:
""" """
logger = logger or self.sheerka.log
context.log(logger, f"Adding concept {concept} to set {concept_set}", who=self.logger_name) context.log(f"Adding concept {concept} to set {concept_set}", who=self.logger_name)
assert concept.id assert concept.id
assert concept_set.id assert concept_set.id
@@ -61,14 +57,13 @@ class SheerkaSetsManager:
else: else:
return self.sheerka.ret(self.logger_name, True, self.sheerka.new(BuiltinConcepts.SUCCESS)) return self.sheerka.ret(self.logger_name, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
except Exception as error: except Exception as error:
context.log_error(logger, "Failed to add to set.", who=self.logger_name) context.log_error("Failed to add to set.", who=self.logger_name)
return self.sheerka.ret(self.logger_name, False, ErrorConcept(error), error.args[0]) return self.sheerka.ret(self.logger_name, False, ErrorConcept(error), error.args[0])
def add_concepts_to_set(self, context, concepts, concept_set, logger=None): def add_concepts_to_set(self, context, concepts, concept_set):
"""Adding multiple concepts at the same time""" """Adding multiple concepts at the same time"""
logger = logger or self.sheerka.log
context.log(logger, f"Adding concepts {concepts} to set {concept_set}", who=self.logger_name) context.log(f"Adding concepts {concepts} to set {concept_set}", who=self.logger_name)
previous = self.sheerka.sdp.get_safe(GROUP_PREFIX + concept_set.id) previous = self.sheerka.sdp.get_safe(GROUP_PREFIX + concept_set.id)
new_ids = [c.id for c in concepts] if previous is None else previous + [c.id for c in concepts] new_ids = [c.id for c in concepts] if previous is None else previous + [c.id for c in concepts]
@@ -76,21 +71,18 @@ class SheerkaSetsManager:
self.sheerka.sdp.set(context.event.get_digest(), GROUP_PREFIX + concept_set.id, new_ids) self.sheerka.sdp.set(context.event.get_digest(), GROUP_PREFIX + concept_set.id, new_ids)
return self.sheerka.ret(self.logger_name, True, self.sheerka.new(BuiltinConcepts.SUCCESS)) return self.sheerka.ret(self.logger_name, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
except Exception as error: except Exception as error:
context.log_error(logger, "Failed to add to set.", who=self.logger_name) context.log_error("Failed to add to set.", who=self.logger_name)
return self.sheerka.ret(self.logger_name, False, ErrorConcept(error), error.args[0]) return self.sheerka.ret(self.logger_name, False, ErrorConcept(error), error.args[0])
def get_set_elements(self, context, concept, logger=None): def get_set_elements(self, context, concept):
""" """
Concept is supposed to be a set Concept is supposed to be a set
Returns all elements if the set Returns all elements if the set
:param context: :param context:
:param concept: :param concept:
:param logger:
:return: :return:
""" """
logger = logger or self.sheerka.log
# noinspection PyShadowingNames # noinspection PyShadowingNames
def _get_set_elements(context, concept, sub_concept): def _get_set_elements(context, concept, sub_concept):
if not (isinstance(sub_concept, Concept) and sub_concept.id): if not (isinstance(sub_concept, Concept) and sub_concept.id):
@@ -105,13 +97,13 @@ class SheerkaSetsManager:
else: else:
# This methods sucks, but I don't have enough tools (like proper AST manipulation functions) # This methods sucks, but I don't have enough tools (like proper AST manipulation functions)
# to do it properly now. It will be enhanced later # to do it properly now. It will be enhanced later
concepts = self._get_concepts(context, ids, True, logger) concepts = self._get_concepts(context, ids, True)
globals_ = {"xx__concepts__xx": concepts, "sheerka": self.sheerka} globals_ = {"xx__concepts__xx": concepts, "sheerka": self.sheerka}
locals_ = {} locals_ = {}
exec(new_condition, globals_, locals_) exec(new_condition, globals_, locals_)
return locals_["result"] return locals_["result"]
else: else:
return self._get_concepts(context, ids, False, logger) return self._get_concepts(context, ids, False)
# it may be a concept that references a set # it may be a concept that references a set
if not sub_concept.metadata.is_evaluated: if not sub_concept.metadata.is_evaluated:
@@ -160,30 +152,27 @@ class SheerkaSetsManager:
return False return False
def isaset(self, context, concept, logger=None): def isaset(self, context, concept):
""" """
True if exists All_<concept_id> in sdp or if concept references to a concept that has all_<concept_id> True if exists All_<concept_id> in sdp or if concept references to a concept that has all_<concept_id>
:param context: :param context:
:param concept: :param concept:
:param logger:
:return: :return:
""" """
"""""" """"""
logger = logger or self.sheerka.log
if not (isinstance(concept, Concept) and concept.id): if not (isinstance(concept, Concept) and concept.id):
return None return None
# it may be a concept that references a set # it may be a concept that references a set
if not concept.metadata.is_evaluated: if not concept.metadata.is_evaluated:
with context.push(desc=f"Evaluating concept {concept}") as sub_context: with context.push(desc=f"Evaluating concept {concept}") as sub_context:
evaluated = self.sheerka.evaluate_concept(sub_context, concept, logger) evaluated = self.sheerka.evaluate_concept(sub_context, concept)
if evaluated.key != concept.key: if evaluated.key != concept.key:
return False return False
if concept.body: if concept.body:
return self.isaset(context, concept.body, logger) return self.isaset(context, concept.body)
res = self.sheerka.sdp.get_safe(GROUP_PREFIX + concept.id) res = self.sheerka.sdp.get_safe(GROUP_PREFIX + concept.id)
return res is not None return res is not None
@@ -211,7 +200,7 @@ for x in xx__concepts__xx:
""" """
return expression return expression
def _get_concepts(self, context, ids, evaluate, logger): def _get_concepts(self, context, ids, evaluate):
""" """
Gets concepts from a list of concepts ids Gets concepts from a list of concepts ids
:param ids: :param ids:
@@ -229,7 +218,7 @@ for x in xx__concepts__xx:
with context.push(desc=f"Evaluating concepts of a set") as sub_context: with context.push(desc=f"Evaluating concepts of a set") as sub_context:
for element_id in ids: for element_id in ids:
concept = self.sheerka.get_by_id(element_id) concept = self.sheerka.get_by_id(element_id)
evaluated = self.sheerka.evaluate_concept(context, concept, logger) evaluated = self.sheerka.evaluate_concept(context, concept)
result.append(evaluated) result.append(evaluated)
return result return result
+26 -21
View File
@@ -40,6 +40,7 @@ class Sheerka(Concept):
def __init__(self, skip_builtins_in_db=False, debug=False, loggers=None): def __init__(self, skip_builtins_in_db=False, debug=False, loggers=None):
self.init_logging(debug, loggers) self.init_logging(debug, loggers)
self.loggers = loggers
super().__init__(BuiltinConcepts.SHEERKA, True, True, BuiltinConcepts.SHEERKA) super().__init__(BuiltinConcepts.SHEERKA, True, True, BuiltinConcepts.SHEERKA)
self.log.debug("Starting Sheerka.") self.log.debug("Starting Sheerka.")
@@ -110,7 +111,7 @@ class Sheerka(Concept):
event = Event("Initializing Sheerka.", user=self.name) event = Event("Initializing Sheerka.", user=self.name)
self.sdp.save_event(event) self.sdp.save_event(event)
exec_context = ExecutionContext(self.key, event, self) with ExecutionContext(self.key, event, self, "Initializing Sheerka.", self.init_log) as exec_context:
self.initialize_builtin_concepts() self.initialize_builtin_concepts()
self.initialize_builtin_parsers() self.initialize_builtin_parsers()
@@ -121,6 +122,7 @@ class Sheerka(Concept):
exec_context.add_values(return_values=res) exec_context.add_values(return_values=res)
if not self.skip_builtins_in_db: if not self.skip_builtins_in_db:
self.sdp.save_result(exec_context) self.sdp.save_result(exec_context)
self.init_log.debug(f"Sheerka successfully initialized")
except IOError as e: except IOError as e:
res = ReturnValueConcept(self, False, self.get(BuiltinConcepts.ERROR), e) res = ReturnValueConcept(self, False, self.get(BuiltinConcepts.ERROR), e)
@@ -191,8 +193,7 @@ class Sheerka(Concept):
self.evaluators.append(evaluator) self.evaluators.append(evaluator)
def initialize_concepts_definitions(self, execution_context): def initialize_concepts_definitions(self, execution_context):
self.init_log.debug("Initializing concepts definitions") self.init_log.debug("Initializing concepts grammars.")
# definitions = self.sdp.get_safe(self.CONCEPTS_DEFINITIONS_ENTRY, load_origin=False)
definitions = self.get_concepts_definitions(execution_context) definitions = self.get_concepts_definitions(execution_context)
if definitions is None: if definitions is None:
@@ -234,7 +235,7 @@ class Sheerka(Concept):
evt_digest = self.sdp.save_event(event) evt_digest = self.sdp.save_event(event)
self.log.debug(f"{evt_digest=}") self.log.debug(f"{evt_digest=}")
with ExecutionContext(self.key, event, self, f"Evaluating '{text}'") as execution_context: with ExecutionContext(self.key, event, self, f"Evaluating '{text}'", self.log) as execution_context:
user_input = self.ret(self.name, True, self.new(BuiltinConcepts.USER_INPUT, body=text, user_name=user_name)) user_input = self.ret(self.name, True, self.new(BuiltinConcepts.USER_INPUT, body=text, user_name=user_name))
reduce_requested = self.ret(self.name, True, self.new(BuiltinConcepts.REDUCE_REQUESTED)) reduce_requested = self.ret(self.name, True, self.new(BuiltinConcepts.REDUCE_REQUESTED))
@@ -261,7 +262,7 @@ class Sheerka(Concept):
return ret return ret
def execute(self, execution_context, return_values, execution_steps, logger=None): def execute(self, execution_context, return_values, execution_steps):
""" """
Executes process for all initial contexts Executes process for all initial contexts
:param execution_context: :param execution_context:
@@ -270,7 +271,7 @@ class Sheerka(Concept):
:param logger: logger to use (if not directly called by sheerka) :param logger: logger to use (if not directly called by sheerka)
:return: :return:
""" """
return self.execute_handler.execute(execution_context, return_values, execution_steps, logger) return self.execute_handler.execute(execution_context, return_values, execution_steps)
def set_id_if_needed(self, obj: Concept, is_builtin: bool): def set_id_if_needed(self, obj: Concept, is_builtin: bool):
""" """
@@ -287,7 +288,7 @@ class Sheerka(Concept):
obj.metadata.id = self.sdp.get_next_key(entry) obj.metadata.id = self.sdp.get_next_key(entry)
self.log.debug(f"Setting id '{obj.metadata.id}' to concept '{obj.metadata.name}'.") self.log.debug(f"Setting id '{obj.metadata.id}' to concept '{obj.metadata.name}'.")
def create_new_concept(self, context, concept: Concept, logger=None): def create_new_concept(self, context, concept: Concept):
""" """
Adds a new concept to the system Adds a new concept to the system
:param context: :param context:
@@ -296,12 +297,12 @@ class Sheerka(Concept):
:return: digest of the new concept :return: digest of the new concept
""" """
return self.create_new_concept_handler.create_new_concept(context, concept, logger) return self.create_new_concept_handler.create_new_concept(context, concept)
def modify_concept(self, context, concept: Concept, logger): def modify_concept(self, context, concept: Concept):
return self.modify_concept_handler.modify_concept(context, concept, logger) return self.modify_concept_handler.modify_concept(context, concept)
def add_concept_to_set(self, context, concept, concept_set, logger=None): def add_concept_to_set(self, context, concept, concept_set):
""" """
Add an entry in sdp to tell that concept isa concept_set Add an entry in sdp to tell that concept isa concept_set
:param context: :param context:
@@ -310,9 +311,9 @@ class Sheerka(Concept):
:param logger: :param logger:
:return: :return:
""" """
return self.sets_handler.add_concept_to_set(context, concept, concept_set, logger) return self.sets_handler.add_concept_to_set(context, concept, concept_set)
def set_isa(self, context, concept, concept_set, logger=None): def set_isa(self, context, concept, concept_set):
""" """
:param context: :param context:
@@ -321,7 +322,7 @@ class Sheerka(Concept):
:param logger: :param logger:
:return: :return:
""" """
return self.sets_handler.set_isa(context, concept, concept_set, logger) return self.sets_handler.set_isa(context, concept, concept_set)
def get_set_elements(self, context, concept): def get_set_elements(self, context, concept):
""" """
@@ -334,7 +335,7 @@ class Sheerka(Concept):
return self.sets_handler.get_set_elements(context, concept) return self.sets_handler.get_set_elements(context, concept)
def evaluate_concept(self, context, concept: Concept, logger=None): def evaluate_concept(self, context, concept: Concept):
""" """
Evaluation a concept Evaluation a concept
It means that if the where clause is True, will evaluate the body It means that if the where clause is True, will evaluate the body
@@ -343,7 +344,7 @@ class Sheerka(Concept):
:param logger: :param logger:
:return: value of the evaluation or error :return: value of the evaluation or error
""" """
return self.evaluate_concept_handler.evaluate_concept(context, concept, logger) return self.evaluate_concept_handler.evaluate_concept(context, concept)
def add_in_cache(self, concept: Concept): def add_in_cache(self, concept: Concept):
""" """
@@ -424,18 +425,20 @@ class Sheerka(Concept):
return result return result
def get_concepts_definitions(self, context): def get_concepts_definitions(self, context):
if self.concepts_definitions_cache: if self.concepts_definitions_cache:
return self.concepts_definitions_cache return self.concepts_definitions_cache
encoded = self.sdp.get_safe( encoded_bnf = self.sdp.get_safe(
self.CONCEPTS_DEFINITIONS_ENTRY, self.CONCEPTS_DEFINITIONS_ENTRY,
load_origin=False) or {} load_origin=False) or {}
self.concepts_definitions_cache = {} self.concepts_definitions_cache = {}
bnf_parser = self.parsers[BNF_PARSER_CLASS]() bnf_parser = self.parsers[BNF_PARSER_CLASS]()
for k, v in encoded.items(): for k, v in encoded_bnf.items():
key, id_ = core.utils.unstr_concept(k) key, id_ = core.utils.unstr_concept(k)
concept = self.new((key, id_)) concept = self.new((key, id_))
context.log(f"Parsing BNF definition for {concept}", context.who)
rule_result = bnf_parser.parse(context, v) rule_result = bnf_parser.parse(context, v)
if rule_result.status: if rule_result.status:
self.concepts_definitions_cache[concept] = rule_result.value.value self.concepts_definitions_cache[concept] = rule_result.value.value
@@ -681,10 +684,12 @@ class Sheerka(Concept):
@staticmethod @staticmethod
def init_logging(debug, loggers): def init_logging(debug, loggers):
core.sheerka_logger.set_enabled(loggers) core.sheerka_logger.init_config(loggers)
if debug: if debug:
# log_format = "%(asctime)s %(name)s [%(levelname)s] %(message)s" log_format = "%(asctime)s"
log_format = "%(asctime)s [%(levelname)s] %(message)s" if "show-name" in loggers:
log_format += " %(name)s"
log_format += " [%(levelname)s] %(message)s"
log_level = logging.DEBUG log_level = logging.DEBUG
else: else:
log_format = "%(message)s" log_format = "%(message)s"
+19 -8
View File
@@ -2,21 +2,32 @@ import logging
import sys import sys
enabled = [] enabled = []
disabled = ["init", "sdp", "parsers", "evaluators", "verbose"] disabled = ["init", "sdp", "parsers", "evaluators", "verbose", "stats"]
console_handler = logging.StreamHandler(sys.stdout) console_handler = logging.StreamHandler(sys.stdout)
all_loggers = {} all_loggers = {}
def init_config(loggers):
def set_enabled(to_enable): if loggers is None:
if to_enable is None:
return return
if not hasattr(to_enable, "__iter__"): if not hasattr(loggers, "__iter__"):
to_enable = [to_enable] loggers = [loggers]
enabled.extend(to_enable) if "all" in loggers:
disabled.clear()
for logger in loggers:
if logger == "all":
continue
if logger.startswith("-"):
disabled.append(logger[1:])
elif logger.startswith("+"):
enabled.append(logger[1:])
else:
enabled.append(logger)
def to_discard(logger_class): def to_discard(logger_class):
@@ -40,7 +51,7 @@ def get_logger(logger_name):
all_loggers[logger_name] = logger all_loggers[logger_name] = logger
for d in disabled: for d in disabled:
if logger_name.startswith(d + ".") and to_discard(d): if (logger_name == d or logger_name.startswith(d + ".")) and to_discard(d):
logger.disabled = True logger.disabled = True
for e in enabled: for e in enabled:
+3 -3
View File
@@ -47,7 +47,7 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
isinstance(return_value.value.value, DefConceptNode) isinstance(return_value.value.value, DefConceptNode)
def eval(self, context, return_value): def eval(self, context, return_value):
context.log(self.log, "Adding a new concept", self.name) context.log("Adding a new concept", self.name)
def_concept_node = return_value.value.value def_concept_node = return_value.value.value
sheerka = context.sheerka sheerka = context.sheerka
@@ -86,10 +86,10 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
sheerka.is_success(def_concept_node.definition): sheerka.is_success(def_concept_node.definition):
concept.bnf = def_concept_node.definition.value.value concept.bnf = def_concept_node.definition.value.value
ret = sheerka.create_new_concept(context, concept, self.verbose_log) ret = sheerka.create_new_concept(context, concept)
if not ret.status: if not ret.status:
error_cause = sheerka.value(ret.body) error_cause = sheerka.value(ret.body)
context.log(self.log, f"Failed to add concept '{concept.name}'. Reason: {error_cause}", self.name) context.log(f"Failed to add concept '{concept.name}'. Reason: {error_cause}", self.name)
return sheerka.ret(self.name, ret.status, ret.value, parents=[return_value]) return sheerka.ret(self.name, ret.status, ret.value, parents=[return_value])
@staticmethod @staticmethod
+5 -5
View File
@@ -34,14 +34,14 @@ class AddConceptInSetEvaluator(OneReturnValueEvaluator):
sheerka.new(BuiltinConcepts.USER_INPUT, body=name_node.tokens, user_name="N/A")) sheerka.new(BuiltinConcepts.USER_INPUT, body=name_node.tokens, user_name="N/A"))
with context.push(desc=f"Recognizing '{name_node}'") as sub_context: with context.push(desc=f"Recognizing '{name_node}'") as sub_context:
r = sheerka.execute(sub_context, ret_val, ALL_STEPS, self.verbose_log) r = sheerka.execute(sub_context, ret_val, ALL_STEPS)
one_r = core.builtin_helpers.expect_one(context, r) one_r = core.builtin_helpers.expect_one(context, r)
sub_context.add_values(return_values=one_r) sub_context.add_values(return_values=one_r)
return one_r return one_r
isa_node = return_value.value.value isa_node = return_value.value.value
sheerka = context.sheerka sheerka = context.sheerka
context.log(self.log, f"Adding a concept {isa_node.concept} to set {isa_node.set}", self.name) context.log(f"Adding concept '{isa_node.concept}' to set '{isa_node.set}'", self.name)
# Try to recognize the concept # Try to recognize the concept
res = _resolve(isa_node.concept) res = _resolve(isa_node.concept)
@@ -62,11 +62,11 @@ class AddConceptInSetEvaluator(OneReturnValueEvaluator):
parents=[return_value]) parents=[return_value])
concept_set = res.value concept_set = res.value
res = sheerka.add_concept_to_set(context, concept, concept_set, self.verbose_log) res = sheerka.set_isa(context, concept, concept_set)
if not res.status: if not res.status:
context.log(self.log, f"Failed. Reason: {sheerka.value(res.body)}.", self.name) context.log(f"Failed. Reason: {sheerka.value(res.body)}.", self.name)
else: else:
context.log(self.log, f"Concept added.", self.name) context.log(f"Concept added.", self.name)
return sheerka.ret( return sheerka.ret(
self.name, self.name,
+3 -3
View File
@@ -24,7 +24,7 @@ class ConceptEvaluator(OneReturnValueEvaluator):
def eval(self, context, return_value): def eval(self, context, return_value):
sheerka = context.sheerka sheerka = context.sheerka
concept = return_value.value.value concept = return_value.value.value
context.log(self.verbose_log, f"Evaluating concept {concept}.", self.name) context.log(f"Evaluating concept {concept}.", self.name)
# If the concept that is requested is in the context(at least its name), drop the call. # If the concept that is requested is in the context(at least its name), drop the call.
# Why ? # Why ?
@@ -32,11 +32,11 @@ class ConceptEvaluator(OneReturnValueEvaluator):
# The body should be 'property_a', and not a concept called 'a' # The body should be 'property_a', and not a concept called 'a'
if context.obj and concept.name in context.obj.props: if context.obj and concept.name in context.obj.props:
value = context.obj.props[concept.name].value value = context.obj.props[concept.name].value
context.log(self.verbose_log, f"{concept.name} is a property. Returning value '{value}'.", self.name) context.log(f"{concept.name} is a property. Returning value '{value}'.", self.name)
return sheerka.ret(self.name, True, value, parents=[return_value]) return sheerka.ret(self.name, True, value, parents=[return_value])
evaluated = sheerka.evaluate_concept(context, concept, self.verbose_log) evaluated = sheerka.evaluate_concept(context, concept)
if evaluated.key != concept.key: if evaluated.key != concept.key:
# evaluated.key != concept.key means that we have transformed the concept # evaluated.key != concept.key means that we have transformed the concept
+2 -2
View File
@@ -29,10 +29,10 @@ class EvalEvaluator(AllReturnValuesEvaluator):
for ret_val in return_values: for ret_val in return_values:
if ret_val.status and isinstance(ret_val.body, Concept) and ret_val.body.body: if ret_val.status and isinstance(ret_val.body, Concept) and ret_val.body.body:
context.log(self.verbose_log, f"Evaluating {ret_val.body}", who=self) context.log(f"Evaluating {ret_val.body}", who=self)
result.append(sheerka.ret(self.name, True, ret_val.body.body, parents=[ret_val, self.eval_requested])) result.append(sheerka.ret(self.name, True, ret_val.body.body, parents=[ret_val, self.eval_requested]))
elif ret_val.status and sheerka.isaset(context, ret_val.body): elif ret_val.status and sheerka.isaset(context, ret_val.body):
context.log(self.verbose_log, f"Evaluating set {ret_val.body}", who=self) context.log(f"Evaluating set {ret_val.body}", who=self)
result.append(sheerka.ret( result.append(sheerka.ret(
self.name, self.name,
True, True,
+1 -1
View File
@@ -44,7 +44,7 @@ class LexerNodeEvaluator(OneReturnValueEvaluator):
if not hasattr(nodes, "__iter__"): if not hasattr(nodes, "__iter__"):
nodes = [nodes] nodes = [nodes]
context.log(self.verbose_log, f"{nodes=}", self.name) context.log(f"{nodes=}", self.name)
for node in nodes: for node in nodes:
if isinstance(node, SourceCodeNode): if isinstance(node, SourceCodeNode):
@@ -45,9 +45,9 @@ class MultipleSameSuccessEvaluator(AllReturnValuesEvaluator):
def eval(self, context, return_values): def eval(self, context, return_values):
sheerka = context.sheerka sheerka = context.sheerka
context.log(self.verbose_log, f"{len(self.success)} successful return value(s)", who=self) context.log(f"{len(self.success)} successful return value(s)", who=self)
for s in self.success: for s in self.success:
context.log(self.verbose_log, f"{s}", who=self) context.log(f"{s}", who=self)
if not core.builtin_helpers.is_same_success(sheerka, self.success): if not core.builtin_helpers.is_same_success(sheerka, self.success):
return None return None
+2 -2
View File
@@ -35,8 +35,8 @@ class OneErrorEvaluator(AllReturnValuesEvaluator):
return to_process and nb_evaluators_in_error == 1 return to_process and nb_evaluators_in_error == 1
def eval(self, context, return_values): def eval(self, context, return_values):
context.log(self.verbose_log, f"1 return value in error, {len(self.eaten)} item(s) eaten", who=self) context.log(f"1 return value in error, {len(self.eaten)} item(s) eaten", who=self)
context.log(self.verbose_log, f"{self.return_value_in_error}", who=self) context.log(f"{self.return_value_in_error}", who=self)
sheerka = context.sheerka sheerka = context.sheerka
return sheerka.ret(self.name, False, self.return_value_in_error.value, parents=self.eaten) return sheerka.ret(self.name, False, self.return_value_in_error.value, parents=self.eaten)
+2 -2
View File
@@ -37,8 +37,8 @@ class OneSuccessEvaluator(AllReturnValuesEvaluator):
return to_process and nb_successful_evaluators == 1 return to_process and nb_successful_evaluators == 1
def eval(self, context, return_values): def eval(self, context, return_values):
context.log(self.verbose_log, f"1 successful return value, {len(self.eaten)} item(s) eaten", who=self) context.log(f"1 successful return value, {len(self.eaten)} item(s) eaten", who=self)
context.log(self.verbose_log, f"{self.successful_return_value}", who=self) context.log(f"{self.successful_return_value}", who=self)
sheerka = context.sheerka sheerka = context.sheerka
return sheerka.ret(self.name, True, self.successful_return_value.value, parents=self.eaten) return sheerka.ret(self.name, True, self.successful_return_value.value, parents=self.eaten)
+16 -58
View File
@@ -31,35 +31,35 @@ class PythonEvaluator(OneReturnValueEvaluator):
sheerka = context.sheerka sheerka = context.sheerka
node = return_value.value.value node = return_value.value.value
try: try:
context.log(self.verbose_log, f"Evaluating python node {node}.", self.name) context.log(f"Evaluating python node {node}.", self.name)
# Do not evaluate if the ast refers to a concept (leave it to ConceptEvaluator) # Do not evaluate if the ast refers to a concept (leave it to ConceptEvaluator)
if isinstance(node.ast_, ast.Expression) and isinstance(node.ast_.body, ast.Name): if isinstance(node.ast_, ast.Expression) and isinstance(node.ast_.body, ast.Name):
c = context.sheerka.get(node.ast_.body.id) c = context.sheerka.get(node.ast_.body.id)
if not context.sheerka.isinstance(c, BuiltinConcepts.UNKNOWN_CONCEPT): if not context.sheerka.isinstance(c, BuiltinConcepts.UNKNOWN_CONCEPT):
context.log(self.verbose_log, "It's a simple concept. Not for me.", self.name) context.log("It's a simple concept. Not for me.", self.name)
not_for_me = context.sheerka.new(BuiltinConcepts.NOT_FOR_ME, body=node) not_for_me = context.sheerka.new(BuiltinConcepts.NOT_FOR_ME, body=node)
return sheerka.ret(self.name, False, not_for_me, parents=[return_value]) return sheerka.ret(self.name, False, not_for_me, parents=[return_value])
# get locals # get locals
my_globals = self.get_globals(context, node) my_globals = self.get_globals(context, node)
my_locals = {} my_locals = {}
context.log(self.verbose_log, f"globals={my_globals}", self.name) context.log(f"globals={my_globals}", self.name)
# eval # eval
if isinstance(node.ast_, ast.Expression): if isinstance(node.ast_, ast.Expression):
context.log(self.verbose_log, "Evaluating using 'eval'.", self.name) context.log("Evaluating using 'eval'.", self.name)
compiled = compile(node.ast_, "<string>", "eval") compiled = compile(node.ast_, "<string>", "eval")
evaluated = eval(compiled, my_globals, my_locals) evaluated = eval(compiled, my_globals, my_locals)
else: else:
context.log(self.verbose_log, "Evaluating using 'exec'.", self.name) context.log("Evaluating using 'exec'.", self.name)
evaluated = self.exec_with_return(node.ast_, my_globals, my_locals) evaluated = self.exec_with_return(node.ast_, my_globals, my_locals)
context.log(self.verbose_log, f"{evaluated=}", self.name) context.log(f"{evaluated=}", self.name)
return sheerka.ret(self.name, True, evaluated, parents=[return_value]) return sheerka.ret(self.name, True, evaluated, parents=[return_value])
except Exception as error: except Exception as error:
context.log_error(self.verbose_log, error, self.name) context.log_error(error, self.name)
error = sheerka.new(BuiltinConcepts.ERROR, body=error) error = sheerka.new(BuiltinConcepts.ERROR, body=error)
return sheerka.ret(self.name, False, error, parents=[return_value]) return sheerka.ret(self.name, False, error, parents=[return_value])
@@ -74,8 +74,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
"Concept": core.concept.Concept "Concept": core.concept.Concept
} }
if context.obj: if context.obj:
context.log(self.verbose_log, context.log(f"Concept '{context.obj}' is in context. Adding it and its properties to locals.", self.name)
f"Concept '{context.obj}' is in context. Adding it and its properties to locals.", self.name)
for prop_name, prop_value in context.obj.props.items(): for prop_name, prop_value in context.obj.props.items():
if isinstance(prop_value.value, Concept): if isinstance(prop_value.value, Concept):
@@ -90,10 +89,10 @@ class PythonEvaluator(OneReturnValueEvaluator):
unreferenced_names_visitor.visit(node_concept) unreferenced_names_visitor.visit(node_concept)
for name in unreferenced_names_visitor.names: for name in unreferenced_names_visitor.names:
context.log(self.verbose_log, f"Resolving '{name}'.", self.name) context.log(f"Resolving '{name}'.", self.name)
if name in node.concepts: if name in node.concepts:
context.log(self.verbose_log, f"Using value from node.", self.name) context.log(f"Using value from node.", self.name)
concept = node.concepts[name] concept = node.concepts[name]
return_concept = False return_concept = False
@@ -101,20 +100,19 @@ class PythonEvaluator(OneReturnValueEvaluator):
c_key, c_id, return_concept = self.resolve_name(name) c_key, c_id, return_concept = self.resolve_name(name)
if c_key in my_locals: if c_key in my_locals:
context.log(self.verbose_log, f"Using value from property.", self.name) context.log(f"Using value from property.", self.name)
continue continue
context.log(self.verbose_log, f"Instantiating new concept with {c_key=}, {c_id=}.", self.name) context.log(f"Instantiating new concept with {c_key=}, {c_id=}.", self.name)
new = context.sheerka.new new = context.sheerka.new
concept = new((None, c_id)) if c_id else new(c_key) concept = new((None, c_id)) if c_id else new(c_key)
if context.sheerka.isinstance(concept, BuiltinConcepts.UNKNOWN_CONCEPT): if context.sheerka.isinstance(concept, BuiltinConcepts.UNKNOWN_CONCEPT):
context.log(self.verbose_log, f"({c_key=}, {c_id=}) is not a concept. Skipping.", self.name) context.log(f"({c_key=}, {c_id=}) is not a concept. Skipping.", self.name)
continue continue
context.log(self.verbose_log, f"Evaluating '{concept}'", self.name) context.log(f"Evaluating '{concept}'", self.name)
with context.push(self.name, desc=f"Evaluating '{concept}'", obj=concept) as sub_context: with context.push(self.name, desc=f"Evaluating '{concept}'", obj=concept) as sub_context:
sub_context.log_new(self.verbose_log) evaluated = context.sheerka.evaluate_concept(sub_context, concept)
evaluated = context.sheerka.evaluate_concept(sub_context, concept, self.verbose_log)
sub_context.add_values(return_values=evaluated) sub_context.add_values(return_values=evaluated)
if evaluated.key == concept.key: if evaluated.key == concept.key:
@@ -141,47 +139,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
return key, id_, use_concept return key, id_, use_concept
else: else:
return to_resolve, None, False return to_resolve, None, False
#
# if not to_resolve.startswith("__C__"):
# return to_resolve, None, False
#
# context.log(self.verbose_log, f"Resolving name '{to_resolve}'.", self.name)
#
# if len(to_resolve) >= 18 and to_resolve[:18] == "__C__USE_CONCEPT__":
# use_concept = True
# index = 18
# else:
# use_concept = False
# index = 5
#
# try:
# next_index = to_resolve.index("__", index)
# if next_index == index:
# context.log(self.verbose_log, f"Error: no key between '__'.", self.name)
# return None
# concept_key = to_resolve[index: next_index]
# except ValueError:
# context.log(self.verbose_log, f"Error: Missing trailing '__'.", self.name)
# return None
#
# if next_index == len(to_resolve) - 5:
# context.log(self.verbose_log, f"Recognized concept '{concept_key}'", self.name)
# return concept_key, None, use_concept
#
# index = next_index + 2
# try:
# next_index = to_resolve.index("__", index)
# if next_index == index:
# context.log(self.verbose_log, f"Error: no id between '__'.", self.name)
# return None
#
# concept_id = to_resolve[index: next_index]
# except ValueError:
# context.log(self.verbose_log, f"Recognized concept '{concept_key}'.", self.name)
# return concept_key, None, use_concept
#
# context.log(self.verbose_log, f"Recognized concept '{concept_key}' (id='{concept_id}').", self.name)
# return concept_key, concept_id, use_concept
@staticmethod @staticmethod
def expr_to_expression(expr): def expr_to_expression(expr):
+4 -5
View File
@@ -41,14 +41,13 @@ class TooManySuccessEvaluator(AllReturnValuesEvaluator):
sheerka = context.sheerka sheerka = context.sheerka
if self.verbose_log.isEnabledFor(logging.DEBUG): if self.verbose_log.isEnabledFor(logging.DEBUG):
for s in self.success: for s in self.success:
context.log(self.verbose_log, s, self.name) context.log(s, self.name)
context.log(self.verbose_log, f"value={sheerka.value(s.value)}", self.name) context.log(f"value={sheerka.value(s.value)}", self.name)
if not core.builtin_helpers.is_same_success(sheerka, self.success): if not core.builtin_helpers.is_same_success(sheerka, self.success):
context.log(self.verbose_log, context.log(f"Values are different. Raising {BuiltinConcepts.TOO_MANY_SUCCESS}.", self.name)
f"Values are different. Raising {BuiltinConcepts.TOO_MANY_SUCCESS}.", self.name)
too_many_success = sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS, body=self.success) too_many_success = sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS, body=self.success)
return sheerka.ret(self.name, False, too_many_success, parents=self.eaten) return sheerka.ret(self.name, False, too_many_success, parents=self.eaten)
context.log(self.verbose_log, f"Values are the same. Nothing to do.", self.name) context.log(f"Values are the same. Nothing to do.", self.name)
return None return None
+12 -4
View File
@@ -100,20 +100,28 @@ class BaseParser:
if ret.status: if ret.status:
value = context.return_value_to_str(ret) value = context.return_value_to_str(ret)
context.log(self.log, f"Recognized '{source}' as {value}", self.name) context.log(f"Recognized '{source}' as {value}", self.name)
else: else:
context.log(self.log, f"Failed to recognize '{source}'", self.name) context.log(f"Failed to recognize '{source}'", self.name)
def log_multiple_results(self, context, source, list_of_ret): def log_multiple_results(self, context, source, list_of_ret):
if not self.log.isEnabledFor(logging.DEBUG): if not self.log.isEnabledFor(logging.DEBUG):
return return
context.log(self.log, f"Recognized '{source}' as multiple concepts", self.name) context.log(f"Recognized '{source}' as multiple concepts", self.name)
for r in list_of_ret: for r in list_of_ret:
value = context.return_value_to_str(r) value = context.return_value_to_str(r)
context.log(self.log, f" Recognized '{value}'", self.name) context.log(f" Recognized '{value}'", self.name)
def get_return_value_body(self, sheerka, source, tree, try_parse): def get_return_value_body(self, sheerka, source, tree, try_parse):
"""
All parsers must return their result in a standard way
:param sheerka:
:param source:
:param tree:
:param try_parse:
:return:
"""
if len(self.error_sink) == 1 and isinstance(self.error_sink[0], Concept): if len(self.error_sink) == 1 and isinstance(self.error_sink[0], Concept):
return self.error_sink[0] return self.error_sink[0]
+2 -1
View File
@@ -665,8 +665,9 @@ class ConceptLexerParser(BaseParser):
self.sheerka = context.sheerka self.sheerka = context.sheerka
concepts_to_resolve = set() concepts_to_resolve = set()
# ## Gets the grammars
for concept, concept_def in concepts_definitions.items(): for concept, concept_def in concepts_definitions.items():
# ## Gets the grammars
context.log(f"Resolving grammar for '{concept}'", context.who)
concept.init_key() # make sure that the key is initialized concept.init_key() # make sure that the key is initialized
grammar = self.get_model(concept_def, concepts_to_resolve) grammar = self.get_model(concept_def, concepts_to_resolve)
self.concepts_grammars[concept] = grammar self.concepts_grammars[concept] = grammar
@@ -56,7 +56,6 @@ class ConceptsWithConceptsParser(BaseParser):
prop_name = list(concept.props.keys())[index] prop_name = list(concept.props.keys())[index]
concept.compiled[prop_name] = node.concept concept.compiled[prop_name] = node.concept
context.log( context.log(
self.verbose_log,
f"Setting property '{prop_name}='{node.concept}'.", f"Setting property '{prop_name}='{node.concept}'.",
self.name) self.name)
index += 1 index += 1
@@ -66,7 +65,6 @@ class ConceptsWithConceptsParser(BaseParser):
value = sheerka.new(BuiltinConcepts.PARSER_RESULT, parser=self, source=node.source, body=node.node) value = sheerka.new(BuiltinConcepts.PARSER_RESULT, parser=self, source=node.source, body=node.node)
concept.compiled[prop_name] = [context.sheerka.ret(self.name, True, value)] concept.compiled[prop_name] = [context.sheerka.ret(self.name, True, value)]
context.log( context.log(
self.verbose_log,
f"Setting property '{prop_name}'='Python({node.source})'.", f"Setting property '{prop_name}'='Python({node.source})'.",
self.name) self.name)
index += 1 index += 1
+3 -4
View File
@@ -230,7 +230,7 @@ class DefaultParser(BaseParser):
token = self.get_token() token = self.get_token()
if token.value == Keywords.DEF: if token.value == Keywords.DEF:
self.next_token() self.next_token()
self.context.log(self.verbose_log, "Keyword DEF found.", self.name) self.context.log("Keyword DEF found.", self.name)
return self.parse_def_concept(token) return self.parse_def_concept(token)
else: else:
return self.parse_isa_concept() return self.parse_isa_concept()
@@ -411,14 +411,13 @@ class DefaultParser(BaseParser):
# ask the other parsers if they recognize the tokens # ask the other parsers if they recognize the tokens
with self.context.push(self.name, desc=f"Parsing {keyword}") as sub_context: with self.context.push(self.name, desc=f"Parsing {keyword}") as sub_context:
sub_context.log_new(self.verbose_log)
to_parse = self.sheerka.ret( to_parse = self.sheerka.ret(
sub_context.who, sub_context.who,
True, True,
self.sheerka.new(BuiltinConcepts.USER_INPUT, body=tokens)) self.sheerka.new(BuiltinConcepts.USER_INPUT, body=tokens))
steps = [BuiltinConcepts.PARSING] steps = [BuiltinConcepts.PARSING]
parsed = self.sheerka.execute(sub_context, to_parse, steps, self.verbose_log) parsed = self.sheerka.execute(sub_context, to_parse, steps)
parsing_result = core.builtin_helpers.expect_one(sub_context, parsed, self.verbose_log) parsing_result = core.builtin_helpers.expect_one(sub_context, parsed)
sub_context.add_values(return_values=parsing_result) sub_context.add_values(return_values=parsing_result)
if not parsing_result.status: if not parsing_result.status:
+4 -5
View File
@@ -24,17 +24,17 @@ class ExactConceptParser(BaseParser):
:return: :return:
""" """
context.log(self.verbose_log, f"Parsing '{text}'", self.name) context.log(f"Parsing '{text}'", self.name)
res = [] res = []
sheerka = context.sheerka sheerka = context.sheerka
try: try:
words = self.get_words(text) words = self.get_words(text)
except LexerError as e: except LexerError as e:
context.log(self.verbose_log, f"Error found in tokenizer {e}", self.name) context.log(f"Error found in tokenizer {e}", self.name)
return sheerka.ret(self.name, False, sheerka.new(BuiltinConcepts.ERROR, body=e)) return sheerka.ret(self.name, False, sheerka.new(BuiltinConcepts.ERROR, body=e))
if len(words) > self.MAX_WORDS_SIZE: if len(words) > self.MAX_WORDS_SIZE:
context.log(self.verbose_log, f"Max words reached. Stopping.", self.name) context.log(f"Max words reached. Stopping.", self.name)
return sheerka.ret(self.name, False, sheerka.new(BuiltinConcepts.CONCEPT_TOO_LONG, body=text)) return sheerka.ret(self.name, False, sheerka.new(BuiltinConcepts.CONCEPT_TOO_LONG, body=text))
recognized = False recognized = False
@@ -50,7 +50,7 @@ class ExactConceptParser(BaseParser):
concepts = result if isinstance(result, list) else [result] concepts = result if isinstance(result, list) else [result]
for concept in concepts: for concept in concepts:
context.log(self.verbose_log, f"Recognized concept {concept}.", self.name) context.log(f"Recognized concept {concept}.", self.name)
# update the properties if needed # update the properties if needed
for i, token in enumerate(combination): for i, token in enumerate(combination):
if token.startswith(VARIABLE_PREFIX): if token.startswith(VARIABLE_PREFIX):
@@ -59,7 +59,6 @@ class ExactConceptParser(BaseParser):
if self.verbose_log.isEnabledFor(logging.DEBUG): if self.verbose_log.isEnabledFor(logging.DEBUG):
prop_name = list(concept.props.keys())[index] prop_name = list(concept.props.keys())[index]
context.log( context.log(
self.verbose_log,
f"Added property {index}: {prop_name}='{words[i]}'.", f"Added property {index}: {prop_name}='{words[i]}'.",
self.name) self.name)
+1 -1
View File
@@ -302,7 +302,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(Concept(name="a", body="'concept_a'")) sheerka.add_in_cache(Concept(name="a", body="'concept_a'"))
sheerka.add_in_cache(Concept(name="b", body="'concept_b'")) sheerka.add_in_cache(Concept(name="b", body="'concept_b'"))
concept = Concept("foo", body="a + b").def_prop("a", "'prop_a'") concept = Concept("foo", body="a + b").def_prop("a", "'prop_a'").init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == 'prop_aconcept_b' assert evaluated.body == 'prop_aconcept_b'
@@ -15,7 +15,7 @@ def get_ret_val(concept_name, concept_set_name):
return ReturnValueConcept("some_name", True, ParserResultConcept(value=IsaConceptNode([], n1, n2))) return ReturnValueConcept("some_name", True, ParserResultConcept(value=IsaConceptNode([], n1, n2)))
class TestAssConceptInSetEvaluator(TestUsingMemoryBasedSheerka): class TestAddConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("ret_val, expected", [ @pytest.mark.parametrize("ret_val, expected", [
(ReturnValueConcept("some_name", True, ParserResultConcept(value=IsaConceptNode([]))), True), (ReturnValueConcept("some_name", True, ParserResultConcept(value=IsaConceptNode([]))), True),
@@ -53,12 +53,10 @@ class TestAssConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
def test_i_can_add_concept_to_a_set_of_concept(self): def test_i_can_add_concept_to_a_set_of_concept(self):
context = self.get_context() context = self.get_context()
foo = Concept("foo") foo = Concept("foo")
context.sheerka.set_id_if_needed(foo, False) context.sheerka.create_new_concept(context, foo)
context.sheerka.add_in_cache(foo)
bar = Concept("bar") bar = Concept("bar")
context.sheerka.set_id_if_needed(bar, False) context.sheerka.create_new_concept(context, bar)
context.sheerka.add_in_cache(bar)
ret_val = get_ret_val("foo", "bar") ret_val = get_ret_val("foo", "bar")
res = AddConceptInSetEvaluator().eval(context, ret_val) res = AddConceptInSetEvaluator().eval(context, ret_val)
@@ -69,12 +67,10 @@ class TestAssConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
def test_i_can_add_concept_with_a_body_to_a_set_of_concept(self): def test_i_can_add_concept_with_a_body_to_a_set_of_concept(self):
context = self.get_context() context = self.get_context()
foo = Concept("foo", body="1") foo = Concept("foo", body="1")
context.sheerka.set_id_if_needed(foo, False) context.sheerka.create_new_concept(context, foo)
context.sheerka.add_in_cache(foo)
bar = Concept("bar") bar = Concept("bar")
context.sheerka.set_id_if_needed(bar, False) context.sheerka.create_new_concept(context, bar)
context.sheerka.add_in_cache(bar)
ret_val = get_ret_val("foo", "bar") ret_val = get_ret_val("foo", "bar")
res = AddConceptInSetEvaluator().eval(context, ret_val) res = AddConceptInSetEvaluator().eval(context, ret_val)
@@ -85,12 +81,10 @@ class TestAssConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
def test_i_cannot_add_the_same_concept_twice(self): def test_i_cannot_add_the_same_concept_twice(self):
context = self.get_context() context = self.get_context()
foo = Concept("foo") foo = Concept("foo")
context.sheerka.set_id_if_needed(foo, False) context.sheerka.create_new_concept(context, foo)
context.sheerka.add_in_cache(foo)
bar = Concept("bar") bar = Concept("bar")
context.sheerka.set_id_if_needed(bar, False) context.sheerka.create_new_concept(context, bar)
context.sheerka.add_in_cache(bar)
ret_val = get_ret_val("foo", "bar") ret_val = get_ret_val("foo", "bar")
AddConceptInSetEvaluator().eval(context, ret_val) AddConceptInSetEvaluator().eval(context, ret_val)
@@ -98,5 +92,5 @@ class TestAssConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
assert not res.status assert not res.status
assert context.sheerka.isinstance(res.value, BuiltinConcepts.CONCEPT_ALREADY_IN_SET) assert context.sheerka.isinstance(res.value, BuiltinConcepts.CONCEPT_ALREADY_IN_SET)
assert res.value.concept == foo assert res.value.concept.key == foo.key
assert res.value.concept_set == bar assert res.value.concept_set.key == bar.key