Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ontology): add default values for missing comments (DEV-337) #141

Merged
merged 13 commits into from Jan 10, 2022
2 changes: 1 addition & 1 deletion knora/dsp_tools.py
Expand Up @@ -163,7 +163,7 @@ def program(user_args: list[str]) -> None:
create_ontology(input_file=args.datamodelfile,
lists_file=args.listfile,
server=args.server,
user=args.user,
user_mail=args.user,
password=args.password,
verbose=args.verbose,
dump=args.dump if args.dump else False)
Expand Down
20 changes: 13 additions & 7 deletions knora/dsplib/models/group.py
Expand Up @@ -211,7 +211,7 @@ def toJsonObj(self, action: Actions):
tmp['selfjoin'] = self._selfjoin
return tmp

def create(self):
def create(self) -> 'Group':
jsonobj = self.toJsonObj(Actions.Create)
jsondata = json.dumps(jsonobj)
result = self._con.post(Group.ROUTE, jsondata)
Expand All @@ -238,11 +238,17 @@ def delete(self):
return Group.fromJsonObj(self._con, result['group'])

@staticmethod
def getAllGroups(con: Connection) -> List['Group']:
result = con.get(Group.ROUTE)
if 'groups' not in result:
raise BaseError("Request got no groups!")
return list(map(lambda a: Group.fromJsonObj(con, a), result['groups']))
def getAllGroups(con: Connection) -> Optional[List['Group']]:
try:
result = con.get(Group.ROUTE)
groups = []
for group_item in result['groups']:
group = Group.fromJsonObj(con, group_item)
groups.append(group)
return groups
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
except BaseError:
# return None if no groups are found or an error happened
return None

@staticmethod
def getAllGroupsForProject(con: Connection, proj_shortcode: str) -> List['Group']:
Expand All @@ -265,7 +271,7 @@ def createDefinitionFileObj(self):
}
return group

def print(self):
def print(self) -> None:
print('Group Info:')
print(' Id: {}'.format(self._id))
print(' Name: {}'.format(self._name))
Expand Down
23 changes: 10 additions & 13 deletions knora/dsplib/models/project.py
Expand Up @@ -8,10 +8,9 @@
from knora.dsplib.utils.set_encoder import SetEncoder
from .connection import Connection
from .helpers import Actions, BaseError
from .langstring import Languages, LangStringParam, LangString
from .langstring import Languages, LangString
from .model import Model


"""
This module implements the handling (CRUD) of Knora projects.

Expand Down Expand Up @@ -310,7 +309,7 @@ def logo(self, value: str) -> None:
self._changed.add('logo')

@classmethod
def fromJsonObj(cls, con: Connection, json_obj: Any) -> Any:
def fromJsonObj(cls, con: Connection, json_obj: Any) -> 'Project':
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
"""
Internal method! Should not be used directly!

Expand Down Expand Up @@ -358,7 +357,7 @@ def fromJsonObj(cls, con: Connection, json_obj: Any) -> Any:
status=status,
logo=logo)

def toJsonObj(self, action: Actions) -> Any:
def toJsonObj(self, action: Actions) -> dict[str, str]:
"""
Internal method! Should not be used directly!

Expand Down Expand Up @@ -390,6 +389,7 @@ def toJsonObj(self, action: Actions) -> Any:
if self._status is None:
raise BaseError("status must be defined (True or False!")
tmp['status'] = self._status

elif action == Actions.Update:
if self._shortcode is not None and 'shortcode' in self._changed:
tmp['shortcode'] = self._shortcode
Expand Down Expand Up @@ -446,20 +446,17 @@ def read(self) -> 'Project':
else:
return None # Todo: throw exception

def update(self) -> Union['Project', None]:
def update(self) -> 'Project':
"""
Udate the project info in Knora with the modified data in this project instance
Update the project information on the DSP with the modified data in this project instance

