diff --git a/demo/horizontal/emmo2meta.py b/demo/horizontal/emmo2meta.py index 91753a914..d5259b154 100644 --- a/demo/horizontal/emmo2meta.py +++ b/demo/horizontal/emmo2meta.py @@ -269,7 +269,7 @@ def get_dim(restriction, name, descr=None): Property( name, type=ptype, - dims=dimensions, + shape=dimensions, unit=unit, description=descr, ) diff --git a/ontopy/ontology.py b/ontopy/ontology.py index f413358bd..406e72b28 100644 --- a/ontopy/ontology.py +++ b/ontopy/ontology.py @@ -13,6 +13,7 @@ import uuid import tempfile import types +import re from pathlib import Path from collections import defaultdict from collections.abc import Iterable @@ -50,7 +51,7 @@ ) if TYPE_CHECKING: - from typing import List, Sequence + from typing import Iterator, List, Sequence # Default annotations to look up @@ -2107,6 +2108,82 @@ def difference(self, other: owlready2.Ontology) -> set: s2 = set(other.get_unabbreviated_triples(blank="_:b")) return s1.difference(s2) + def find( + self, text: str, domain="world", case_sensitive=False, regex=False + ) -> "Iterator": + """A simple alternative to the Owlready2 `search()` method. + + This method searches through all literal strings in the given domain. + + Args: + text: Free text string to search for. + domain: Domain to search. Should be one of: + - "ontology": Current ontology. + - "imported": Current and all imported ontologies. + - "world": The world. + case_sensitive: Whether the search is case sensitive. + regex: Whether to use regular expression search. + + Returns: + Iterator over `(subject, predicate, literal_string)` triples, + converted to EMMOntoPy objects. + + """ + # pylint: disable=too-many-locals,too-many-branches + + if domain == "ontology": + ontologies = [self] + elif domain == "imported": + ontologies = [self] + self.get_imported_ontologies(recursive=True) + elif domain == "world": + ontologies = [self.world] + else: + raise ValueError( + "`domain` must be 'ontology', 'imported' or 'world'. " + f"Got: {domain}" + ) + + # Define our match function + if regex: + flags = 0 if case_sensitive else re.IGNORECASE + pattern = re.compile(f"{text}", flags=flags) + + def matchfun(string): + """Match function using regex.""" + return re.match(pattern, string) + + else: + if not case_sensitive: + text = text.lower() + + def matchfun(string): + """Match function without regex.""" + if case_sensitive: + return text in string + return text in string.lower() + + ontology_storid = self.world._abbreviate( + "http://www.w3.org/2002/07/owl#Ontology" + ) + for onto in ontologies: + for s, p, o, _ in onto._get_data_triples_spod_spod( + None, None, None, None + ): + predicate = self.world.get(self.world._unabbreviate(p)) + if isinstance(o, str) and matchfun(o): + assert isinstance( + s, int + ), "subject should be a storid" # nosec + if s >= 0: + subject = self.world.get(self.world._unabbreviate(s)) + if s == ontology_storid: + yield self.world.get_ontology( + subject.iri + ), predicate, o + yield subject, predicate, o + else: + yield BlankNode(self.world, s), predicate, o + class BlankNode: """Represents a blank node. diff --git a/tests/ontopy_tests/test_ontology.py b/tests/ontopy_tests/test_ontology.py new file mode 100644 index 000000000..fb2b57a8e --- /dev/null +++ b/tests/ontopy_tests/test_ontology.py @@ -0,0 +1,44 @@ +"""Test Ontology class methods.""" + +from ontopy import get_ontology +from ontopy.testutils import ontodir + +animal = get_ontology(ontodir / "mammal.ttl").load() + + +def test_find(): + """Test find() method.""" + m1 = (animal.chasing, animal.prefLabel, "chasing") + m2 = (animal.Mouse, animal.prefLabel, "Mouse") + # for domain in "ontology", "imported", "world": + assert m1 not in animal.find("chas", domain="ontology") + assert m2 in animal.find("Mouse", domain="ontology") + assert m2 in animal.find("Mouse", domain="ontology", regex=True) + assert m2 in animal.find("Mouse", domain="ontology", case_sensitive=True) + assert m2 in animal.find( + "Mouse", domain="ontology", regex=True, case_sensitive=True + ) + assert m2 not in animal.find( + "mouse", domain="ontology", case_sensitive=True + ) + assert m2 in animal.find("mouse", domain="ontology", case_sensitive=False) + + assert m1 in animal.find("chas", domain="imported", regex=True) + assert m1 in animal.find("chas", domain="imported", case_sensitive=True) + assert m1 in animal.find( + "chas", domain="imported", regex=True, case_sensitive=True + ) + + assert m1 in animal.find("Chas", domain="imported") + assert m1 in animal.find("Chas", domain="imported", regex=True) + assert m1 not in animal.find("Chas", domain="imported", case_sensitive=True) + assert m1 not in animal.find( + "Chas", domain="imported", regex=True, case_sensitive=True + ) + + assert m2 not in animal.imported_ontologies[0].find( + "mouse", domain="ontology" + ) + assert m2 in animal.imported_ontologies[0].find( + "mouse", domain="world", regex=True + ) diff --git a/tests/test_basic.py b/tests/test_basic.py index 8be94e665..670ac5de0 100755 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -7,6 +7,11 @@ from ontopy.ontology import Ontology +# if True: +# from emmopy import get_emmo +# emmo = get_emmo() + + @pytest.mark.filterwarnings("ignore:adding new IRI to ontology:UserWarning") def test_basic(emmo: "Ontology") -> None: from ontopy import get_ontology