Compare commits

..

6 commits

Author SHA1 Message Date
07edcc0a8e Merge remote-tracking branch 'github/development' into development 2025-02-05 16:27:01 +01:00
a95a99f722 Merge remote-tracking branch 'github/development' into development 2025-02-05 16:26:37 +01:00
Inte Vleminckx
51b8bdb001 Add test for bytes type 2025-02-05 16:26:30 +01:00
e0136937b9 cleanup 2025-02-05 16:26:22 +01:00
Inte Vleminckx
98f36c4cf0 Adding bytes as a type 2025-02-05 16:24:22 +01:00
Inte Vleminckx
86cd7027f3 Adding bytes as a type 2025-02-05 16:01:56 +01:00
11 changed files with 77 additions and 17 deletions

View file

@ -5,6 +5,7 @@ from services.primitives.boolean_type import Boolean
from services.primitives.integer_type import Integer from services.primitives.integer_type import Integer
from services.primitives.string_type import String from services.primitives.string_type import String
from services.primitives.actioncode_type import ActionCode from services.primitives.actioncode_type import ActionCode
from services.primitives.bytes_type import Bytes
from uuid import UUID from uuid import UUID
from typing import Optional from typing import Optional
from util.timer import Timer from util.timer import Timer
@ -41,6 +42,7 @@ class ODAPI:
self.create_integer_value = self.od.create_integer_value self.create_integer_value = self.od.create_integer_value
self.create_string_value = self.od.create_string_value self.create_string_value = self.od.create_string_value
self.create_actioncode_value = self.od.create_actioncode_value self.create_actioncode_value = self.od.create_actioncode_value
self.create_bytes_value = self.od.create_bytes_value
self.__recompute_mappings() self.__recompute_mappings()
@ -208,6 +210,8 @@ class ODAPI:
tgt = self.create_actioncode_value(name, value) tgt = self.create_actioncode_value(name, value)
else: else:
tgt = self.create_string_value(name, value) tgt = self.create_string_value(name, value)
elif isinstance(value, bytes):
tgt = self.create_bytes_value(name, value)
else: else:
raise Exception("Unimplemented type "+value) raise Exception("Unimplemented type "+value)
self.__recompute_mappings() self.__recompute_mappings()
@ -235,6 +239,10 @@ class ODAPI:
if to_overwrite_type != "String": if to_overwrite_type != "String":
raise Exception(f"Cannot assign string value '{value}' to value of type {to_overwrite_type}.") raise Exception(f"Cannot assign string value '{value}' to value of type {to_overwrite_type}.")
String(referred_model, self.state).create(value) String(referred_model, self.state).create(value)
elif isinstance(value, bytes):
if to_overwrite_type != "Bytes":
raise Exception(f"Cannot assign bytes value '{value}' to value of type {to_overwrite_type}.")
Bytes(referred_model, self.state).create(value)
else: else:
raise Exception("Unimplemented type "+value) raise Exception("Unimplemented type "+value)

View file