:return: JSON-object from Knora refecting the update
Returns: JSON object returned as response from DSP reflecting the update
"""

jsonobj = self.toJsonObj(Actions.Update)
if jsonobj:
jsondata = json.dumps(jsonobj, cls=SetEncoder)
result = self._con.put(Project.IRI + quote_plus(self.id), jsondata)
return Project.fromJsonObj(self._con, result['project'])
else:
return None
jsondata = json.dumps(jsonobj, cls=SetEncoder)
result = self._con.put(Project.IRI + quote_plus(self.id), jsondata)
return Project.fromJsonObj(self._con, result['project'])

def delete(self) -> 'Project':
"""
Expand Down
11 changes: 5 additions & 6 deletions knora/dsplib/models/propertyclass.py
Expand Up @@ -348,14 +348,13 @@ def resolve_propref(resref: str):
}],
"@context": self._context.toJsonObj()
}
if self._comment is not None:
if not self._comment.isEmpty():
tmp['@graph'][0]["rdfs:comment"] = self._comment.toJsonLdObj()
if self._subject is not None:
if self._comment:
tmp['@graph'][0]["rdfs:comment"] = self._comment.toJsonLdObj()
if self._subject:
tmp['@graph'][0]["knora-api:subjectType"] = resolve_propref(self._subject)
if self._object is not None:
if self._object:
tmp['@graph'][0]["knora-api:objectType"] = resolve_propref(self._object)
if self._gui_element is not None:
if self._gui_element:
tmp['@graph'][0]["salsah-gui:guiElement"] = {
"@id": self._gui_element
}
Expand Down
4 changes: 2 additions & 2 deletions knora/dsplib/models/resourceclass.py
Expand Up @@ -570,7 +570,7 @@ def addProperty(self,
property_id: str,
cardinality: Cardinality,
gui_order: Optional[int] = None,
) -> Optional[LastModificationDate]:
) -> LastModificationDate:
if self._has_properties.get(property_id) is None:
latest_modification_date, resclass = HasProperty(con=self._con,
context=self._context,
Expand Down Expand Up @@ -701,7 +701,7 @@ def resolve_resref(resref: str):
else:
superclasses = list(map(resolve_resref, self._superclasses))
if self._comment is None or self._comment.isEmpty():
self._comment = LangString("no comment available")
self._comment = LangString({"en": "[no comment provided]"})
if self._label is None or self._label.isEmpty():
self._label = LangString("no label available")
tmp = {
Expand Down
20 changes: 10 additions & 10 deletions knora/dsplib/utils/expand_all_lists.py
@@ -1,32 +1,32 @@
from typing import Dict, List
from typing import Dict, List, Any

from knora.dsplib.utils.excel_to_json_lists import make_json_list_from_excel, prepare_list_creation


def expand_lists_from_excel(data_model: Dict) -> List[str]:
def expand_lists_from_excel(data_model: Dict[Any, Any]) -> List[str]:
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
"""
Gets all lists from an ontology and expands them to json if they are only referenced via an Excel file
Gets all list definitions from a data model and expands them to JSON if they are only referenced via an Excel file

Args:
data_model: The data model (json) the lists are read from
data_model: The data model (JSON) the lists are read from

Returns:
A list of all expanded lists. It can be added to the root node of an ontology as list section.
A list of all expanded lists. It can be added to the root node of an ontology as lists section.
"""
# create and add lists from Excel references to the ontology
lists = data_model['project'].get('lists')
lists = data_model["project"].get("lists")

if not lists:
return []

new_lists = []
for rootnode in lists:
nodes = rootnode['nodes']
nodes = rootnode["nodes"]
# check if the folder parameter is used
if rootnode.get('nodes') and isinstance(nodes, dict) and nodes.get('folder'):
if rootnode.get("nodes") and isinstance(nodes, dict) and nodes.get("folder"):
# get the Excel files from the folder and create the rootnode of the list
excel_folder = nodes['folder']
rootnode, excel_files = prepare_list_creation(excel_folder, rootnode.get('name'), rootnode.get('comments'))
excel_folder = nodes["folder"]
rootnode, excel_files = prepare_list_creation(excel_folder, rootnode.get("name"), rootnode.get("comments"))

# create the list from the Excel files
make_json_list_from_excel(rootnode, excel_files)
Expand Down
97 changes: 67 additions & 30 deletions knora/dsplib/utils/onto_create_lists.py
@@ -1,43 +1,52 @@
import json
from typing import Any, Dict, List
from typing import Any, Dict, List, Optional

from .expand_all_lists import expand_lists_from_excel
from .onto_validate import validate_ontology
from ..models.connection import Connection
from ..models.helpers import BaseError
from ..models.listnode import ListNode
from ..models.project import Project


def list_creator(con: Connection, project: Project, parent_node: ListNode, nodes: List[Dict[Any, Any]]) -> List[Dict[Any, Any]]:
def create_list_node(con: Connection, project: Project, parent_node: ListNode, nodes: List[Dict[Any, Any]]) -> List[
Dict[Any, Any]]:
"""
Creates the list on the DSP server

Args:
con: The connection to the DSP server
project: The project which the lists should be added
parent_node: The root node of the list
con: Connection to the DSP server
project: Project which the lists should be added to
parent_node: Root node of the list
nodes: List of nodes the list is made of

Returns:
The list of all nodes with their names and respective IDs
"""
nodelist = []
for node in nodes:
new_node = ListNode(con=con, project=project, label=node["labels"], comments=node.get("comments"),
name=node["name"],
parent=parent_node).create()
if node.get('nodes') is not None:
subnode_list = list_creator(con, project, new_node, node['nodes'])
nodelist.append({new_node.name: {"id": new_node.id, 'nodes': subnode_list}})
else:
nodelist.append({new_node.name: {"id": new_node.id}})
new_node = None
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
try:
new_node = ListNode(con=con, project=project, label=node["labels"], comments=node.get("comments"),
name=node["name"],
parent=parent_node).create()
except BaseError as err:
print(f"ERROR while trying to create list node '{node['name']}'. The error message was {err.message}")
exit(1)
if new_node:
# if node has child nodes, call the method recursively
if node.get("nodes"):
subnode_list = create_list_node(con, project, new_node, node["nodes"])
nodelist.append({new_node.name: {"id": new_node.id, "nodes": subnode_list}})
else:
nodelist.append({new_node.name: {"id": new_node.id}})
return nodelist


def create_lists(input_file: str, lists_file: str, server: str, user: str, password: str, verbose: bool,
dump: bool = False) -> Dict[str, Any]:
"""
Creates the lists on the DSP server
Handles the list creation

Args:
input_file: Path to the json data model file
Expand All @@ -61,7 +70,7 @@ def create_lists(input_file: str, lists_file: str, server: str, user: str, passw
new_lists = expand_lists_from_excel(data_model)

# add the newly created lists from Excel to the ontology
data_model['project']['lists'] = new_lists
data_model["project"]["lists"] = new_lists

# validate the ontology
if validate_ontology(data_model):
Expand All @@ -77,28 +86,56 @@ def create_lists(input_file: str, lists_file: str, server: str, user: str, passw
con.start_logging()

# get the project which must exist
project = Project(con=con, shortcode=data_model['project']['shortcode'], ).read()
assert project is not None
project: Optional[Project] = None
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
try:
project = Project(con=con, shortcode=data_model["project"]["shortcode"]).read()
except BaseError as err:
print(
f"ERROR while trying to create the lists. Referenced project couldn't be read from the server. The error message was: {err.message}")
exit(1)

# create the lists
if verbose:
print('Create lists...')
print("Create lists...")

lists = data_model['project'].get('lists')
all_lists: Optional[List[ListNode]] = ListNode.getAllLists(con, project.id)
lists = data_model["project"].get("lists")
list_root_nodes = {}
if lists is not None:
if lists:
for rootnode in lists:
rootnode_name = rootnode["name"]
# check if list already exists
list_exists: bool = False
if all_lists:
for list_item in all_lists:
if list_item.project == project.id and list_item.name == rootnode_name:
list_root_nodes[list_item.name] = {"id": list_item.id, "nodes": rootnode["nodes"]}
list_exists = True
if list_exists:
print(f"WARN List '{rootnode_name}' already exists. Skipping...")
continue

if verbose:
print(' Create list:' + rootnode['name'])
root_list_node = ListNode(con=con, project=project, label=rootnode['labels'],
comments=rootnode.get('comments'),
name=rootnode['name']).create()
if rootnode.get('nodes') is not None:
list_nodes = list_creator(con, project, root_list_node, rootnode['nodes'])
list_root_nodes[rootnode['name']] = {'id': root_list_node.id, 'nodes': list_nodes}

with open(lists_file, 'w', encoding='utf-8') as fp:
print(f"Creating list '{rootnode_name}'.")

root_list_node = None
try:
root_list_node = ListNode(con=con, project=project, label=rootnode["labels"],
comments=rootnode.get("comments"),
name=rootnode_name).create()
except BaseError as err:
print(f"ERROR while trying to create the list '{rootnode_name}'. The error message was: {err.message}")
exit(1)
except Exception as exception:
print(
f"ERROR while trying to create the list '{rootnode_name}'. The error message was: {exception}")
exit(1)
if rootnode.get("nodes") and root_list_node and project:
list_nodes = create_list_node(con, project, root_list_node, rootnode["nodes"])
list_root_nodes[rootnode["name"]] = {"id": root_list_node.id, "nodes": list_nodes}

with open(lists_file, "w", encoding="utf-8") as fp:
json.dump(list_root_nodes, fp, indent=3, sort_keys=True)
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
print(f'The IRI for the created nodes can be found in {lists_file}.')
print(f"The IRI for the created nodes can be found in '{lists_file}'.")

return list_root_nodes