[EPD-196] Fix pre-existing test-isolation leak breaking azure responses mocks

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 <noreply@anthropic.com>
This commit is contained in:
Joao Moura
2026-07-13 23:25:23 -07:00
parent 79488fda15
commit ad0523b92c

View File

@@ -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")