Skip to content
Permalink
Browse files
fix: restrict the creation of classes without cardinalities (DEV-305) (
…#136)

* integrate cardinality adding into resource creation

* fix code smells

* remove test files

* update error message to be more readable

* fix order of entity creation

* add error message when cardinalities are empty

* Improve code after review

* Remove unused code
  • Loading branch information
irinaschubert committed Jan 4, 2022
1 parent 9ce6722 commit 5604a5be2e4be6094d73c8d782699c4beab59a37
Showing with 156 additions and 273 deletions.
  1. +156 −115 knora/dsplib/utils/onto_create_ontology.py
  2. +0 −158 testdata/test-permissions.xml
@@ -1,4 +1,5 @@
"""This module handles the ontology creation and upload to a DSP server. This includes the creation and upload of lists."""
"""This module handles the ontology creation and upload to a DSP server. This includes the creation of the project,
groups, users, lists, resource classes, properties and cardinalities. """
import json
from typing import Dict, List, Optional, Set

@@ -39,7 +40,7 @@ def create_ontology(input_file: str,
user: str,
password: str,
verbose: bool,
dump: bool) -> bool:
dump: bool) -> None:
"""
Creates the ontology from a json input file on a DSP server
@@ -55,6 +56,9 @@ def create_ontology(input_file: str,
Returns:
True if successful
"""

knora_api_prefix = "knora-api:"

