예제 #1
0
 def test_get_identifier(self):
     """Test the get_identifier method."""
     self.assertEqual(
         OntologyParser.get_parser(YML_FILE).identifier, "parser_test")
     self.assertEqual(
         OntologyParser.get_parser("parser_test").identifier, "parser_test")
     self.assertEqual(OntologyParser.get_parser("emmo").identifier, "emmo")
예제 #2
0
 def test_get_namespace_name(self):
     """Test the get_namespace_name method."""
     self.assertItemsEqual(
         OntologyParser.get_parser(YML_FILE).namespaces.keys(),
         ["parser_test"],
     )
     self.assertItemsEqual(
         OntologyParser.get_parser("parser_test").namespaces.keys(),
         ["parser_test"],
     )
     self.assertItemsEqual(
         OntologyParser.get_parser("emmo").namespaces.keys(),
         [
             "mereotopology",
             "physical",
             "top",
             "semiotics",
             "perceptual",
             "reductionistic",
             "holistic",
             "physicalistic",
             "math",
             "properties",
             "materials",
             "metrology",
             "models",
             "manufacturing",
             "isq",
             "siunits",
         ],
     )
예제 #3
0
 def test_get_file_path(self):
     """Test the get_file_path method."""
     self.assertEqual(
         OntologyParser.parse_file_path("test/my_file.yml"),
         "test/my_file.yml",
     )
     self.assertEqual(
         OntologyParser.parse_file_path("my_file").lower(),
         os.path.abspath(
             os.path.relpath(
                 os.path.join(
                     os.path.dirname(__file__),
                     "..",
                     "osp",
                     "core",
                     "ontology",
                     "docs",
                     "my_file.yml",
                 ))).lower(),
     )
     self.assertEqual(
         OntologyParser.parse_file_path("emmo").lower(),
         os.path.abspath(
             os.path.relpath(
                 os.path.join(
                     os.path.dirname(__file__),
                     "..",
                     "osp",
                     "core",
                     "ontology",
                     "docs",
                     "emmo.yml",
                 ))).lower(),
     )
     self.assertEqual(
         OntologyParser.parse_file_path("city").lower(),
         os.path.abspath(
             os.path.relpath(
                 os.path.join(
                     os.path.dirname(__file__),
                     "..",
                     "osp",
                     "core",
                     "ontology",
                     "docs",
                     "city.ontology.yml",
                 ))).lower(),
     )
예제 #4
0
    def test_parse_guess_format(self):
        """Test the parsing a file without providing the format."""
        modified_yml_config_path = Path(YML_FILE)
        modified_yml_config_path = str(
            modified_yml_config_path.with_name(
                modified_yml_config_path.stem + "_mod" +
                modified_yml_config_path.suffix))
        try:
            # Create a copy of YML_FILE and remove the 'format' keyword.
            with open(modified_yml_config_path, "w") as modified_yml_config:
                with open(YML_FILE, "r") as yml_config:
                    modified_yml_config.write(
                        re.sub(
                            r"^[\s]*format:[\s].*",
                            "",
                            yml_config.read(),
                            flags=re.MULTILINE,
                        ))

            parser = OntologyParser.get_parser(modified_yml_config_path)
            g1 = rdflib.Graph()
            g1.parse(RDF_FILE, format="ttl")
            self.assertTrue(parser.graph, g1)
        finally:
            if os.path.exists(modified_yml_config_path):
                os.remove(modified_yml_config_path)
예제 #5
0
    def test_parse_yml_download(self):
        """Test downloading owl ontologies."""
        def request_callback(request):
            headers = {"request-id": "728d329e-0e86-11e4-a748-0c84dc037c13"}
            return 200, headers, "<ns1:a> <ns1:b> <ns1:c> ."

        url = "http://my_ontology.com/ontology.owl"
        responses.add_callback(
            responses.GET,
            url,
            callback=request_callback,
            content_type="text/plain",
        )
        doc = dict(YML_DOC)
        doc["ontology_file"] = url
        with tempfile.TemporaryDirectory() as tempdir:
            yml_path = os.path.join(tempdir, "parser_test.yml")
            with open(yml_path, "w") as file:
                yaml.safe_dump(doc, file)
            try:
                parser = OntologyParser.get_parser(yml_path)
                self.assertIn(
                    (
                        rdflib.URIRef("ns1:a"),
                        rdflib.URIRef("ns1:b"),
                        rdflib.URIRef("ns1:c"),
                    ),
                    parser.graph,
                )
            except EmptyOntologyFileError:
                pass
