diff --git a/src/robot_interface/core/config.py b/src/robot_interface/core/config.py index b3a7adc..86cbe5a 100644 --- a/src/robot_interface/core/config.py +++ b/src/robot_interface/core/config.py @@ -5,23 +5,14 @@ class AgentSettings(object): """ Agent port configuration. - :param actuating_receiver_port: Port for receiving actuation commands. - :type actuating_receiver_port: int - :param main_receiver_port: Port for receiving main messages. - :type main_receiver_port: int - :param video_sender_port: Port used for sending video frames. - :type video_sender_port: int - :param audio_sender_port: Port used for sending audio data. - :type audio_sender_port: int - :ivar actuating_receiver_port: Port for receiving actuation commands. - :type actuating_receiver_port: int + :vartype actuating_receiver_port: int :ivar main_receiver_port: Port for receiving main messages. - :type main_receiver_port: int + :vartype main_receiver_port: int :ivar video_sender_port: Port used for sending video frames. - :type video_sender_port: int + :vartype video_sender_port: int :ivar audio_sender_port: Port used for sending audio data. - :type audio_sender_port: int + :vartype audio_sender_port: int """ def __init__( self, @@ -40,31 +31,18 @@ class VideoConfig(object): """ Video configuration constants. - :param camera_index: Index of the camera to use. - :type camera_index: int - :param resolution: Video resolution mode. - :type resolution: int - :param color_space: Color space identifier. - :type color_space: int - :param fps: Frames per second of the video stream. - :type fps: int - :param stream_name: Name of the video stream. - :type stream_name: str - :param image_buffer: Internal buffer size for video frames. - :type image_buffer: int - :ivar camera_index: Index of the camera used. - :type camera_index: int + :vartype camera_index: int :ivar resolution: Video resolution mode. - :type resolution: int + :vartype resolution: int :ivar color_space: Color space identifier. - :type color_space: int + :vartype color_space: int :ivar fps: Frames per second of the video stream. - :type fps: int + :vartype fps: int :ivar stream_name: Name of the video stream. - :type stream_name: str + :vartype stream_name: str :ivar image_buffer: Internal buffer size for video frames. - :type image_buffer: int + :vartype image_buffer: int """ def __init__( self, @@ -87,19 +65,12 @@ class AudioConfig(object): """ Audio configuration constants. - :param sample_rate: Audio sampling rate in Hz. - :type sample_rate: int - :param chunk_size: Size of audio chunks to capture/process. - :type chunk_size: int - :param channels: Number of audio channels. - :type channels: int - :ivar sample_rate: Audio sampling rate in Hz. - :type sample_rate: int + :vartype sample_rate: int :ivar chunk_size: Size of audio chunks to capture/process. - :type chunk_size: int + :vartype chunk_size: int :ivar channels: Number of audio channels. - :type channels: int + :vartype channels: int """ def __init__(self, sample_rate=16000, chunk_size=512, channels=1): self.sample_rate = sample_rate @@ -111,15 +82,10 @@ class MainConfig(object): """ Main system configuration. - :param poll_timeout_ms: Timeout for polling events, in milliseconds. - :type poll_timeout_ms: int - :param max_handler_time_ms: Maximum allowed handler time, in milliseconds. - :type max_handler_time_ms: int - :ivar poll_timeout_ms: Timeout for polling events, in milliseconds. - :type poll_timeout_ms: int + :vartype poll_timeout_ms: int :ivar max_handler_time_ms: Maximum allowed handler time, in milliseconds. - :type max_handler_time_ms: int + :vartype max_handler_time_ms: int """ def __init__(self, poll_timeout_ms=100, max_handler_time_ms=50): self.poll_timeout_ms = poll_timeout_ms @@ -130,23 +96,14 @@ class Settings(object): """ Global settings container. - :param agent_settings: Agent settings instance or None for defaults. - :type agent_settings: AgentSettings | None - :param video_config: VideoConfig instance or None for defaults. - :type video_config: VideoConfig | None - :param audio_config: AudioConfig instance or None for defaults. - :type audio_config: AudioConfig | None - :param main_config: MainConfig instance or None for defaults. - :type main_config: MainConfig | None - :ivar agent_settings: Agent-related port configuration. - :type agent_settings: AgentSettings + :vartype agent_settings: AgentSettings :ivar video_config: Video stream configuration. - :type video_config: VideoConfig + :vartype video_config: VideoConfig :ivar audio_config: Audio stream configuration. - :type audio_config: AudioConfig + :vartype audio_config: AudioConfig :ivar main_config: Main system-level configuration. - :type main_config: MainConfig + :vartype main_config: MainConfig """ def __init__(self, agent_settings=None, video_config=None, audio_config=None, main_config=None): self.agent_settings = agent_settings or AgentSettings() diff --git a/src/robot_interface/endpoints/actuation_receiver.py b/src/robot_interface/endpoints/actuation_receiver.py index 027d417..a844ddf 100644 --- a/src/robot_interface/endpoints/actuation_receiver.py +++ b/src/robot_interface/endpoints/actuation_receiver.py @@ -20,7 +20,7 @@ class ActuationReceiver(ReceiverBase): :type port: int :ivar _tts_service: The text-to-speech service object from the Qi session. - :vartype _tts_service: ssl.SSLSession | None + :vartype _tts_service: qi.Session | None """ def __init__(self, zmq_context, port=settings.agent_settings.actuating_receiver_port): diff --git a/src/robot_interface/endpoints/audio_sender.py b/src/robot_interface/endpoints/audio_sender.py index 6f3b135..448d6f3 100644 --- a/src/robot_interface/endpoints/audio_sender.py +++ b/src/robot_interface/endpoints/audio_sender.py @@ -24,13 +24,13 @@ class AudioSender(SocketBase): :type port: int :ivar thread: Thread used for sending audio. - :type thread: threading.Thread | None + :vartype thread: threading.Thread | None :ivar audio: PyAudio instance. - :type audio: pyaudio.PyAudio | None + :vartype audio: pyaudio.PyAudio | None :ivar microphone: Selected microphone information. - :type microphone: dict | None + :vartype microphone: dict | None """ def __init__(self, zmq_context, port=settings.agent_settings.audio_sender_port): super(AudioSender, self).__init__(str("audio")) # Convert future's unicode_literal to str @@ -51,7 +51,6 @@ class AudioSender(SocketBase): Will not start if no microphone is available. """ - if not self.microphone: logger.info("Not listening: no microphone available.") return diff --git a/src/robot_interface/endpoints/socket_base.py b/src/robot_interface/endpoints/socket_base.py index 248c7dd..12797a3 100644 --- a/src/robot_interface/endpoints/socket_base.py +++ b/src/robot_interface/endpoints/socket_base.py @@ -7,17 +7,20 @@ class SocketBase(object): """ Base class for endpoints associated with a ZeroMQ socket. - :ivar identifier: The identifier of the endpoint. + :param identifier: The identifier of the endpoint. :type identifier: str + + :ivar identifier: The identifier of the endpoint. + :vartype identifier: str :ivar port: The port used by the socket, set by `create_socket`. - :type port: int | None + :vartype port: int | None :ivar socket: The ZeroMQ socket object, set by `create_socket`. - :type socket: zmq.Socket | None + :vartype socket: zmq.Socket | None :ivar bound: Whether the socket is bound or connected, set by `create_socket`. - :type bound: bool | None + :vartype bound: bool | None """ __metaclass__ = ABCMeta @@ -43,8 +46,7 @@ class SocketBase(object): :param port: The port to use. :type port: int - :param options: A list of options to be set on the socket. The list contains tuples where the first element contains the option - and the second the value, for example (zmq.CONFLATE, 1). + :param options: A list of tuples where the first element contains the option and the second the value. :type options: list[tuple[int, int]] :param bind: Whether to bind the socket or connect to it. @@ -73,7 +75,7 @@ class SocketBase(object): Description of the endpoint. Used for negotiation. :return: A dictionary with the following keys: id, port, bind. See API specification at: - https://utrechtuniversity.youtrack.cloud/articles/N25B-A-14/RI-CB-Communication#negotiation + https://utrechtuniversity.youtrack.cloud/articles/N25B-A-14/RI-CB-Communication#negotiation :rtype: dict """ return { diff --git a/src/robot_interface/endpoints/video_sender.py b/src/robot_interface/endpoints/video_sender.py index 1bc0617..16ea498 100644 --- a/src/robot_interface/endpoints/video_sender.py +++ b/src/robot_interface/endpoints/video_sender.py @@ -24,7 +24,7 @@ class VideoSender(SocketBase): """ Prepares arguments for retrieving video images from Pepper and starts video loop on a separate thread. - Will not start of no qi session is available. + Will not start if no qi session is available. """ if not state.qi_session: logging.info("No Qi session available. Not starting video loop.") diff --git a/src/robot_interface/state.py b/src/robot_interface/state.py index 2e2b149..b625867 100644 --- a/src/robot_interface/state.py +++ b/src/robot_interface/state.py @@ -14,16 +14,16 @@ class State(object): detect this via the `exit_event` property being set. :ivar is_initialized: Flag indicating whether the state setup (exit handlers, QI session) has completed. - :type is_initialized: bool + :vartype is_initialized: bool :ivar exit_event: A thread event used to signal all threads that the program is shutting down. - :type exit_event: threading.Event | None + :vartype exit_event: threading.Event | None :ivar sockets: A list of ZeroMQ socket wrappers (`SocketBase`) that need to be closed during deinitialization. - :type sockets: List[SocketBase] + :vartype sockets: List[SocketBase] :ivar qi_session: The QI session object used for interaction with the robot/platform services. - :type qi_session: None | ssl.SSLSession + :vartype qi_session: None | qi.Session """ def __init__(self): self.is_initialized = False diff --git a/src/robot_interface/utils/timeblock.py b/src/robot_interface/utils/timeblock.py index 3b50fff..584963b 100644 --- a/src/robot_interface/utils/timeblock.py +++ b/src/robot_interface/utils/timeblock.py @@ -7,13 +7,22 @@ class TimeBlock(object): limit, or if no limit is given, the callback will be called with the time that the block took. :param callback: The callback function that is called when the block of code is over, - unless the code block did not exceed the time limit. + unless the code block did not exceed the time limit. :type callback: Callable[[float], None] :param limit_ms: The number of milliseconds the block of code is allowed to take. If it - exceeds this time, or if it's None, the callback function will be called with the time the - block took. + exceeds this time, or if it's None, the callback function will be called with the time the + block took. :type limit_ms: int | None + + :ivar limit_ms: The number of milliseconds the block of code is allowed to take. + :vartype limit_ms: float | None + + :ivar callback: The callback function that is called when the block of code is over. + :vartype callback: Callable[[float], None] + + ivar start: The start time of the block, set when entering the context. + :vartype start: float | None """ def __init__(self, callback, limit_ms=None): self.limit_ms = float(limit_ms) if limit_ms is not None else None diff --git a/test/common/microphone_utils.py b/test/common/microphone_utils.py index 911f4a2..65499ea 100644 --- a/test/common/microphone_utils.py +++ b/test/common/microphone_utils.py @@ -23,9 +23,6 @@ class MicrophoneUtils(object): The result must contain at least "index", as this is used to identify the microphone, and "name" for logging. It must have one or more channels (`maxInputChannels`), and a default sample rate of at least 16000 Hz. - - :param pyaudio_instance: A mocked or real PyAudio instance used to query microphone information. - :type pyaudio_instance: PyAudio """ result = choose_mic_default(pyaudio_instance) assert "index" in result @@ -47,12 +44,6 @@ class MicrophoneUtils(object): Tests the robustness of the interactive selection when the user first enters a non-integer value, ensuring the system prompts again without error and accepts a valid integer on the second attempt. - - :param pyaudio_instance: A mocked or real PyAudio instance. - :type pyaudio_instance: PyAudio - - :param mocker: The fixture used for mocking built-in functions and system objects. - :type mocker: pytest_mock.plugin.MockerFixture """ microphones = get_microphones(pyaudio_instance) target_microphone = next(microphones) @@ -74,12 +65,6 @@ class MicrophoneUtils(object): """ Tests that the interactive selection method prevents the user from entering a negative integer as a microphone index. - - :param pyaudio_instance: A mocked or real PyAudio instance. - :type pyaudio_instance: PyAudio - - :param mocker: The fixture used for mocking built-in functions and system objects. - :type mocker: pytest_mock.plugin.MockerFixture """ microphones = get_microphones(pyaudio_instance) target_microphone = next(microphones) @@ -101,12 +86,6 @@ class MicrophoneUtils(object): """ Tests that the interactive selection method prevents the user from entering an index that exceeds the total number of available microphones. - - :param pyaudio_instance: A mocked or real PyAudio instance. - :type pyaudio_instance: PyAudio - - :param mocker: The fixture used for mocking built-in functions and system objects. - :type mocker: pytest_mock.plugin.MockerFixture """ real_count = len(list(get_microphones(pyaudio_instance))) mock_input = mocker.patch("__builtin__.raw_input", side_effect=[str(real_count), "0"]) @@ -126,12 +105,6 @@ class MicrophoneUtils(object): Tests the core interactive functionality by simulating the selection of a random valid microphone index and verifying that the correct microphone information is returned. - - :param pyaudio_instance: A mocked or real PyAudio instance. - :type pyaudio_instance: PyAudio - - :param mocker: The fixture used for mocking built-in functions and system objects. - :type mocker: pytest_mock.plugin.MockerFixture """ microphones = list(get_microphones(pyaudio_instance)) random_index = random.randrange(len(microphones)) @@ -143,6 +116,9 @@ class MicrophoneUtils(object): assert result["index"] == microphones[random_index]["index"] def test_choose_mic_no_arguments(self, pyaudio_instance, mocker): + """ + Tests `choose_mic_arguments` when no command-line arguments are provided, + """ mocker.patch.object(sys, "argv", []) result = choose_mic_arguments(pyaudio_instance) @@ -153,12 +129,6 @@ class MicrophoneUtils(object): """ Tests `choose_mic_arguments` when the microphone name is passed as a separate argument. - - :param pyaudio_instance: A mocked or real PyAudio instance. - :type pyaudio_instance: PyAudio - - :param mocker: The fixture used for mocking built-in functions and system objects. - :type mocker: pytest_mock.plugin.MockerFixture """ for mic in get_microphones(pyaudio_instance): mocker.patch.object(sys, "argv", ["--microphone", mic["name"]]) @@ -172,12 +142,6 @@ class MicrophoneUtils(object): """ Tests `choose_mic_arguments` when the microphone name is passed using an equals sign (`--microphone=NAME`). - - :param pyaudio_instance: A mocked or real PyAudio instance. - :type pyaudio_instance: PyAudio - - :param mocker: The fixture used for mocking built-in functions and system objects. - :type mocker: pytest_mock.plugin.MockerFixture """ for mic in get_microphones(pyaudio_instance): mocker.patch.object(sys, "argv", ["--microphone={}".format(mic["name"])]) @@ -191,12 +155,6 @@ class MicrophoneUtils(object): """ Tests `choose_mic_arguments` when a non-existent microphone name is passed via command-line arguments, expecting the function to return None. - - :param pyaudio_instance: A mocked or real PyAudio instance. - :type pyaudio_instance: PyAudio - - :param mocker: The fixture used for mocking built-in functions and system objects. - :type mocker: pytest_mock.plugin.MockerFixture """ mocker.patch.object(sys, "argv", ["--microphone", "Surely this microphone doesn't exist"]) @@ -208,12 +166,6 @@ class MicrophoneUtils(object): """ Tests `choose_mic` function when a valid microphone is specified via command-line arguments. - - :param pyaudio_instance: A mocked or real PyAudio instance. - :type pyaudio_instance: PyAudio - - :param mocker: The fixture used for mocking built-in functions and system objects. - :type mocker: pytest_mock.plugin.MockerFixture """ mic = next(get_microphones(pyaudio_instance)) mocker.patch.object(sys, "argv", ["--microphone", mic["name"]]) @@ -228,12 +180,6 @@ class MicrophoneUtils(object): Tests `choose_mic` function when no command-line arguments are provided, verifying that the function falls back correctly to the system's default microphone selection. - - :param pyaudio_instance: A mocked or real PyAudio instance. - :type pyaudio_instance: PyAudio - - :param mocker: The fixture used for mocking built-in functions and system objects. - :type mocker: pytest_mock.plugin.MockerFixture """ default_mic = choose_mic_default(pyaudio_instance) mocker.patch.object(sys, "argv", []) diff --git a/test/unit/test_actuation_receiver.py b/test/unit/test_actuation_receiver.py index 7ea504c..74620ab 100644 --- a/test/unit/test_actuation_receiver.py +++ b/test/unit/test_actuation_receiver.py @@ -23,9 +23,6 @@ def test_handle_unimplemented_endpoint(zmq_context): """ Tests that the ``ActuationReceiver.handle_message`` method can handle an unknown or unimplemented endpoint without raising an error. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context """ receiver = ActuationReceiver(zmq_context) # Should not error @@ -39,12 +36,6 @@ def test_speech_message_no_data(zmq_context, mocker): """ Tests that the message handler logs a warning when a speech actuation request (`actuate/speech`) is received but contains empty string data. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context - - :param mocker: The pytest-mock fixture used to patch `logging.warn`. - :type mocker: pytest_mock.plugin.MockerFixture """ mock_warn = mocker.patch("logging.warn") @@ -58,12 +49,6 @@ def test_speech_message_invalid_data(zmq_context, mocker): """ Tests that the message handler logs a warning when a speech actuation request (`actuate/speech`) is received with data that is not a string (e.g., a boolean). - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context - - :param mocker: The pytest-mock fixture used to patch `logging.warn`. - :type mocker: pytest_mock.plugin.MockerFixture """ mock_warn = mocker.patch("logging.warn") @@ -77,12 +62,6 @@ def test_speech_no_qi(zmq_context, mocker): """ Tests the actuation receiver's behavior when processing a speech request but the global state does not have an active QI session. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context - - :param mocker: The pytest-mock fixture used to patch the global state. - :type mocker: pytest_mock.plugin.MockerFixture """ mock_state = mocker.patch("robot_interface.endpoints.actuation_receiver.state") @@ -99,12 +78,6 @@ def test_speech(zmq_context, mocker): """ Tests the core speech actuation functionality by mocking the QI TextToSpeech service and verifying that it is called correctly. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context - - :param mocker: The pytest-mock fixture used to patch state and modules. - :type mocker: pytest_mock.plugin.MockerFixture """ mock_state = mocker.patch("robot_interface.endpoints.actuation_receiver.state") diff --git a/test/unit/test_audio_sender.py b/test/unit/test_audio_sender.py index 8923ba0..13cd4bf 100644 --- a/test/unit/test_audio_sender.py +++ b/test/unit/test_audio_sender.py @@ -24,12 +24,6 @@ def zmq_context(): def test_no_microphone(zmq_context, mocker): """ Tests the scenario where no valid microphone can be chosen for recording. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context - - :param mocker: The pytest-mock fixture used to patch internal dependencies. - :type mocker: pytest_mock.plugin.MockerFixture """ mock_info_logger = mocker.patch("robot_interface.endpoints.audio_sender.logger.info") mock_choose_mic = mocker.patch("robot_interface.endpoints.audio_sender.choose_mic") @@ -49,12 +43,6 @@ def test_unicode_mic_name(zmq_context, mocker): """ Tests the robustness of the `AudioSender` when handling microphone names that contain Unicode characters. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context - - :param mocker: The pytest-mock fixture used to patch internal dependencies. - :type mocker: pytest_mock.plugin.MockerFixture """ mocker.patch("robot_interface.endpoints.audio_sender.threading") mock_choose_mic = mocker.patch("robot_interface.endpoints.audio_sender.choose_mic") @@ -74,12 +62,6 @@ def test_unicode_mic_name(zmq_context, mocker): def _fake_read(num_frames): """ Helper function to simulate reading raw audio data from a microphone stream. - - :param num_frames: The number of audio frames requested. - :type num_frames: int - - :return: A byte string containing random data, simulating audio. - :rtype: str """ return os.urandom(num_frames * 4) @@ -87,9 +69,6 @@ def _fake_read(num_frames): def test_sending_audio(mocker): """ Tests the successful sending of audio data over a ZeroMQ socket. - - :param mocker: The pytest-mock fixture used to patch internal dependencies. - :type mocker: pytest_mock.plugin.MockerFixture """ mock_choose_mic = mocker.patch("robot_interface.endpoints.audio_sender.choose_mic") mock_choose_mic.return_value = {"name": u"Some mic", "index": 0L} @@ -118,9 +97,6 @@ def test_sending_audio(mocker): def _fake_read_error(num_frames): """ Helper function to simulate an I/O error during microphone stream reading. - - :param num_frames: The number of audio frames requested. - :type num_frames: int """ raise IOError() @@ -128,9 +104,6 @@ def _fake_read_error(num_frames): def test_break_microphone(mocker): """ Tests the error handling when the microphone stream breaks (raises an IOError). - - :param mocker: The pytest-mock fixture used to patch internal dependencies. - :type mocker: pytest_mock.plugin.MockerFixture """ mock_choose_mic = mocker.patch("robot_interface.endpoints.audio_sender.choose_mic") mock_choose_mic.return_value = {"name": u"Some mic", "index": 0L} diff --git a/test/unit/test_main_receiver.py b/test/unit/test_main_receiver.py index c37bdff..2fb8dfc 100644 --- a/test/unit/test_main_receiver.py +++ b/test/unit/test_main_receiver.py @@ -20,9 +20,6 @@ def zmq_context(): def test_handle_ping(zmq_context): """ Tests the receiver's ability to handle the "ping" endpoint with data. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context """ receiver = MainReceiver(zmq_context) response = receiver.handle_message({"endpoint": "ping", "data": "pong"}) @@ -37,9 +34,6 @@ def test_handle_ping_none(zmq_context): """ Tests the receiver's ability to handle the ping endpoint when the data field is explicitly set to None. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context """ receiver = MainReceiver(zmq_context) response = receiver.handle_message({"endpoint": "ping", "data": None}) @@ -54,12 +48,6 @@ def test_handle_ping_none(zmq_context): def test_handle_negotiate_ports(mock_state, zmq_context): """ Tests the handling of the "negotiate/ports" endpoint. - - :param mock_state: Mocked global application state. - :type mock_state: mock.Mock - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context """ receiver = MainReceiver(zmq_context) mock_state.sockets = [receiver] @@ -85,9 +73,6 @@ def test_handle_unimplemented_endpoint(zmq_context): """ Tests that the receiver correctly handles a request to a completely unknown or non-existent endpoint. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context """ receiver = MainReceiver(zmq_context) response = receiver.handle_message({ @@ -108,9 +93,6 @@ def test_handle_unimplemented_negotiation_endpoint(zmq_context): The expected behavior is to return a specific "negotiate/error" response with a descriptive error string. - - :param zmq_context: The ZeroMQ context fixture. - :type zmq_context: zmq.Context """ receiver = MainReceiver(zmq_context) response = receiver.handle_message({ diff --git a/test/unit/test_microphone_utils.py b/test/unit/test_microphone_utils.py index 7cb13de..df31ca3 100644 --- a/test/unit/test_microphone_utils.py +++ b/test/unit/test_microphone_utils.py @@ -15,7 +15,7 @@ class MockPyAudio: the core PyAudio methods required for device enumeration. :ivar devices: A list of dictionaries representing mock audio devices. - :type devices: List[Dict[str, Any]] + :vartype devices: List[Dict[str, Any]] """ def __init__(self): # You can predefine fake device info here