From d5f5e34eadaeea441094d280b7e6039738d04f4a Mon Sep 17 00:00:00 2001 From: Xingyao Wang Date: Wed, 18 Jun 2025 14:22:55 -0400 Subject: [PATCH] Fix deprecation warnings in OpenHands CLI (#9199) Co-authored-by: openhands --- openhands/cli/suppress_warnings.py | 58 +++++++-- tests/unit/test_cli_suppress_warnings.py | 150 +++++++++++++++++++++++ 2 files changed, 201 insertions(+), 7 deletions(-) create mode 100644 tests/unit/test_cli_suppress_warnings.py diff --git a/openhands/cli/suppress_warnings.py b/openhands/cli/suppress_warnings.py index 3f61cd7186..1bab74d745 100644 --- a/openhands/cli/suppress_warnings.py +++ b/openhands/cli/suppress_warnings.py @@ -1,10 +1,54 @@ -"""Module to suppress common warnings.""" +"""Module to suppress common warnings in CLI mode.""" import warnings -# Suppress pydub warning about ffmpeg/avconv -warnings.filterwarnings( - 'ignore', - message="Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work", - category=RuntimeWarning, -) + +def suppress_cli_warnings(): + """Suppress common warnings that appear during CLI usage.""" + + # Suppress pydub warning about ffmpeg/avconv + warnings.filterwarnings( + 'ignore', + message="Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work", + category=RuntimeWarning, + ) + + # Suppress Pydantic serialization warnings + warnings.filterwarnings( + 'ignore', + message='.*Pydantic serializer warnings.*', + category=UserWarning, + ) + + # Suppress specific Pydantic serialization unexpected value warnings + warnings.filterwarnings( + 'ignore', + message='.*PydanticSerializationUnexpectedValue.*', + category=UserWarning, + ) + + # Suppress httpx deprecation warnings about content parameter + warnings.filterwarnings( + 'ignore', + message=".*Use 'content=<...>' to upload raw bytes/text content.*", + category=DeprecationWarning, + ) + + # Suppress general deprecation warnings from dependencies during CLI usage + # This catches the "Call to deprecated method get_events" warning + warnings.filterwarnings( + 'ignore', + message='.*Call to deprecated method.*', + category=DeprecationWarning, + ) + + # Suppress other common dependency warnings that don't affect functionality + warnings.filterwarnings( + 'ignore', + message='.*Expected .* fields but got .*', + category=UserWarning, + ) + + +# Apply warning suppressions when module is imported +suppress_cli_warnings() diff --git a/tests/unit/test_cli_suppress_warnings.py b/tests/unit/test_cli_suppress_warnings.py new file mode 100644 index 0000000000..6bcb3d4efd --- /dev/null +++ b/tests/unit/test_cli_suppress_warnings.py @@ -0,0 +1,150 @@ +"""Test warning suppression functionality in CLI mode.""" + +import warnings +from io import StringIO +from unittest.mock import patch + +from openhands.cli.suppress_warnings import suppress_cli_warnings + + +class TestWarningSuppressionCLI: + """Test cases for CLI warning suppression.""" + + def test_suppress_pydantic_warnings(self): + """Test that Pydantic serialization warnings are suppressed.""" + # Apply suppression + suppress_cli_warnings() + + # Capture stderr to check if warnings are printed + captured_output = StringIO() + with patch('sys.stderr', captured_output): + # Trigger Pydantic serialization warning + warnings.warn( + 'Pydantic serializer warnings: PydanticSerializationUnexpectedValue', + UserWarning, + stacklevel=2, + ) + + # Should be suppressed (no output to stderr) + output = captured_output.getvalue() + assert 'Pydantic serializer warnings' not in output + + def test_suppress_httpx_warnings(self): + """Test that httpx deprecation warnings are suppressed.""" + # Apply suppression + suppress_cli_warnings() + + # Capture stderr to check if warnings are printed + captured_output = StringIO() + with patch('sys.stderr', captured_output): + # Trigger httpx deprecation warning + warnings.warn( + "Use 'content=<...>' to upload raw bytes/text content.\n headers, stream = encode_request(", + DeprecationWarning, + stacklevel=2, + ) + + # Should be suppressed (no output to stderr) + output = captured_output.getvalue() + assert 'content=' not in output + + def test_suppress_deprecated_method_warnings(self): + """Test that deprecated method warnings are suppressed.""" + # Apply suppression + suppress_cli_warnings() + + # Capture stderr to check if warnings are printed + captured_output = StringIO() + with patch('sys.stderr', captured_output): + # Trigger deprecated method warning + warnings.warn( + 'Call to deprecated method get_events. (Use search_events instead)', + DeprecationWarning, + stacklevel=2, + ) + + # Should be suppressed (no output to stderr) + output = captured_output.getvalue() + assert 'deprecated method' not in output + + def test_suppress_expected_fields_warnings(self): + """Test that expected fields warnings are suppressed.""" + # Apply suppression + suppress_cli_warnings() + + # Capture stderr to check if warnings are printed + captured_output = StringIO() + with patch('sys.stderr', captured_output): + # Trigger expected fields warning + warnings.warn( + 'Expected 9 fields but got 5: Expected `Message`', + UserWarning, + stacklevel=2, + ) + + # Should be suppressed (no output to stderr) + output = captured_output.getvalue() + assert 'Expected 9 fields' not in output + + def test_regular_warnings_not_suppressed(self): + """Test that regular warnings are NOT suppressed.""" + # Apply suppression + suppress_cli_warnings() + + # Capture stderr to check if warnings are printed + captured_output = StringIO() + with patch('sys.stderr', captured_output): + # Trigger a regular warning that should NOT be suppressed + warnings.warn( + 'This is a regular warning that should appear', + UserWarning, + stacklevel=2, + ) + + # Should NOT be suppressed (should appear in stderr) + output = captured_output.getvalue() + assert 'regular warning' in output + + def test_module_import_applies_suppression(self): + """Test that importing the module automatically applies suppression.""" + # Reset warnings filters + warnings.resetwarnings() + + # Re-import the module to trigger suppression again + import importlib + + import openhands.cli.suppress_warnings + + importlib.reload(openhands.cli.suppress_warnings) + + # Capture stderr to check if warnings are printed + captured_output = StringIO() + with patch('sys.stderr', captured_output): + warnings.warn( + 'Pydantic serializer warnings: test', UserWarning, stacklevel=2 + ) + + # Should be suppressed (no output to stderr) + output = captured_output.getvalue() + assert 'Pydantic serializer warnings' not in output + + def test_warning_filters_are_applied(self): + """Test that warning filters are properly applied.""" + # Reset warnings filters + warnings.resetwarnings() + + # Apply suppression + suppress_cli_warnings() + + # Check that filters are in place + filters = warnings.filters + + # Should have filters for the specific warning patterns + filter_messages = [f[1] for f in filters if f[1] is not None] + + # Check that our specific patterns are in the filters + assert any( + 'Pydantic serializer warnings' in str(msg) for msg in filter_messages + ) + assert any('content=' in str(msg) for msg in filter_messages) + assert any('deprecated method' in str(msg) for msg in filter_messages)