From 89162e4e8c5301f54a52488ff4ac027c4cc6dd89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Dom=C3=ADnguez?= <43052541+kysrpex@users.noreply.github.com> Date: Thu, 27 May 2021 15:29:13 +0200 Subject: [PATCH] Add autocompletion for namespaces (IPython only) (#599) * Add autocompletion for namespaces. * Unit tests for IPython autocompletion. --- osp/core/ontology/namespace.py | 49 +++++++++++++++++++++++++++++----- tests/test_namespace.py | 10 +++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/osp/core/ontology/namespace.py b/osp/core/ontology/namespace.py index 84993e60..b7eefcc3 100644 --- a/osp/core/ontology/namespace.py +++ b/osp/core/ontology/namespace.py @@ -4,7 +4,7 @@ from collections.abc import Iterable import rdflib import logging - +import itertools from osp.core.ontology.entity import OntologyEntity from osp.core.ontology.relationship import OntologyRelationship from osp.core.ontology.cuba import rdflib_cuba @@ -32,6 +32,17 @@ def __init__(self, name, namespace_registry, iri): self._reference_by_label = \ namespace_registry._get_reference_by_label(self._iri) + def __dir__(self): + """Attributes available for the OntologyNamespace class. + + Returns: + Iterable: the available attributes, which include the methods and + the ontology entities in the namespace. + """ + entity_autocompletion = self._iter_labels() \ + if self._reference_by_label else self._iter_suffixes() + return itertools.chain(dir(super()), entity_autocompletion) + def __str__(self): """Transform the namespace to a human readable string. @@ -254,20 +265,46 @@ def _get_from_label(self, label, lang=None, case_sensitive=False): results[0] = results[0].inverse return results[0] - def __iter__(self): - """Iterate over the ontology entities in the namespace. + def _iter_iris(self): + """Iterate over the IRIs of the ontology entities in the namespace. - :return: An iterator over the entities. - :rtype: Iterator[OntologyEntity] + :return: An iterator over the entity IRIs. + :rtype: Iterator[rdflib.URIRef] """ types = [rdflib.OWL.DatatypeProperty, rdflib.OWL.ObjectProperty, rdflib.OWL.Class] - return (self._namespace_registry.from_iri(s) + return (s for t in types for s, _, _ in self._graph.triples((None, rdflib.RDF.type, t)) if s in self) + def __iter__(self): + """Iterate over the ontology entities in the namespace. + + :return: An iterator over the entities. + :rtype: Iterator[OntologyEntity] + """ + return (self._namespace_registry.from_iri(iri) + for iri in self._iter_iris()) + + def _iter_labels(self): + """Iterate over the labels of the ontology entities in the namespace. + + :return: An iterator over the entity labels. + :rtype: Iterator[str] + """ + return itertools.chain(*(self._get_labels_for_iri(iri) + for iri in self._iter_iris())) + + def _iter_suffixes(self): + """Iterate over suffixes of the ontology entities in the namespace. + + :return: An iterator over the entity suffixes. + :rtype: Iterator[str] + """ + return (str(iri)[len(str(self._iri)):] for iri in self._iter_iris()) + def __contains__(self, item): """Check whether the given entity is part of the namespace. diff --git a/tests/test_namespace.py b/tests/test_namespace.py index 274e6ba4..81efd853 100644 --- a/tests/test_namespace.py +++ b/tests/test_namespace.py @@ -515,6 +515,16 @@ def test_get_entity_name(self): "City_T" ) + def test_autocompletion_ipython(self): + """Checks that all the expected ontology entities are in __dir__. + + The check is done just for the `cuba` namespace. + """ + expected = {'activeRelationship', 'passiveRelationship', + 'relationship', 'attribute', 'path', 'Entity', 'File', + 'Nothing', 'Wrapper'} + self.assertSetEqual(set(dir(cuba)) & expected, expected) + if __name__ == "__main__": unittest.main()