Refactord Concept class to regroup all builtins properties into a ConceptMetadata class

This commit is contained in:
2019-11-30 18:16:20 +01:00
parent 5e539a4b28
commit 75c8793d53
13 changed files with 186 additions and 147 deletions
+79 -39
View File
@@ -1,4 +1,5 @@
import hashlib
from dataclasses import dataclass
from enum import Enum
import logging
@@ -6,6 +7,14 @@ from core.tokenizer import Tokenizer, TokenKind
log = logging.getLogger(__name__)
PROPERTIES_FOR_DIGEST = ("name", "key",
"definition", "definition_type",
"is_builtin", "is_unique",
"where", "pre", "post", "body",
"desc")
PROPERTIES_TO_SERIALIZE = PROPERTIES_FOR_DIGEST + tuple(["id"])
VARIABLE_PREFIX = "__var__"
class ConceptParts(Enum):
"""
@@ -17,6 +26,26 @@ class ConceptParts(Enum):
POST = "post"
BODY = "body"
@staticmethod
def get_parts():
return set(item.value for item in ConceptParts)
@dataclass
class ConceptMetadata:
name: str
is_builtin: bool
is_unique: bool
key: str # name od the concept, where prop are replaced. to ease search
body: str # main method, can also be the value of the concept
where: str # condition to recognize variables in name
pre: str # list of pre conditions before calling the main function
post: str # list of post conditions after calling the main function
definition: str # regex used to define the concept
definition_type: str # definition can be done with something else than regex
desc: str # possible description for the concept
id: str # unique identifier for a concept. The id will never be modified (but the key can)
class Concept:
"""
@@ -24,51 +53,49 @@ class Concept:
A concept is a the base object of our universe
Everything is a concept
"""
props_for_digest = ("is_builtin", "is_unique", "key", "name", "where", "pre", "post", "body", "desc")
props_to_serialize = ("id", "is_builtin", "is_unique", "key", "name", "where", "pre", "post", "body", "desc")
concept_parts = set(item.value for item in ConceptParts)
PROPERTY_PREFIX = "__var__"
def __init__(self, name=None,
is_builtin=False,
is_unique=False,
key=None,
body=None,
where=None,
pre=None,
post=None,
body=None,
definition=None,
definition_type=None,
desc=None,
obj=None):
id=None):
self.name = str(name) if name else None
self.is_builtin = is_builtin
self.is_unique = is_unique
self.key = str(key) if key else None # name od the concept, where prop are replaced. to ease search
metadata = ConceptMetadata(
str(name) if name else None,
is_builtin,
is_unique,
str(key) if key else None,
body,
where,
pre,
post,
definition,
definition_type,
desc,
id
)
self.where = where # condition to recognize variables in name
self.pre = pre # list of pre conditions before calling the main function
self.post = post # list of post conditions after calling the main function
self.body = body # main method, can also be the value of the concept
self.desc = desc
self.id = None # unique identifier for a concept. The id will never be modified
self.obj = obj # main of principal property of the concept
self.metadata = metadata
self.props = {} # list of Property for this concept
self.functions = {} # list of helper functions
self.codes = {} # cached ast for the where, pre, post and body parts
self.cached_asts = {} # cached ast for the where, pre, post and body parts
def __repr__(self):
return f"({self.id}){self.name}"
return f"({self.metadata.id}){self.metadata.name}"
def __eq__(self, other):
if not isinstance(other, Concept):
return False
# check the attributes
for prop in self.props_to_serialize:
if getattr(self, prop) != getattr(other, prop):
for prop in PROPERTIES_TO_SERIALIZE:
if getattr(self.metadata, prop) != getattr(other.metadata, prop):
# print(prop) # use full to know which id does not match
return False
@@ -80,10 +107,19 @@ class Concept:
return True
def __hash__(self):
return hash(self.name)
return hash(self.metadata.name)
def get_key(self):
return self.key
@property
def name(self):
return self.metadata.name
@property
def id(self):
return self.metadata.id
@property
def key(self):
return self.metadata.key
def init_key(self, tokens=None):
"""
@@ -94,11 +130,11 @@ class Concept:
:param tokens:
:return:
"""
if self.key is not None:
if self.metadata.key is not None:
return self
if tokens is None:
tokens = iter(Tokenizer(self.name))
tokens = iter(Tokenizer(self.metadata.name))
variables = list(self.props.keys())
@@ -112,14 +148,18 @@ class Concept:
if not first:
key += " "
if variables is not None and token.value in variables:
key += self.PROPERTY_PREFIX + str(variables.index(token.value))
key += VARIABLE_PREFIX + str(variables.index(token.value))
else:
key += token.value[1:-1] if token.type == TokenKind.STRING else token.value
first = False
self.key = key
self.metadata.key = key
return self
@property
def body(self):
return self.metadata.body
def add_codes(self, codes):
"""
Gets the ASTs for 'where', 'pre', 'post' and 'body'
@@ -131,12 +171,12 @@ class Concept:
:param codes:
:return:
"""
possibles_codes = self.concept_parts
possibles_codes = ConceptParts.get_parts()
if codes is None:
return
for key in codes:
if key in possibles_codes:
self.codes[ConceptParts(key)] = codes[key]
self.cached_asts[ConceptParts(key)] = codes[key]
return self
@@ -145,7 +185,7 @@ class Concept:
Returns the digest of the event
:return: hexa form of the sha256
"""
return hashlib.sha256(f"Concept:{self.to_dict(self.props_for_digest)}".encode("utf-8")).hexdigest()
return hashlib.sha256(f"Concept:{self.to_dict(PROPERTIES_FOR_DIGEST)}".encode("utf-8")).hexdigest()
def to_dict(self, props_to_use=None):
"""
@@ -153,9 +193,9 @@ class Concept:
:return:
"""
props_to_use = props_to_use or self.props_to_serialize
props_to_use = props_to_use or PROPERTIES_TO_SERIALIZE
props_as_dict = dict((prop, getattr(self, prop)) for prop in props_to_use)
props_as_dict = dict((prop, getattr(self.metadata, prop)) for prop in props_to_use)
props_as_dict["props"] = [(p, self.props[p].value) for p in self.props]
return props_as_dict
@@ -165,9 +205,9 @@ class Concept:
:param as_dict:
:return:
"""
for prop in self.props_to_serialize:
for prop in PROPERTIES_TO_SERIALIZE:
if prop in as_dict:
setattr(self, prop, as_dict[prop])
setattr(self.metadata, prop, as_dict[prop])
if "props" in as_dict:
for n, v in as_dict["props"]:
self.set_prop(n, v)