Skip to content

Commit

Permalink
Wip/dsp 1365 excel in out (#51)
Browse files Browse the repository at this point in the history
* Prepration for use in dsp-tools-app

* Bugfix for downloading ontologies

Listnodes do have a „comments“ property and not „comment“…

* Bugfixes with for anything ontology

* Bugfix for backend

If a project description has no languages, it must be passed as an array (for whatever reason…)

* Ongoing work for accomodating GUI

* Same modifications

* Some changes to the list creator

* Doku update
  • Loading branch information
lrosenth committed Mar 31, 2021
1 parent 7f5328a commit 1176d89
Show file tree
Hide file tree
Showing 15 changed files with 703 additions and 120 deletions.
1 change: 0 additions & 1 deletion MANIFEST.in
Expand Up @@ -2,4 +2,3 @@ include README.md
include knora/dsplib/utils/knora-schema.json
include knora/dsplib/utils/knora-schema-lists.json
include knora/dsplib/utils/knora-data-schema.xsd
include knora/icons/knora-py-logo.png
2 changes: 1 addition & 1 deletion docs/dsp-tools-xmlupload.md
Expand Up @@ -224,7 +224,7 @@ _Options_:

##### `<text>`-element
The `<text>`-element has the following options:
- _encoding_: either "utf8" or "hex64" [required]
- _encoding_: either "utf8" or "xml" [required]
- _utf8_: The element describes a simple text without markup. The text is a simple utf-8 string
- _xml_: The element describes a complex text containing markup. It must be follow the XML-format as defined by the
[DSP standard mapping](https://docs.knora.org/03-apis/api-v1/xml-to-standoff-mapping/) .
Expand Down
5 changes: 4 additions & 1 deletion knora/dsp_tools.py
@@ -1,6 +1,7 @@
import argparse
import sys
import os
import pkg_resources # part of setuptools

sys.path.append(os.path.dirname(os.path.realpath(__file__)))

Expand All @@ -13,11 +14,13 @@


def program(args):
version = pkg_resources.require("dsp-tools")[0].version

#
# parse the arguments of the command line
#
parser = argparse.ArgumentParser(
description="A program to create and manipulate ontologies based on the DaSCH Service Platform"
description=f"dsp-tools (Version {version}) DaSCH Service Platform data modelling tools (© 2021 by DaSCH)."
)

subparsers = parser.add_subparsers(title="Subcommands",
Expand Down
111 changes: 78 additions & 33 deletions knora/dsplib/models/listnode.py
Expand Up @@ -43,6 +43,22 @@ def default(self, obj):
In addition there is a static methods ``getAllProjects`` which returns a list of all projects
"""

def list_creator(con: Connection, project: Project, parent_node: 'ListNode', nodes: List[dict]):
nodelist: List['ListNode'] = []
for node in nodes:
newnode = ListNode(
con=con,
project=project,
label=node["labels"],
comments=node.get("comments"),
name=node["name"],
parent=parent_node
)
if node.get('nodes') is not None:
newnode.children = list_creator(con, project, newnode, node['nodes'])
nodelist.append(newnode)
return nodelist


@strict
class ListNode(Model):
Expand Down Expand Up @@ -118,7 +134,7 @@ class ListNode(Model):
_id: Union[str, None]
_project: Union[str, None]
_label: LangString
_comment: LangString
_comments: LangString
_name: Union[str, None]
_parent: Union[str, None]
_isRootNode: bool
Expand All @@ -130,7 +146,7 @@ def __init__(self,
id: Optional[str] = None,
project: Optional[Union[Project, str]] = None,
label: LangStringParam = None,
comment: LangStringParam = None,
comments: LangStringParam = None,
name: Optional[str] = None,
parent: Optional[Union['ListNode', str]] = None,
isRootNode: Optional[bool] = None,
Expand All @@ -144,15 +160,15 @@ def __init__(self,
READ:
* The "con" and "id" attributes are required
UPDATE:
* Only "label", "comment" and "name" may be changed
* Only "label", "comments" and "name" may be changed
DELETE:
* Not yet implemented in the Knora-backend
:param con: A valid Connection instance with a user logged in that has the appropriate permissions
:param id: IRI of the project [readonly, cannot be modified after creation of instance]
:param project: IRI of project. Only used for the creation of a new list (root node) [write].
:param label: A LangString instance with language depenedent labels. Setting this attributes overwites all entries with the new ones. In order to add/remove a specific entry, use "addLabel" or "rmLabel". At least one label is required [read/write].
:param comment: A LangString instance with language depenedent comments. Setting this attributes overwites all entries with the new ones.In order to add/remove a specific entry, use "addComment" or "rmComment".
:param comments: A LangString instance with language depenedent comments. Setting this attributes overwites all entries with the new ones.In order to add/remove a specific entry, use "addComment" or "rmComment".
:param name: A unique name for the ListNode (unique regarding the whole list) [read/write].
:param parent: Is required and allowed only for the CREATE operation. Otherwise use the "children" attribute [write].
:param isRootNode: Is True if the ListNode is a root node of a list Cannot be set [read].
Expand All @@ -165,7 +181,7 @@ def __init__(self,
self._project = project.id if isinstance(project, Project) else str(project) if project is not None else None
self._id = str(id) if id is not None else None
self._label = LangString(label)
self._comment = LangString(comment)
self._comments = LangString(comments)
self._name = str(name) if name is not None else None
if parent and isinstance(parent, ListNode):
self._parent = parent.id
Expand Down Expand Up @@ -237,35 +253,35 @@ def rmLabel(self, lang: Union[Languages, str]) -> None:
self._changed.add('label')

@property
def comment(self) -> Optional[LangString]:
return self._comment
def comments(self) -> Optional[LangString]:
return self._comments

@comment.setter
def comment(self, value: Optional[Union[LangString, str]]) -> None:
self._comment = LangString(value)
self._changed.add('comment')
@comments.setter
def comments(self, value: Optional[Union[LangString, str]]) -> None:
self._comments = LangString(value)
self._changed.add('comments')

def addComment(self, lang: Union[Languages, str], value: str) -> None:
"""
Add/replace a node comment with the given language (executed at next update)
Add/replace a node comments with the given language (executed at next update)
:param lang: The language the comment, either a string "EN", "DE", "FR", "IT" or a Language instance
:param value: The text of the comment
:param lang: The language the comments, either a string "EN", "DE", "FR", "IT" or a Language instance
:param value: The text of the comments
:return: None
"""

self._comment[lang] = value
self._changed.add('comment')
self._comments[lang] = value
self._changed.add('comments')

def rmComment(self, lang: Union[Languages, str]) -> None:
"""
Remove a comment from a list node (executed at next update)
Remove a comments from a list node (executed at next update)
:param lang: The language the comment to be removed is in, either a string "EN", "DE", "FR", "IT" or a Language instance
:return: None
"""
del self._comment[lang]
self._changed.add('comment')
del self._comments[lang]
self._changed.add('comments')

@property
def name(self) -> Optional[str]:
Expand Down Expand Up @@ -299,6 +315,10 @@ def isRootNode(self, value: bool) -> None:
def children(self) -> Optional[List['ListNode']]:
return self._children

@children.setter
def children(self, value: List['ListNode']) -> None:
self._children = value

@staticmethod
def __getChildren(con: Connection,
parent_iri: str,
Expand Down Expand Up @@ -358,8 +378,11 @@ def fromJsonObj(cls, con: Connection, json_obj: Any) -> Any:
raise BaseError('ListNode id is missing')
project = json_obj.get('projectIri')
label = LangString.fromJsonObj(json_obj.get('labels'))
comment = LangString.fromJsonObj(json_obj.get('comments'))
name = json_obj.get('name')
comments = LangString.fromJsonObj(json_obj.get('comments'))
if json_obj.get('name') is not None:
name = json_obj['name']
else:
name = id.rsplit('/', 1)[-1]
parent = json_obj.get('parentNodeIri')
isRootNode = json_obj.get('isRootNode')

Expand All @@ -376,7 +399,7 @@ def fromJsonObj(cls, con: Connection, json_obj: Any) -> Any:
id=id,
project=project,
label=label,
comment=comment,
comments=comments,
name=name,
parent=parent,
isRootNode=isRootNode,
Expand All @@ -401,8 +424,8 @@ def toJsonObj(self, action: Actions, listIri: str = None) -> Any:
if self._label.isEmpty():
raise BaseError("There must be a valid ListNode label!")
tmp['labels'] = self._label.toJsonObj()
if not self._comment.isEmpty():
tmp['comments'] = self._comment.toJsonObj()
if not self._comments.isEmpty():
tmp['comments'] = self._comments.toJsonObj()
else:
tmp['comments'] = []
if self._name is not None:
Expand All @@ -418,8 +441,8 @@ def toJsonObj(self, action: Actions, listIri: str = None) -> Any:
tmp['projectIri'] = self._project
if not self._label.isEmpty() and 'label' in self._changed:
tmp['labels'] = self._label.toJsonObj()
if not self._comment.isEmpty() and 'comment' in self._changed:
tmp['comments'] = self._comment.toJsonObj()
if not self._comments.isEmpty() and 'comments' in self._changed:
tmp['comments'] = self._comments.toJsonObj()
if self._name is not None and 'name' in self._changed:
tmp['name'] = self._name
return tmp
Expand Down Expand Up @@ -534,13 +557,35 @@ def _createDefinitionFileObj(self, children: List["ListNode"]):
"name": listnode.name,
"labels": listnode.label.createDefinitionFileObj(),
}
if not listnode.comment.isEmpty():
listnodeobj["comment"] = listnode.comment.createDefinitionFileObj()
if not listnode.comments.isEmpty():
listnodeobj["comments"] = listnode.comments.createDefinitionFileObj()
if listnode.children:
listnodeobj["nodes"] = self._createDefinitionFileObj(listnode.children)
listnodeobjs.append(listnodeobj)
return listnodeobjs

@staticmethod
def readDefinitionFileObj(con: Connection, project: Project, rootnode: Any) -> 'ListNode':
"""
Reads a JSON obj that corresponds to the syntax of the input to "create_onto".
:param self:
:param con: Connection object
:param project: Project instance
:param rootnode: root node of the list
:return: an instance of ListNode corresponding to the root node
"""
root_list_node = ListNode(
con=con,
project=project,
label=rootnode['labels'],
comments=rootnode.get('comments'),
name=rootnode['name']
)
listnodes = list_creator(con, project, root_list_node, rootnode.get('nodes'))
root_list_node.children = listnodes
return root_list_node

def createDefinitionFileObj(self):
"""
Create an object that corresponds to the syntax of the input to "create_onto".
Expand All @@ -550,8 +595,8 @@ def createDefinitionFileObj(self):
"name": self._name,
"labels": self._label.createDefinitionFileObj(),
}
if not self._comment.isEmpty():
listnode["comment"] = self._comment.createDefinitionFileObj()
if not self._comments.isEmpty():
listnode["comments"] = self._comments.createDefinitionFileObj()
if self._children:
listnode["nodes"] = self._createDefinitionFileObj(self._children)
return listnode
Expand All @@ -573,9 +618,9 @@ def print(self):
print(' {}: {}'.format(lbl[0], lbl[1]))
else:
print(' None')
print(' Comment: ')
if self._comment.isEmpty():
for lbl in self._comment.items():
print(' Comments: ')
if self._comments.isEmpty():
for lbl in self._comments.items():
print(' {}: {}'.format(lbl[0], lbl[1]))
else:
print(' None')
Expand Down
10 changes: 6 additions & 4 deletions knora/dsplib/models/ontology.py
Expand Up @@ -5,7 +5,7 @@
from urllib.parse import quote_plus

from .connection import Connection
from .helpers import Actions, BaseError, Context, LastModificationDate, OntoInfo
from .helpers import Actions, BaseError, Context, LastModificationDate, OntoInfo, WithId
from .model import Model
from .project import Project
from .propertyclass import PropertyClass
Expand Down Expand Up @@ -259,9 +259,11 @@ def fromJsonObj(cls, con: Connection, json_obj: Any) -> 'Ontology':
# ToDo: parse standoff classes

properties_obj = list(filter(lambda a: a.get(knora_api + ':isResourceProperty') is not None, json_obj.get('@graph')))
property_classes = list(map(lambda a: PropertyClass.fromJsonObj(con=con,
context=context,
json_obj=a), properties_obj))
#property_classes = list(map(lambda a: PropertyClass.fromJsonObj(con=con,
# context=context,
# json_obj=a), properties_obj))
property_classes = [PropertyClass.fromJsonObj(con=con, context=context, json_obj=a) for a in properties_obj
if WithId(a.get(knora_api + ':objectType')).str() != "knora-api:LinkValue"]
return cls(con=con,
id=id,
label=label,
Expand Down
11 changes: 11 additions & 0 deletions knora/dsplib/models/resourceclass.py
Expand Up @@ -642,6 +642,17 @@ def fromJsonObj(cls, con: Connection, context: Context, json_obj: Any) -> Any:
superclasses: List[str] = list(map(lambda a: a['@id'], supercls))
has_props: List[Any] = list(filter(lambda a: a.get('@type') == (owl + ':Restriction'), superclasses_obj))
has_properties: Dict[HasProperty] = dict(map(lambda a: HasProperty.fromJsonObj(con, context, a), has_props))
#
# now remove the ...Value stuff from resource pointers: A resource pointer is returned as 2 properties:
# one a direct link, the other the pointer to a link value
#
tmp = dict(has_properties)
for key in tmp.keys():
key_with_value = key
if key.endswith("Value"):
key = key.removesuffix("Value")
if key in has_properties:
del has_properties[key_with_value]
else:
superclasses = None
has_properties = None
Expand Down
2 changes: 2 additions & 0 deletions knora/dsplib/utils/knora-schema.json
Expand Up @@ -231,6 +231,7 @@
"isPartOf",
"isRegionOf",
"isAnnotationOf",
"hasRepresentation",
"seqnum"
]
},
Expand Down Expand Up @@ -287,6 +288,7 @@
"Geometry",
"Geonames",
"Interval",
"TimeStamp",
"List",
"Pulldown",
"Radio",
Expand Down
2 changes: 1 addition & 1 deletion knora/dsplib/utils/onto_commons.py
Expand Up @@ -16,7 +16,7 @@ def list_creator(con: Connection, project: Project, parent_node: ListNode, nodes
con=con,
project=project,
label=node["labels"],
comment=node.get("comments"),
comments=node.get("comments"),
name=node["name"],
parent=parent_node
).create()
Expand Down

0 comments on commit 1176d89

Please sign in to comment.