From 5e4546260840a24d02471ad8cbb02ab10aa950a5 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Sun, 31 Mar 2024 00:58:51 -0400 Subject: [PATCH] major updates to mocha-shell --- python/mocha-shell.py | 330 +++++++++++------- python/mocha/core/InstanceKey.py | 5 +- .../mocha/definitions/KnownAttributeGuids.py | 5 +- python/mocha/definitions/KnownClassGuids.py | 2 + python/mocha/oms/Oms.py | 64 +++- python/mocha/oms/OmsResult.py | 9 + python/mocha/oms/__init__.py | 1 + .../mocha/oms/db/sqlite/SQLiteDatabaseOms.py | 7 +- 8 files changed, 287 insertions(+), 136 deletions(-) create mode 100644 python/mocha/oms/OmsResult.py diff --git a/python/mocha-shell.py b/python/mocha-shell.py index 1f705ec..5e018ae 100644 --- a/python/mocha-shell.py +++ b/python/mocha-shell.py @@ -47,9 +47,6 @@ atexit.register(readline.write_history_file, histfile) colorama.init() -def clear(): - print("\033c", end='') - class MochaShell (REPLApplication): def print_instance_list(self, instances : list): @@ -190,32 +187,44 @@ class MochaShell (REPLApplication): prompt += "> " return prompt - def process_input(self, value): - parms = value.split(' ') + def interactive_create_attribute(self, attr_class : InstanceReference): - if len(parms) > 0: + att_Name = self.oms.get_instance_by_global_identifier(KnownAttributeGuids.Name) - if parms[0] == "cd": - os.chdir(parse_cwd(parms[1])) + name = input("name: ") + if name == "": + print("please specify a name") + return None - elif parms[0] == "ls": + attr = self.oms.create_instance_of(attr_class) + self.oms.set_attribute_value(attr, att_Name, name) + return attr + + def process_input(self, value, quotes): + + if len(value) > 0: + + if value[0] == "cd": + os.chdir(parse_cwd(value[1])) + + elif value[0] == "ls": os.system("ls --color=always") - elif parms[0] == "open": + elif value[0] == "open": - if len(parms) == 2: + if len(value) == 2: - if parms[1] == "database": + if value[1] == "database": - if len(parms) > 2: + if len(value) > 2: - self.open_file(self.oms, parms[2]) + self.open_file(self.oms, value[2]) return else: print("usage: open database|tenant 'filename'") - elif parms[1] == "tenant": + elif value[1] == "tenant": print("error: not implemented") @@ -224,131 +233,212 @@ class MochaShell (REPLApplication): else: # default to "open database ..." - self.open_file(self.oms, parms[1]) + self.open_file(self.oms, value[1]) return else: print("usage: open database|tenant 'filename'") - elif parms[0] == "create": + elif value[0] == "create": - self.create_file(self.oms, parms[1]) + if len (value) > 1: - self.open_file(self.oms, parms[1]) + self.create_file(self.oms, value[1]) - # print ("error: no database open, use `open filename.mql` first") + self.open_file(self.oms, value[1]) - elif parms[0] == "instance": + else: - if parms[1] == "create": + print("usage: create filename.mql") + # print ("error: no database open, use `open filename.mql` first") - if len(parms) == 3: + elif value[0] == "instance": - iid = self.parse(parms[2]) - inst = self.oms.create_instance_of(iid) - print(inst) + if len(value) > 1: - else: - print("usage: instance create class_iid [index]") + if value[1] == "create": - elif parms[1] == "get": + if len(value) == 3: - if len(parms) == 3: - iid = self.parse(parms[2]) - print(iid) + iid = self.parse(value[2]) + inst = self.oms.create_instance_of(iid) + print(inst) - elif parms[1] == "list": + else: + print("usage: instance create class_iid [index]") - if not self.oms.is_open(): - self.print_error_not_open() - return + elif value[1] == "get": - ik_of = None - if len(parms) > 2: - ik_of = self.parse(parms[2]) + if len(value) == 3: + iid = self.parse(value[2]) + print(iid) - instances = self.oms.get_instances(ik_of) - self.print_instance_list(instances) - - elif parms[0] == "attribute": - - if parms[1] == "list": - - if len(parms) == 3: - - inst_id = self.parse(parms[2]) - if inst_id is None: - print("invalid inst id " + parms[2] + " (inst not found)") - return - - attrs = self.oms.get_attributes(inst_id) - self.print_instance_list_with_attribute_values(attrs, self.oms, inst_id) - - else: - - print ("usage: attribute list instance_id") - - elif parms[1] == "get": - - if len(parms) == 4: + elif value[1] == "list": if not self.oms.is_open(): self.print_error_not_open() return - inst_id = self.parse(parms[2]) - att_id = self.parse(parms[3]) + ik_of = None + if len(value) > 2: + ik_of = self.parse(value[2]) + instances = self.oms.get_instances(ik_of) + self.print_instance_list(instances) + + else: + + print("usage: instance create|get|list") + + elif value[0] == "attribute": + + if len(value) > 1: + + if value[1] == "create": + + if len(value) > 2: + + if value[2] == "text" or value[2] == "richtext": + + attrClass = self.oms.get_instance_by_global_identifier(KnownClassGuids.TextAttribute) + if value[2] == "richtext": + attrClass = self.oms.get_instance_by_global_identifier(KnownClassGuids.RichTextAttribute) + + attr = self.interactive_create_attribute(attrClass) + + if attr is None: + return + + att_MaximumLength = self.oms.get_instance_by_global_identifier(KnownAttributeGuids.MaximumLength) + + maxlen = input("maximum length (leave empty for infinite): ") + if maxlen != "": + self.oms.set_attribute_value(attr, att_MaximumLength, int(maxlen)) + + elif value[2] == "boolean": + + attrClass = self.oms.get_instance_by_global_identifier(KnownClassGuids.BooleanAttribute) + attr = self.interactive_create_attribute(attrClass) + + if attr is None: + return + + elif value[2] == "numeric": + + attrClass = self.oms.get_instance_by_global_identifier(KnownClassGuids.NumericAttribute) + attr = self.interactive_create_attribute(attrClass) + + if attr is None: + return + + att_MinimumValue = self.oms.get_instance_by_global_identifier(KnownAttributeGuids.MinimumValue) + att_MaximumValue = self.oms.get_instance_by_global_identifier(KnownAttributeGuids.MaximumValue) + + if att_MinimumValue is None: + print("warning: numeric attribute `Minimum Value` is not defined") + else: + minimum_value = input("minimum value (empty for infinite): ") + if minimum_value != "": + self.oms.set_attribute_value(attr, att_MinimumValue, int(minimum_value)) + + if att_MaximumValue is None: + print("warning: numeric attribute `Maximum Value` is not defined") + else: + maximum_value = input("maximum value (empty for infinite): ") + if maximum_value != "": + self.oms.set_attribute_value(attr, att_MaximumValue, int(maximum_value)) + + else: + + print("usage: attribute create text|boolean|numeric|date|xml|richtext") + + else: + + print("usage: attribute create text|boolean|numeric|date|xml|richtext") + + if value[1] == "list": + + if len(value) == 3: + + inst_id = self.parse(value[2]) + if inst_id is None: + print("invalid inst id " + value[2] + " (inst not found)") + return + + attrs = self.oms.get_attributes(inst_id) + self.print_instance_list_with_attribute_values(attrs, self.oms, inst_id) + + else: + + print ("usage: attribute list instance_id") + + elif value[1] == "get": + + if len(value) == 4: + + if not self.oms.is_open(): + self.print_error_not_open() + return + + inst_id = self.parse(value[2]) + att_id = self.parse(value[3]) + + if inst_id is None: + print("invalid inst id " + self.strip(value[2]) + " (inst not found)") + return + if att_id is None: + print("invalid inst id " + self.strip(value[3]) + " (inst not found)") + return + + value = self.oms.get_attribute_value(inst_id, att_id) + print(value) + + else: + + print("usage: attribute get inst_iid|inst_gid att_iid|att_gid") + + elif value[1] == "set": + + if len(value) == 5: + + if not self.oms.is_open(): + self.print_error_not_open() + return + + inst_id = self.parse(value[2]) + att_id = self.parse(value[3]) + value = value[4] + + if inst_id is None: + print("invalid inst id " + self.strip(value[2]) + " (inst not found)") + return + if att_id is None: + print("invalid inst id " + self.strip(value[3]) + " (inst not found)") + return + + result = self.oms.set_attribute_value(inst_id, att_id, value) + if result.success: + print("ok") + else: + print ("error: " + result.message) + + else: + + print("usage: attribute set inst_iid|inst_gid att_iid|att_gid value") + else: + + print("usage: attribute list|get|set") + + elif value[0] == "relationship": + + if value[1] == "list": + + if len(value) == 3: + + inst_id = self.parse(value[2]) if inst_id is None: - print("invalid inst id " + self.strip(parms[2]) + " (inst not found)") - return - if att_id is None: - print("invalid inst id " + self.strip(parms[3]) + " (inst not found)") - return - - value = self.oms.get_attribute_value(inst_id, att_id) - print(value) - - else: - - print("usage: attribute get inst_iid|inst_gid att_iid|att_gid") - - elif parms[1] == "set": - - if len(parms) == 5: - - if not self.oms.is_open(): - self.print_error_not_open() - return - - inst_id = self.parse(parms[2]) - att_id = self.parse(parms[3]) - value = parms[4] - - if inst_id is None: - print("invalid inst id " + self.strip(parms[2]) + " (inst not found)") - return - if att_id is None: - print("invalid inst id " + self.strip(parms[3]) + " (inst not found)") - return - - self.oms.set_attribute_value(inst_id, att_id, value) - print("ok") - - else: - - print("usage: attribute set inst_iid|inst_gid att_iid|att_gid value") - - elif parms[0] == "relationship": - - if parms[1] == "list": - - if len(parms) == 3: - - inst_id = self.parse(parms[2]) - if inst_id is None: - print("invalid inst id " + parms[2] + " (inst not found)") + print("invalid inst id " + value[2] + " (inst not found)") return rels = self.oms.get_relationships(inst_id) @@ -358,9 +448,9 @@ class MochaShell (REPLApplication): print ("usage: relationship list instance_id") - elif parms[0] == "user": + elif value[0] == "user": - if parms[1] == "list": + if value[1] == "list": ik_User = self.oms.get_instance_by_global_identifier(KnownClassGuids.User) ik_UserName = self.oms.get_instance_by_global_identifier(KnownAttributeGuids.UserName) @@ -378,11 +468,11 @@ class MochaShell (REPLApplication): return - elif parms[1] == "set-password": + elif value[1] == "set-password": - if len(parms) > 2: + if len(value) > 2: - my_username = parms[2] + my_username = value[2] my_user = self.oms.get_user_by_username(my_username) if my_user is None: @@ -401,12 +491,12 @@ class MochaShell (REPLApplication): print("Sorry, passwords do not match.") return - elif parms[0] == "close": + elif value[0] == "close": self.oms.close() else: - print("invalid cmd '" + parms[0] + "'") + print("invalid cmd '" + value[0] + "'") if __name__ == '__main__': diff --git a/python/mocha/core/InstanceKey.py b/python/mocha/core/InstanceKey.py index 0225aed..9936a91 100644 --- a/python/mocha/core/InstanceKey.py +++ b/python/mocha/core/InstanceKey.py @@ -21,4 +21,7 @@ class InstanceKey(): def __str__(self): return str(self.get_class_index()) + '$' + str(self.get_instance_index()) - \ No newline at end of file + + + def __eq__(self, other): + return self.__class_id == other.__class_id and self.__inst_id == other.__inst_id \ No newline at end of file diff --git a/python/mocha/definitions/KnownAttributeGuids.py b/python/mocha/definitions/KnownAttributeGuids.py index 89508ba..7ee244b 100644 --- a/python/mocha/definitions/KnownAttributeGuids.py +++ b/python/mocha/definitions/KnownAttributeGuids.py @@ -49,4 +49,7 @@ ForegroundColor = Guid.parse("BB4B6E0DD9BA403D9E8193E8F7FB31C8") IPAddress = Guid.parse("ADE5A3C3A84E4798BC5BE08F21380208") Token = Guid.parse("da7686b638034f1597f67f8f3ae16668") -DebugDefinitionFileName = Guid.parse("03bf47c7dc9743c8a8c9c6147bee4e1f") \ No newline at end of file +DebugDefinitionFileName = Guid.parse("03bf47c7dc9743c8a8c9c6147bee4e1f") + +MinimumValue = Guid.parse('{bc90ffdf-9b6e-444a-a484-f9d06d7f3c31}') +MaximumValue = Guid.parse('{b9353b1c-2597-4097-96eb-449a6fafcdab}') diff --git a/python/mocha/definitions/KnownClassGuids.py b/python/mocha/definitions/KnownClassGuids.py index bdb6036..bd7a2b6 100644 --- a/python/mocha/definitions/KnownClassGuids.py +++ b/python/mocha/definitions/KnownClassGuids.py @@ -14,6 +14,8 @@ BooleanAttribute = Guid.parse("{EA830448-A403-4ED9-A3D3-048D5D5C3A03}") NumericAttribute = Guid.parse("{9DE86AF1-EFD6-4B71-9DCC-202F247C94CB}") DateAttribute = Guid.parse("{0B7B1812-DFB4-4F25-BF6D-CEB0E1DF8744}") +RichTextAttribute = Guid.parse("{9e393eb5-0b2d-4c31-bc8c-419f9af8aee6}") + Element = Guid.parse("{91929595-3dbd-4eae-8add-6120a49797c7}") ElementContent = Guid.parse("{f85d4f5e-c69f-4498-9913-7a8554e233a4}") diff --git a/python/mocha/oms/Oms.py b/python/mocha/oms/Oms.py index c6fc348..dbddddf 100644 --- a/python/mocha/oms/Oms.py +++ b/python/mocha/oms/Oms.py @@ -3,6 +3,8 @@ from ..definitions import KnownClassGuids, KnownInstanceGuids, KnownAttributeGui from framework import Guid +from .OmsResult import OmsResult + class Oms: def __init__(self): pass @@ -38,6 +40,10 @@ class Oms: self.assign_relationship(ik_current, self.get_instance_by_global_identifier(KnownRelationshipGuids.Relationship__has_sibling__Relationship), sibling_relationship) return ik_current + + def get_parent_class(self, instance : InstanceReference) -> InstanceReference: + ik = InstanceKey(1, instance.get_instance_key().get_class_index()) + return self.get_instance_by_key(ik) def assign_attribute(self, instance : InstanceReference, attribute : InstanceReference, value : str): pass @@ -45,12 +51,43 @@ class Oms: def assign_relationship(self, instance : InstanceReference, relationship : InstanceReference, related_instances : InstanceReference|list): pass - def get_attribute_value(self, inst : InstanceReference, att : InstanceReference, default_value = None): + def get_attribute_value_internal(self, inst : InstanceReference, att : InstanceReference, default_value = None): pass - def set_attribute_value(self, inst : InstanceReference, att : InstanceReference, value): + def get_attribute_value(self, inst : InstanceReference, att : InstanceReference, default_value = None): + value = self.get_attribute_value_internal(inst, att, default_value) + pclass = self.get_parent_class(att) + if pclass is not None: + if pclass.get_global_identifier() == KnownClassGuids.NumericAttribute: + return float(value) + + return value + + def set_attribute_value_internal(self, inst : InstanceReference, att : InstanceReference, value): pass + def set_attribute_value(self, inst : InstanceReference, att : InstanceReference, value) -> OmsResult: + + if inst is None or att is None: + return OmsResult(False, "no value specified for instance reference: inst | att") + + pclass = self.get_parent_class(att) + if pclass is not None: + if pclass.get_global_identifier() == KnownClassGuids.NumericAttribute: + try: + val = float(value) + max_val = self.get_attribute_value(att, self.get_instance_by_global_identifier(KnownAttributeGuids.MaximumValue)) + min_val = self.get_attribute_value(att, self.get_instance_by_global_identifier(KnownAttributeGuids.MinimumValue)) + + if val < min_val or val > max_val: + return OmsResult(False, "parameter out of range: value") + + except ValueError: + return OmsResult(False, "parameter type mismatch: expected int, got " + str(type(value))) + + self.set_attribute_value_internal(inst, att, value) + return OmsResult.SUCCESS + def get_instance_by_key(self, key : InstanceKey): pass @@ -103,7 +140,7 @@ class Oms: user = self.create_instance_of(self.get_instance_by_global_identifier(KnownClassGuids.User), global_identifier) if password is not None: - self.assign_user_password(user, password) + self.set_user_password(user, password) def before_init(self): pass @@ -113,14 +150,15 @@ class Oms: self.create_class(1, 2, 'Attribute', KnownClassGuids.Attribute) ik_Relationship = self.create_class(1, 3, 'Relationship', KnownClassGuids.Relationship) - self.create_class(1, 4, 'Text Attribute', KnownClassGuids.TextAttribute) - self.create_class(1, 5, 'Boolean Attribute', KnownClassGuids.BooleanAttribute) + ik_TextAttribute = self.create_class(1, 4, 'Text Attribute', KnownClassGuids.TextAttribute) + ik_BooleanAttribute = self.create_class(1, 5, 'Boolean Attribute', KnownClassGuids.BooleanAttribute) self.create_class(1, 6, 'Element', KnownClassGuids.Element) - self.create_class(1, 20, 'Numeric Attribute', KnownClassGuids.NumericAttribute) + ik_NumericAttribute = self.create_class(1, 20, 'Numeric Attribute', KnownClassGuids.NumericAttribute) + ik_RichTextAttribute = self.create_class(1, 2737, 'Rich Text Attribute', KnownClassGuids.RichTextAttribute) - self.create_instance_of(self.get_instance_by_global_identifier(KnownClassGuids.TextAttribute), KnownAttributeGuids.Name) - self.create_instance_of(self.get_instance_by_global_identifier(KnownClassGuids.TextAttribute), KnownAttributeGuids.Value) - self.create_instance_of(self.get_instance_by_global_identifier(KnownClassGuids.TextAttribute), KnownAttributeGuids.Token) + att_Name = self.create_instance_of(ik_TextAttribute, KnownAttributeGuids.Name) + att_Value = self.create_instance_of(ik_TextAttribute, KnownAttributeGuids.Value) + att_Token = self.create_instance_of(ik_TextAttribute, KnownAttributeGuids.Token) rel_Relationship__has_source__Class = self.create_instance_of(self.get_instance_by_global_identifier(KnownClassGuids.Relationship), KnownRelationshipGuids.Relationship__has_source__Class) rel_Relationship__has_destination__Class = self.create_instance_of(self.get_instance_by_global_identifier(KnownClassGuids.Relationship), KnownRelationshipGuids.Relationship__has_destination__Class) @@ -173,6 +211,14 @@ class Oms: self.update_relationship(rel_Class__has__Instance, None, None, None, None, rel_Instance__for__Class) self.update_relationship(rel_Instance__for__Class, None, None, None, None, rel_Class__has__Instance) + ik_MaximumLength = self.create_instance_of(ik_NumericAttribute, KnownAttributeGuids.MaximumLength) + self.set_attribute_value(ik_MaximumLength, att_Name, "Maximum Length") + + ik_MinimumValue = self.create_instance_of(ik_NumericAttribute, KnownAttributeGuids.MinimumValue) + self.set_attribute_value(ik_MinimumValue, att_Name, "Minimum Value") + ik_MaximumValue = self.create_instance_of(ik_NumericAttribute, KnownAttributeGuids.MaximumValue) + self.set_attribute_value(ik_MaximumValue, att_Name, "Maximum Value") + self.update_class_instances() def update_relationship(self, relationship : InstanceReference, src_class : InstanceReference, type : str, dst_class : InstanceReference, singular: bool, sibling_relationship : InstanceReference): diff --git a/python/mocha/oms/OmsResult.py b/python/mocha/oms/OmsResult.py new file mode 100644 index 0000000..9e72f7a --- /dev/null +++ b/python/mocha/oms/OmsResult.py @@ -0,0 +1,9 @@ +class OmsResult: + + def __init__(self, success : bool, message : str): + self.success = success + self.message = message + + +OmsResult.SUCCESS = OmsResult(True, "the operation completed successfully") + \ No newline at end of file diff --git a/python/mocha/oms/__init__.py b/python/mocha/oms/__init__.py index 4085b15..ecf6cbb 100644 --- a/python/mocha/oms/__init__.py +++ b/python/mocha/oms/__init__.py @@ -1 +1,2 @@ from .Oms import Oms +from .OmsResult import OmsResult diff --git a/python/mocha/oms/db/sqlite/SQLiteDatabaseOms.py b/python/mocha/oms/db/sqlite/SQLiteDatabaseOms.py index e36dd25..f923285 100644 --- a/python/mocha/oms/db/sqlite/SQLiteDatabaseOms.py +++ b/python/mocha/oms/db/sqlite/SQLiteDatabaseOms.py @@ -180,7 +180,7 @@ class SQLiteDatabaseOms (DatabaseOms): # return retval - def get_attribute_value(self, inst : InstanceReference, att : InstanceReference, default_value = None): + def get_attribute_value_internal(self, inst : InstanceReference, att : InstanceReference, default_value = None): if inst is None or att is None: return None @@ -190,10 +190,7 @@ class SQLiteDatabaseOms (DatabaseOms): return results[0][0] return None - def set_attribute_value(self, inst : InstanceReference, att : InstanceReference, value): - if inst is None or att is None: - return - + def set_attribute_value_internal(self, inst : InstanceReference, att : InstanceReference, value): cursor = self.conn.execute("INSERT INTO attributes (src_inst_id, att_inst_id, att_value, effective_date) VALUES (?, ?, ?, CURRENT_TIMESTAMP)", [inst.dbid, att.dbid, value]) self.conn.commit()