def merge_slot(self, slot: SlotDefinition, merged_slots: List[SlotDefinitionName]) -> None: """ Merge parent slot information into target slot :param slot: target slot :param merged_slots: list of slot names that have been merged. Used to do a distal ancestor resolution """ if slot.name not in merged_slots: if slot.is_a: if slot.is_a in self.schema.slots: self.merge_slot(self.schema.slots[slot.is_a], merged_slots) merge_slots(slot, self.schema.slots[slot.is_a]) else: self.raise_value_error( f'Slot: "{slot.name}" - unknown is_a reference: {slot.is_a}' ) for mixin in slot.mixins: if mixin in self.schema.slots: self.merge_slot(self.schema.slots[mixin], merged_slots) merge_slots(slot, self.schema.slots[mixin]) else: self.raise_value_error( f'Slot: "{slot.name}" - unknown mixin reference: {mixin}' ) merged_slots.append(slot.name)
def process_slot_usages(self, cls: ClassDefinition) -> None: """ Connect any slot usage items :param cls: class to process :return: usage item """ for slotname, slot_usage in cls.slot_usage.items(): if slot_usage.alias: self.raise_value_error(f'Class: "{cls.name}" - alias not permitted in slot_usage slot:' f' {slot_usage.alias}') # Construct a new slot # If we've already assigned a parent, use it parent_slot = self.schema.slots.get(slot_usage.is_a) # Follow the ancestry of the class to get the most proximal parent if not parent_slot: parent_slot = self.slot_definition_for(slotname, cls) if not parent_slot and slotname in self.schema.slots: parent_slot = self.schema.slots[slotname] if not parent_slot: # This test is here because it is really easy to break things in the slot merge utilities. It should # stay self.logger.error(f'class "{cls.name}" slot "{slotname}" -- error occurred. This should not happen') else: child_name = slot_usage_name(slotname, cls) slot_alias = parent_slot.alias if parent_slot.alias else slotname new_slot = SlotDefinition(name=child_name, alias=slot_alias, domain=cls.name, is_usage_slot=Bool(True), usage_slot_name=slotname, owner=cls.name, domain_of=[cls.name], imported_from=cls.imported_from) self.schema.slots[child_name] = new_slot merge_slots(new_slot, slot_usage, inheriting=False, skip=['name', 'alias', 'domain', 'is_usage_slot', 'usage_slot_name', 'owner', 'domain_of']) # Copy the parent definition. If there is no parent definition, the slot is being defined # locally as a slot_usage if parent_slot is not None: new_slot.is_a = parent_slot.name merge_slots(new_slot, parent_slot) # This situation occurs when we are doing chained overrides. Kludgy, but it works... if parent_slot.name in cls.slots: if child_name in cls.slots: del cls.slots[cls.slots.index(child_name)] cls.slots[cls.slots.index(parent_slot.name)] = child_name elif child_name not in cls.slots: cls.slots.append(child_name) elif not new_slot.range: new_slot.range = self.schema.default_range
def merge_type(self, typ: TypeDefinition, merged_types: List[TypeDefinitionName]) -> None: """ Merge parent type information into target type :param typ: target type :param merged_types: list of type names that have bee merged. """ if typ.name not in merged_types: if typ.typeof: if typ.typeof in self.schema.types: reftyp = self.schema.types[cast(TypeDefinitionName, typ.typeof)] self.merge_type(reftyp, merged_types) merge_slots(typ, reftyp, [SlotDefinitionName('imported_from')]) else: self.raise_value_error(f'Type: "{typ.name}" - unknown typeof reference: {typ.typeof}', typ.typeof) merged_types.append(typ.name)
def process_slot_usages(self, cls: ClassDefinition) -> None: """ Connect any slot usage items :param cls: class to process :return: usage item """ for slotname, slot_usage in cls.slot_usage.items(): if slot_usage.alias: self.raise_value_error(f'Class: "{cls.name}" - alias not permitted in slot_usage slot:' f' {slot_usage.alias}') # Construct a new slot # Follow the ancestry of the class to get the most proximal parent parent_slot = self.slot_definition_for(slotname, cls) if not parent_slot and slotname in self.schema.slots: parent_slot = self.schema.slots[slotname] # If parent slot is still not defined, it means that we introduced a NEW slot in the slot usages if not parent_slot: self.logger.warning(f'class "{cls.name}" slot "{slotname}" does not reference an existing slot. ' f'New slot was created.') child_name = slotname slot_alias = None else: child_name = slot_usage_name(slotname, cls) slot_alias = parent_slot.alias if parent_slot.alias else slotname new_slot = SlotDefinition(name=child_name, alias=slot_alias, domain=cls.name, is_usage_slot=Bool(True), usage_slot_name=slotname, owner=cls.name, domain_of=[cls.name]) self.schema.slots[child_name] = new_slot merge_slots(new_slot, slot_usage, inheriting=False) # Copy the parent definition. If there is no parent definition, the slot is being defined # locally as a slot_usage if parent_slot is not None: new_slot.is_a = parent_slot.name merge_slots(new_slot, parent_slot) # This situation occurs when we are doing chained overrides. Kludgy, but it works... if parent_slot.name in cls.slots: if child_name in cls.slots: del cls.slots[cls.slots.index(child_name)] cls.slots[cls.slots.index(parent_slot.name)] = child_name else: cls.slots.append(child_name)
def process_slot_usages(self, cls: ClassDefinition) -> None: """ Connect any slot usage items :param cls: class to process :return: usage item """ for slotname, slot_usage in cls.slot_usage.items(): # Construct a new slot # Follow the ancestry of the class to get the most proximal parent parent_slot = self.slot_definition_for(slotname, cls) if not parent_slot and slotname in self.schema.slots: parent_slot = self.schema.slots[slotname] # If parent slot is still not defined, it means that we introduced a NEW slot in the slot usages if not parent_slot: print( f'Warning: class "{cls.name}" slot "{slotname}" does not reference an existing slot. ' f'New slot was created.', file=sys.stderr) child_name = slotname slot_alias = None else: child_name = slot_usage_name(slotname, cls) slot_alias = slotname new_slot = SlotDefinition(name=child_name, alias=slot_alias, domain=cls.name, is_usage_slot=True) self.schema.slots[child_name] = new_slot merge_slots(new_slot, slot_usage) # Copy the parent definition. If there is no parent definition, the slot is being defined # locally as a slot_usage if parent_slot is not None: new_slot.is_a = parent_slot.name merge_slots(new_slot, parent_slot) # This situation occurs when we are doing chained overrides. Kludgy, but it works... if parent_slot.name in cls.slots: if child_name in cls.slots: del cls.slots[cls.slots.index(child_name)] cls.slots[cls.slots.index(parent_slot.name)] = child_name