Skip to content

Commit

Permalink
Merge pull request #285 from mnamici/duplicate-assertions
Browse files Browse the repository at this point in the history
Handle duplicate assertions
  • Loading branch information
mnamici authored Sep 26, 2024
2 parents 949f1a5 + ab0e524 commit 4003a5c
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 234 deletions.
41 changes: 18 additions & 23 deletions eddy/core/items/edges/common/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@
##########################################################################


from abc import ABCMeta, abstractmethod
from itertools import permutations
from abc import (
ABCMeta,
abstractmethod,
)
from collections import defaultdict

from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import (
QtCore,
QtGui,
)

from eddy.core.commands.edges import CommandEdgeAnchorMove
from eddy.core.commands.edges import CommandEdgeBreakpointAdd
Expand Down Expand Up @@ -541,7 +546,7 @@ class AxiomEdge(AbstractEdge):

def __init__(self,**kwargs):
super().__init__(**kwargs)
self._annotationsMap = {}
self._annotationsMap = defaultdict(list)
self._annotations = []

@property
Expand All @@ -567,27 +572,17 @@ def addAnnotation(self, annotation):
Add an annotation regarding self
:type: annotation: Annotation
"""
if annotation.assertionProperty in self._annotationsMap:
if not annotation in self._annotationsMap[annotation.assertionProperty]:
self._annotationsMap[annotation.assertionProperty].append(annotation)
else:
currList = list()
currList.append(annotation)
self._annotationsMap[annotation.assertionProperty] = currList
self.annotations.append(annotation)
if annotation not in self.annotations:
self.annotations.append(annotation)
self._annotationsMap[annotation.assertionProperty].append(annotation)

def removeAnnotation(self, annotation):
"""
Remove an annotation regarding self
:type: annotation: Annotation
"""
if annotation.assertionProperty in self._annotationsMap:
currList = self._annotationsMap[annotation.assertionProperty]
if annotation in currList:
currList.remove(annotation)
if len(currList) < 1:
self._annotationsMap.pop(annotation.assertionProperty, None)
if annotation in self.annotations:
self.annotations.remove(annotation)
else:
raise KeyError('Cannot find the annotation')
if annotation in self.annotations:
self.annotations.remove(annotation)
self._annotationsMap[annotation.assertionProperty].remove(annotation)
if not self._annotationsMap[annotation.assertionProperty]:
del self._annotationsMap[annotation.assertionProperty]
121 changes: 55 additions & 66 deletions eddy/core/owl.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
##########################################################################


from collections import defaultdict
from enum import unique
import re

Expand All @@ -48,7 +49,10 @@

from eddy.core.datatypes.common import Enum_
from eddy.core.datatypes.owl import Namespace
from eddy.core.functions.signals import connect
from eddy.core.functions.signals import (
connect,
disconnect,
)

K_FUNCTIONAL = 'functional'
K_ASYMMETRIC = 'asymmetric'
Expand All @@ -59,11 +63,13 @@
K_TRANSITIVE = 'transitive'
K_DEPRECATED = 'deprecated'


class Literal(QtCore.QObject):
"""
Represents Literals
"""
sgnLiteralModified = QtCore.pyqtSignal()

def __init__(self, lexicalForm, datatype=None, language=None, parent=None):
"""
:type lexicalForm:str
Expand Down Expand Up @@ -141,6 +147,7 @@ def __str__(self):
def __repr__(self):
return str(self)


class Facet(QtCore.QObject):
"""
Represents Annotation Assertions
Expand Down Expand Up @@ -188,6 +195,7 @@ def __str__(self):
def __repr__(self):
return str(self)


class Annotation(QtCore.QObject):
"""
Represents Annotations
Expand All @@ -206,6 +214,10 @@ def __init__(self, property, value, type=None, language=None, parent=None):
self._property = property
if not (isinstance(value, IRI) or isinstance(value, str)):
raise ValueError('The value of an annotation must be either an IRI or a string')
if isinstance(type, str) and type.isspace():
type = None
if isinstance(language, str) and language.isspace():
language = None
self._value = value
self._datatype = type
self._language = language
Expand Down Expand Up @@ -291,20 +303,6 @@ def getObjectResourceString(self, prefixedForm):
else:
result += '^^<{}>'.format(self.datatype)
return result
'''
result = ''
if self._language:
result += '"{}@{}"'.format(self._value,self._language)
else:
result = '"{}"'.format(self._value)
if self._datatype:
prefixedType = self._datatype.manager.getShortestPrefixedForm(self._datatype)
if prefixedForm and prefixedType:
result += '^^{}'.format(str(prefixedType))
else:
result += '^^<{}>'.format(self._datatype)
return result
'''

