diff --git a/intelmq/bots/collectors/stomp/collector.py b/intelmq/bots/collectors/stomp/collector.py index 28ff63e222..3cb12215ab 100644 --- a/intelmq/bots/collectors/stomp/collector.py +++ b/intelmq/bots/collectors/stomp/collector.py @@ -10,9 +10,10 @@ stomp = None else: import stomp.exception +from packaging.version import Version from intelmq.lib.bot import CollectorBot -from intelmq.lib.mixins import StompMixin +from intelmq.lib.mixins.stomp import StompMixin, stomp_version if stomp is not None: @@ -28,7 +29,7 @@ def __init__(self, n6stompcollector, conn, destination, connect_kwargs=None): self.connect_kwargs = connect_kwargs self.destination = destination super().__init__() - if stomp.__version__ >= (5, 0, 0): + if stomp_version() >= Version("5.0.0"): # set the function directly, as the argument print_to_log logs to the generic logger self._PrintingListener__print = n6stompcollector.logger.debug @@ -112,13 +113,14 @@ def init(self): self.stomp_bot_runtime_initial_check() # (note: older versions of `stomp.py` do not play well with reconnects) - self._auto_reconnect = (stomp.__version__ >= (4, 1, 21)) + installed_version = stomp_version() + self._auto_reconnect = (installed_version >= Version("4.1.21")) self.__conn, connect_kwargs = self.prepare_stomp_connection() self.__conn.set_listener('', StompListener(self, self.__conn, self.exchange, connect_kwargs=connect_kwargs)) connect_and_subscribe(self.__conn, self.logger, self.exchange, - start=stomp.__version__ < (4, 1, 20), + start=installed_version < Version("4.1.20"), connect_kwargs=connect_kwargs) def shutdown(self): diff --git a/intelmq/bots/outputs/stomp/output.py b/intelmq/bots/outputs/stomp/output.py index 6beb0fa567..5004ae0208 100644 --- a/intelmq/bots/outputs/stomp/output.py +++ b/intelmq/bots/outputs/stomp/output.py @@ -8,9 +8,10 @@ import stomp except ImportError: stomp = None +from packaging.version import Version from intelmq.lib.bot import OutputBot -from intelmq.lib.mixins import StompMixin +from intelmq.lib.mixins.stomp import StompMixin, stomp_version class StompOutputBot(OutputBot, StompMixin): @@ -62,7 +63,7 @@ def connect(self): self.logger.debug('Connecting.') # based on the documentation at: # https://github.com/jasonrbriggs/stomp.py/wiki/Simple-Example - if stomp.__version__ < (4, 1, 20): + if stomp_version() < Version("4.1.20"): self._conn.start() self._conn.connect(**self._connect_kwargs) self.logger.debug('Connected.') diff --git a/intelmq/lib/mixins/stomp.py b/intelmq/lib/mixins/stomp.py index b83e3e528f..975e3a5607 100644 --- a/intelmq/lib/mixins/stomp.py +++ b/intelmq/lib/mixins/stomp.py @@ -8,6 +8,8 @@ import os import ssl import sys +from importlib.metadata import PackageNotFoundError, version +from packaging.version import Version from typing import ( Any, Callable, @@ -27,6 +29,16 @@ from intelmq.lib.exceptions import MissingDependencyError +def stomp_version() -> Version: + try: + return Version(version("stomp.py")) + except PackageNotFoundError: + stomp_module_version = stomp.__version__ + if isinstance(stomp_module_version, tuple): + stomp_module_version = ".".join(str(part) for part in stomp_module_version) + return Version(stomp_module_version) + + class StompMixin: """A mixin that provides certain common methods for STOMP bots.""" @@ -121,9 +133,10 @@ def __verify_dependency(cls) -> None: if stomp is None: raise MissingDependencyError('stomp', additional_text=cls._DEPENDENCY_NAME_REMARK) - if stomp.__version__ < (4, 1, 12): + installed_version = stomp_version() + if installed_version < Version("4.1.12"): raise MissingDependencyError('stomp', version="4.1.12", - installed=stomp.__version__, + installed=str(installed_version), additional_text=cls._DEPENDENCY_NAME_REMARK) @classmethod diff --git a/intelmq/tests/bots/outputs/stomp/test_output.py b/intelmq/tests/bots/outputs/stomp/test_output.py index 8c57558670..de08201b86 100644 --- a/intelmq/tests/bots/outputs/stomp/test_output.py +++ b/intelmq/tests/bots/outputs/stomp/test_output.py @@ -4,6 +4,27 @@ # -*- coding: utf-8 -*- import os +from types import SimpleNamespace +from unittest.mock import Mock + +from packaging.version import Version if os.environ.get('INTELMQ_TEST_EXOTIC'): import intelmq.bots.outputs.stomp.output + +from intelmq.bots.outputs.stomp.output import StompOutputBot + + +def test_connect_with_string_stomp_version(monkeypatch): + bot = StompOutputBot.__new__(StompOutputBot) + bot.logger = Mock() + bot._connect_kwargs = {"wait": True} + bot._conn = SimpleNamespace(start=Mock(), connect=Mock()) + + monkeypatch.setattr("intelmq.bots.outputs.stomp.output.stomp_version", + lambda: Version("8.2.0")) + + bot.connect() + + bot._conn.start.assert_not_called() + bot._conn.connect.assert_called_once_with(wait=True) diff --git a/intelmq/tests/lib/test_stomp_mixin.py b/intelmq/tests/lib/test_stomp_mixin.py new file mode 100644 index 0000000000..22610f5471 --- /dev/null +++ b/intelmq/tests/lib/test_stomp_mixin.py @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: 2026 BharatDeva +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +from types import SimpleNamespace + +from importlib.metadata import PackageNotFoundError +from packaging.version import Version + +import intelmq.lib.mixins.stomp as stomp + + +def test_stomp_version_uses_distribution_metadata(monkeypatch): + monkeypatch.setattr(stomp, "version", lambda _: "8.2.0") + monkeypatch.setattr(stomp, "stomp", SimpleNamespace(__version__=(4, 1, 12))) + + assert stomp.stomp_version() == Version("8.2.0") + + +def test_stomp_version_falls_back_to_tuple_module_version(monkeypatch): + def missing_distribution(_): + raise PackageNotFoundError + + monkeypatch.setattr(stomp, "version", missing_distribution) + monkeypatch.setattr(stomp, "stomp", SimpleNamespace(__version__=(4, 1, 12))) + + assert stomp.stomp_version() == Version("4.1.12")