From 40996df329aa18ac8e99d7ec8d14f77db31d9a61 Mon Sep 17 00:00:00 2001 From: francescalb Date: Thu, 19 Jan 2023 15:00:09 +0100 Subject: [PATCH 1/6] Added possibility to update ontology. Needs to be conitnued once issue #525 is fixed --- ontopy/excelparser.py | 45 ++++++++++++++++------ tests/test_excelparser/test_excelparser.py | 21 ++++++++++ tools/excel2onto | 41 +++++++++++++++++++- 3 files changed, 93 insertions(+), 14 deletions(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 5e7288844..857eb887d 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -44,6 +44,7 @@ def create_ontology_from_excel( # pylint: disable=too-many-arguments imports: list = None, catalog: dict = None, force: bool = False, + input_ontology: Union[ontopy.ontology.Ontology, None] = None, ) -> Tuple[ontopy.ontology.Ontology, dict, dict]: """ Creates an ontology from an Excel-file. @@ -72,6 +73,12 @@ def create_ontology_from_excel( # pylint: disable=too-many-arguments catalog: Imported ontologies with (name, full path) key/value-pairs. force: Forcibly make an ontology by skipping concepts that are erroneously defined or other errors in the excel sheet. + input_ontolgy: Ontology that should be updated. + Default is None, + which means that a completely new ontology is generated. + If an input_ontology to be updated is provided, + the metadata sheet in the excel sheet will not be considered. + Returns: A tuple with the: @@ -139,6 +146,7 @@ def _relative_to_absolute_paths(path): base_iri_from_metadata=base_iri_from_metadata, catalog=catalog, force=force, + input_ontology=input_ontology, ) @@ -150,6 +158,7 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran base_iri_from_metadata: bool = True, catalog: dict = None, force: bool = False, + input_ontology: Union[ontopy.ontology.Ontology, None] = None, ) -> Tuple[ontopy.ontology.Ontology, dict]: """ Create an ontology from a pandas DataFrame. @@ -166,15 +175,17 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran data = data[data["prefLabel"].str.len() > 0] data.reset_index(drop=True, inplace=True) - # Make new ontology - onto, catalog = get_metadata_from_dataframe( - metadata, base_iri, imports=imports - ) - - # Set given or default base_iri if base_iri_from_metadata is False. - if not base_iri_from_metadata: - onto.base_iri = base_iri + if input_ontology: + onto = input_ontology + catalog = {} + else: # Create new ontology + onto, catalog = get_metadata_from_dataframe( + metadata, base_iri, imports=imports + ) + # Set given or default base_iri if base_iri_from_metadata is False. + if not base_iri_from_metadata: + onto.base_iri = base_iri labels = set(data["prefLabel"]) for altlabel in data["altLabel"].str.strip(): if not altlabel == "nan": @@ -192,6 +203,7 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran } onto.sync_python_names() + with onto: remaining_rows = set(range(len(data))) all_added_rows = [] @@ -202,7 +214,11 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran name = row["prefLabel"] try: onto.get_by_label(name) - if onto.world[onto.base_iri + name]: + print(onto.get_by_label(name).iri) + if onto.base_iri in [ + a.namespace.base_iri + for a in onto.get_by_label_all(name) + ]: if not force: raise ExcelError( f'Concept "{name}" already in ontology' @@ -223,7 +239,6 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran continue except NoSuchLabelError: pass - if row["subClassOf"] == "nan": if not force: raise ExcelError(f"{row[0]} has no subClassOf") @@ -231,7 +246,6 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran concepts_with_errors["missing_parents"].append(name) else: parent_names = str(row["subClassOf"]).split(";") - parents = [] invalid_parent = False for parent_name in parent_names: @@ -264,6 +278,7 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran parents = [owlready2.Thing] concept = onto.new_entity(name, parents) + print("baseiri_after_defintion:", onto.get_by_label(name).iri) added_rows.add(index) # Add elucidation try: @@ -379,11 +394,17 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran onto.sync_attributes( name_policy="uuid", name_prefix="EMMO_", class_docstring="elucidation" ) + print( + [ + a.iri + for a in onto.get_by_label_all("*") + if a.namespace.base_iri == onto.base_iri + ] + ) onto.dir_label = False concepts_with_errors = { key: set(value) for key, value in concepts_with_errors.items() } - return onto, catalog, concepts_with_errors diff --git a/tests/test_excelparser/test_excelparser.py b/tests/test_excelparser/test_excelparser.py index 34c069d4b..7dce3cabe 100644 --- a/tests/test_excelparser/test_excelparser.py +++ b/tests/test_excelparser/test_excelparser.py @@ -1,8 +1,10 @@ """Test the Excel parser module.""" +import pytest from typing import TYPE_CHECKING from ontopy import get_ontology from ontopy.excelparser import create_ontology_from_excel +from ontopy.utils import NoSuchLabelError if TYPE_CHECKING: from pathlib import Path @@ -14,6 +16,9 @@ def test_excelparser(repo_dir: "Path") -> None: onto = get_ontology(str(ontopath)).load() xlspath = repo_dir / "tests" / "test_excelparser" / "onto.xlsx" + update_xlspath = ( + repo_dir / "tests" / "test_excelparser" / "onto_update.xlsx" + ) ontology, catalog, errors = create_ontology_from_excel(xlspath, force=True) assert onto == ontology @@ -33,3 +38,19 @@ def test_excelparser(repo_dir: "Path") -> None: } assert len(ontology.get_by_label_all("Atom")) == 2 + onto_length = len(list(onto.get_entities())) + with pytest.raises(NoSuchLabelError): + onto.ATotallyNewPattern + + updated_onto, _, _ = create_ontology_from_excel( + update_xlspath, force=True, input_ontology=ontology + ) + # print(set(list(onto.get_entities())).symmetric_difference(list(updated_onto.get_entities()))) + # assert len(list(updated_onto.get_entities())) == onto_length + 1 + assert updated_onto.ATotallyNewPattern + + assert updated_onto.Pattern.iri == onto.Pattern.iri + + new_onto, catalog, errors = create_ontology_from_excel(xlspath, force=True) + + assert updated_onto.Pattern.iri != new_onto.Pattern.iri diff --git a/tools/excel2onto b/tools/excel2onto index 0e00f962e..96bbe6b77 100755 --- a/tools/excel2onto +++ b/tools/excel2onto @@ -7,8 +7,10 @@ ontology_template.xlsx import argparse import sys import os +import warnings from ontopy.excelparser import create_ontology_from_excel, ExcelError from ontopy.utils import write_catalog +from ontopy import get_ontology import owlready2 # pylint: disable=C0411 @@ -37,21 +39,56 @@ def main(): help="Whether to force generation of ontology on non-fatal error.", ) + parser.add_argument( + "--update", + "-u", + default=True, + help="Whether to update the the ontology with new concepts or" + "or regenerate the full ontology." + "Currently only supports adding new concepts" + "Default is True.", + ) + + parser.add_argument( + "--input_ontology", + "-i", + default="ontology.ttl", + help="Path of previously generated ontology to update with" + " new concepts." + "Deafult is the same 'output'(ontology.ttl).", + ) + try: args = parser.parse_args() except SystemExit as exc: sys.exit(exc.code) # Exit without traceback on invalid arguments + if args.update: + try: + input_ontology = get_ontology(args.input_ontology).load() + except FileNotFoundError as err: + if args.force: + warnings.warn( + "Did not find the input ontology, " + "will fully generate a new one." + ) + input_ontology = None + else: + raise err + try: ontology, catalog, _ = create_ontology_from_excel( - args.excelpath, force=args.force + args.excelpath, + force=args.force, + input_ontology=input_ontology, ) except ExcelError as exc: parser.exit(1, f"ERROR: {exc}\n") # Save new ontology as turtle ontology.save(os.path.join(args.output), format="turtle", overwrite=True) - write_catalog(catalog) + if not args.update: + write_catalog(catalog) if __name__ == "__main__": From 3fa51887363143a5f529241e8f47fe202b8a0a6a Mon Sep 17 00:00:00 2001 From: francescalb Date: Thu, 19 Jan 2023 19:11:28 +0100 Subject: [PATCH 2/6] Updated test to test that updated onto has unchanged old classes and correct new class --- tests/test_excelparser/test_excelparser.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/test_excelparser/test_excelparser.py b/tests/test_excelparser/test_excelparser.py index 7dce3cabe..70d202888 100644 --- a/tests/test_excelparser/test_excelparser.py +++ b/tests/test_excelparser/test_excelparser.py @@ -45,12 +45,6 @@ def test_excelparser(repo_dir: "Path") -> None: updated_onto, _, _ = create_ontology_from_excel( update_xlspath, force=True, input_ontology=ontology ) - # print(set(list(onto.get_entities())).symmetric_difference(list(updated_onto.get_entities()))) - # assert len(list(updated_onto.get_entities())) == onto_length + 1 assert updated_onto.ATotallyNewPattern - assert updated_onto.Pattern.iri == onto.Pattern.iri - - new_onto, catalog, errors = create_ontology_from_excel(xlspath, force=True) - - assert updated_onto.Pattern.iri != new_onto.Pattern.iri + assert len(list(onto.classes())) + 1 == len(list(updated_onto.classes())) From 66f81789137e548a6075aec58592d0ed62010107 Mon Sep 17 00:00:00 2001 From: francescalb Date: Thu, 19 Jan 2023 19:57:56 +0100 Subject: [PATCH 3/6] Added update_onto.xlsx --- ontopy/excelparser.py | 9 --------- tests/test_excelparser/onto_update.xlsx | Bin 0 -> 11640 bytes 2 files changed, 9 deletions(-) create mode 100755 tests/test_excelparser/onto_update.xlsx diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index 857eb887d..eabf0c0cc 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -214,7 +214,6 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran name = row["prefLabel"] try: onto.get_by_label(name) - print(onto.get_by_label(name).iri) if onto.base_iri in [ a.namespace.base_iri for a in onto.get_by_label_all(name) @@ -278,7 +277,6 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran parents = [owlready2.Thing] concept = onto.new_entity(name, parents) - print("baseiri_after_defintion:", onto.get_by_label(name).iri) added_rows.add(index) # Add elucidation try: @@ -394,13 +392,6 @@ def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-bran onto.sync_attributes( name_policy="uuid", name_prefix="EMMO_", class_docstring="elucidation" ) - print( - [ - a.iri - for a in onto.get_by_label_all("*") - if a.namespace.base_iri == onto.base_iri - ] - ) onto.dir_label = False concepts_with_errors = { key: set(value) for key, value in concepts_with_errors.items() diff --git a/tests/test_excelparser/onto_update.xlsx b/tests/test_excelparser/onto_update.xlsx new file mode 100755 index 0000000000000000000000000000000000000000..415c8cc1230d7e334f708b1acd4679baa0fa6467 GIT binary patch literal 11640 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 P{Gxb1;0V%u|MmX?F- Date: Thu, 19 Jan 2023 20:11:00 +0100 Subject: [PATCH 4/6] typo --- ontopy/excelparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py index eabf0c0cc..71775f48f 100755 --- a/ontopy/excelparser.py +++ b/ontopy/excelparser.py @@ -73,7 +73,7 @@ def create_ontology_from_excel( # pylint: disable=too-many-arguments catalog: Imported ontologies with (name, full path) key/value-pairs. force: Forcibly make an ontology by skipping concepts that are erroneously defined or other errors in the excel sheet. - input_ontolgy: Ontology that should be updated. + input_ontology: Ontology that should be updated. Default is None, which means that a completely new ontology is generated. If an input_ontology to be updated is provided, From 7795e7efa5e8610e15397f8e187775258e943398 Mon Sep 17 00:00:00 2001 From: francescalb Date: Thu, 19 Jan 2023 23:35:31 +0100 Subject: [PATCH 5/6] Added test for tools with pathfixes --- ontopy/ontology.py | 2 - .../{ => result_ontology}/catalog-v001.xml | 6 +-- .../{ => result_ontology}/fromexcelonto.ttl | 0 tests/test_excelparser/test_excelparser.py | 8 +++- tests/tools/test_excel2onto.py | 39 +++++++++++++++++++ tools/excel2onto | 21 +++++++--- 6 files changed, 64 insertions(+), 12 deletions(-) rename tests/test_excelparser/{ => result_ontology}/catalog-v001.xml (65%) rename tests/test_excelparser/{ => result_ontology}/fromexcelonto.ttl (100%) create mode 100644 tests/tools/test_excel2onto.py diff --git a/ontopy/ontology.py b/ontopy/ontology.py index dd75384a7..77028aa6b 100644 --- a/ontopy/ontology.py +++ b/ontopy/ontology.py @@ -540,7 +540,6 @@ def _load( # pylint: disable=too-many-arguments,too-many-locals,too-many-branch ): """Help function for load().""" web_protocol = "http://", "https://", "ftp://" - url = str(filename) if filename else self.base_iri.rstrip("/#") if url.startswith(web_protocol): baseurl = os.path.dirname(url) @@ -594,7 +593,6 @@ def getmtime(path): ) self.world._iri_mappings.update(iris) resolved_url = self.world._iri_mappings.get(url, url) - # Append paths from catalog file to onto_path for path in sorted(dirs, reverse=True): if path not in owlready2.onto_path: diff --git a/tests/test_excelparser/catalog-v001.xml b/tests/test_excelparser/result_ontology/catalog-v001.xml similarity index 65% rename from tests/test_excelparser/catalog-v001.xml rename to tests/test_excelparser/result_ontology/catalog-v001.xml index 698ab79a1..c7eff86b2 100644 --- a/tests/test_excelparser/catalog-v001.xml +++ b/tests/test_excelparser/result_ontology/catalog-v001.xml @@ -2,8 +2,8 @@ - - - + + + diff --git a/tests/test_excelparser/fromexcelonto.ttl b/tests/test_excelparser/result_ontology/fromexcelonto.ttl similarity index 100% rename from tests/test_excelparser/fromexcelonto.ttl rename to tests/test_excelparser/result_ontology/fromexcelonto.ttl diff --git a/tests/test_excelparser/test_excelparser.py b/tests/test_excelparser/test_excelparser.py index 70d202888..9ae141e34 100644 --- a/tests/test_excelparser/test_excelparser.py +++ b/tests/test_excelparser/test_excelparser.py @@ -12,7 +12,13 @@ def test_excelparser(repo_dir: "Path") -> None: """Basic test for creating an ontology from an Excel file.""" - ontopath = repo_dir / "tests" / "test_excelparser" / "fromexcelonto.ttl" + ontopath = ( + repo_dir + / "tests" + / "test_excelparser" + / "result_ontology" + / "fromexcelonto.ttl" + ) onto = get_ontology(str(ontopath)).load() xlspath = repo_dir / "tests" / "test_excelparser" / "onto.xlsx" diff --git a/tests/tools/test_excel2onto.py b/tests/tools/test_excel2onto.py new file mode 100644 index 000000000..59505d7b7 --- /dev/null +++ b/tests/tools/test_excel2onto.py @@ -0,0 +1,39 @@ +"""Test the `ontograph` tool.""" +from pathlib import Path +import os +import pytest + + +@pytest.mark.parametrize("tool", ["excel2onto"], indirect=True) +def test_run(tool, tmpdir: Path) -> None: + """Check that running `excel2onto` works.""" + test_file = ( + Path(__file__).resolve().parent.parent + / "test_excelparser" + / "onto.xlsx" + ) + test_file2 = ( + Path(__file__).resolve().parent.parent + / "test_excelparser" + / "onto_update.xlsx" + ) + + tool.main([f"--output={str(tmpdir)}/onto.ttl", "--force", str(test_file)]) + + tool.main( + [ + f"--output={str(tmpdir)}/onto.ttl", + "--force", + "--input_ontology=newonto.ttl", + str(test_file2), + ] + ) + + tool.main( + [ + f"--output={str(tmpdir)}/ontology.ttl", + "--force", + "--update=False", + str(test_file), + ] + ) diff --git a/tools/excel2onto b/tools/excel2onto index 96bbe6b77..5013c28f0 100755 --- a/tools/excel2onto +++ b/tools/excel2onto @@ -19,8 +19,16 @@ def english(string): return owlready2.locstr(string, lang="en") -def main(): - """Main run function.""" +def main(argv: list = None): + """Main run function. + + Parameters: + argv: List of arguments, similar to `sys.argv[1:]`. + Mainly for testing purposes, since it allows one to invoke the tool + manually / through Python. + + """ + parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "excelpath", @@ -59,7 +67,7 @@ def main(): ) try: - args = parser.parse_args() + args = parser.parse_args(args=argv) except SystemExit as exc: sys.exit(exc.code) # Exit without traceback on invalid arguments @@ -78,7 +86,7 @@ def main(): try: ontology, catalog, _ = create_ontology_from_excel( - args.excelpath, + os.path.abspath(args.excelpath), force=args.force, input_ontology=input_ontology, ) @@ -87,8 +95,9 @@ def main(): # Save new ontology as turtle ontology.save(os.path.join(args.output), format="turtle", overwrite=True) - if not args.update: - write_catalog(catalog) + dirname = os.path.dirname(args.output) + if (not args.update) or (not os.path.exists(dirname + "/catalog-v001.xml")): + write_catalog(catalog, directory=dirname) if __name__ == "__main__": From 92a659a703003dd0c023a18e0cf683835f1a2a16 Mon Sep 17 00:00:00 2001 From: francescalb Date: Thu, 19 Jan 2023 23:54:59 +0100 Subject: [PATCH 6/6] Fixed default ontology to update to be same as output --- tools/excel2onto | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/excel2onto b/tools/excel2onto index 5013c28f0..525fae061 100755 --- a/tools/excel2onto +++ b/tools/excel2onto @@ -51,7 +51,7 @@ def main(argv: list = None): "--update", "-u", default=True, - help="Whether to update the the ontology with new concepts or" + help="Whether to update the the ontology with new concepts " "or regenerate the full ontology." "Currently only supports adding new concepts" "Default is True.", @@ -60,10 +60,10 @@ def main(argv: list = None): parser.add_argument( "--input_ontology", "-i", - default="ontology.ttl", + default=None, help="Path of previously generated ontology to update with" " new concepts." - "Deafult is the same 'output'(ontology.ttl).", + "Deafult is the same as 'output'.", ) try: @@ -73,7 +73,10 @@ def main(argv: list = None): if args.update: try: - input_ontology = get_ontology(args.input_ontology).load() + if args.input_ontology: + input_ontology = get_ontology(args.input_ontology).load() + else: + input_ontology = get_ontology(args.output).load() except FileNotFoundError as err: if args.force: warnings.warn(