Coverage for oc_ocdm/counter_handler/in_memory_counter_handler.py: 92%

91 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2025-05-30 22:05 +0000

1#!/usr/bin/python 

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

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

4# 

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

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

7# and this permission notice appear in all copies. 

8# 

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

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

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

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

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

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

15# SOFTWARE. 

16from __future__ import annotations 

17 

18from typing import TYPE_CHECKING 

19 

20if TYPE_CHECKING: 

21 from typing import List, Dict 

22 

23from oc_ocdm.counter_handler.counter_handler import CounterHandler 

24 

25 

26class InMemoryCounterHandler(CounterHandler): 

27 """A concrete implementation of the ``CounterHandler`` interface that temporarily stores 

28 the counter values in the volatile system memory.""" 

29 

30 def __init__(self) -> None: 

31 """ 

32 Constructor of the ``InMemoryCounterHandler`` class. 

33 """ 

34 self.short_names: List[str] = ["an", "ar", "be", "br", "ci", "de", "id", "pl", "ra", "re", "rp"] 

35 self.prov_short_names: List[str] = ["se"] 

36 self.metadata_short_names: List[str] = ["di"] 

37 self.entity_counters: Dict[str, int] = {key: 0 for key in self.short_names} 

38 self.prov_counters: Dict[str, Dict[str, List[int]]] = {key1: {key2: [] for key2 in self.prov_short_names} 

39 for key1 in self.short_names} 

40 self.metadata_counters: Dict[str, Dict[str, int]] = {} 

41 

42 def set_counter(self, new_value: int, entity_short_name: str, prov_short_name: str = "", 

43 identifier: int = 1, supplier_prefix: str = "") -> None: 

44 """ 

45 It allows to set the counter value of graph and provenance entities. 

46 

47 :param new_value: The new counter value to be set 

48 :type new_value: int 

49 :param entity_short_name: The short name associated either to the type of the entity itself 

50 or, in case of a provenance entity, to the type of the relative graph entity. 

51 :type entity_short_name: str 

52 :param prov_short_name: In case of a provenance entity, the short name associated to the type 

53 of the entity itself. An empty string otherwise. 

54 :type prov_short_name: str 

55 :param identifier: In case of a provenance entity, the counter value that identifies the relative 

56 graph entity. The integer value '1' otherwise. 

57 :type identifier: int 

58 :raises ValueError: if ``new_value`` is a negative integer, ``identifier`` is less than or equal to zero, 

59 ``entity_short_name`` is not a known short name or ``prov_short_name`` is not a known provenance short name. 

60 :return: None 

61 """ 

62 if new_value < 0: 

63 raise ValueError("new_value must be a non negative integer!") 

64 

65 if entity_short_name not in self.short_names: 

66 raise ValueError("entity_short_name is not a known short name!") 

67 

68 if prov_short_name != "": 

69 if prov_short_name not in self.prov_short_names: 

70 raise ValueError("prov_short_name is not a known provenance short name!") 

71 if identifier <= 0: 

72 raise ValueError("identifier must be a positive non-zero integer number!") 

73 

74 identifier -= 1 # Internally we use zero_indexing! 

75 if prov_short_name in self.prov_short_names: 

76 # It's a provenance entity! 

77 missing_counters: int = identifier - (len(self.prov_counters[entity_short_name][prov_short_name]) - 1) 

78 if missing_counters > 0: 

79 self.prov_counters[entity_short_name][prov_short_name] += [0] * missing_counters 

80 self.prov_counters[entity_short_name][prov_short_name][identifier] = new_value 

81 else: 

82 # It's an entity! 

83 self.entity_counters[entity_short_name] = new_value 

84 

85 def read_counter(self, entity_short_name: str, prov_short_name: str = "", identifier: int = 1, supplier_prefix: str = "") -> int: 

86 """ 

87 It allows to read the counter value of graph and provenance entities. 

88 

89 :param entity_short_name: The short name associated either to the type of the entity itself 

90 or, in case of a provenance entity, to the type of the relative graph entity. 

91 :type entity_short_name: str 

92 :param prov_short_name: In case of a provenance entity, the short name associated to the type 

93 of the entity itself. An empty string otherwise. 

94 :type prov_short_name: str 

95 :param identifier: In case of a provenance entity, the counter value that identifies the relative 

96 graph entity. The integer value '1' otherwise. 

97 :type identifier: int 

98 :raises ValueError: if ``identifier`` is less than or equal to zero, ``entity_short_name`` 

99 is not a known short name or ``prov_short_name`` is not a known provenance short name. 

100 :return: The requested counter value. 

101 """ 

102 if entity_short_name not in self.short_names: 

103 raise ValueError("entity_short_name is not a known short name!") 

104 

105 if prov_short_name != "": 

106 if prov_short_name not in self.prov_short_names: 

107 raise ValueError("prov_short_name is not a known provenance short name!") 

108 if identifier <= 0: 

109 raise ValueError("identifier must be a positive non-zero integer number!") 

110 

111 identifier -= 1 # Internally we use zero_indexing! 

112 if prov_short_name in self.prov_short_names: 

113 # It's a provenance entity! 

114 missing_counters: int = identifier - (len(self.prov_counters[entity_short_name][prov_short_name]) - 1) 

115 if missing_counters > 0: 

116 self.prov_counters[entity_short_name][prov_short_name] += [0] * missing_counters 

117 return self.prov_counters[entity_short_name][prov_short_name][identifier] 

118 else: 

119 # It's an entity! 

120 return self.entity_counters[entity_short_name] 

121 

