Coverage for rdflib_ocdm/abstract_entity.py: 86%

7 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-11-01 22:02 +0000

1#!/usr/bin/python 

2# -*- coding: utf-8 -*- 

3# Copyright (c) 2016, Silvio Peroni <essepuntato@gmail.com> 

4# Copyright (c) 2023, Arcangelo Massari <arcangelo.massari@unibo.it> 

5# 

6# Permission to use, copy, modify, and/or distribute this software for any purpose 

7# with or without fee is hereby granted, provided that the above copyright notice 

8# and this permission notice appear in all copies. 

9# 

10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 

11# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 

12# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, 

13# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 

14# DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 

15# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 

16# SOFTWARE. 

17 

18 

19from __future__ import annotations 

20 

21from abc import ABC 

22from typing import TYPE_CHECKING 

23 

24from rdflib import RDF, RDFS, Graph, Literal, URIRef 

25 

26from rdflib_ocdm.support import create_literal, create_type 

27 

28if TYPE_CHECKING: 

29 from typing import ClassVar, Dict, Iterable, List, Optional 

30 

31class AbstractEntity(ABC): # pragma: no cover 

32 """ 

33 Abstract class which represents a generic entity.  

34 It sits at the top of the entity class hierarchy. 

35 """ 

36 

37 short_name_to_type_iri: ClassVar[Dict[str, URIRef]] = {} 

38 

39 def __init__(self) -> None: 

40 """ 

41 Constructor of the ``AbstractEntity`` class. 

42 """ 

43 self.g: Graph = Graph() 

44 self.res: URIRef = URIRef("") 

45 

46 def remove_every_triple(self) -> None: 

47 """ 

48 Remover method that removes every triple from the current entity. 

49 

50 :return: None 

51 """ 

52 self.g.remove((None, None, None)) 

53 

54 # LABEL 

55 def get_label(self) -> Optional[str]: 

56 """ 

57 Getter method corresponding to the ``rdfs:label`` RDF predicate. 

58 

59 :return: The requested value if found, None otherwise 

60 """ 

61 return self._get_literal(RDFS.label) 

62 

63 def create_label(self, string: str) -> None: 

64 """ 

65 Setter method corresponding to the ``rdfs:label`` RDF predicate. 

66 

67 **WARNING: this is a functional property, hence any existing value will be overwritten!** 

68 

69 :param string: The value that will be set as the object of the property related to this method 

70 :type string: str 

71 :return: None 

72 """ 

73 self.remove_label() 

74 self._create_literal(RDFS.label, string) 

75 

76 def remove_label(self) -> None: 

77 """ 

78 Remover method corresponding to the ``rdfs:label`` RDF predicate. 

79 

80 :return: None 

81 """ 

82 self.g.remove((self.res, RDFS.label, None)) 

83 

84 def _create_literal(self, p: URIRef, s: str, dt: URIRef = None, nor: bool = True) -> None: 

85 """ 

86 Adds an RDF triple with a literal object inside the graph of the entity 

87 

88 :param p: The predicate 

89 :type p: URIRef 

90 :param s: The string to add as a literal value 

91 :type s: str 

92 :param dt: The object's datatype, if present 

93 :type dt: URIRef, optional 

94 :param nor: Whether to normalize the graph or not 

95 :type nor: bool, optional 

96 :return: None 

97 """ 

98 create_literal(self.g, self.res, p, s, dt, nor) 

99 

100 # TYPE 

101 def get_types(self) -> List[URIRef]: 

102 """ 

103 Getter method corresponding to the ``rdf:type`` RDF predicate. 

104 

105 :return: A list containing the requested values if found, None otherwise 

106 """ 

107 uri_list: List[URIRef] = self._get_multiple_uri_references(RDF.type) 

108 return uri_list 

109 

110 def _create_type(self, res_type: URIRef, identifier: str = None) -> None: 

111 """ 

112 Setter method corresponding to the ``rdf:type`` RDF predicate. 

113 

114 :param res_type: The value that will be set as the object of the property related to this method 

115 :type res_type: URIRef 

116 :return: None 

117 """ 

118 create_type(self.g, self.res, res_type, identifier) 

119 

120 def remove_type(self) -> None: 

121 """ 

122 Remover method corresponding to the ``rdf:type`` RDF predicate. 

123 

124 :return: None 

125 """ 

126 self.g.remove((self.res, RDF.type, None)) 

127 

128 # Overrides __str__ method 

129 def __str__(self) -> str: 

130 return str(self.res) 

131 

132 def add_triples(self, iterable_of_triples: Iterable) -> None: 

133 """ 

134 A utility method that allows to add a batch of triples into the graph of the entity. 

135 

136 **WARNING: Only triples that have this entity as their subject will be imported!** 

137 

138 :param iterable_of_triples: A collection of triples to be added to the entity 

139 :type iterable_of_triples: Iterable 

140 :return: None 

141 """ 

142 for s, p, o in iterable_of_triples: 

143 if s == self.res: # This guarantees that only triples belonging to the resource will be added 

144 self.g.add((s, p, o)) 

145 

146 def _get_literal(self, predicate: URIRef) -> Optional[str]: 

147 result: Optional[str] = None 

148 for o in self.g.objects(self.res, predicate): 

149 if type(o) == Literal: 

150 result = str(o) 

151 break 

152 return result 

153 

154 def _get_multiple_literals(self, predicate: URIRef) -> List[str]: 

155 result: List[str] = [] 

156 for o in self.g.objects(self.res, predicate): 

157 if type(o) == Literal: 

158 result.append(str(o)) 

159 return result 

160 

161 def _get_uri_reference(self, predicate: URIRef) -> Optional[URIRef]: 

162 result: Optional[URIRef] = None 

163 for o in self.g.objects(self.res, predicate): 

164 if type(o) == URIRef: 

165 result = o 

166 break 

167 return result 

168 

169 def _get_multiple_uri_references(self, predicate: URIRef) -> List[URIRef]: 

170 result: List[URIRef] = [] 

171 for o in self.g.objects(self.res, predicate): 

172 if type(o) == URIRef: 

173 result.append(o) 

174 return result