From c3753073ca0bf6951340edc8f3416487177c2041 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 1 Aug 2026 23:17:29 +0000 Subject: [PATCH] test(rekognition): make off-loop read test robust to sys.modules eviction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `test_local_image_read_runs_off_the_event_loop_thread` failed in the full CI suite ("_read_file_bytes was never called") while passing in isolation. Root cause is cross-module test pollution, not the production change: `tests/unit/test_cloud_ai_integrator.py` deletes every `youtube_extension.*cloud_ai*` entry from `sys.modules` at collection time. The aws_rekognition module key matches, so after that eviction the test's late `import ... as _rek_mod` binds a *fresh* module object, while the provider instance's `_prepare_image_input` still resolves `_read_file_bytes` from the original module's globals. The patch landed on the stale module and the read ran unintercepted — correct bytes returned, but the recording wrapper never fired. Patch the method's own `__globals__` via `patch.dict` instead of a re-imported module attribute. That namespace is exactly what `_prepare_image_input` resolves names from and cannot drift regardless of sys.modules churn. Verified: old test fails / new test passes when test_cloud_ai_integrator runs first in the same session; full file 95 passed. --- tests/unit/test_aws_rekognition_provider.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_aws_rekognition_provider.py b/tests/unit/test_aws_rekognition_provider.py index 98fff260f..29324cd4c 100644 --- a/tests/unit/test_aws_rekognition_provider.py +++ b/tests/unit/test_aws_rekognition_provider.py @@ -1132,23 +1132,30 @@ async def test_local_image_read_runs_off_the_event_loop_thread(self, tmp_path): """ import threading - from youtube_extension.integrations.cloud_ai.providers import ( - aws_rekognition as _rek_mod, - ) - image = tmp_path / "frame.jpg" image.write_bytes(b"BINARY-IMAGE-PAYLOAD") provider = _make_provider() + # Patch the exact namespace `_prepare_image_input` resolves + # `_read_file_bytes` from — the method's own module globals — instead of a + # freshly re-imported module object. Sibling test modules (notably + # test_cloud_ai_integrator) evict the cloud_ai modules from sys.modules at + # collection time, so a late `import ... as _rek_mod` here can bind a + # *different* module object than the one whose globals this provider's + # method actually uses, leaving the patch on a stale module and the read + # unintercepted (correct bytes returned, but the wrapper never runs). + # `__globals__` is ground truth and cannot drift. + method_globals = type(provider)._prepare_image_input.__globals__ + real_read = method_globals['_read_file_bytes'] + loop_thread_id = threading.get_ident() observed: dict[str, int] = {} - real_read = _rek_mod._read_file_bytes def _recording_read(path): observed['thread_id'] = threading.get_ident() return real_read(path) - with patch.object(_rek_mod, '_read_file_bytes', _recording_read): + with patch.dict(method_globals, {'_read_file_bytes': _recording_read}): result = await provider._prepare_image_input(str(image)) assert result == {'Bytes': b"BINARY-IMAGE-PAYLOAD"}