예제 #6
0
 def test_parse_rdf(self):
     """Test parsing an rdf file."""
     with tempfile.TemporaryDirectory() as tempdir:
         new_config = self.config_file
         new_config["namespaces"] = {}
         new_yml_path = os.path.join(tempdir, os.path.basename(YML_FILE))
         new_ttl_path = os.path.join(tempdir, os.path.basename(RDF_FILE))
         with open(new_yml_path, "w") as file:
             yaml.dump(new_config, file)
         shutil.copy(RDF_FILE, new_ttl_path)
         self.assertRaises(TypeError, new_yml_path, self.parser.parse)
     with tempfile.TemporaryDirectory() as tempdir:
         new_config = self.config_file
         new_config["identifier"] = "x"
         new_yml_path = os.path.join(tempdir, os.path.basename(YML_FILE))
         new_ttl_path = os.path.join(tempdir, os.path.basename(RDF_FILE))
         with open(new_yml_path, "w") as file:
             yaml.dump(new_config, file)
         shutil.copy(RDF_FILE, new_ttl_path)
         self.assertRaises(TypeError, new_yml_path, self.parser.parse)
     with tempfile.TemporaryDirectory() as tempdir:
         new_config = self.config_file
         new_config["namespaces"] = {}
         new_config["identifier"] = "x"
         new_config["invalid"] = True
         new_yml_path = os.path.join(tempdir, os.path.basename(YML_FILE))
         new_ttl_path = os.path.join(tempdir, os.path.basename(RDF_FILE))
         with open(new_yml_path, "w") as file:
             yaml.dump(new_config, file)
         shutil.copy(RDF_FILE, new_ttl_path)
         self.assertRaises(TypeError, new_yml_path, self.parser.parse)
     with tempfile.TemporaryDirectory() as tempdir:
         config = dict(
             identifier="parser_test",
             ontology_file=RDF_FILE,
             namespaces={
                 "parser_test": "http://www.osp-core.com/parser_test"
             },
             format="ttl",
             file="file.ttl",
         )
         new_yml_path = os.path.join(tempdir, "file.yml")
         new_ttl_path = os.path.join(tempdir, "file.ttl")
         with open(new_yml_path, "w") as file:
             yaml.dump(config, file)
         shutil.copy(RDF_FILE, new_ttl_path)
         rdf = rdflib.Graph()
         rdf.parse(RDF_FILE, format="ttl")
         parser = OntologyParser.get_parser(new_yml_path)
         graph = parser.graph
     self.assertEqual(len(graph), len(rdf))
     self.assertTrue(isomorphic(graph, rdf))
     self.assertIn(
         rdflib.URIRef("http://www.osp-core.com/parser_test#"),
         list(parser.namespaces.values()),
     )
예제 #7
0
    def _get_replaced_packages(self, new_packages):
        """Get package paths to install.

        Get the package paths that by replacing the package paths of
        already installed packages with new packages,

        Args:
            new_packages (List[str]): Path to new package files.

        Returns:
            List[str]: Resulting list of package paths.
        """
        installed = dict(self.get_installed_packages(return_path=True))
        for pkg in new_packages:
            installed[OntologyParser.get_parser(pkg).identifier] = pkg
        return installed.values()
예제 #8
0
 def test_install(self):
     """Test the store method."""
     parser = OntologyParser.get_parser(YML_FILE)
     with tempfile.TemporaryDirectory() as destination:
         parser.install(destination)
         self.assertItemsEqual(os.listdir(destination),
                               ["parser_test.xml", "parser_test.yml"])
         with open(os.path.join(destination, "parser_test.yml")) as f:
             yml_doc = yaml.safe_load(f)
             self.assertEqual(yml_doc["ontology_file"], "parser_test.xml")
             yml_doc["ontology_file"] = YML_DOC["ontology_file"]
             self.assertEqual(yml_doc["format"], "xml")
             copy = YML_DOC.copy()
             del yml_doc["format"]
             del copy["format"]
             self.assertEqual(yml_doc, copy)
         g = rdflib.Graph()
         g.parse(os.path.join(destination, "parser_test.xml"), format="xml")
         self.assertTrue(isomorphic(g, parser.graph))
