1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- from services.bottom.V0 import Bottom
- from uuid import UUID
- class CDAPI:
- def __init__(self, state, m: UUID):
- self.state = state
- self.bottom = Bottom(state)
- self.m = m
- self.mm = UUID(state.read_value(state.read_dict(state.read_root(), "SCD")))
- # pre-compute some things
- # element -> name
- self.type_model_names = {
- self.bottom.read_outgoing_elements(self.m, e)[0]
- : e for e in self.bottom.read_keys(self.m)
- }
- inh_type, = self.bottom.read_outgoing_elements(self.mm, "Inheritance")
- inh_links = []
- for tm_element, tm_name in self.type_model_names.items():
- types = self.bottom.read_outgoing_elements(tm_element, "Morphism")
- if inh_type in types:
- inh_links.append(tm_element)
- # for each inheritance link we add the parent and child to the sub types map
- # name -> name
- self.direct_sub_types = { type_name: set() for type_name in self.bottom.read_keys(self.m) } # empty initially
- self.direct_super_types = { type_name: set() for type_name in self.bottom.read_keys(self.m) } # empty initially
- for link in inh_links:
- tm_source = self.bottom.read_edge_source(link)
- tm_target = self.bottom.read_edge_target(link)
- parent_name = self.type_model_names[tm_target]
- child_name = self.type_model_names[tm_source]
- self.direct_sub_types[parent_name].add(child_name)
- self.direct_super_types[child_name].add(parent_name)
- def get_transitive_sub_types(type_name: str):
- # includes the type itself - reason: if we want to get all the instances of some type and its subtypes, we don't have to consider the type itself as an extra case
- return [type_name, *(sub_type for child_name in self.direct_sub_types.get(type_name, set()) for sub_type in get_transitive_sub_types(child_name) )]
- def get_transitive_super_types(type_name: str):
- # includes the type itself - reason: if we want to check if something is an instance of a type, we check if its type or one of its super types is equal to the type we're looking for, without having to consider the instance's type itself as an extra case
- return [type_name, *(super_type for parent_name in self.direct_super_types.get(type_name, set()) for super_type in get_transitive_super_types(parent_name))]
- # The transitive sub-/super-types of every type includes the type itself.
- # This is because, often we want to know if an instance's type is 'compatible' (substitutible) with a specified type.
- self.transitive_sub_types = { type_name: set(get_transitive_sub_types(type_name)) for type_name in self.direct_sub_types }
- self.transitive_super_types = { type_name: set(get_transitive_super_types(type_name)) for type_name in self.direct_super_types }
- def get(self, type_name: str):
- return self.bottom.read_outgoing_elements(self.m, type_name)[0]
- def is_direct_subtype(self, super_type_name: str, sub_type_name: str):
- return sub_type_name in self.direct_sub_types[super_type_name]
- def is_direct_supertype(self, sub_type_name: str, super_type_name: str):
- return super_type_name in self.direct_super_types[sub_type_name]
- # Note: according to this function, every class is a subtype of itself
- def is_subtype(self, super_type_name: str, sub_type_name: str):
- return sub_type_name in self.transitive_sub_types[super_type_name]
- # Note: according to this function, every class is a supertype of itself
- def is_supertype(self, sub_type_name: str, super_type_name: str):
- return super_type_name in self.transitive_super_types[sub_type_name]
- # # The edge connecting an object to the value of a slot must be named `{object_name}_{attr_name}`
- def get_attr_link_name(self, class_name, attr_name):
- attr_type_link = self.find_attribute_type(class_name, attr_name)
- if attr_type_link != None:
- return self.type_model_names[attr_type_link]
- # Attributes are inherited, so when we instantiate an attribute of a class, the AttributeLink may contain the name of the superclass
- def find_attribute_type(self, class_name: str, attr_name: str):
- assoc_name = f"{class_name}_{attr_name}"
- type_edges = self.bottom.read_outgoing_elements(self.m, assoc_name)
- if len(type_edges) == 1:
- return type_edges[0]
- else:
- for supertype in self.direct_super_types[class_name]:
- result = self.find_attribute_type(supertype, attr_name)
- if result != None:
- return result
- def get_type(self, type_name: str):
- return next(k for k, v in self.type_model_names.items() if v == type_name)
|