def __hash__(self):
result = self._property.__hash__()
Expand All @@ -320,16 +318,21 @@ def __hash__(self):
return result

def __eq__(self, other):
if not isinstance(other, AnnotationAssertion):
return False
return self.assertionProperty == other.assertionProperty and self.value == other.value and self.datatype == other.datatype and self.language == other.value
return (
isinstance(other, Annotation)
and self.assertionProperty == other.assertionProperty
and self.value == other.value
and self.datatype == other.datatype
and self.language == other.language
)

def __str__(self):
return 'Annotation(<{}> {})'.format(self.assertionProperty,self.getObjectResourceString(True))

def __repr__(self):
return str(self)


class AnnotationAssertion(QtCore.QObject):
"""
Represents Annotation Assertions
Expand All @@ -349,6 +352,10 @@ def __init__(self, subject, property, value, type=None, language=None, parent=No
self._property = property
if not (isinstance(value, IRI) or isinstance(value, str)):
raise ValueError('The value of an annotation assertion must be either an IRI or a string')
if isinstance(type, str) and type.isspace():
type = None
if isinstance(language, str) and language.isspace():
language = None
self._value = value
self._datatype = type
self._language = language
Expand Down Expand Up @@ -438,20 +445,6 @@ def getObjectResourceString(self, prefixedForm):
else:
result += '^^<{}>'.format(self.datatype)
return result
'''
result = ''
if self._language:
result += '"{}@{}"'.format(self._value,self._language)
else:
result = '"{}"'.format(self._value)
if self._datatype:
prefixedType = self._datatype.manager.getShortestPrefixedForm(self._datatype)
if prefixedForm and prefixedType:
result += '^^{}'.format(str(prefixedType))
else:
result += '^^<{}>'.format(self._datatype)
return result
'''

def __hash__(self):
result = self._property.__hash__()
Expand All @@ -467,20 +460,25 @@ def __hash__(self):
return result

def __eq__(self, other):
if not isinstance(other, AnnotationAssertion):
return False
return (self.assertionProperty == other.assertionProperty and
self.subject == other.subject and
self.value == other.value and
self.datatype == other.datatype and
self.language == other.language)
return (
isinstance(other, AnnotationAssertion)
and self.assertionProperty == other.assertionProperty
and self.subject == other.subject
and self.value == other.value
and self.datatype == other.datatype
and self.language == other.language
)

def __str__(self):
return 'AnnotationAssertion(<{}> <{}> {})'.format(self.assertionProperty,self.subject,self.getObjectResourceString(True))
return 'AnnotationAssertion(<{}> <{}> {})'.format(
self.assertionProperty,self.subject,
self.getObjectResourceString(True),
)

def __repr__(self):
return str(self)


class IRI(QtCore.QObject):
"""
Represents International Resource Identifiers (https://www.ietf.org/rfc/rfc3987.txt)
Expand Down Expand Up @@ -513,7 +511,7 @@ def __init__(self, namespace,suffix=None, functional=False, invFuctional=False,
self._isTransitive = transitive
self._manager = None
self.components = parse(IRI.concat(self._namespace, self._suffix))
self._annotationAssertionsMap = {}
self._annotationAssertionsMap = defaultdict(list)
self._annotationAssertions = []

@staticmethod
Expand Down Expand Up @@ -759,9 +757,9 @@ def scheme(self):
# INTERFACE
#################################
def setMetaProperties(self, metaDict):
'''
"""
:type: metaDict: dict
'''
"""
for k,v in metaDict.items():
if k==K_FUNCTIONAL:
self.functional = v
Expand Down Expand Up @@ -847,10 +845,10 @@ def getAllLabelAnnotationAssertions(self):
return None

def getLabelAnnotationAssertion(self, lang=None):
'''
"""
:type lang:str
:rtype AnnotationAssertion
'''
"""
return self.getAnnotationAssertion(AnnotationAssertionProperty.Label.value, lang=lang)

def getAnnotationAssertion(self, annotationProperty, lang=None):
Expand All @@ -868,33 +866,24 @@ def addAnnotationAssertion(self, annotation):
Add an annotation assertion regarding self
:type: annotation: AnnotationAssertion
"""
if annotation.assertionProperty in self._annotationAssertionsMap:
if not annotation in self._annotationAssertionsMap[annotation.assertionProperty]:
self._annotationAssertionsMap[annotation.assertionProperty].append(annotation)
else:
currList = list()
currList.append(annotation)
self._annotationAssertionsMap[annotation.assertionProperty] = currList
self._annotationAssertions.append(annotation)
self.sgnAnnotationAdded.emit(annotation)
connect(annotation.sgnAnnotationModified, self.onAnnotationAssertionModified)
if annotation not in self._annotationAssertions:
self._annotationAssertions.append(annotation)
self._annotationAssertionsMap[annotation.assertionProperty].append(annotation)
self.sgnAnnotationAdded.emit(annotation)
connect(annotation.sgnAnnotationModified, self.onAnnotationAssertionModified)

def removeAnnotationAssertion(self, annotation):
"""
Remove an annotation assertion regarding self
:type: annotation: AnnotationAssertion
"""
if annotation.assertionProperty in self._annotationAssertionsMap:
currList = self._annotationAssertionsMap[annotation.assertionProperty]
if annotation in currList:
currList.remove(annotation)
if len(currList) < 1:
self._annotationAssertionsMap.pop(annotation.assertionProperty, None)
if annotation in self._annotationAssertions:
self.annotationAssertions.remove(annotation)
self.sgnAnnotationRemoved.emit(annotation)
else:
raise KeyError('Cannot find the annotation assertion')
if annotation in self._annotationAssertions:
self.annotationAssertions.remove(annotation)
self._annotationAssertionsMap[annotation.assertionProperty].remove(annotation)
if not self._annotationAssertionsMap[annotation.assertionProperty]:
del self._annotationAssertionsMap[annotation.assertionProperty]
self.sgnAnnotationRemoved.emit(annotation)
disconnect(annotation.sgnAnnotationModified, self.onAnnotationAssertionModified)

def isAbsolute(self):
"""
Expand Down
33 changes: 14 additions & 19 deletions eddy/ui/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,32 +406,29 @@ def onInputChanged(self, _):

@QtCore.pyqtSlot()
def accept(self):

subjectStr = self.widget('subject_switch').currentText()
subjectStr = self.widget('subject_switch').currentText().strip()
subjectIRI = self.project.getIRI(subjectStr)
propertyStr = self.widget('property_switch').currentText()
propertyStr = self.widget('property_switch').currentText().strip()
propertyIRI = self.project.getIRI(propertyStr)
activeTab = self.widget('main_widget').currentWidget()
if activeTab is self.widget('literal_widget'):
value = self.widget('value_textedit').toPlainText()
if not value:
value = ' '
typeStr = self.widget('type_switch').currentText()
typeIRI = None
if typeStr:
typeIRI = self.project.getIRI(typeStr)
language = None
typeStr = self.widget('type_switch').currentText().strip()
typeIRI = self.project.getIRI(typeStr) if typeStr else None
if self.widget('lang_switch').isEnabled():
language = self.widget('lang_switch').currentText()
if language not in self.project.getLanguages():
langStr = self.widget('lang_switch').currentText().strip()
language = langStr if langStr else None
if language and language not in self.project.getLanguages():
self.project.addLanguageTag(language)
else:
value = self.widget('full_iri_field').value()
try:
parse(value, rule='IRI')
value = self.project.getIRI(value)
typeIRI = self.project.getIRI('http://www.w3.org/2001/XMLSchema#anyURI')
language = ''
language = None
except ValueError:
dialog = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Warning,
Expand Down Expand Up @@ -640,19 +637,17 @@ def onTypeSwitched(self, index):

@QtCore.pyqtSlot()
def accept(self):
propertyStr = self.widget('property_switch').currentText()
propertyStr = self.widget('property_switch').currentText().strip()
propertyIRI = self.project.getIRI(propertyStr)
value = self.widget('value_textedit').toPlainText()
if not value:
value = ' '
typeStr = self.widget('type_switch').currentText()
typeIRI = None
if typeStr:
typeIRI = self.project.getIRI(typeStr)
language = None
typeStr = self.widget('type_switch').currentText().strip()
typeIRI = self.project.getIRI(typeStr) if typeStr else None
if self.widget('lang_switch').isEnabled():
language = self.widget('lang_switch').currentText()
if language not in self.project.getLanguages():
langStr = self.widget('lang_switch').currentText().strip()
language = langStr if langStr else None
if language and language not in self.project.getLanguages():
self.project.addLanguageTag(language)
if not self.annotation:
annotation = Annotation(propertyIRI, value, typeIRI, language)
Expand Down
Loading

0 comments on commit 4003a5c

Please sign in to comment.