From 9672a1f0157d747983ef87462d7e4fe199b4d996 Mon Sep 17 00:00:00 2001 From: Julio Quinteros Pro Date: Sat, 14 Feb 2026 16:04:08 -0300 Subject: [PATCH 1/2] Fix Langfuse test isolation to prevent flaky failures Fixes test_log_langfuse_v2_handles_null_usage_values flaky test failure by properly cleaning up sys.modules['langfuse'] in tearDown. Changes: - Store original langfuse module in setUp before mocking - Restore original or remove mock in tearDown to prevent state pollution - Remove invalid print_verbose parameter from log_event_on_langfuse Root Cause: The tearDown method was not cleaning up sys.modules['langfuse'] after each test, causing mock state to leak between tests. This caused intermittent failures in CI, especially when tests run in parallel or in different orders. Impact: This test has a long history of flakiness with multiple attempted fixes (#20475, #17599, #17594, #17591, #17588). The missing sys.modules cleanup was the underlying issue causing continued failures despite those patches. Co-Authored-By: Claude Sonnet 4.5 --- tests/test_litellm/integrations/test_langfuse.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/test_litellm/integrations/test_langfuse.py b/tests/test_litellm/integrations/test_langfuse.py index 7168f5a4332..84dfbaf638a 100644 --- a/tests/test_litellm/integrations/test_langfuse.py +++ b/tests/test_litellm/integrations/test_langfuse.py @@ -32,6 +32,9 @@ class TestLangfuseUsageDetails(unittest.TestCase): ) self.env_patcher.start() + # Store original langfuse module if it exists for cleanup + self._original_langfuse_module = sys.modules.get("langfuse") + # Create mock objects self.mock_langfuse_client = MagicMock() # Mock the client attribute to prevent errors during logger initialization @@ -39,7 +42,7 @@ class TestLangfuseUsageDetails(unittest.TestCase): self.mock_langfuse_trace = MagicMock() self.mock_langfuse_generation = MagicMock() self.mock_langfuse_generation.trace_id = "test-trace-id" - + # Mock span method for trace (used by log_provider_specific_information_as_span and _log_guardrail_information_as_span) self.mock_langfuse_span = MagicMock() self.mock_langfuse_span.end = MagicMock() @@ -109,7 +112,6 @@ class TestLangfuseUsageDetails(unittest.TestCase): response_obj=response_obj, level=level, litellm_call_id=kwargs.get("litellm_call_id", None), - print_verbose=True, # Add the missing parameter ) # Bind the method to the instance @@ -127,6 +129,12 @@ class TestLangfuseUsageDetails(unittest.TestCase): self.env_patcher.stop() self.langfuse_module_patcher.stop() + # Restore original langfuse module or remove mock to prevent test pollution + if self._original_langfuse_module is not None: + sys.modules["langfuse"] = self._original_langfuse_module + elif "langfuse" in sys.modules: + del sys.modules["langfuse"] + def test_langfuse_usage_details_type(self): """Test that LangfuseUsageDetails TypedDict is properly defined with the correct fields""" # Create an instance of LangfuseUsageDetails From 76e1b2c015647df60e81faf2bbcb7e2aab25f14c Mon Sep 17 00:00:00 2001 From: Julio Quinteros Pro Date: Sun, 15 Feb 2026 12:21:51 -0300 Subject: [PATCH 2/2] Remove redundant sys.modules cleanup in Langfuse test tearDown The manual sys.modules restoration code was redundant because patch.dict.stop() automatically handles the cleanup. This simplifies the tearDown method and removes the now-unused _original_langfuse_module instance variable. Addresses review comment: https://github.com/BerriAI/litellm/pull/21214#pullrequestreview-3802348462 Co-Authored-By: Claude Sonnet 4.5 --- tests/test_litellm/integrations/test_langfuse.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/test_litellm/integrations/test_langfuse.py b/tests/test_litellm/integrations/test_langfuse.py index 84dfbaf638a..65a48828823 100644 --- a/tests/test_litellm/integrations/test_langfuse.py +++ b/tests/test_litellm/integrations/test_langfuse.py @@ -32,9 +32,6 @@ class TestLangfuseUsageDetails(unittest.TestCase): ) self.env_patcher.start() - # Store original langfuse module if it exists for cleanup - self._original_langfuse_module = sys.modules.get("langfuse") - # Create mock objects self.mock_langfuse_client = MagicMock() # Mock the client attribute to prevent errors during logger initialization @@ -127,13 +124,7 @@ class TestLangfuseUsageDetails(unittest.TestCase): def tearDown(self): self.env_patcher.stop() - self.langfuse_module_patcher.stop() - - # Restore original langfuse module or remove mock to prevent test pollution - if self._original_langfuse_module is not None: - sys.modules["langfuse"] = self._original_langfuse_module - elif "langfuse" in sys.modules: - del sys.modules["langfuse"] + self.langfuse_module_patcher.stop() # patch.dict automatically restores sys.modules def test_langfuse_usage_details_type(self): """Test that LangfuseUsageDetails TypedDict is properly defined with the correct fields"""