예제 #9
0
    def _get_new_packages(self, packages):
        """From the given list of packages, return the ones that are new.

        Args:
            packages (List[str]): Path to ontology file.

        Returns:
            List[str]: List of package path that are new
        """
        result = set(packages)
        installed = set(self.get_installed_packages())
        for pkg in packages:
            identifier = OntologyParser.get_parser(pkg).identifier
            if identifier in installed:
                logger.info(
                    "Skipping package %s with identifier %s, "
                    "because it is already installed." % (pkg, identifier)
                )
                result.remove(pkg)
        return result
예제 #10
0
from osp.core.cuds import Cuds
from osp.core.session.core_session import CoreSession
from osp.core.utils.general import branch, export_cuds, import_cuds

from .test_transport_session import assertJsonLdEqual

# Load the ontology for the test.
try:
    from osp.core.namespaces import test_importexport
except ImportError:  # If the ontology is not installed.
    from osp.core.ontology.namespace_registry import namespace_registry
    from osp.core.ontology.parser.parser import OntologyParser

    namespace_registry.load_parser(
        OntologyParser.get_parser(
            str(Path(__file__).parent / "test_importexport.owl.yml")))
    test_importexport = namespace_registry.test_importexport
# Load also the city ontology.
try:
    from osp.core.namespaces import city
except ImportError:
    from osp.core.ontology import Parser
    from osp.core.ontology.namespace_registry import namespace_registry

    Parser().parse("city")
    city = namespace_registry.city


