diff --git a/examples/ontology-from-excel/make_microstructure_onto.py b/examples/ontology-from-excel/make_microstructure_onto.py
index 418d812b7..19664e507 100755
--- a/examples/ontology-from-excel/make_microstructure_onto.py
+++ b/examples/ontology-from-excel/make_microstructure_onto.py
@@ -4,7 +4,7 @@
from ontopy.excelparser import create_ontology_from_excel
from ontopy.utils import write_catalog
-ontology, catalog = create_ontology_from_excel("tool/onto.xlsx")
+ontology, catalog = create_ontology_from_excel("tool/microstructure.xlsx")
ontology.save("microstructure_ontology.ttl", format="turtle", overwrite=True)
write_catalog(catalog)
diff --git a/examples/ontology-from-excel/tool/microstructure.xlsx b/examples/ontology-from-excel/tool/microstructure.xlsx
new file mode 100755
index 000000000..0e786cb02
Binary files /dev/null and b/examples/ontology-from-excel/tool/microstructure.xlsx differ
diff --git a/ontopy/excelparser.py b/ontopy/excelparser.py
index a2dfb091a..ccdcdc32b 100755
--- a/ontopy/excelparser.py
+++ b/ontopy/excelparser.py
@@ -9,17 +9,23 @@
Note that correct case is mandatory.
"""
+from typing import Tuple, Union, Sequence
import warnings
-from typing import Tuple, Union
-import pyparsing
+
import pandas as pd
+import pyparsing
+
import ontopy
-from ontopy import World
-from ontopy.utils import NoSuchLabelError
+from ontopy import get_ontology
+from ontopy.utils import EMMOntoPyException, NoSuchLabelError
from ontopy.manchester import evaluate
import owlready2 # pylint: disable=C0411
+class ExcelError(EMMOntoPyException):
+ """Raised on errors in Excel file."""
+
+
def english(string):
"""Returns `string` as an English location string."""
return owlready2.locstr(string, lang="en")
@@ -29,118 +35,276 @@ def create_ontology_from_excel( # pylint: disable=too-many-arguments
excelpath: str,
concept_sheet_name: str = "Concepts",
metadata_sheet_name: str = "Metadata",
+ imports_sheet_name: str = "ImportedOntologies",
base_iri: str = "http://emmo.info/emmo/domain/onto#",
base_iri_from_metadata: bool = True,
+ imports: list = None,
catalog: dict = None,
+ force: bool = False,
) -> Tuple[ontopy.ontology.Ontology, dict]:
"""
- Creates an ontology from an excelfile.
+ Creates an ontology from an Excel-file.
+
+ Arguments:
+ excelpath: Path to Excel workbook.
+ concept_sheet_name: Name of sheet where concepts are defined.
+ The second row of this sheet should contain column names that are
+ supported. Currently these are 'prefLabel','altLabel',
+ 'Elucidation', 'Comments', 'Examples', 'subClassOf', 'Relations'.
+ Multiple entries are separated with ';'.
+ metadata_sheet_name: Name of sheet where metadata are defined.
+ The first row contains column names 'Metadata name' and 'Value'
+ Supported 'Metadata names' are: 'Ontology IRI',
+ 'Ontology vesion IRI', 'Ontology version Info', 'Title',
+ 'Abstract', 'License', 'Comment', 'Author', 'Contributor'.
+ Multiple entries are separated with a semi-colon (`;`).
+ imports_sheet_name: Name of sheet where imported ontologies are
+ defined.
+ Column name is 'Imported ontologies'.
+ Fully resolvable URL or path to imported ontologies provided one
+ per row.
+ base_iri: Base IRI of the new ontology.
+ base_iri_from_metadata: Whether to use base IRI defined from metadata.
+ imports: List of imported ontologies.
+ catalog: Imported ontologies with (name, full path) key/value-pairs.
+ force: Forcibly make an ontology by skipping concepts with a prefLabel
+ that is erroneously defined.
+
+ Returns:
+ A tuple of the created ontology and the associated catalog of ontology
+ names and resolvable path as dict.
+
- Catalog is dict of imported ontologies with key name and value path.
"""
+ # Get imported ontologies from optional "Imports" sheet
+ if not imports:
+ imports = []
+ try:
+ imports_frame = pd.read_excel(
+ excelpath, sheet_name=imports_sheet_name, skiprows=[1]
+ )
+ except ValueError:
+ pass
+ else:
+ imports.extend(imports_frame["Imported ontologies"].to_list())
+
# Read datafile TODO: Some magic to identify the header row
conceptdata = pd.read_excel(
excelpath, sheet_name=concept_sheet_name, skiprows=[0, 2]
)
metadata = pd.read_excel(excelpath, sheet_name=metadata_sheet_name)
return create_ontology_from_pandas(
- conceptdata, metadata, base_iri, base_iri_from_metadata, catalog
+ data=conceptdata,
+ metadata=metadata,
+ imports=imports,
+ base_iri=base_iri,
+ base_iri_from_metadata=base_iri_from_metadata,
+ catalog=catalog,
+ force=force,
)
-def create_ontology_from_pandas( # pylint: disable=too-many-locals,too-many-branches,too-many-statements
+def create_ontology_from_pandas( # pylint:disable=too-many-locals,too-many-branches,too-many-statements,too-many-arguments
data: pd.DataFrame,
metadata: pd.DataFrame,
+ imports: list,
base_iri: str = "http://emmo.info/emmo/domain/onto#",
base_iri_from_metadata: bool = True,
catalog: dict = None,
+ force: bool = False,
) -> Tuple[ontopy.ontology.Ontology, dict]:
"""
Create an ontology from a pandas DataFrame.
"""
- # Remove Concepts without prefLabel and make all to string
+ # Remove lines with empty prefLabel
data = data[data["prefLabel"].notna()]
- data = data.astype({"prefLabel": "str"})
+ # Convert all data to string, remove spaces, and finally remove
+ # additional rows with empty prefLabel.
+ data = data.astype(str)
+ data["prefLabel"] = data["prefLabel"].str.strip()
+ 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)
+ onto, catalog = get_metadata_from_dataframe(
+ metadata, base_iri, imports=imports
+ )
- # base_iri from metadata if it exists and base_iri_from_metadata
+ # 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":
+ labels.update(altlabel.split(";"))
+
onto.sync_python_names()
with onto:
- # loop through the rows until no more are added
- new_loop = True
- final_loop = False
- while new_loop:
- number_of_added_classes = 0
- for _, row in data.iterrows():
+ remaining_rows = set(range(len(data)))
+ while remaining_rows:
+ added_rows = set()
+ for index in remaining_rows:
+ row = data.loc[index]
name = row["prefLabel"]
try:
- if isinstance(
- onto.get_by_label(name), owlready2.ThingClass
- ):
- continue
+ onto.get_by_label(name)
+ if not force:
+ raise ExcelError(
+ f'Concept "{name}" already in ontology'
+ )
+ warnings.warn(
+ f'Ignoring concept "{name}" since it is already in '
+ "the ontology."
+ )
+ # What to do if we want to add info to this concept?
+ # Should that be not allowed?
+ # If it should be allowed the index has to be added to
+ # added_rows
+ continue
+ except (ValueError, TypeError) as err:
+ warnings.warn(
+ f'Ignoring concept "{name}". '
+ f'The following error was raised: "{err}"'
+ )
+ continue
except NoSuchLabelError:
pass
- parent_names = str(row["subClassOf"]).split(";")
+ if pd.isna(row["subClassOf"]):
+ if not force:
+ raise ExcelError(f"{row[0]} has no subClassOf")
+ parent_names = [] # Should be "owl:Thing"
+ else:
+ parent_names = str(row["subClassOf"]).split(";")
+
+ parents = []
+ invalid_parent = False
+ for parent_name in parent_names:
+ try:
+ parent = onto.get_by_label(parent_name.strip())
+ except (NoSuchLabelError, ValueError) as exc:
+ if parent_name not in labels:
+ if force:
+ warnings.warn(
+ f'Invalid parents for "{name}": '
+ f'"{parent_name}".'
+ )
+ break
+ raise ExcelError(
+ f'Invalid parents for "{name}": {exc}\n'
+ "Have you forgotten an imported ontology?"
+ ) from exc
+ invalid_parent = True
+ break
+ else:
+ parents.append(parent)
- try:
- parents = [onto.get_by_label(pn) for pn in parent_names]
- except NoSuchLabelError:
- if final_loop is True:
- parents = owlready2.Thing
+ if invalid_parent:
+ continue
- warnings.warn(
- "Missing at least one of the defined parents. "
- f"Concept: {name}; Defined parents: {parent_names}"
- )
- new_loop = False
- else:
- continue
+ if not parents:
+ parents = [owlready2.Thing]
concept = onto.new_entity(name, parents)
+ added_rows.add(index)
# Add elucidation
- _add_literal(
- row, concept.elucidation, "Elucidation", only_one=True
- )
+ try:
+ _add_literal(
+ row,
+ concept.elucidation,
+ "Elucidation",
+ only_one=True,
+ )
+ except AttributeError as err:
+ if force:
+ _add_literal(
+ row,
+ concept.comment,
+ "Elucidation",
+ only_one=True,
+ )
+ warnings.warn("Elucidation added as comment.")
+ else:
+ raise ExcelError(
+ f"Not able to add elucidations. {err}."
+ ) from err
# Add examples
- _add_literal(row, concept.example, "Examples")
+ try:
+ _add_literal(
+ row, concept.example, "Examples", expected=False
+ )
+ except AttributeError:
+ if force:
+ warnings.warn(
+ "Not able to add examples. "
+ "Did you forget to import an ontology?."
+ )
# Add comments
- _add_literal(row, concept.comment, "Comments")
+ _add_literal(row, concept.comment, "Comments", expected=False)
- # Add altLAbels
- _add_literal(row, concept.altLabel, "altLabel")
+ # Add altLabels
+ try:
+ _add_literal(
+ row, concept.altLabel, "altLabel", expected=False
+ )
+ except AttributeError as err:
+ if force is True:
+ _add_literal(
+ row,
+ concept.label,
+ "altLabel",
+ expected=False,
+ )
+ warnings.warn("altLabel added as rdfs.label.")
+ else:
+ raise ExcelError(
+ f"Not able to add altLabels. " f"{err}."
+ ) from err
- number_of_added_classes += 1
+ remaining_rows.difference_update(added_rows)
- if number_of_added_classes == 0:
- final_loop = True
+ # Detect infinite loop...
+ if not added_rows and remaining_rows:
+ unadded = [data.loc[i].prefLabel for i in remaining_rows]
+ if force is True:
+ warnings.warn(
+ f"Not able to add the following concepts: {unadded}."
+ " Will continue without these."
+ )
+ remaining_rows = False
+ else:
+ raise ExcelError(
+ f"Not able to add the following concepts: {unadded}."
+ )
# Add properties in a second loop
- for _, row in data.iterrows():
+ for index in added_rows:
+ row = data.loc[index]
properties = row["Relations"]
if isinstance(properties, str):
try:
- concept = onto.get_by_label(row["prefLabel"])
+ concept = onto.get_by_label(row["prefLabel"].strip())
except NoSuchLabelError:
pass
props = properties.split(";")
for prop in props:
try:
concept.is_a.append(evaluate(onto, prop))
- except pyparsing.ParseException as err:
+ except pyparsing.ParseException as exc:
warnings.warn(
f"Error in Property assignment for: {concept}. "
f"Property to be Evaluated: {prop}. "
- f"Error is {err}."
+ f"Error is {exc}."
)
+ except NoSuchLabelError as exc:
+ if force is True:
+ pass
+ else:
+ raise ExcelError(exc) from exc
# Synchronise Python attributes to ontology
onto.sync_attributes(
@@ -154,11 +318,10 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra
metadata: pd.DataFrame,
base_iri: str,
base_iri_from_metadata: bool = True,
+ imports: Sequence = (),
catalog: dict = None,
) -> Tuple[ontopy.ontology.Ontology, dict]:
- """
- Create ontology with metadata from pd.DataFrame
- """
+ """Create ontology with metadata from pd.DataFrame"""
# base_iri from metadata if it exists and base_iri_from_metadata
if base_iri_from_metadata:
@@ -169,54 +332,73 @@ def get_metadata_from_dataframe( # pylint: disable=too-many-locals,too-many-bra
"More than one Ontology IRI given. The first was chosen."
)
base_iri = base_iris[0] + "#"
- except (TypeError, ValueError, AttributeError):
+ except (TypeError, ValueError, AttributeError, IndexError):
pass
- # Make new ontology
- world = World()
- onto = world.get_ontology(base_iri)
+ # Create new ontology
+ onto = get_ontology(base_iri)
- # Get imported ontologies from metadata
- try:
- imported_ontology_paths = _parse_literal(
- metadata,
- "Imported ontologies",
- metadata=True,
- )
- except (TypeError, ValueError, AttributeError):
- imported_ontology_paths = []
# Add imported ontologies
catalog = {} if catalog is None else catalog
- for path in imported_ontology_paths:
- imported = onto.world.get_ontology(path).load()
- onto.imported_ontologies.append(imported)
- catalog[imported.base_iri.rstrip("/")] = path
+ locations = set()
+ for location in imports:
+ if not pd.isna(location) and location not in locations:
+ imported = onto.world.get_ontology(location).load()
+ onto.imported_ontologies.append(imported)
+ catalog[imported.base_iri.rstrip("#/")] = location
+ locations.add(location)
with onto:
# Add title
- _add_literal(
- metadata, onto.metadata.title, "Title", metadata=True, only_one=True
- )
+ try:
+ _add_literal(
+ metadata,
+ onto.metadata.title,
+ "Title",
+ metadata=True,
+ only_one=True,
+ )
+ except AttributeError:
+ pass
# Add license
- _add_literal(metadata, onto.metadata.license, "License", metadata=True)
+ try:
+ _add_literal(
+ metadata, onto.metadata.license, "License", metadata=True
+ )
+ except AttributeError:
+ pass
- # Add authors onto.metadata.author does not work!
- _add_literal(metadata, onto.metadata.creator, "Author", metadata=True)
+ # Add authors/creators
+ try:
+ _add_literal(
+ metadata, onto.metadata.creator, "Author", metadata=True
+ )
+ except AttributeError:
+ pass
# Add contributors
- _add_literal(
- metadata, onto.metadata.contributor, "Contributor", metadata=True
- )
+ try:
+ _add_literal(
+ metadata,
+ onto.metadata.contributor,
+ "Contributor",
+ metadata=True,
+ )
+ except AttributeError:
+ pass
# Add versionInfo
- _add_literal(
- metadata,
- onto.metadata.versionInfo,
- "Ontology version Info",
- metadata=True,
- only_one=True,
- )
+ try:
+ _add_literal(
+ metadata,
+ onto.metadata.versionInfo,
+ "Ontology version Info",
+ metadata=True,
+ only_one=True,
+ )
+ except AttributeError:
+ pass
return onto, catalog
@@ -235,9 +417,9 @@ def _parse_literal(
values = data.loc[data["Metadata name"] == name]["Value"].item()
else:
values = data[name]
- if not pd.isna(values):
+ if not (pd.isna(values) or values == "nan"):
return str(values).split(sep)
- return values.split(sep)
+ return []
def _add_literal( # pylint: disable=too-many-arguments
@@ -247,7 +429,9 @@ def _add_literal( # pylint: disable=too-many-arguments
metadata: bool = False,
only_one: bool = False,
sep: str = ";",
+ expected: bool = True,
) -> None:
+ """Append literal data to ontological entity."""
try:
name_list = _parse_literal(data, name, metadata=metadata, sep=sep)
if only_one is True and len(name_list) > 1:
@@ -258,4 +442,8 @@ def _add_literal( # pylint: disable=too-many-arguments
else:
destination.extend([english(nm) for nm in name_list])
except (TypeError, ValueError, AttributeError):
- warnings.warn(f"No {name} added.")
+ if expected:
+ if metadata:
+ warnings.warn(f"Missing metadata {name}")
+ else:
+ warnings.warn(f"{data[0]} has no {name}")
diff --git a/ontopy/ontology.py b/ontopy/ontology.py
index bf1077c87..8fc6db5f8 100644
--- a/ontopy/ontology.py
+++ b/ontopy/ontology.py
@@ -321,7 +321,7 @@ def get_by_label(
if entity:
return entity
- raise NoSuchLabelError(f"No label annotations matches {label}")
+ raise NoSuchLabelError(f"No label annotations matches {label!r}")
def get_by_label_all(self, label, label_annotations=None, namespace=None):
"""Like get_by_label(), but returns a list with all matching labels.
diff --git a/tests/test_excelparser.py b/tests/test_excelparser.py
index 22d871e9a..9cf1fd3ee 100644
--- a/tests/test_excelparser.py
+++ b/tests/test_excelparser.py
@@ -1,17 +1,20 @@
+"""Test the Excel parser module."""
+from typing import TYPE_CHECKING
+
from ontopy import get_ontology
from ontopy.excelparser import create_ontology_from_excel
-from ontopy.utils import write_catalog
+
+if TYPE_CHECKING:
+ from pathlib import Path
def test_excelparser(repo_dir: "Path") -> None:
+ """Basic test for creating an ontology from an Excel file."""
ontopath = (
repo_dir / "tests" / "testonto" / "excelparser" / "fromexcelonto.ttl"
)
+
onto = get_ontology(str(ontopath)).load()
xlspath = repo_dir / "tests" / "testonto" / "excelparser" / "onto.xlsx"
- ontology, catalog = create_ontology_from_excel(xlspath)
+ ontology, catalog = create_ontology_from_excel(xlspath, force=True)
assert onto == ontology
-
-
-if __name__ == "__main__":
- test_excelparser()
diff --git a/tests/testonto/excelparser/fromexcelonto.ttl b/tests/testonto/excelparser/fromexcelonto.ttl
index f3434c173..6953c53d5 100644
--- a/tests/testonto/excelparser/fromexcelonto.ttl
+++ b/tests/testonto/excelparser/fromexcelonto.ttl
@@ -6,57 +6,42 @@
@prefix term: .
a owl:Ontology ;
- term:creator "Astrid Marthinsen"@en,
- "Georg Schmidt"@en,
+ term:contributor "SINTEF"@en,
+ "SINTEF Industry"@en ;
+ term:creator "Francesca L. Bleken"@en,
"Jesper Friis"@en,
- "Sylvain Gouttebroze"@en,
- "Tomas Manik"@en,
- "Ulrike Cihak-Bayr"@en ;
- term:title "Microstructure ontology based on EMMO - Top concepts"@en ;
+ "Sylvain Gouttebroze"@en ;
+ term:title "A test domain ontology"@en ;
owl:imports ;
owl:versionInfo "0.01"@en .
:EMMO_0264be35-e8ad-5b35-a1a3-84b37bde22d1 a owl:Class ;
emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Temporal pattern occurring in a time interval"@en ;
emmo:EMMO_b432d2d5_25f4_4165_99c5_5935a7763c1a "Light house during one night"@en ;
- rdfs:subClassOf [ a owl:Restriction ;
- owl:onProperty emmo:EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f ;
- owl:someValuesFrom :EMMO_b41c9cb3-3b2d-509f-9c93-aa04da134307 ],
- [ a owl:Restriction ;
- owl:onProperty emmo:EMMO_e1097637_70d2_4895_973f_2396f04fa204 ;
- owl:someValuesFrom emmo:EMMO_d4f7d378_5e3b_468a_baa1_a7e98358cda7 ],
- :EMMO_138590b8-3333-515d-87ab-717aac8434e6,
+ rdfs:subClassOf :EMMO_138590b8-3333-515d-87ab-717aac8434e6,
:EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8 ;
core:prefLabel "FiniteTemporalPattern"@en .
-:EMMO_70269d17-fbaa-54a6-8905-ce4dee45e0dd a owl:Class ;
+:EMMO_1c81f1eb-8b94-5e74-96de-1aeacbdb5b93 a owl:Class ;
+ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "The boundary of a grain"@en ;
+ rdfs:subClassOf :EMMO_472ed27e-ce08-53cb-8453-56ab363275c4 ;
+ core:prefLabel "GrainBoundary"@en .
+
+:EMMO_6920d08f-b1e4-5789-9778-f75f4514ef46 a owl:Class ;
+ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ;
rdfs:subClassOf owl:Thing ;
- core:prefLabel "Particle"@en .
+ core:prefLabel "SpatioTemporalBoundary"@en .
:EMMO_76b2eb15-3ab7-52b3-ade2-755aa390d63e a owl:Class ;
emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Spatial pattern localized in a volume of space"@en ;
emmo:EMMO_b432d2d5_25f4_4165_99c5_5935a7763c1a "Textured surface after etching"@en ;
- rdfs:subClassOf [ a owl:Restriction ;
- owl:onProperty emmo:EMMO_e1097637_70d2_4895_973f_2396f04fa204 ;
- owl:someValuesFrom emmo:EMMO_f1a51559_aa3d_43a0_9327_918039f0dfed ],
- [ a owl:Restriction ;
- owl:onProperty emmo:EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f ;
- owl:someValuesFrom :EMMO_472ed27e-ce08-53cb-8453-56ab363275c4 ],
- :EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8,
+ rdfs:subClassOf :EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8,
:EMMO_5f50f77e-f321-53e3-af76-fe5b0a347479 ;
core:prefLabel "FiniteSpatialPattern"@en .
-:EMMO_903bf818-c0b4-56ef-9673-799ba204795d a owl:Class ;
- rdfs:subClassOf owl:Thing ;
- core:prefLabel "Precipitate"@en .
-
-:EMMO_b0f0e57e-464d-562f-80ec-b216c92d5e88 a owl:Class ;
- rdfs:subClassOf owl:Thing ;
- core:prefLabel "Grain"@en .
-
-:EMMO_d35b8f2a-64c0-5f57-a569-308bc8f8a1c5 a owl:Class ;
- rdfs:subClassOf owl:Thing ;
- core:prefLabel "Phase"@en .
+:EMMO_b04965e6-a9bb-591f-8f8a-1adcb2c8dc39 a owl:Class ;
+ rdfs:subClassOf emmo:EMMO_21f56795_ee72_4858_b571_11cfaa59c1a8 ;
+ core:prefLabel "1"@en .
:EMMO_e0b20a22-7e6f-5c81-beca-35bc5358e11b a owl:Class ;
emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ;
@@ -64,14 +49,28 @@
:EMMO_9fa9ca88-2891-538a-a8dd-ccb8a08b9890 ;
core:prefLabel "FiniteSpatioTemporalPattern"@en .
+:EMMO_e633d033-2af6-5f04-a706-dab826854fb1 a owl:Class ;
+ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "The boundary of a subgrain"@en ;
+ rdfs:subClassOf owl:Thing ;
+ core:prefLabel "SubgrainBoundary"@en .
+
+:EMMO_f8ad57d3-6cb5-5628-99e6-eb5915bece3a a owl:Class ;
+ rdfs:subClassOf owl:Thing ;
+ core:prefLabel "SubSubgrainBoundary"@en .
+
:EMMO_138590b8-3333-515d-87ab-717aac8434e6 a owl:Class ;
emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Pattern with only temporal aspect"@en ;
emmo:EMMO_b432d2d5_25f4_4165_99c5_5935a7763c1a "Voltage in AC plug"@en ;
- rdfs:subClassOf :EMMO_9fa9ca88-2891-538a-a8dd-ccb8a08b9890 ;
+ rdfs:subClassOf owl:Thing ;
core:prefLabel "TemporalPattern"@en .
-:EMMO_472ed27e-ce08-53cb-8453-56ab363275c4 a owl:Class ;
+:EMMO_1b2bfe71-5da9-5c46-b137-be45c3e3f9c3 a owl:Class ;
emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ;
+ rdfs:subClassOf emmo:EMMO_649bf97b_4397_4005_90d9_219755d92e34 ;
+ core:prefLabel "Boundary"@en .
+
+:EMMO_472ed27e-ce08-53cb-8453-56ab363275c4 a owl:Class ;
+ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 " "@en ;
rdfs:subClassOf :EMMO_1b2bfe71-5da9-5c46-b137-be45c3e3f9c3 ;
core:prefLabel "SpatialBoundary"@en .
@@ -81,36 +80,23 @@
rdfs:subClassOf :EMMO_9fa9ca88-2891-538a-a8dd-ccb8a08b9890 ;
core:prefLabel "SpatialPattern"@en .
-:EMMO_b41c9cb3-3b2d-509f-9c93-aa04da134307 a owl:Class ;
- emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ;
- rdfs:subClassOf :EMMO_1b2bfe71-5da9-5c46-b137-be45c3e3f9c3 ;
- core:prefLabel "TemporalBoundary"@en .
-
-:EMMO_cd254842-c697-55f6-917d-9805c77b9187 a owl:Class ;
+:EMMO_9fa9ca88-2891-538a-a8dd-ccb8a08b9890 a owl:Class ;
emmo:EMMO_21ae69b4_235e_479d_8dd8_4f756f694c1b "A"@en,
"Just"@en,
"Test"@en ;
+ emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ;
+ rdfs:subClassOf :EMMO_cd254842-c697-55f6-917d-9805c77b9187 ;
+ core:prefLabel "SpatioTemporalPattern"@en .
+
+:EMMO_cd254842-c697-55f6-917d-9805c77b9187 a owl:Class ;
emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "everything that can be perceived or measured"@en ;
rdfs:comment " this definition is much broader than definition of pattern such as \"the regular and repeated way in which something happens or is\""@en,
"a pattern is defined from a contrast"@en ;
rdfs:subClassOf emmo:EMMO_649bf97b_4397_4005_90d9_219755d92e34 ;
core:prefLabel "Pattern"@en .
-:EMMO_1b2bfe71-5da9-5c46-b137-be45c3e3f9c3 a owl:Class ;
- emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ;
- rdfs:subClassOf emmo:EMMO_649bf97b_4397_4005_90d9_219755d92e34 ;
- core:prefLabel "Boundary"@en .
-
:EMMO_4b32833e-0833-56a7-903c-28a6a8191fe8 a owl:Class ;
emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "Pattern occuring within a boundary in the 4D space"@en ;
rdfs:comment "Every physical patterns are FinitePattern"@en ;
- rdfs:subClassOf [ a owl:Restriction ;
- owl:onProperty emmo:EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f ;
- owl:someValuesFrom :EMMO_1b2bfe71-5da9-5c46-b137-be45c3e3f9c3 ],
- :EMMO_cd254842-c697-55f6-917d-9805c77b9187 ;
- core:prefLabel "FinitePattern"@en .
-
-:EMMO_9fa9ca88-2891-538a-a8dd-ccb8a08b9890 a owl:Class ;
- emmo:EMMO_967080e5_2f42_4eb2_a3a9_c58143e835f9 "NEED elucidation"@en ;
rdfs:subClassOf :EMMO_cd254842-c697-55f6-917d-9805c77b9187 ;
- core:prefLabel "SpatioTemporalPattern"@en .
+ core:prefLabel "FinitePattern"@en .
diff --git a/tests/testonto/excelparser/onto.xlsx b/tests/testonto/excelparser/onto.xlsx
index 01ad4a91d..9e7f2bf6f 100755
Binary files a/tests/testonto/excelparser/onto.xlsx and b/tests/testonto/excelparser/onto.xlsx differ
diff --git a/tools/excel2onto b/tools/excel2onto
index 6aee6a601..23e067a1e 100755
--- a/tools/excel2onto
+++ b/tools/excel2onto
@@ -7,7 +7,7 @@ ontology_template.xlsx
import argparse
import sys
import os
-from ontopy.excelparser import create_ontology_from_excel
+from ontopy.excelparser import create_ontology_from_excel, ExcelError
from ontopy.utils import write_catalog
import owlready2 # pylint: disable=C0411
@@ -30,12 +30,24 @@ def main():
default="ontology.ttl",
help="Name of output ontology, ´ontology.ttl´ is default",
)
+ parser.add_argument(
+ "--force",
+ "-f",
+ action="store_true",
+ help="Whether to force generation of ontology on non-fatal error.",
+ )
+
try:
args = parser.parse_args()
except SystemExit as exc:
sys.exit(exc.code) # Exit without traceback on invalid arguments
- ontology, catalog = create_ontology_from_excel(args.excelpath)
+ try:
+ ontology, catalog = create_ontology_from_excel(
+ args.excelpath, force=args.force
+ )
+ 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)
diff --git a/tools/ontoversion b/tools/ontoversion
index 7c39e97c0..8b29ea525 100755
--- a/tools/ontoversion
+++ b/tools/ontoversion
@@ -46,7 +46,7 @@ def main(argv: list = None):
fmt = args.format if args.format else guess_format(args.iri, fmap=FMAP)
try:
graph.parse(args.iri, format=fmt)
- except Exception as err:
+ except Exception as err: # pylint: disable=W0703
print("rdflib could not parse the ontology.")
print(err)
sys.exit()