From ad0523b92c8ed196f2ae38054a54e4304782864a Mon Sep 17 00:00:00 2001 From: Joao Moura Date: Mon, 13 Jul 2026 23:25:23 -0700 Subject: [PATCH] [EPD-196] Fix pre-existing test-isolation leak breaking azure responses mocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not caused by this PR's change — a latent leak in test_openai_completion_module_is_imported exposed by pytest-randomly's per-run ordering (CI seed 756721157 placed it before the azure responses tests on the same xdist worker of the py3.10 shard). Mechanism: the test monkeypatch.delitem's crewai.llms.providers.openai.completion from sys.modules and re-imports it, which rebinds the parent package's `completion` attribute to the new module object. monkeypatch teardown restores only the sys.modules entry, leaving the package attribute pointing at the stale re-imported module. On Python 3.10, `from crewai.llms.providers.openai.completion import OpenAICompletion` resolves through the parent package attribute while mock.patch targets the sys.modules entry, so the azure responses tests' OpenAICompletion patch silently missed and a real delegate was built (last_response_id None, reset_chain never called). Python 3.11+ resolves via sys.modules, hiding the leak. Fix: record the package attribute with monkeypatch.setattr alongside the delitem so teardown restores both bindings consistently. Reproduced on pristine origin/main (py3.10, -n0, culprit test followed by the three azure responses tests) and verified green after the fix, including a replay of the failing CI worker's exact 181-test order. Co-Authored-By: Claude Fable 5 --- lib/crewai/tests/llms/openai/test_openai.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/crewai/tests/llms/openai/test_openai.py b/lib/crewai/tests/llms/openai/test_openai.py index d5bc797d8..18ad22d5c 100644 --- a/lib/crewai/tests/llms/openai/test_openai.py +++ b/lib/crewai/tests/llms/openai/test_openai.py @@ -212,6 +212,18 @@ def test_openai_completion_module_is_imported(monkeypatch): """ module_name = "crewai.llms.providers.openai.completion" + # The LLM(...) call below re-imports the module, which also rebinds the + # parent package's `completion` attribute to the NEW module object. + # monkeypatch.delitem only restores the sys.modules entry at teardown, so + # without also restoring the package attribute the two diverge for the + # rest of the process. On Python 3.10 `from ...openai.completion import X` + # then resolves through the stale package attribute while mock.patch + # targets the restored sys.modules entry, making later patches of + # OpenAICompletion silently miss (breaks e.g. test_azure_responses.py). + import crewai.llms.providers.openai as openai_pkg + + if hasattr(openai_pkg, "completion"): + monkeypatch.setattr(openai_pkg, "completion", openai_pkg.completion) monkeypatch.delitem(sys.modules, module_name, raising=False) LLM(model="gpt-4o")