class TestImportExport(unittest.TestCase):
    """Loads files containing CUDS and checks the correctness of the data.
예제 #11
0
    def _install(self, files, filter_func, clear):
        """Install the ontology.

        Args:
            files (List[str]): The ontology files to install
            filter_func (Callable): Function that takes the list of files
                as input and returns a list of files that need to be installed.
            clear (bool): Whether it is necessary to clear what is already
                installed.
        """
        # Determine whether the namespace names need to be unbound from the
        # `osp.core.namespaces` and `osp.core` modules manually (Python 3.6)
        # or not.
        python_36 = (sys.version_info.major, sys.version_info.minor) <= (3, 6)
        if python_36 and clear:
            from osp.core.ontology.namespace_registry import namespace_registry

            unbound_manually = (
                True
                if self.namespace_registry is namespace_registry
                else False
            )
        else:
            unbound_manually = False

        os.makedirs(self.path, exist_ok=True)
        # Save existing namespace names if namespaces have to be unbound
        # manually. Otherwise, just set the variable
        # to `None` in order to save computation time.
        unbound_manually = (
            set(ns for ns in self.namespace_registry)
            if unbound_manually
            else set()
        )
        if clear:
            self.namespace_registry.clear()
        files = self._sort_for_installation(
            filter_func(files),
            set(self.get_installed_packages()) if not clear else set(),
        )
        installed_packages = set()
        for file in files:
            parser = OntologyParser.get_parser(file)
            self.namespace_registry.load_parser(parser)
            # serialize the result
            parser.install(self.path)
            installed_packages.add(parser.identifier)
        if clear:
            all_ontology_files, files_to_keep = set(), set()
            for ext in ("yml", "xml"):
                all_ontology_files |= set(
                    os.path.basename(x)
                    for x in glob.glob(os.path.join(self.path, f"*.{ext}"))
                )
                files_to_keep |= set(
                    f"{identifier}.{ext}" for identifier in installed_packages
                )
            files_to_remove = all_ontology_files - files_to_keep
            for file in files_to_remove:
                os.remove(os.path.join(self.path, file))
        if python_36:  # Bound and unbound namespaces manually
            from ... import core
            from .. import namespaces

            if unbound_manually:
                unbound_manually = unbound_manually.difference(
                    ns for ns in self.namespace_registry
                )  # Remove the namespaces that are kept installed.
            self.namespace_registry.update_namespaces(
                modules=[core, namespaces], remove=unbound_manually
            )
        self.namespace_registry.store(self.path)
예제 #12
0
    def _sort_for_installation(self, files, installed):
        """Get the right order to install the files.

        Args:
            files (List[str]): The list of file paths to sort.

        Raises:
            RuntimeError: Unsatisfied requirements after installation.

        Returns:
            List[str]: The sorted list of file paths.
        """
        result = list()
        files = {OntologyParser.get_parser(f).identifier: f for f in files}
        requirements = {
            n: OntologyParser.get_parser(f).requirements
            for n, f in files.items()
        }

        # If the requirements for an ontology package are bundled with
        # OSP-core, try to install them automatically.
        package_and_dependents = dict()
        try:
            package_and_dependents: Dict[
                str, Set[str]
            ] = self._resolve_dependencies_install(files, requirements, dict())
            files.update(
                {
                    OntologyParser.get_parser(f).identifier: f
                    for f in package_and_dependents
                }
            )
            requirements.update(
                {
                    n: OntologyParser.get_parser(f).requirements
                    for n, f in files.items()
                }
            )
        except FileNotFoundError:
            pass

        # order the files
        while requirements:
            add_to_result = list()
            for namespace, req in requirements.items():
                req -= installed | set(result)
                if not req:
                    add_to_result.append(namespace)
            if not add_to_result:
                raise RuntimeError(
                    "Installation failed. Unsatisfied requirements: \n - %s"
                    % "\n - ".join(
                        ["%s: %s" % (n, r) for n, r in requirements.items()]
                    )
                )
            result += add_to_result
            for x in add_to_result:
                del requirements[x]
        dependencies_to_install = set(package_and_dependents) - set(installed)
        if dependencies_to_install:
            logger.info(
                "Also installing dependencies: %s."
                % ", ".join(dependencies_to_install)
            )
        logger.info("Will install the following namespaces: %s" % result)
        return [files[n] for n in result]
예제 #13
0
 def test_parse(self):
     """Test the parsing a file."""
     parser = OntologyParser.get_parser(YML_FILE)
     g1 = rdflib.Graph()
     g1.parse(RDF_FILE, format="ttl")
     self.assertTrue(parser.graph, g1)
예제 #14
0
 def test_get_requirements(self):
     """Test the get_requirements() method."""
     self.assertEqual(
         OntologyParser.get_parser(YML_FILE).requirements, set())
     self.assertEqual(
         OntologyParser.get_parser("parser_test").requirements, {"city"})
예제 #15
0
    def _resolve_dependencies_install(
        self,
        files: Dict[str, str],
        requirements: Dict[str, Set[str]],
        dependents: Dict[str, Set[str]],
    ) -> Dict[str, Set[str]]:
        """Find and resolve the dependencies of the packages to be installed.

        Automatic resolution of dependencies is only feasible if the
        dependency is bundled with OSP-core.

        Args:
            files: The packages that are going to be installed together with
                their file path.
            requirements: The dependencies for each package that is going to
                be installed.
            dependents: A dictionary with package names and the packages
                that depend on them.
        """
        initial_files = files
        additional_files: Dict[str, str] = dict()
        # The statement below avoids installing the file bundled with
        # OSP-core when the user provides a custom file providing the same
        # package identifier.
        requirements = {
            n: {req for req in requirements_set if req not in initial_files}
            for n, requirements_set in requirements.items()
        }
        new_requirements: Dict[str, Set[str]] = dict()
        for package, requirements_set in requirements.items():
            # Queue the requirements for installation if bundled with
            # OSP-core and not already queued.
            actually_missing_requirements = {
                package
                for package in requirements_set
                if package not in additional_files
            }
            for requirement in actually_missing_requirements:
                try:
                    parser = OntologyParser.get_parser(requirement)
                    additional_files[parser.identifier] = requirement
                    new_requirements.update(
                        {parser.identifier: parser.requirements}
                    )
                except FileNotFoundError:
                    pass

            # Store which packages are requiring the requirements that were
            # queued for installation to show the information on the logs.
            # In addition, the `dependents` dictionary keys are the
            # additional packages to be installed.
            initially_missing_requirements = {
                package
                for package in requirements_set
                if package not in initial_files
            }
            for requirement in initially_missing_requirements:
                dependents[requirement] = dependents.get(
                    requirement, set()
                ) | {package}
        files.update(additional_files)
        new_requirements_exist = bool(
            {req for req_set in new_requirements.values() for req in req_set}
            - {req for req_set in requirements.values() for req in req_set}
        )
        if new_requirements_exist:
            requirements.update(new_requirements)
            dependents = self._resolve_dependencies_install(
                files, requirements, dependents
            )
        return dependents
예제 #16
0
    def _get_remaining_packages(self, remove_packages):
        """Get package paths to install.

        Get list of packages that remain after given list of packages
        have been removed.

        Args:
            remove_packages (List[str]): List of packages to remove.

        Raises:
            ValueError: Given package to remove is not installed

        Returns:
            List[str]: The remaining packages.
        """
        remove_pkgs = set()
        installed_pkgs = dict(self.get_installed_packages(return_path=True))
        for pkg in remove_packages:
            if pkg.endswith(".yml") and os.path.exists(pkg):
                pkg = OntologyParser.get_parser(pkg).identifier
            if pkg in installed_pkgs:
                remove_pkgs.add(pkg)
            else:
                raise ValueError(
                    "Could not uninstall %s. No file nor "
                    "installed ontology package. "
                    "Make sure to only specify valid "
                    "yml files or ontology package names." % pkg
                )

        remaining_packages = {
            k: v for k, v in installed_pkgs.items() if k not in remove_pkgs
        }

        # Block package removal if another package depends on it.
        remaining_packages_requirements = {
            name: OntologyParser.get_parser(path).requirements
            for name, path in remaining_packages.items()
        }
        all_conflicts = self._resolve_dependencies_removal(
            remaining_packages_requirements, dict(), set(remove_pkgs)
        )
        if all_conflicts:
            """Raise an exception."""
            message = (
                "Cannot remove package{plural} {cannot_remove}{comma} "
                "because other installed packages depend on {pronoun}: "
                "{dependency_list}. "
                "Please remove the packages {all_packages_to_remove} "
                "all together."
            )
            cannot_remove = set(
                conflict
                for conflicts in all_conflicts.values()
                for conflict in conflicts
                if conflict in remove_pkgs
            )
            plural = "s" if len(cannot_remove) > 1 else ""
            comma = ";" if plural else ","
            pronoun = "them" if plural else "it"
            cannot_remove = ", ".join(cannot_remove)
            one_dependency = next(iter(all_conflicts.values()))
            all_dependencies_equal = all(
                one_dependency == x for x in all_conflicts.values()
            )
            if all_dependencies_equal:
                dependency_list = ", ".join(all_conflicts)
            else:
                dependency_list = set()
                for package, conflicts in all_conflicts.items():
                    dependency_list.add(
                        f"package {package} depends on "
                        f"{', '.join(conflicts)}"
                    )
                dependency_list = "; ".join(dependency_list)
            all_packages_to_remove = set(all_conflicts) | remove_pkgs
            last_package = all_packages_to_remove.pop()
            all_packages_to_remove = (
                ", ".join(all_packages_to_remove) + " and " + last_package
            )
            message = message.format(
                plural=plural,
                cannot_remove=cannot_remove,
                comma=comma,
                pronoun=pronoun,
                dependency_list=dependency_list,
                all_packages_to_remove=all_packages_to_remove,
            )
            raise RuntimeError(message)

        return [v for v in remaining_packages.values()]
예제 #17
0
"""Test the API of CUDS objects using the foaf ontology."""
import uuid

import rdflib
import unittest2 as unittest

try:
    from osp.core.namespaces import foaf
except ImportError:
    from osp.core.ontology.namespace_registry import namespace_registry
    from osp.core.ontology.parser.parser import OntologyParser

    namespace_registry.load_parser(OntologyParser.get_parser("foaf"))
    foaf = namespace_registry.foaf


class TestAPIfoaf(unittest.TestCase):
    """Test the API of CUDS objects using the foaf ontology."""
    def test_creation(self):
        """Test creation of objectes are possible."""
        c = foaf.Person()
        self.assertTrue(c.is_a(foaf.Person))

    def test_uid(self):
        """Test that the uid variable contains an uid."""
        c = foaf.Person()
        self.assertIsInstance(c.uid, (uuid.UUID, rdflib.URIRef))

    def test_relations(self):
        """Test some relationships."""
        a = foaf.Person()