IDS peak ICV v1.3.0
Loading...
Searching...
No Matches
metadata.py
Go to the documentation of this file.
1from typing import Any, Dict, Type, TypeVar, List
2
3from ids_peak_common.datatypes.metadata_key import MetadataKey
4from ids_peak_common.exceptions import OutOfRangeException, InvalidCastException
5
6T = TypeVar("T")
7
8
9def _validate_key_type(key: MetadataKey, value: Any) -> None:
10 from typing import get_origin, get_args
11
12 expected_type = key.type
13 origin = get_origin(expected_type)
14
15 if origin:
16 inner_type = get_args(expected_type)[0]
17
18 actual_origin = type(value)
19 if not actual_origin is origin:
20 raise InvalidCastException(
21 f"Value for key '{key.string_value}' must be of type {origin.__name__}, "
22 f"got {actual_origin.__name__}"
23 )
24
25 for v in value:
26 if not isinstance(v, inner_type):
27 raise InvalidCastException(
28 f"Inner value for key '{key.string_value}' must be of type {inner_type.__name__}, "
29 f"got {type(v).__name__} (value={v})"
30 )
31
32 elif not isinstance(value, expected_type):
33 raise InvalidCastException(
34 f"Value for key '{key.string_value}' must be of type {expected_type.__name__}, "
35 f"got {type(value).__name__}"
36 )
37
38
40 """!
41 @brief
42 A type-safe container for metadata key-value pairs.
43
44 This class provides a flexible mechanism for storing and retrieving metadata:
45 - Arbitrary runtime keys (string string_values).
46 - Strongly typed keys defined in a schema.
47
48 Values are stored in a Python dictionary but accessed with additional
49 safety checks to ensure type correctness.
50
51 Example usage::
52
53 metadata = Metadata()
54 metadata.set_value_by_key(MetadataKey.DEVICE_FRAME_ID, 1)
55 print(metadata.get_value_by_key(MetadataKey.DEVICE_FRAME_ID)) # outputs: 1
56 print(metadata.has_entry_by_key(MetadataKey.DEVICE_FRAME_ID)) # outputs: True
57
58 @ingroup ids_peak_common_python_types
59 """
60
61 def __init__(self) -> None:
62 """!
63 @brief Initialize an empty metadata container."""
64 self._data: Dict[str, Any] = {}
65
66 def set_value_by_name(self, key: str, value: Any) -> None:
67 """!
68 @brief
69 Store a value using a string-based key.
70
71 @param key: Runtime string string_value.
72 @param value: Value to store.
73 """
74 self._data[key] = value
75
76 def has_entry_by_name(self, key: str) -> bool:
77 """!
78 @brief
79 Check if a string key is present in the metadata.
80
81 @param key: The metadata key.
82 @return True if the key exists, False otherwise.
83 """
84 return key in self._data
85
86 def try_get_value_by_name(self, key: str) -> Any:
87 """!
88 @brief
89 Retrieve a value by string key, returning None if not found.
90
91 @param key: The metadata key.
92 @return The stored value if found, otherwise None.
93 """
94 return self._data.get(key, None)
95
96 def get_value_by_name(self, expected_type: Type[T], key: str) -> T:
97 """!
98 @brief
99 Retrieve the value for a key and validate that it is of the expected type.
100
101 @param expected_type: The expected type of the stored value.
102 @param key: The metadata key.
103 @exception OutOfRangeException: If the key does not exist.
104 @exception InvalidCastException: If the stored type does not match.
105 @return The stored value cast to the expected type.
106 """
107 if key not in self._data:
108 raise OutOfRangeException(f"There is no value named '{key}'")
109
110 value = self._data[key]
111 if not isinstance(value, expected_type):
112 raise InvalidCastException(
113 f"Value for key '{key}' is of type {type(value).__name__}, "
114 f"expected {expected_type.__name__}"
115 )
116 return value
117
118 def set_value_by_key(self, key: MetadataKey, value: Any) -> None:
119 """!
120 @brief
121 Store a value using a strongly typed metadata key.
122
123 @param key: A MetadataKey object containing key name and expected type.
124 @param value: The value to store.
125 @exception InvalidCastException: If the value type does not match the trait type.
126 """
127 _validate_key_type(key, value)
128
129 self._data[key.string_value] = value
130
131 def has_entry_by_key(self, key: MetadataKey) -> bool:
132 """!
133 @brief
134 Check if a strongly typed metadata key is present and matches the expected type.
135
136 @param key: A MetadataKey object.
137 @return True if the key exists and type matches, False otherwise.
138 """
139 if key.string_value not in self._data:
140 return False
141
142 from typing import get_origin, get_args
143
144 expected_type = key.type
145 origin = get_origin(expected_type)
146 args = get_args(expected_type)
147
148 if (origin is list) and args:
149 element_type = args[0]
150 return all(isinstance(v, element_type) for v in self._data[key.string_value])
151 else:
152 return isinstance(self._data[key.string_value], key.type)
153
154 def get_value_by_key(self, key: MetadataKey) -> Any:
155 """!
156 @brief
157 Retrieve the value of a strongly typed metadata key.
158
159 @param key: A MetadataKey object.
160 @exception OutOfRangeException: If the key does not exist.
161 @exception InvalidCastException: If the type does not match.
162 @return The stored value.
163 """
164 if key.string_value not in self._data:
165 raise OutOfRangeException(f"Key '{key.string_value}' not found")
166
167 value = self._data[key.string_value]
168 _validate_key_type(key, value)
169 return value
170
171 def get_key_names(self) -> List[str]:
172 """!
173 @brief
174 Returns a list of metadata key names.
175
176 @return A list of metadata key names
177 """
178 return list(self._data.keys())
179
180 def __eq__(self, other: Any) -> bool:
181 """!
182 @brief
183 Check if two metadata are equal.
184
185 @param other: Another Metadata object
186
187 @return True if metadata are equal, False otherwise
188 """
189 if isinstance(other, Metadata):
190 return self._data == other._data
191 return False
192
193 def __ne__(self, other: Any) -> bool:
194 """!
195 @brief
196 Check if two metadata are not equal.
197
198 @param other: Another metadata object
199
200 @return True if metadata are not equal, False otherwise
201 """
202 return not self.__eq__(other)
203
204 def __str__(self) -> str:
205 """!
206 @brief
207 Return a human-readable string of metadata keys and values.
208
209 Example:
210 { "DeviceFrameID": 42, "DeviceTimestamp": 1695472000, "custom_data": "xyz" }
211 """
212 items = [f'"{k}": {v!r}' for k, v in self._data.items()]
213
214 return f"( {', '.join(items)} )"
215
216 def __repr__(self) -> str:
217 """!
218 @brief
219 Return an unambiguous string of the Metadata object.
220 """
221 return f"{self.__class__.__name__}{str(self)}"
A type-safe container for metadata key-value pairs.
Definition metadata.py:39
bool has_entry_by_key(self, MetadataKey key)
Check if a strongly typed metadata key is present and matches the expected type.
Definition metadata.py:131
List[str] get_key_names(self)
Returns a list of metadata key names.
Definition metadata.py:171
bool has_entry_by_name(self, str key)
Check if a string key is present in the metadata.
Definition metadata.py:76
Any get_value_by_key(self, MetadataKey key)
Retrieve the value of a strongly typed metadata key.
Definition metadata.py:154
T get_value_by_name(self, Type[T] expected_type, str key)
Retrieve the value for a key and validate that it is of the expected type.
Definition metadata.py:96
None set_value_by_name(self, str key, Any value)
Store a value using a string-based key.
Definition metadata.py:66
None set_value_by_key(self, MetadataKey key, Any value)
Store a value using a strongly typed metadata key.
Definition metadata.py:118
Any try_get_value_by_name(self, str key)
Retrieve a value by string key, returning None if not found.
Definition metadata.py:86
bool __ne__(self, Any other)
Check if two metadata are not equal.
Definition metadata.py:193
None __init__(self)
Initialize an empty metadata container.
Definition metadata.py:61
str __str__(self)
Return a human-readable string of metadata keys and values.
Definition metadata.py:204
str __repr__(self)
Return an unambiguous string of the Metadata object.
Definition metadata.py:216
bool __eq__(self, Any other)
Check if two metadata are equal.
Definition metadata.py:180
None _validate_key_type(MetadataKey key, Any value)
Definition metadata.py:9