@ -47,7 +47,7 @@ def bootstrap_constraint(class_node, type_name: str, python_type: str, scd_root:
bottom.create_edge(constraint_node, scd_node, "Morphism") bottom.create_edge(constraint_node, scd_node, "Morphism")
bottom.create_edge(constraint_link, scd_link, "Morphism") bottom.create_edge(constraint_link, scd_link, "Morphism")
def bootstrap_primitive_types(scd_root, state, integer_type, boolean_type, float_type, string_type, type_type, actioncode_type): def bootstrap_primitive_types(scd_root, state, integer_type, boolean_type, float_type, string_type, type_type, actioncode_type, bytes_type):
# Order is important: Integer must come first # Order is important: Integer must come first
class_integer = bootstrap_type("Integer", scd_root, integer_type, state) class_integer = bootstrap_type("Integer", scd_root, integer_type, state)
class_type = bootstrap_type("Type", scd_root, type_type, state) class_type = bootstrap_type("Type", scd_root, type_type, state)
@ -55,6 +55,7 @@ def bootstrap_primitive_types(scd_root, state, integer_type, boolean_type, float
class_float = bootstrap_type("Float", scd_root, float_type, state) class_float = bootstrap_type("Float", scd_root, float_type, state)
class_string = bootstrap_type("String", scd_root, string_type, state) class_string = bootstrap_type("String", scd_root, string_type, state)
class_actioncode = bootstrap_type("ActionCode", scd_root, actioncode_type, state) class_actioncode = bootstrap_type("ActionCode", scd_root, actioncode_type, state)
class_bytes = bootstrap_type("Bytes", scd_root, bytes_type, state)
# Can only create constraints after ActionCode type has been created: # Can only create constraints after ActionCode type has been created:
bootstrap_constraint(class_integer, "Integer", "int", scd_root, integer_type, actioncode_type, state) bootstrap_constraint(class_integer, "Integer", "int", scd_root, integer_type, actioncode_type, state)
@ -63,3 +64,4 @@ def bootstrap_primitive_types(scd_root, state, integer_type, boolean_type, float
bootstrap_constraint(class_float, "Float", "float", scd_root, float_type, actioncode_type, state) bootstrap_constraint(class_float, "Float", "float", scd_root, float_type, actioncode_type, state)
bootstrap_constraint(class_string, "String", "str", scd_root, string_type, actioncode_type, state) bootstrap_constraint(class_string, "String", "str", scd_root, string_type, actioncode_type, state)
bootstrap_constraint(class_actioncode, "ActionCode", "str", scd_root, actioncode_type, actioncode_type, state) bootstrap_constraint(class_actioncode, "ActionCode", "str", scd_root, actioncode_type, actioncode_type, state)
bootstrap_constraint(class_bytes, "Bytes", "bytes", scd_root, bytes_type, actioncode_type, state)

View file

@ -2,15 +2,7 @@ from state.base import State, UUID
from services.bottom.V0 import Bottom from services.bottom.V0 import Bottom
from services.primitives.boolean_type import Boolean from services.primitives.boolean_type import Boolean
from services.primitives.string_type import String from services.primitives.string_type import String
from bootstrap.primitive import ( from bootstrap.primitive import bootstrap_primitive_types
bootstrap_primitive_types
# bootstrap_boolean_type,
# bootstrap_float_type,
# bootstrap_integer_type,
# bootstrap_string_type,
# bootstrap_type_type,
# bootstrap_actioncode_type
)
def create_model_root(bottom: Bottom, model_name: str) -> UUID: def create_model_root(bottom: Bottom, model_name: str) -> UUID:
@ -32,6 +24,7 @@ def bootstrap_scd(state: State) -> UUID:
float_type_root = create_model_root(bottom, "Float") float_type_root = create_model_root(bottom, "Float")
type_type_root = create_model_root(bottom, "Type") type_type_root = create_model_root(bottom, "Type")
actioncode_type_root = create_model_root(bottom, "ActionCode") actioncode_type_root = create_model_root(bottom, "ActionCode")
bytes_type_root = create_model_root(bottom, "Bytes")
# create MCL, without morphism links # create MCL, without morphism links
@ -132,7 +125,8 @@ def bootstrap_scd(state: State) -> UUID:
float_type_root, float_type_root,
string_type_root, string_type_root,
type_type_root, type_type_root,
actioncode_type_root) actioncode_type_root,
bytes_type_root)
# bootstrap_integer_type(mcl_root, integer_type_root, integer_type_root, actioncode_type_root, state) # bootstrap_integer_type(mcl_root, integer_type_root, integer_type_root, actioncode_type_root, state)
# bootstrap_boolean_type(mcl_root, boolean_type_root, integer_type_root, actioncode_type_root, state) # bootstrap_boolean_type(mcl_root, boolean_type_root, integer_type_root, actioncode_type_root, state)
# bootstrap_float_type(mcl_root, float_type_root, integer_type_root, actioncode_type_root, state) # bootstrap_float_type(mcl_root, float_type_root, integer_type_root, actioncode_type_root, state)

View file

@ -16,6 +16,8 @@ def display_value(val: any, type_name: str, indentation=0, newline_character='\n
return '"'+val+'"'.replace('\n', newline_character) return '"'+val+'"'.replace('\n', newline_character)
elif type_name == "Integer" or type_name == "Boolean": elif type_name == "Integer" or type_name == "Boolean":
return str(val) return str(val)
elif type_name == "Bytes":
return val
else: else:
raise Exception("don't know how to display value" + type_name) raise Exception("don't know how to display value" + type_name)
@ -48,6 +50,9 @@ class TBase(Transformer):
def CODE(self, token): def CODE(self, token):
return _Code(str(token[1:-1])) # strip the `` return _Code(str(token[1:-1])) # strip the ``
def BYTES(self, token):
return (bytes(token[2:-1], "utf-8"), token.line) # Strip b"" or b''
def INDENTED_CODE(self, token): def INDENTED_CODE(self, token):
skip = 4 # strip the ``` and the following newline character skip = 4 # strip the ``` and the following newline character
space_count = 0 space_count = 0

View file

@ -21,6 +21,7 @@ literal: INT
| STR | STR
| BOOL | BOOL
| CODE | CODE
| BYTES
| INDENTED_CODE | INDENTED_CODE
INT: /[0-9]+/ INT: /[0-9]+/
@ -28,6 +29,8 @@ STR: /"[^"]*"/
| /'[^']*'/ | /'[^']*'/
BOOL: "True" | "False" BOOL: "True" | "False"
CODE: /`[^`]*`/ CODE: /`[^`]*`/
BYTES: /b"[^"]*"/
| /b'[^']*'/
INDENTED_CODE: /```[^`]*```/ INDENTED_CODE: /```[^`]*```/
type_name: IDENTIFIER type_name: IDENTIFIER
@ -67,7 +70,7 @@ def parse_od(state,
primitive_types = { primitive_types = {
type_name : UUID(state.read_value(state.read_dict(state.read_root(), type_name))) type_name : UUID(state.read_value(state.read_dict(state.read_root(), type_name)))
for type_name in ["Integer", "String", "Boolean", "ActionCode"] for type_name in ["Integer", "String", "Boolean", "ActionCode", "Bytes"]
} }
class T(Transformer): class T(Transformer):
@ -89,6 +92,10 @@ def parse_od(state,
def CODE(self, token): def CODE(self, token):
return (_Code(str(token[1:-1])), token.line) # strip the `` return (_Code(str(token[1:-1])), token.line) # strip the ``
def BYTES(self, token):
# return (bytes(token[2:-1], "utf-8"), token.line) # Strip b"" or b''
return (bytes(token[2:-1], "utf-8"), token.line) # Strip b"" or b''
def INDENTED_CODE(self, token): def INDENTED_CODE(self, token):
skip = 4 # strip the ``` and the following newline character skip = 4 # strip the ``` and the following newline character
space_count = 0 space_count = 0

View file

@ -9,7 +9,7 @@ def render_od(state, m_id, mm_id, hide_names=True):
m_od = od.OD(mm_id, m_id, state) m_od = od.OD(mm_id, m_id, state)
serialized = set(["Integer", "String", "Boolean", "ActionCode"]) # assume these types always already exist serialized = set(["Integer", "String", "Boolean", "ActionCode", "Bytes"]) # assume these types always already exist
def display_name(name: str): def display_name(name: str):
# object names that start with "__" are hidden # object names that start with "__" are hidden

View file

@ -5,6 +5,7 @@ from services.primitives.integer_type import Integer
from services.primitives.string_type import String from services.primitives.string_type import String
from services.primitives.boolean_type import Boolean from services.primitives.boolean_type import Boolean
from services.primitives.actioncode_type import ActionCode from services.primitives.actioncode_type import ActionCode
from services.primitives.bytes_type import Bytes
from api.cd import CDAPI from api.cd import CDAPI
from typing import Optional from typing import Optional
@ -147,6 +148,13 @@ class OD:
actioncode_t.create(value) actioncode_t.create(value)
return self.create_model_ref(name, "ActionCode", actioncode_node) return self.create_model_ref(name, "ActionCode", actioncode_node)
def create_bytes_value(self, name: str, value: str):
from services.primitives.bytes_type import Bytes
bytes_node = self.bottom.create_node()
bytes_t = Bytes(bytes_node, self.bottom.state)
bytes_t.create(value)
return self.create_model_ref(name, "Bytes", bytes_node)
# Identical to the same SCD method: # Identical to the same SCD method:
def create_model_ref(self, name: str, type_name: str, model: UUID): def create_model_ref(self, name: str, type_name: str, model: UUID):
# create element + morphism links # create element + morphism links
@ -389,6 +397,8 @@ def read_primitive_value(bottom, modelref: UUID, mm: UUID):
return Boolean(referred_model, bottom.state).read(), typ_name return Boolean(referred_model, bottom.state).read(), typ_name
elif typ_name == "ActionCode": elif typ_name == "ActionCode":
return ActionCode(referred_model, bottom.state).read(), typ_name return ActionCode(referred_model, bottom.state).read(), typ_name
elif typ_name == "Bytes":
return Bytes(referred_model, bottom.state).read(), typ_name
else: else:
raise Exception("Unimplemented type:", typ_name) raise Exception("Unimplemented type:", typ_name)

View file

@ -0,0 +1,24 @@
from uuid import UUID
from state.base import State
from services.bottom.V0 import Bottom
class Bytes:
def __init__(self, model: UUID, state: State):
self.model = model
self.bottom = Bottom(state)
type_model_id_node, = self.bottom.read_outgoing_elements(state.read_root(), "Bytes")
self.type_model = UUID(self.bottom.read_value(type_model_id_node))
def create(self, value: bool):
if "bytes" in self.bottom.read_keys(self.model):
instance, = self.bottom.read_outgoing_elements(self.model, "bytes")
self.bottom.delete_element(instance)
_instance = self.bottom.create_node(value)
self.bottom.create_edge(self.model, _instance, "bytes")
_type, = self.bottom.read_outgoing_elements(self.type_model, "Bytes")
self.bottom.create_edge(_instance, _type, "Morphism")
def read(self):
instance, = self.bottom.read_outgoing_elements(self.model, "bytes")
return self.bottom.read_value(instance)

View file

@ -2,13 +2,14 @@ from abc import ABC, abstractmethod
from typing import Any, List, Tuple, Optional, Union from typing import Any, List, Tuple, Optional, Union
from uuid import UUID, uuid4 from uuid import UUID, uuid4
primitive_types = (int, float, str, bool) primitive_types = (int, float, str, bool, bytes)
INTEGER = ("Integer",) INTEGER = ("Integer",)
FLOAT = ("Float",) FLOAT = ("Float",)
STRING = ("String",) STRING = ("String",)
BOOLEAN = ("Boolean",) BOOLEAN = ("Boolean",)
TYPE = ("Type",) TYPE = ("Type",)
type_values = (INTEGER, FLOAT, STRING, BOOLEAN, TYPE) BYTES = ("Bytes",)
type_values = (INTEGER, FLOAT, STRING, BOOLEAN, TYPE, BYTES)
Node = UUID Node = UUID

View file

@ -171,3 +171,12 @@ def test_create_nodevalue_string_type(state):
def test_create_nodevalue_invalid_type(state): def test_create_nodevalue_invalid_type(state):
id1 = state.create_nodevalue(("Class",)) id1 = state.create_nodevalue(("Class",))
assert id1 == None assert id1 == None
@pytest.mark.usefixtures("state")
def test_create_nodevalue_bytes_type(state):
id1 = state.create_nodevalue(("Bytes",))
assert id1 != None
v = state.read_value(id1)
assert v == ("Bytes",)

View file

@ -4,7 +4,7 @@ from concrete_syntax.textual_od import parser, renderer
from services.scd import SCD from services.scd import SCD
from util.timer import Timer from util.timer import Timer
PRIMITIVE_TYPES = set(["Integer", "String", "Boolean", "ActionCode"]) PRIMITIVE_TYPES = set(["Integer", "String", "Boolean", "ActionCode", "Bytes"])
# Merges N models. The models must have the same meta-model. # Merges N models. The models must have the same meta-model.
# Care should be taken to avoid naming collisions before calling this function. # Care should be taken to avoid naming collisions before calling this function.
@ -12,7 +12,7 @@ def merge_models(state, mm, models: list[UUID]):
with Timer("merge_models"): with Timer("merge_models"):
primitive_types = { primitive_types = {
type_name : UUID(state.read_value(state.read_dict(state.read_root(), type_name))) type_name : UUID(state.read_value(state.read_dict(state.read_root(), type_name)))
for type_name in ["Integer", "String", "Boolean", "ActionCode"] for type_name in ["Integer", "String", "Boolean", "ActionCode", "Bytes"]
} }
merged = state.create_node() merged = state.create_node()