From 3affc4a3ec58281e788c05c3fe30debeaf76e9fa Mon Sep 17 00:00:00 2001 From: Bartok9 <259807879+Bartok9@users.noreply.github.com> Date: Wed, 12 Aug 2026 13:25:04 -0400 Subject: [PATCH] fix(communication): require positive callback_max_workers ThreadPoolExecutor rejects non-positive max_workers with a generic error. Validate callback_max_workers as a positive int up front on BaseConnector. Signed-off-by: Bartok9 --- .../rai/communication/base_connector.py | 8 +++- .../test_base_connector_workers.py | 43 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/communication/test_base_connector_workers.py diff --git a/src/rai_core/rai/communication/base_connector.py b/src/rai_core/rai/communication/base_connector.py index c99b6a2e8..64590b1ea 100644 --- a/src/rai_core/rai/communication/base_connector.py +++ b/src/rai_core/rai/communication/base_connector.py @@ -72,9 +72,15 @@ class ParametrizedCallback(BaseModel, Generic[T]): class BaseConnector(Generic[T]): def __init__(self, callback_max_workers: int = 4): + if not isinstance(callback_max_workers, int) or isinstance( + callback_max_workers, bool + ): + raise ValueError( + f"callback_max_workers must be a positive int, got {callback_max_workers!r}" + ) if callback_max_workers <= 0: raise ValueError( - f"callback_max_workers must be positive, got {callback_max_workers!r}" + f"callback_max_workers must be a positive int, got {callback_max_workers!r}" ) self.callback_max_workers = callback_max_workers self.logger = logging.getLogger(self.__class__.__name__) diff --git a/tests/communication/test_base_connector_workers.py b/tests/communication/test_base_connector_workers.py new file mode 100644 index 000000000..01390e144 --- /dev/null +++ b/tests/communication/test_base_connector_workers.py @@ -0,0 +1,43 @@ +# Copyright (C) 2025 Robotec.AI +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from rai.communication.base_connector import BaseConnector, BaseMessage + + +class _Msg(BaseMessage): + pass + + +class _Conn(BaseConnector[_Msg]): + def send_message(self, message, target, **kwargs): + pass + + def receive_message(self, source, timeout_sec, **kwargs): + pass + + def service_call(self, message, target, timeout_sec, **kwargs): + pass + + +@pytest.mark.parametrize("bad", [0, -1, 1.5, True, "4", None]) +def test_callback_max_workers_rejects_non_positive(bad): + with pytest.raises(ValueError, match="callback_max_workers must be a positive int"): + _Conn(callback_max_workers=bad) # type: ignore[arg-type] + + +def test_callback_max_workers_accepts_positive(): + c = _Conn(callback_max_workers=2) + assert c.callback_max_workers == 2 + c.callback_executor.shutdown(wait=False)