122 def increment_counter(self, entity_short_name: str, prov_short_name: str = "", identifier: int = 1, supplier_prefix: str = "") -> int: 

123 """ 

124 It allows to increment the counter value of graph and provenance entities by one unit. 

125 

126 :param entity_short_name: The short name associated either to the type of the entity itself 

127 or, in case of a provenance entity, to the type of the relative graph entity. 

128 :type entity_short_name: str 

129 :param prov_short_name: In case of a provenance entity, the short name associated to the type 

130 of the entity itself. An empty string otherwise. 

131 :type prov_short_name: str 

132 :param identifier: In case of a provenance entity, the counter value that identifies the relative 

133 graph entity. The integer value '1' otherwise. 

134 :type identifier: int 

135 :raises ValueError: if ``identifier`` is less than or equal to zero, ``entity_short_name`` 

136 is not a known short name or ``prov_short_name`` is not a known provenance short name. 

137 :return: The newly-updated (already incremented) counter value. 

138 """ 

139 if entity_short_name not in self.short_names: 

140 raise ValueError("entity_short_name is not a known short name!") 

141 

142 if prov_short_name != "": 

143 if prov_short_name not in self.prov_short_names: 

144 raise ValueError("prov_short_name is not a known provenance short name!") 

145 if identifier <= 0: 

146 raise ValueError("identifier must be a positive non-zero integer number!") 

147 

148 identifier -= 1 # Internally we use zero_indexing! 

149 if prov_short_name in self.prov_short_names: 

150 # It's a provenance entity! 

151 missing_counters: int = identifier - (len(self.prov_counters[entity_short_name][prov_short_name]) - 1) 

152 if missing_counters > 0: 

153 self.prov_counters[entity_short_name][prov_short_name] += [0]*missing_counters 

154 self.prov_counters[entity_short_name][prov_short_name][identifier] += 1 

155 return self.prov_counters[entity_short_name][prov_short_name][identifier] 

156 else: 

157 # It's an entity! 

158 self.entity_counters[entity_short_name] += 1 

159 return self.entity_counters[entity_short_name] 

160 

161 def set_metadata_counter(self, new_value: int, entity_short_name: str, dataset_name: str) -> None: 

162 """ 

163 It allows to set the counter value of metadata entities. 

164 

165 :param new_value: The new counter value to be set 

166 :type new_value: int 

167 :param entity_short_name: The short name associated either to the type of the entity itself. 

168 :type entity_short_name: str 

169 :param dataset_name: In case of a ``Dataset``, its name. Otherwise, the name of the relative dataset. 

170 :type dataset_name: str 

171 :raises ValueError: if ``new_value`` is a negative integer, ``dataset_name`` is None or 

172 ``entity_short_name`` is not a known metadata short name. 

173 :return: None 

174 """ 

175 if new_value < 0: 

176 raise ValueError("new_value must be a non negative integer!") 

177 

178 if dataset_name is None: 

179 raise ValueError("dataset_name must be provided!") 

180 

181 if entity_short_name not in self.metadata_short_names: 

182 raise ValueError("entity_short_name is not a known metadata short name!") 

183 

184 if dataset_name not in self.metadata_counters: 

185 self.metadata_counters[dataset_name] = {key: 0 for key in self.metadata_short_names} 

186 

187 self.metadata_counters[dataset_name][entity_short_name] = new_value 

188 

189 def read_metadata_counter(self, entity_short_name: str, dataset_name: str) -> int: 

190 """ 

191 It allows to read the counter value of metadata entities. 

192 

193 :param entity_short_name: The short name associated either to the type of the entity itself. 

194 :type entity_short_name: str 

195 :param dataset_name: In case of a ``Dataset``, its name. Otherwise, the name of the relative dataset. 

196 :type dataset_name: str 

197 :raises ValueError: if ``dataset_name`` is None or ``entity_short_name`` is not a known metadata short name. 

198 :return: The requested counter value. 

199 """ 

200 if dataset_name is None: 

201 raise ValueError("dataset_name must be provided!") 

202 

203 if entity_short_name not in self.metadata_short_names: 

204 raise ValueError("entity_short_name is not a known metadata short name!") 

205 

206 if dataset_name not in self.metadata_counters: 

207 return 0 

208 else: 

209 if entity_short_name not in self.metadata_counters[dataset_name]: 

210 return 0 

211 else: 

212 return self.metadata_counters[dataset_name][entity_short_name] 

213 

214 def increment_metadata_counter(self, entity_short_name: str, dataset_name: str) -> int: 

215 """ 

216 It allows to increment the counter value of metadata entities by one unit. 

217 

218 :param entity_short_name: The short name associated either to the type of the entity itself. 

219 :type entity_short_name: str 

220 :param dataset_name: In case of a ``Dataset``, its name. Otherwise, the name of the relative dataset. 

221 :type dataset_name: str 

222 :raises ValueError: if ``dataset_name`` is None or ``entity_short_name`` is not a known metadata short name. 

223 :return: The newly-updated (already incremented) counter value. 

224 """ 

225 if dataset_name is None: 

226 raise ValueError("dataset_name must be provided!") 

227 

228 if entity_short_name not in self.metadata_short_names: 

229 raise ValueError("entity_short_name is not a known metadata short name!") 

230 

231 if dataset_name not in self.metadata_counters: 

232 self.metadata_counters[dataset_name] = {key: 0 for key in self.metadata_short_names} 

233 

234 self.metadata_counters[dataset_name][entity_short_name] += 1 

235 return self.metadata_counters[dataset_name][entity_short_name]