From b7f60051b406d3c7a2d795b1605bc1301afebf2b Mon Sep 17 00:00:00 2001 From: "Francesca L. Bleken" <48128015+francescalb@users.noreply.github.com> Date: Fri, 22 Sep 2023 08:34:18 +0200 Subject: [PATCH] Corrected bug so that asking for entities in imported does not return all in world (#655) * Corrected bug so that asking for entities in imported does not return all in world --- ontopy/ontology.py | 107 +++++++++++++++++++-------- ontopy/patch.py | 1 + tests/test_classes.py | 56 +++++++++++++++ tests/test_get_by_label_new.py | 128 --------------------------------- 4 files changed, 135 insertions(+), 157 deletions(-) create mode 100644 tests/test_classes.py delete mode 100644 tests/test_get_by_label_new.py diff --git a/ontopy/ontology.py b/ontopy/ontology.py index aaedf4e2c..13a28c75e 100644 --- a/ontopy/ontology.py +++ b/ontopy/ontology.py @@ -218,13 +218,13 @@ def __dir__(self): lst = list(self.get_entities(imported=self._dir_imported)) if self._dir_preflabel: dirset.update( - dir.prefLabel.first() + str(dir.prefLabel.first()) for dir in lst if hasattr(dir, "prefLabel") ) if self._dir_label: dirset.update( - dir.label.first() for dir in lst if hasattr(dir, "label") + str(dir.label.first()) for dir in lst if hasattr(dir, "label") ) if self._dir_name: dirset.update(dir.name for dir in lst if hasattr(dir, "name")) @@ -1062,51 +1062,100 @@ def get_entities( # pylint: disable=too-many-arguments def classes(self, imported=False): """Returns an generator over all classes. - If `imported` is `True`, will imported classes are also returned. + Arguments: + imported: if `True`, entities in imported ontologies + are also returned. + """ + return self._entities("classes", imported=imported) + + def _entities( + self, entity_type, imported=False + ): # pylint: disable=too-many-branches + """Returns an generator over all entities of the desired type. + This is a helper function for `classes()`, `individuals()`, + `object_properties()`, `data_properties()` and + `annotation_properties()`. + + Arguments: + entity_type: The type of entity desired given as a string. + Can be any of `classes`, `individuals`, + `object_properties`, `data_properties` and + `annotation_properties`. + imported: if `True`, entities in imported ontologies + are also returned. """ + + generator = [] if imported: - return self.world.classes() - return super().classes() + ontologies = self.get_imported_ontologies(recursive=True) + ontologies.append(self) + for onto in ontologies: + if entity_type == "classes": + for cls in list(onto.classes()): + generator.append(cls) + elif entity_type == "individuals": + for ind in list(onto.individuals()): + generator.append(ind) + elif entity_type == "object_properties": + for prop in list(onto.object_properties()): + generator.append(prop) + elif entity_type == "data_properties": + for prop in list(onto.data_properties()): + generator.append(prop) + elif entity_type == "annotation_properties": + for prop in list(onto.annotation_properties()): + generator.append(prop) + else: + if entity_type == "classes": + generator = super().classes() + elif entity_type == "individuals": + generator = super().individuals() + elif entity_type == "object_properties": + generator = super().object_properties() + elif entity_type == "data_properties": + generator = super().data_properties() + elif entity_type == "annotation_properties": + generator = super().annotation_properties() + + for entity in generator: + yield entity def individuals(self, imported=False): """Returns an generator over all individuals. - If `imported` is `True`, will imported individuals are also returned. + Arguments: + imported: if `True`, entities in imported ontologies + are also returned. """ - if imported: - return self.world.individuals() - return super().individuals() + return self._entities("individuals", imported=imported) def object_properties(self, imported=False): - """Returns an generator over all object properties. + """Returns an generator over all object_properties. - If `imported` is true, will imported object properties are also - returned. + Arguments: + imported: if `True`, entities in imported ontologies + are also returned. """ - if imported: - return self.world.object_properties() - return super().object_properties() + return self._entities("object_properties", imported=imported) def data_properties(self, imported=False): - """Returns an generator over all data properties. + """Returns an generator over all data_properties. - If `imported` is true, will imported data properties are also - returned. + Arguments: + imported: if `True`, entities in imported ontologies + are also returned. """ - if imported: - return self.world.data_properties() - return super().data_properties() + return self._entities("data_properties", imported=imported) def annotation_properties(self, imported=False): - """Returns a generator iterating over all annotation properties - defined in the current ontology. + """Returns an generator over all annotation_properties. + + Arguments: + imported: if `True`, entities in imported ontologies + are also returned. - If `imported` is true, annotation properties in imported ontologies - will also be included. """ - if imported: - return self.world.annotation_properties() - return super().annotation_properties() + return self._entities("annotation_properties", imported=imported) def get_root_classes(self, imported=False): """Returns a list or root classes.""" @@ -1203,7 +1252,7 @@ def sync_reasoner( else: raise ValueError( f"unknown reasoner '{reasoner}'. Supported reasoners " - 'are "Pellet", "HermiT" and "FaCT++".' + "are 'Pellet', 'HermiT' and 'FaCT++'." ) # For some reason we must visit all entities once before running diff --git a/ontopy/patch.py b/ontopy/patch.py index 05235d9e3..a37c5de60 100644 --- a/ontopy/patch.py +++ b/ontopy/patch.py @@ -123,6 +123,7 @@ def get_annotations( ontologies. """ onto = self.namespace.ontology + annotations = { get_preferred_label(_): _._get_values_for_class(self) for _ in onto.annotation_properties(imported=imported) diff --git a/tests/test_classes.py b/tests/test_classes.py new file mode 100644 index 000000000..b4fd7e072 --- /dev/null +++ b/tests/test_classes.py @@ -0,0 +1,56 @@ +import pytest + +from ontopy import get_ontology +from ontopy.ontology import NoSuchLabelError + + +def test_classes(repo_dir) -> None: + """Test that classes are returned from imported ontologies when + asked for, but not for the whole world + """ + import ontopy + import owlready2 + + world = ontopy.World() + testonto = world.get_ontology("http://domain_ontology/new_ontology") + testonto.new_entity("Class", owlready2.Thing) + + imported_onto = world.get_ontology( + repo_dir / "tests" / "testonto" / "testonto.ttl" + ).load() + testonto.imported_ontologies.append(imported_onto) + + assert set(testonto.classes(imported=True)) == { + testonto.TestClass, + testonto.get_by_label("models:TestClass"), + testonto.Class, + } + assert set(imported_onto.classes(imported=True)) == { + imported_onto.TestClass, + imported_onto.get_by_label("models:TestClass"), + } + assert set(imported_onto.classes(imported=False)) == { + imported_onto.TestClass + } + + assert ( + set(testonto.individuals(imported=True)) == set() + ) # We currently do not have examples with individuals. + assert set(testonto.individuals(imported=False)) == set() + + assert set(testonto.object_properties(imported=True)) == { + testonto.hasObjectProperty + } + assert set(testonto.object_properties(imported=False)) == set() + + assert set(testonto.annotation_properties(imported=True)) == { + testonto.prefLabel, + testonto.altLabel, + testonto.hasAnnotationProperty, + } + assert set(testonto.annotation_properties(imported=False)) == set() + + assert set(testonto.data_properties(imported=True)) == { + testonto.hasDataProperty + } + assert set(testonto.data_properties(imported=False)) == set() diff --git a/tests/test_get_by_label_new.py b/tests/test_get_by_label_new.py deleted file mode 100644 index 65d9a12e7..000000000 --- a/tests/test_get_by_label_new.py +++ /dev/null @@ -1,128 +0,0 @@ -import pytest - -from ontopy import get_ontology -from ontopy.ontology import NoSuchLabelError - - -def test_get_by_label_onto(repo_dir) -> None: - """Test that label annotations are added correctly if they are not added before - using get_by_label - """ - import ontopy - import owlready2 - - world = ontopy.World() - testonto = world.get_ontology("http://domain_ontology/new_ontology") - testonto.new_entity("Class", owlready2.Thing) - - # THIS IS NOT NONE ANYMORE - # assert testonto._label_annotations == None - - assert testonto.get_by_label("Class") == testonto.Class - - imported_onto = world.get_ontology( - repo_dir / "tests" / "testonto" / "testonto.ttl" - ).load() - testonto.imported_ontologies.append(imported_onto) - assert imported_onto.get_by_label("TestClass") - assert imported_onto.get_by_label("models:TestClass") - print("****classes in testonto, inlcuding imports*****") - print(list(testonto.classes(imported=True))) - print("------classes in imported_onto including imports----------") - print(list(imported_onto.classes(imported=True))) - print("------classes in imported_onto NOT including imports----------") - print(list(imported_onto.classes(imported="text"))) - print("gfgdfsgsd") - - assert testonto.get_by_label("TestClass") - - -''' -def test_get_by_label_all_onto() -> None: - """Test that label annotations are added correctly if they are not added before - using get_by_label_all - """ - import owlready2 - from utilities import setassert - - testonto = get_ontology("http://domain_ontology/new_ontology") - testonto.new_entity("Class", owlready2.Thing) - assert testonto._label_annotations == None - assert testonto.get_by_label_all("*") == {testonto.Class} - testonto.new_annotation_property( - "SpecialAnnotation", owlready2.AnnotationProperty - ) - testonto.Class.SpecialAnnotation.append("This is a comment") - testonto.set_default_label_annotations() - - testonto.new_entity("Klasse", testonto.Class) - - setassert(testonto.Klasse.prefLabel, ["Klasse"]) - - testonto.Klasse.altLabel = "Class2" - setassert( - testonto.get_by_label_all("*"), - { - testonto.prefLabel, - testonto.altLabel, - testonto.Class, - testonto.SpecialAnnotation, - testonto.Klasse, - }, - ) - setassert( - testonto.get_by_label_all("Class*"), - { - testonto.Class, - testonto.Klasse, - }, - ) - - - - -def test_get_by_label_emmo(emmo: "Ontology") -> None: - # Loading emmo-inferred where everything is sqashed into one ontology - emmo = get_ontology().load() - assert emmo[emmo.Atom.name] == emmo.Atom - assert emmo[emmo.Atom.iri] == emmo.Atom - - # Load an ontology with imported sub-ontologies - onto = get_ontology( - "https://raw.githubusercontent.com/BIG-MAP/BattINFO/master/battinfo.ttl" - ).load() - assert str(onto.Electrolyte.prefLabel.first()) == "Electrolyte" - - # Check colon_in_name argument - onto.Atom.altLabel.append("Element:X") - with pytest.raises(NoSuchLabelError): - onto.get_by_label("Element:X") - - assert onto.get_by_label("Element:X", colon_in_label=True) == onto.Atom - - -import pytest - -from ontopy import get_ontology -from ontopy.ontology import NoSuchLabelError - - -# Loading emmo-inferred where everything is sqashed into one ontology -emmo = get_ontology().load() -assert emmo[emmo.Atom.name] == emmo.Atom -assert emmo[emmo.Atom.iri] == emmo.Atom - -# Load an ontology with imported sub-ontologies -onto = get_ontology( - "https://raw.githubusercontent.com/BIG-MAP/BattINFO/master/battinfo.ttl" -).load() -assert str(onto.Electrolyte.prefLabel.first()) == "Electrolyte" - - -# Check colon_in_name argument -onto.Atom.altLabel.append("Element:X") -with pytest.raises(NoSuchLabelError): - onto.get_by_label("Element:X") - -assert onto.get_by_label("Element:X", colon_in_label=True) == onto.Atom -'''