Refactord Concept class to regroup all builtins properties into a ConceptMetadata class
This commit is contained in:
+79
-39
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user