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
chore(xmlupload): refactor xmlupload, add unittests (DEV-1043) #203
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
5080cd7
fix: missing parameter "default_ontology" leads to error on line 275.
jnussbaum 54db92c
add unit test for remove_circular_references()
jnussbaum b0fb96a
move classes from xml_upload.py to own files in knora.dsplib.models
jnussbaum c18a320
hide private methods
jnussbaum c0e2049
reduce number of code smells
jnussbaum ce5ffec
Merge branch 'main' into wip/dev-1043-add-unittests
jnussbaum File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
from typing import Optional | ||
|
||
from knora.dsplib.models.connection import Connection | ||
from knora.dsplib.models.group import Group | ||
from knora.dsplib.models.helpers import BaseError | ||
from knora.dsplib.models.project import Project | ||
|
||
|
||
class ProjectContext: | ||
"""Represents the project context""" | ||
|
||
_projects: list[Project] | ||
_project_map: dict[str, str] # dictionary of (project name:project IRI) pairs | ||
_inv_project_map: dict[str, str] # dictionary of (project IRI:project name) pairs | ||
_groups: Optional[list[Group]] | ||
_group_map: Optional[dict[str, str]] | ||
_shortcode: Optional[str] | ||
_project_name: Optional[str] | ||
|
||
def __init__(self, con: Connection, shortcode: Optional[str] = None): | ||
self._shortcode = shortcode | ||
self._projects = Project.getAllProjects(con=con) | ||
self._project_map: dict[str, str] = {x.shortname: x.id for x in self._projects} | ||
self._inv_project_map: dict[str, str] = {x.id: x.shortname for x in self._projects} | ||
try: | ||
self._groups = Group.getAllGroups(con=con) | ||
except BaseError: | ||
self._groups = None | ||
if self._groups: | ||
self._group_map: dict[str, str] = {self._inv_project_map[x.project] + ':' + x.name: x.id for x in | ||
self._groups} | ||
else: | ||
self._group_map = None | ||
self._project_name = None | ||
# get the project name from the shortcode | ||
if self._shortcode: | ||
for p in self._projects: | ||
if p.shortcode == self._shortcode: | ||
self._project_name = p.shortname | ||
break | ||
|
||
@property | ||
def group_map(self) -> dict[str, str]: | ||
"""Dictionary of (project:group name) and (group id) pairs of all groups in project""" | ||
return self._group_map | ||
|
||
@property | ||
def project_name(self) -> Optional[str]: | ||
"""Name of the project""" | ||
return self._project_name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from lxml import etree | ||
|
||
from knora.dsplib.models.projectContext import ProjectContext | ||
from knora.dsplib.models.xmlerror import XmlError | ||
|
||
|
||
class XmlAllow: | ||
"""Represents the allow element of the XML used for data import""" | ||
|
||
_group: str | ||
_permission: str | ||
|
||
def __init__(self, node: etree.Element, project_context: ProjectContext) -> None: | ||
""" | ||
Constructor which parses the XML DOM allow element | ||
|
||
Args: | ||
node: The DOM node to be processed (represents a single right in a permission set) | ||
project_context: Context for DOM node traversal | ||
|
||
Returns: | ||
None | ||
""" | ||
tmp = node.attrib['group'].split(':') | ||
sysgroups = ['UnknownUser', 'KnownUser', 'ProjectMember', 'Creator', 'ProjectAdmin', 'SystemAdmin'] | ||
if len(tmp) > 1: | ||
if tmp[0]: | ||
if tmp[0] == 'knora-admin' and tmp[1] in sysgroups: | ||
self._group = node.attrib['group'] | ||
else: | ||
self._group = project_context.group_map.get(node.attrib['group']) | ||
if self._group is None: | ||
raise XmlError("Group \"{}\" is not known: Cannot find project!".format(node.attrib['group'])) | ||
else: | ||
if project_context.project_name is None: | ||
raise XmlError("Project shortcode has not been set in ProjectContext") | ||
self._group = project_context.project_name + ':' + tmp[1] | ||
else: | ||
if tmp[0] in sysgroups: | ||
self._group = 'knora-admin:' + node.attrib['group'] | ||
else: | ||
raise XmlError("Group \"{}\" is not known: ".format(node.attrib['group'])) | ||
self._permission = node.text | ||
|
||
@property | ||
def group(self) -> str: | ||
"""The group specified in the allow element""" | ||
return self._group | ||
|
||
@property | ||
def permission(self) -> str: | ||
"""The reference to a set of permissions""" | ||
return self._permission | ||
|
||
def print(self) -> None: | ||
"""Prints the attributes of the XmlAllow instance""" | ||
print(" group=", self._group, " permission=", self._permission) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from lxml import etree | ||
|
||
|
||
class XMLBitstream: | ||
"""Represents a bitstream object (file) of a resource in the XML used for data import""" | ||
|
||
_value: str | ||
_permissions: str | ||
|
||
def __init__(self, node: etree.Element) -> None: | ||
self._value = node.text | ||
self._permissions = node.get('permissions') | ||
|
||
@property | ||
def value(self) -> str: | ||
"""The file path of the bitstream object""" | ||
return self._value | ||
|
||
@property | ||
def permissions(self) -> str: | ||
"""Reference to the set of permissions for the bitstream object""" | ||
return self._permissions | ||
|
||
def print(self) -> None: | ||
"""Prints the bitstream object and its attributes.""" | ||
print(' Bitstream file path: ' + str(self._value)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
class XmlError(Exception): | ||
"""Represents an error raised in the context of the XML import""" | ||
_message: str | ||
|
||
def __init__(self, msg: str): | ||
self._message = msg | ||
|
||
def __str__(self) -> str: | ||
return 'XML-ERROR: ' + self._message |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
from lxml import etree | ||
|
||
from knora.dsplib.models.permission import Permissions | ||
from knora.dsplib.models.projectContext import ProjectContext | ||
from knora.dsplib.models.xmlallow import XmlAllow | ||
|
||
|
||
class XmlPermission: | ||
"""Represents the permission set containing several XmlAllow elements in the XML used for data import""" | ||
|
||
_id: str | ||
_allows: list[XmlAllow] | ||
|
||
def __init__(self, node: etree.Element, project_context: ProjectContext) -> None: | ||
""" | ||
Constructor which parses a XML DOM permissions element representing an named permission set | ||
|
||
Args: | ||
node: The DOM node to be processed (representing an a permission set) | ||
project_context: Context for DOM node traversal | ||
""" | ||
self._allows = [] | ||
self._id = node.attrib['id'] | ||
for allow_node in node: | ||
self._allows.append(XmlAllow(allow_node, project_context)) | ||
|
||
@property | ||
def id(self) -> str: | ||
"""The id of the permission set, p.ex. res-default""" | ||
return self._id | ||
|
||
@property | ||
def allows(self) -> list[XmlAllow]: | ||
"""List of XmlAllow elements defining permissions for specific groups""" | ||
return self._allows | ||
|
||
def get_permission_instance(self) -> Permissions: | ||
"""Returns a list of allow elements of this permission instance""" | ||
permissions = Permissions() | ||
for allow in self._allows: | ||
permissions.add(allow.permission, allow.group) | ||
return permissions | ||
|
||
def __str__(self) -> str: | ||
allow_str: list[str] = [] | ||
for allow in self._allows: | ||
allow_str.append("{} {}".format(allow.permission, allow.group)) | ||
return '|'.join(allow_str) | ||
|
||
def print(self) -> None: | ||
"""Prints the permission set""" | ||
print('Permission: ', self._id) | ||
for a in self._allows: | ||
a.print() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from typing import Optional | ||
|
||
from lxml import etree | ||
|
||
from knora.dsplib.models.xmlvalue import XMLValue | ||
from knora.dsplib.models.xmlerror import XmlError | ||
|
||
|
||
class XMLProperty: | ||
"""Represents a property of a resource in the XML used for data import""" | ||
|
||
_name: str | ||
_valtype: str | ||
_values: list[XMLValue] | ||
|
||
def __init__(self, node: etree.Element, valtype: str, default_ontology: Optional[str] = None): | ||
""" | ||
The constructor for the DSP property | ||
|
||
Args: | ||
node: the property node, p.ex. <decimal-prop></decimal-prop> | ||
valtype: the type of value given by the name of the property node, p.ex. decimal in <decimal-prop> | ||
default_ontology: the name of the ontology | ||
""" | ||
# get the property name which is in format namespace:propertyname, p.ex. rosetta:hasName | ||
tmp_prop_name = node.attrib['name'].split(':') | ||
if len(tmp_prop_name) > 1: | ||
if tmp_prop_name[0]: | ||
self._name = node.attrib['name'] | ||
else: | ||
# replace an empty namespace with the default ontology name | ||
self._name = default_ontology + ':' + tmp_prop_name[1] | ||
else: | ||
self._name = 'knora-admin:' + tmp_prop_name[0] | ||
listname = node.attrib.get('list') # safe the list name if given (only for lists) | ||
self._valtype = valtype | ||
self._values = [] | ||
|
||
# parse the subnodes of the property nodes which contain the actual values of the property | ||
for subnode in node: | ||
if subnode.tag == valtype: # the subnode must correspond to the expected value type | ||
self._values.append(XMLValue(subnode, valtype, listname)) | ||
else: | ||
raise XmlError(f"ERROR Unexpected tag: '{subnode.tag}'. Property may contain only value tags!") | ||
|
||
@property | ||
def name(self) -> str: | ||
"""The name of the property""" | ||
return self._name | ||
|
||
@property | ||
def valtype(self) -> str: | ||
"""The value type of the property""" | ||
return self._valtype | ||
|
||
@property | ||
def values(self) -> list[XMLValue]: | ||
"""List of values of this property""" | ||
return self._values | ||
|
||
def print(self) -> None: | ||
"""Prints the property.""" | ||
print(' Property: {} Type: {}'.format(self._name, self._valtype)) | ||
for value in self._values: | ||
value.print() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docstring is missing, see the other classes