def add_ref( self, fromtype: RefType, fromname: ElementName, totype: RefType, toname: ElementName, ) -> None: """ Add an inverse reference, indicating that to type/name is referenced by from type/name :param fromtype: Referencer type :param fromname: Referencer name :param totype: Referencee type :param toname: Referencee name :return: """ if totype is ClassType: self.classrefs.setdefault(cast(ClassDefinitionName, toname), References()).addref(fromtype, fromname) elif totype is SlotType: self.slotrefs.setdefault(cast(SlotDefinitionName, toname), References()).addref(fromtype, fromname) elif totype is TypeType: self.typerefs.setdefault(cast(TypeDefinitionName, toname), References()).addref(fromtype, fromname) elif totype is SubsetType: self.subsetrefs.setdefault(cast(SubsetDefinitionName, toname), References()).addref( fromtype, fromname) else: raise TypeError("Unknown typ: {typ}")
def summarize_definition(self, typ: RefType, k: DefinitionName, v: Definition) -> None: """ Summarize slot and class definitions :param typ: type (slot or class) :param k: name :param v: definition :return: """ self.summarize_element(typ, k, v) if v.is_a: self.isarefs.setdefault(v.is_a, References()).addref(typ, k) self.add_ref(typ, k, typ, v.is_a) else: self.roots.addref(typ, k) if v.abstract: self.abstracts.addref(typ, k) if v.mixin: self.mixins.addref(typ, k) for mixin in v.mixins: self.mixinrefs.setdefault(mixin, References()).addref(typ, k) self.add_ref(typ, k, typ, mixin) if v.apply_to: self.applytos.addref(typ, k) for applyto in v.apply_to: self.applytorefs.setdefault(applyto, References()).addref(typ, k) self.add_ref(typ, k, typ, applyto)
def children(self, name: str) -> List[str]: """ Gets a list of names of children. Parameters ---------- name: str The name of an element in the Biolink Model. Returns ------- List[str] The names of the given elements children. """ return self._union_of(self.synopsis.isarefs.get(name, References()))
def test_meta_neighborhood(self): """ Test the neighborhood function in the metamodel """ gen = GeneratorTest(LOCAL_YAML_PATH) errfile = StringIO() with redirect_stderr(errfile): gen.neighborhood(['Definition']) self.assertEqual( "Warning: neighborhood(Definition) - Definition is undefined", errfile.getvalue().strip()) self.assertEqual( References( classrefs={ 'class_definition', 'local_name', 'schema_definition', 'subset_definition', 'alt_description', 'definition', 'example', 'slot_definition', 'element' }, slotrefs={'is_a', 'apply_to', 'mixins', 'default_range'}, typerefs={'uriorcurie', 'boolean', 'uri', 'ncname', 'string'}, subsetrefs=set()), gen.neighborhood('definition'))
def test_meta_neighborhood(self): """ Test the neighborhood function in the metamodel """ gen = GeneratorTest(LOCAL_METAMODEL_YAML_FILE) gen.neighborhood([cast(ElementName, 'Definition')]) self.assertEqual("neighborhood(Definition) - Definition is undefined", gen.logstream.getvalue().strip()) gen.logstream.truncate(0) gen.logstream.seek(0) self.assertEqual( References(classrefs={ 'element', 'subset_definition', 'slot_definition', 'local_name', 'extension', 'example', 'class_definition', 'definition', 'alt_description', 'annotation' }, slotrefs={'is_a', 'apply_to', 'mixins', 'owner'}, typerefs={ 'boolean', 'datetime', 'uri', 'string', 'uriorcurie', 'ncname' }, subsetrefs=set()), gen.neighborhood('definition'))
def test_meta_neighborhood(self): """ Test the neighborhood function in the metamodel """ gen = GeneratorTest(LOCAL_METAMODEL_YAML_FILE) errfile = StringIO() with redirect_stderr(errfile): gen.neighborhood([cast(ElementName, 'Definition')]) # Note: There is something about the PyCharm / UnitTest package that, if you are running a lot of tests, the # output ends up getting redirected to the test runner rather than stderr. If there is nothing at all, we # will assume that this is the case. if errfile.getvalue().strip(): self.assertEqual( "Warning: neighborhood(Definition) - Definition is undefined", errfile.getvalue().strip()) else: print( "*** Warning not tested -- stderr redirect isn't working") self.assertEqual( References( classrefs={ cast(ClassDefinitionName, e) for e in [ 'class_definition', 'local_name', 'subset_definition', 'alt_description', 'definition', 'example', 'slot_definition', 'element' ] }, slotrefs={ cast(SlotDefinitionName, e) for e in ['is_a', 'apply_to', 'mixins', 'owner'] }, typerefs={ cast(TypeDefinitionName, e) for e in ['uriorcurie', 'boolean', 'uri', 'ncname', 'string'] }, subsetrefs=set()), gen.neighborhood('definition'))
def neighborhood(self, elements: Union[str, ElementName, List[ElementName]]) \ -> References: """ Return a list of all slots, classes and types that touch any element in elements, including the element itself @param elements: Element names to do proximity with @return: All slots and classes that touch element """ if isinstance(elements, (str, ElementName)): elements = [elements] touches = References() for element in elements: if element in self.schema.classes: touches.classrefs.add(cast(ClassDefinitionName, element)) cls = self.schema.classes[cast(ClassDefinitionName, element)] if cls.is_a: touches.classrefs.add(cls.is_a) # Mixins include apply_to's touches.classrefs.update(set(cls.mixins)) for slotname in cls.slots: slot = self.schema.slots[slotname] if slot.range in self.schema.classes: touches.classrefs.add( cast(ClassDefinitionName, slot.range)) elif slot.range in self.schema.types: touches.typerefs.add( cast(TypeDefinitionName, slot.range)) for cv in self.schema.classes.values(): if cv.is_a == element: touches.classrefs.add(cv.name) if element in self.synopsis.rangerefs: for slotname in self.synopsis.rangerefs[element]: touches.slotrefs.add(slotname) if self.schema.slots[slotname].domain: touches.classrefs.add( self.schema.slots[slotname].domain) if cls.in_subset: touches.subsetrefs.update(cls.in_subset) if element in self.schema.slots: touches.slotrefs.add(cast(SlotDefinitionName, element)) slot = self.schema.slots[cast(SlotDefinitionName, element)] touches.slotrefs.update(set(slot.mixins)) if slot.is_a: touches.slotrefs.add(slot.is_a) if element in self.synopsis.inverses: touches.slotrefs.update(self.synopsis.inverses[cast( SlotDefinitionName, element)]) if slot.domain: touches.classrefs.add(slot.domain) if slot.range in self.schema.classes: touches.classrefs.add(cast(ClassDefinitionName, slot.range)) elif slot.range in self.schema.types: touches.typerefs.add(cast(TypeDefinitionName, slot.range)) if slot.in_subset: touches.subsetrefs.update(slot.in_subset) for sv in self.schema.slots.values(): if sv.is_a == element: touches.slotrefs.add(sv.name) if element in self.schema.types: touches.typerefs.add(cast(TypeDefinitionName, element)) typ = self.schema.types[cast(TypeDefinitionName, element)] if element in self.synopsis.rangerefs: touches.slotrefs.update(self.synopsis.rangerefs[element]) if typ.typeof: touches.typerefs.add(cast(TypeDefinitionName, typ.typeof)) if typ.in_subset: touches.subsetrefs.update(typ.in_subset) for tv in self.schema.types.values(): if tv.typeof == element: touches.slotrefs.add(tv.name) if element in self.schema.subsets: touches.subsetrefs.add(cast(SubsetDefinitionName, element)) if element in self.synopsis.subsetrefs: touches.update(self.synopsis.subsetrefs[cast( SubsetDefinitionName, element)]) if not bool(touches): self.logger.warning( f"neighborhood({element}) - {element} is undefined") return touches