Skip to content

Commit 85c215d

Browse files
authored
Merge pull request #2398 from wagner-intevation/enh-invalid-key-message
ENH: message: show reason for InvalidKey exception
2 parents ecc44ea + dc758e6 commit 85c215d

File tree

5 files changed

+30
-16
lines changed

5 files changed

+30
-16
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ CHANGELOG
1313
### Configuration
1414

1515
### Core
16+
- `intelmq.lib.message`: For invalid message keys, add a hint on the failure to the exception: not allowed by configuration or not matching regular expression (PR#2398 by Sebastian Wagner).
17+
- `intelmq.lib.exceptions.InvalidKey`: Add optional parameter `additional_text` (PR#2398 by Sebastian Wagner).
1618

1719
### Development
1820

intelmq/lib/exceptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ def __init__(self, key: str, value: str, reason: Any = None, object: bytes = Non
8888

8989
class InvalidKey(IntelMQHarmonizationException, KeyError):
9090

91-
def __init__(self, key: str):
92-
message = "invalid key %s" % repr(key)
91+
def __init__(self, key: str, additional_text: Optional[str] = None):
92+
message = f"invalid key {key!r} {additional_text or ''}".strip() # remove trailing whitespace if additional_text is not given
9393
super().__init__(message)
9494

9595

intelmq/lib/message.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import re
1414
import warnings
1515
from collections import defaultdict
16-
from typing import Any, Dict, Iterable, Optional, Sequence, Union
16+
from typing import Any, Dict, Iterable, Optional, Sequence, Union, Tuple
1717
from pkg_resources import resource_filename
1818

1919
import intelmq.lib.exceptions as exceptions
@@ -186,8 +186,9 @@ def is_valid(self, key: str, value: str, sanitize: bool = True) -> bool:
186186
intelmq.lib.exceptions.InvalidKey: if given key is invalid.
187187
188188
"""
189-
if not self.__is_valid_key(key):
190-
raise exceptions.InvalidKey(key)
189+
key_validation = self.__is_valid_key(key)
190+
if not key_validation[0]:
191+
raise exceptions.InvalidKey(key, additional_text=key_validation[1])
191192

192193
if value is None or value in ["", "-", "N/A"]:
193194
return False
@@ -243,8 +244,9 @@ def add(self, key: str, value: str, sanitize: bool = True,
243244
del self[key]
244245
return
245246

246-
if not self.__is_valid_key(key):
247-
raise exceptions.InvalidKey(key)
247+
key_validation = self.__is_valid_key(key)
248+
if not key_validation[0]:
249+
raise exceptions.InvalidKey(key, additional_text=key_validation[1])
248250

249251
try:
250252
if value in ignore:
@@ -330,16 +332,16 @@ def unserialize(message_string: str):
330332
message = json.loads(message_string)
331333
return message
332334

333-
def __is_valid_key(self, key: str):
335+
def __is_valid_key(self, key: str) -> Tuple[bool, str]:
334336
try:
335337
class_name, subitem = self.__get_type_config(key)
336338
except KeyError:
337-
return False
339+
return False, 'This key is not allowed by the harmonization configuration'
338340
if key in self.harmonization_config or key == '__type':
339-
return True
341+
return True, None
340342
if subitem:
341-
return HARMONIZATION_KEY_FORMAT.match(key)
342-
return False
343+
return HARMONIZATION_KEY_FORMAT.match(key), f'Does not match regular expression {HARMONIZATION_KEY_FORMAT.pattern}'
344+
return False, 'This key is not allowed by the harmonization configuration'
343345

344346
def __is_valid_value(self, key: str, value: str):
345347
if key == '__type':
@@ -569,7 +571,7 @@ def __init__(self, message: Union[dict, tuple] = (), auto: bool = False,
569571
if isinstance(message, Event):
570572
super().__init__({}, auto, harmonization)
571573
for key, value in message.items():
572-
if self._Message__is_valid_key(key):
574+
if self._Message__is_valid_key(key)[0]:
573575
self.add(key, value, sanitize=False)
574576
else:
575577
super().__init__(message, auto, harmonization)

intelmq/tests/lib/test_exceptions.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ def test_MissingDependencyError(self):
6464
self.assertIn(repr(depname), exc)
6565
self.assertTrue(exc.endswith(" %s" % additional))
6666

67+
def test_invalid_key(self):
68+
"""
69+
Check intelmq.lib.exceptions.InvalidKey
70+
"""
71+
exc = excs.InvalidKey('test_key', additional_text='TEST').args[0]
72+
self.assertTrue(exc.endswith(' TEST'))
73+
6774

6875
if __name__ == '__main__': # pragma: no cover
6976
unittest.main()

intelmq/tests/lib/test_message.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,10 @@ def test_invalid_type2(self):
168168
def test_report_invalid_key(self):
169169
""" Test if report raises InvalidKey for invalid key in add(). """
170170
report = self.new_report()
171-
with self.assertRaises(exceptions.InvalidKey):
171+
with self.assertRaises(exceptions.InvalidKey) as cm:
172172
report.add('invalid', 0)
173+
self.assertIn('not allowed', cm.exception.args[0])
174+
173175

174176
def test_report_add_raw(self):
175177
""" Test if report can add raw value. """
@@ -764,10 +766,11 @@ def test_invalid_harm_key(self):
764766
message.Event(harmonization={'event': {'foo.bar.': {}}})
765767

766768
def test_invalid_extra_key_name(self):
767-
""" Test if error is raised if an extra field name is invalid. """
769+
""" Test if error is raised when an extra field name is invalid and error message is included in exception. """
768770
event = message.Event(harmonization=HARM)
769-
with self.assertRaises(exceptions.InvalidKey):
771+
with self.assertRaises(exceptions.InvalidKey) as cm:
770772
event.add('extra.foo-', 'bar')
773+
self.assertIn('Does not match regular expression', cm.exception.args[0])
771774

772775

773776
class TestReport(unittest.TestCase):

0 commit comments

Comments
 (0)