IDS peak ICV v1.3.0
Loading...
Searching...
No Matches
archive.py
Go to the documentation of this file.
1from __future__ import annotations
2
3from typing import Any, Dict, List, Type, TypeAlias
4
5from ids_peak_common.serialization.iarchive import IArchive
6from ids_peak_icv.exceptions import NotSupportedException, CorruptedException
7
8T: TypeAlias = IArchive.T
9
10
11class Archive(IArchive):
12 """!
13 @brief
14 A key-value store with type checking, based on a dict.
15
16 Supports only:
17 - bool, int, float, str
18 - IArchive
19 - Lists of the above (with homogeneous element types)
20
21 **Example**
22
23 from ids_peak_icv.serialization import Archive
24
25 archive = Archive()
26
27 archive.set("A", 1)
28 archive.set("B", "Text")
29 archive.set("C", [1, 2, 3])
30
31 sub_archive = Archive()
32 sub_archive.set("a", 1.2)
33 sub_archive.set("b", True)
34 archive.set("D", sub_archive)
35
36 @since ids_peak_icv 1.0
37
38 @ingroup ids_peak_icv_python_serialization
39 """
40 AllowedValue = IArchive.AllowedValue | IArchive
41
42 def __init__(self, data: Dict[str, Archive.AllowedValue] | None = None) -> None:
43 """!
44 @brief
45 Initializes the archive with optional initial data.
46
47 If ``data`` is provided,
48 all entries are validated for supported types
49 before the dict is stored by reference.
50 If ``data`` is ``None``,
51 the archive is initially empty.
52
53 @param data: Optional dictionary of initial key-value pairs.
54
55 @exception NotSupportedException: An entry in data has an unsupported type.
56
57 @since ids_peak_icv 1.0
58 """
59 if data is None:
60 data = {}
61 else:
62 for key, value in data.items():
63 if not self._is_supported_type(value):
65 f"Unsupported value type for key '{key}': {type(value).__name__}"
66 )
67
68 self._storage: Dict = data
69
70 def set(self, key: str, value: AllowedValue) -> None:
71 """!
72 @brief
73 Stores a value under the specified key.
74
75 @param key: The key under which to store the value.
76 @param value: The value to store (restricted types only).
77
78 @exception NotSupportedException: The value has an unsupported type.
79
80 @since ids_peak_icv 1.0
81 """
82 if self._is_supported_type(value):
83 self._storage[key] = value
84 else:
86 f"Unsupported value type: {type(value).__name__}"
87 )
88
89 def get(self, key: str, datatype: Type[T] | None) -> T:
90 """!
91 @brief
92 Returns the value stored under the specified key.
93
94 @param key: Key of the value to retrieve.
95 @param datatype: The expected datatype of the value.
96 If None is given, the type check is not executed.
97
98 @return The stored value.
99
100 @exception CorruptedException: If the key is not found
101 or the specified datatype is not the type of the stored value.
102
103 @since ids_peak_icv 1.0
104 """
105
106 if key not in self._storage:
107 raise CorruptedException(f"The specified key '{key}' is not in the archive.")
108
109 value = self._storage[key]
110 if datatype is not type(value) and datatype is not None:
111 raise CorruptedException(f"The value of the specified key '{key}' is not of the expected datatype.")
112
113 return value
114
115 def get_archive(self, key: str) -> IArchive:
116 """!
117 @brief
118 Returns the archive stored under the given key.
119
120 @param key: Key of the archive to retrieve.
121
122 @return The stored archive.
123
124 @exception CorruptedException: The key is not found
125 or the specified datatype is not of type ``IArchive``.
126
127 @since ids_peak_icv 1.0
128 """
129
130 if key not in self._storage:
131 raise CorruptedException(f"The specified key '{key}' is not in the archive.")
132 value = self._storage[key]
133 if not isinstance(value, IArchive):
134 raise CorruptedException(f"The value of the specified key '{key}' is not of the expected datatype.")
135
136 return value
137
138 def has(self, key: str) -> bool:
139 """!
140 @brief
141 Checks whether a given key exists in the archive.
142
143 @param key: The key to check.
144
145 @return True if the key exists, False otherwise.
146
147 @since ids_peak_icv 1.0
148 """
149 return key in self._storage
150
151 def keys(self) -> List[str]:
152 """!
153 @brief
154 Returns all keys currently stored in the archive.
155
156 @return List of keys.
157
158 @since ids_peak_icv 1.0
159 """
160 return list(self._storage.keys())
161
162 def create_archive(self) -> IArchive:
163 """!
164 @brief
165 Creates a new, empty archive instance.
166
167 @since ids_peak_icv 1.0
168 """
169 return Archive()
170
171 def __str__(self) -> str:
172 """!
173 @brief
174 A string representation of the archive.
175
176 @since ids_peak_icv 1.0
177 """
178 return str(self._storage)
179
180 def __repr__(self) -> str:
181 """!
182 @brief
183 @since ids_peak_icv 1.0
184 """
185 return f"Archive({str(self)})"
186
187 def __eq__(self, other: Any) -> bool:
188 """!
189 @brief
190 @since ids_peak_icv 1.0
191 """
192 if not isinstance(other, Archive):
193 return False
194
195 if set(self._storage.keys()) != set(other._storage.keys()):
196 return False
197
198 for key in self._storage:
199 if not self._compare_values(self._storage[key], other._storage[key]):
200 return False
201
202 return True
203
204 def _compare_values(self, lhs: Any, rhs: Any) -> bool:
205 """!
206 @brief
207 @since ids_peak_icv 1.0
208 """
209 if isinstance(lhs, Archive) and isinstance(rhs, Archive):
210 return bool(lhs == rhs)
211
212 if isinstance(lhs, list) and isinstance(rhs, list):
213 if len(lhs) != len(rhs):
214 return False
215 return all(self._compare_values(val1, val2) for val1, val2 in zip(lhs, rhs))
216
217 return bool(lhs == rhs)
218
219 _ALLOWED_SCALARS = (bool, int, float, str, IArchive)
220
221 def _is_supported_type(self, value: Any) -> bool:
222 """!
223 @brief
224 Returns whether the value’s type is supported.
225
226 @param value: A value or a list whose type is validated.
227
228 @return `True` if the type supported, `False` otherwise.
229
230 @since ids_peak_icv 1.0
231 """
232 if isinstance(value, self._ALLOWED_SCALARS):
233 return True
234 if isinstance(value, list):
235 if len(value) == 0:
236 return True
237 first_type = type(value[0])
238 if all(isinstance(v, first_type) for v in value):
239 if issubclass(first_type, self._ALLOWED_SCALARS):
240 return True
241 return False
Occurs when reading from a file or stream that is incomplete, damaged, or in an unexpected format.
Occurs when a requested operation is not implemented or supported (e.g., exporting to an unsupported ...
Definition exceptions.py:60
A key-value store with type checking, based on a dict.
Definition archive.py:11
T get(self, str key, Type[T]|None datatype)
Returns the value stored under the specified key.
Definition archive.py:89
IArchive create_archive(self)
Creates a new, empty archive instance.
Definition archive.py:162
None __init__(self, Dict[str, Archive.AllowedValue]|None data=None)
Initializes the archive with optional initial data.
Definition archive.py:42
IArchive get_archive(self, str key)
Returns the archive stored under the given key.
Definition archive.py:115
List[str] keys(self)
Returns all keys currently stored in the archive.
Definition archive.py:151
None set(self, str key, AllowedValue value)
Stores a value under the specified key.
Definition archive.py:70
bool _is_supported_type(self, Any value)
Returns whether the value’s type is supported.
Definition archive.py:221
bool _compare_values(self, Any lhs, Any rhs)
Definition archive.py:204
bool has(self, str key)
Checks whether a given key exists in the archive.
Definition archive.py:138
str __str__(self)
A string representation of the archive.
Definition archive.py:171