# read the ontology from the input file
with open(input_file) as f:
onto_json_str = f.read()
@@ -90,7 +94,7 @@ def create_ontology(input_file: str,
# try to read the project to check if it exists
project = Project(con=con, shortcode=data_model["project"]["shortcode"]).read()

# update the project with data from data_model
# update the project with data from the ontology (data_model)
if project.shortname != data_model["project"]["shortname"]:
project.shortname = data_model["project"]["shortname"]
if project.longname != data_model["project"]["longname"]:
@@ -116,11 +120,10 @@ def create_ontology(input_file: str,
status=True).create()
except BaseError as err:
print("Creating project failed: ", err.message)
return False
exit(1)
if verbose:
print("Created project:")
project.print()
assert project is not None

# create the lists
list_root_nodes = create_lists(input_file, lists_file, server, user, password, verbose)
@@ -143,7 +146,7 @@ def create_ontology(input_file: str,
new_groups[new_group.name] = new_group
if verbose:
print("Created group:")
new_group.print() # project.set_default_permissions(new_group.id)
new_group.print()

except BaseError as err:
print(f"ERROR while trying to create group '{group.name}'. The error message was: {err.message}")
@@ -270,7 +273,6 @@ def create_ontology(input_file: str,
except BaseError as err:
tmp_user.print()
print("Updating user failed:", err.message)
return False

# update group and project membership
# Note: memberships are NOT removed here, just added
@@ -301,151 +303,190 @@ def create_ontology(input_file: str,
in_groups=group_ids).create()
except BaseError as err:
print("Creating user failed:", err.message)
return False
if verbose:
print("New user:")
new_user.print()

# create the ontologies
if verbose:
print("Create ontologies...")
ontologies = data_model["project"]["ontologies"]
ontologies = data_model.get("project").get("ontologies")
for ontology in ontologies:
newontology = Ontology(con=con,
project=project,
label=ontology["label"],
name=ontology["name"]).create()
last_modification_date = newontology.lastModificationDate
if verbose:
print("Created empty ontology:")
newontology.print()
new_ontology = None
last_modification_date = None
try:
new_ontology = Ontology(con=con,
project=project,
label=ontology.get("label"),
name=ontology.get("name")).create()
last_modification_date = new_ontology.lastModificationDate
if verbose:
print("Created ontology:")
new_ontology.print()
except BaseError as err:
print(f"ERROR while trying to create ontology. The error message was {err.message}")
exit(1)
except Exception as exception:
print(f"ERROR while trying to create ontology. The error message was {exception}")
exit(1)

# add the prefixes defined in the json file
for prefix, iri in context:
if not prefix in newontology.context:
if prefix not in new_ontology.context:
s = iri.iri + ("#" if iri.hashtag else "")
newontology.context.add_context(prefix, s)
new_ontology.context.add_context(prefix, s)

# create the empty resource classes
resclasses = ontology["resources"]
newresclasses: Dict[str, ResourceClass] = {}
for resclass in resclasses:
resname = resclass.get("name")
super_classes = resclass.get("super")
new_res_classes: Dict[str, ResourceClass] = {}
for res_class in ontology.get("resources"):
res_name = res_class.get("name")
super_classes = res_class.get("super")
if isinstance(super_classes, str):
super_classes = [super_classes]
reslabel = LangString(resclass.get("labels"))
rescomment = resclass.get("comments")
if rescomment is not None:
rescomment = LangString(rescomment)
res_label = LangString(res_class.get("labels"))
res_comment = res_class.get("comments")
if res_comment:
res_comment = LangString(res_comment)
# if no cardinalities are submitted, don't create the class
if not res_class.get("cardinalities"):
print(f"ERROR while trying to add cardinalities to class '{res_name}'. No cardinalities submitted. At"
f"least one direct cardinality is required to create a class with dsp-tools.")
continue

new_res_class = None
try:
last_modification_date, newresclass = ResourceClass(con=con,
context=newontology.context,
ontology_id=newontology.id,
name=resname,
superclasses=super_classes,
label=reslabel,
comment=rescomment).create(last_modification_date)
newontology.lastModificationDate = last_modification_date
last_modification_date, new_res_class = ResourceClass(con=con,
context=new_ontology.context,
ontology_id=new_ontology.id,
name=res_name,
superclasses=super_classes,
label=res_label,
comment=res_comment).create(
last_modification_date)
except BaseError as err:
print("Creating resource class failed:", err.message)
exit(1)
newresclasses[newresclass.id] = newresclass
print(
f"ERROR while trying to create resource class {res_name}. The error message was {err.message}")
except Exception as exception:
print(
f"ERROR while trying to create resource class {res_name}. The error message was {exception}")
new_res_classes[new_res_class.id] = new_res_class
new_ontology.lastModificationDate = last_modification_date

if verbose:
print("New resource class:")
newresclass.print()
print("Created resource class:")
new_res_class.print()

# create the property classes
propclasses = ontology["properties"]
newpropclasses: Dict[str, ResourceClass] = {}
for propclass in propclasses:
propname = propclass.get("name")
proplabel = LangString(propclass.get("labels"))
# get the super-property/ies if defined. Valid forms are:
# - "prefix:superproperty" : fully qualified name of property in another ontology. The prefix has to
# be defined in the prefixes part.
# - "superproperty" : Use of super-property defined in the knora-api ontology
# if omitted, "knora-api:hasValue" is assumed
if propclass.get("super") is not None:
super_props = list(map(lambda a: a if ':' in a else "knora-api:" + a, propclass["super"]))
for prop_class in ontology.get("properties"):
prop_name = prop_class.get("name")
prop_label = LangString(prop_class.get("labels"))

# get the super-property/ies if defined, valid forms are:
# - "prefix:super-property" : fully qualified name of property in another ontology. The prefix has to be
# defined in the prefixes part.
# - "super-property" : super-property defined in the knora-api ontology
# - if omitted, "knora-api:hasValue" is assumed

if prop_class.get("super"):
super_props = []
for super_class in prop_class.get("super"):
if ':' in super_class:
super_props.append(super_class)
else:
super_props.append(knora_api_prefix + super_class)
else:
super_props = ["knora-api:hasValue"]
# get the "object" if defined. Valid forms are:
# - "prefix:object_name" : fully qualified object. The prefix has to be defined in the prefixes part.
# - ":object_name" : The object is defined in the current ontology.
# - "object_name" : The object is defined in "knora-api"
if propclass.get("object") is not None:
tmp = propclass["object"].split(':')

# get the "object" if defined, valid forms are:
# - "prefix:object_name" : fully qualified object. The prefix has to be defined in the prefixes part.
# - ":object_name" : The object is defined in the current ontology.
# - "object_name" : The object is defined in "knora-api"

if prop_class.get("object"):
tmp = prop_class.get("object").split(':')
if len(tmp) > 1:
if tmp[0]:
object = propclass["object"] # fully qualified name
prop_object = prop_class.get("object") # fully qualified name
else:
if verbose:
newontology.print()
object = newontology.name + ':' + tmp[1]
prop_object = new_ontology.name + ':' + tmp[1] # object refers to actual ontology
else:
object = "knora-api:" + propclass["object"]
else:
object = None

if propclass.get("subject") is not None:
subject = propclass["subject"]
prop_object = knora_api_prefix + prop_class.get("object") # object refers to knora-api
else:
subject = None
gui_element = propclass.get("gui_element")
gui_attributes = propclass.get("gui_attributes")
if gui_attributes is not None and gui_attributes.get("hlist") is not None:
gui_attributes['hlist'] = "<" + list_root_nodes[gui_attributes['hlist']]["id"] + ">"
propcomment = propclass.get("comment")
if propcomment is not None:
propcomment = LangString(propcomment)
prop_object = None
prop_subject = prop_class.get("subject")
gui_element = prop_class.get("gui_element")
gui_attributes = prop_class.get("gui_attributes")
if gui_attributes and gui_attributes.get("hlist"):
gui_attributes["hlist"] = "<" + list_root_nodes[gui_attributes["hlist"]]["id"] + ">"
prop_comment = prop_class.get("comment")
if prop_comment:
prop_comment = LangString(prop_comment)
else:
propcomment = "no comment given"
prop_comment = "no comment given"

new_prop_class = None
try:
last_modification_date, newpropclass = PropertyClass(con=con,
context=newontology.context,
label=proplabel,
name=propname,
ontology_id=newontology.id,
superproperties=super_props,
object=object,
subject=subject,
gui_element="salsah-gui:" + gui_element,
gui_attributes=gui_attributes,
comment=propcomment).create(last_modification_date)
newontology.lastModificationDate = last_modification_date
last_modification_date, new_prop_class = PropertyClass(con=con,
context=new_ontology.context,
label=prop_label,
name=prop_name,
ontology_id=new_ontology.id,
superproperties=super_props,
object=prop_object,
subject=prop_subject,
gui_element="salsah-gui:" + gui_element,
gui_attributes=gui_attributes,
comment=prop_comment).create(
last_modification_date)
except BaseError as err:
print("Creating property class failed:", err.message)
return False
newpropclasses[newpropclass.id] = newpropclass
print(
f"ERROR while trying to create property class {prop_name}. The error message was: {err.message}"
)
except Exception as exception:
print(
f"ERROR while trying to create property class {prop_name}. The error message was: {exception}")

new_ontology.lastModificationDate = last_modification_date
if verbose:
print("New property class:")
newpropclass.print()
print("Created property:")
new_prop_class.print()

# Add cardinalities
# Add cardinality/ies to class
switcher = {
"1": Cardinality.C_1,
"0-1": Cardinality.C_0_1,
"0-n": Cardinality.C_0_n,
"1-n": Cardinality.C_1_n
}
for resclass in resclasses:
for cardinfo in resclass["cardinalities"]:
rc = newresclasses.get(newontology.id + '#' + resclass["name"])
cardinality = switcher[cardinfo["cardinality"]]
tmp = cardinfo["propname"].split(':')
if len(tmp) > 1:
if tmp[0]:
propid = cardinfo["propname"] # fully qualified name

for res_class in ontology.get("resources"):
if res_class.get("cardinalities"):
for card_info in res_class.get("cardinalities"):
rc = new_res_classes.get(new_ontology.id + '#' + res_class.get("name"))
cardinality = switcher[card_info.get("cardinality")]
prop_name_for_card = card_info.get("propname")
tmp = prop_name_for_card.split(":")
if len(tmp) > 1:
if tmp[0]:
prop_id = prop_name_for_card # fully qualified name
else:
prop_id = new_ontology.name + ":" + tmp[1] # prop name refers to actual ontology
else:
propid = newontology.name + ':' + tmp[1]
else:
propid = "knora-api:" + cardinfo["propname"]
gui_order = cardinfo.get('gui_order')
last_modification_date = rc.addProperty(
property_id=propid,
cardinality=cardinality,
gui_order=gui_order,
last_modification_date=last_modification_date)
newontology.lastModificationDate = last_modification_date
return True
prop_id = knora_api_prefix + prop_name_for_card # prop name refers to knora-api

try:
last_modification_date = rc.addProperty(
property_id=prop_id,
cardinality=cardinality,
gui_order=card_info.get("gui_order"),
last_modification_date=last_modification_date)
except BaseError as err:
print(
f"ERROR while trying to add cardinality {prop_id} to resource class {res_class.get('name')}."
f"The error message was {err.message}")
except Exception as exception:
print(
f"ERROR while trying to add cardinality {prop_id} to resource class {res_class.get('name')}."
f"The error message was {exception}")

new_ontology.lastModificationDate = last_modification_date

0 comments on commit 5604a5b

Please sign in to comment.