@@ -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