From 16d6b88df30e448bc14b07fadc33aee029f6100c Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Thu, 22 Oct 2026 10:04:35 -0700 Subject: [PATCH] test(annotations): one shared folder_paths stub for the API test modules test_api_images and test_api_prompts installed a MagicMock folder_paths, so whenever one of them was imported before test_api_autotag the later patch("folder_paths.get_output_directory") in test_api_history_outputs left a mock attribute behind and two test_diagnostics_config tests failed. tests/host_stubs.py now installs one real-module stub, used by test_api_images, test_api_prompts and test_api_autotag (and through test_api_images by the annotation modules, whose copy is gone), so the modules pass in either import order. --- tests/host_stubs.py | 29 +++++++++++++++++++++++++++++ tests/test_api_annotations.py | 13 ------------- tests/test_api_autotag.py | 13 ++++++------- tests/test_api_images.py | 7 ++++++- tests/test_api_prompts.py | 7 ++++++- 5 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 tests/host_stubs.py diff --git a/tests/host_stubs.py b/tests/host_stubs.py new file mode 100644 index 00000000..5a61dc09 --- /dev/null +++ b/tests/host_stubs.py @@ -0,0 +1,29 @@ +"""One stand-in for ComfyUI's ``folder_paths`` module, shared by every test. + +Test modules that import the API standalone need a ``folder_paths`` module. +It must be a real module, not a ``MagicMock``: ``patch("folder_paths.x", +create=True)`` then adds and removes plain attributes, while a mock would +hand a later test an auto-created child (or lose the attribute on exit), so +the outcome depended on which test module discovery imported first. +""" + +import sys +import tempfile +import types + + +def install_folder_paths_stub() -> types.ModuleType: + """Install the shared ``folder_paths`` stub unless a real module is there. + + A test that installs its own stand-in for a while (and restores it) is + left alone; a ``MagicMock`` left behind by older code is replaced. + """ + current = sys.modules.get("folder_paths") + if isinstance(current, types.ModuleType): + return current + stub = types.ModuleType("folder_paths") + stub.models_dir = tempfile.gettempdir() + stub.base_path = tempfile.gettempdir() + stub.get_output_directory = tempfile.gettempdir + sys.modules["folder_paths"] = stub + return stub diff --git a/tests/test_api_annotations.py b/tests/test_api_annotations.py index c09dcbc0..e59a65f7 100644 --- a/tests/test_api_annotations.py +++ b/tests/test_api_annotations.py @@ -11,10 +11,8 @@ import hashlib import json import os import sqlite3 -import sys import tempfile import threading -import types import unittest import uuid from pathlib import Path @@ -22,17 +20,6 @@ from unittest.mock import AsyncMock, patch from aiohttp.test_utils import make_mocked_request -# Discovery imports this module before tests/test_api_autotag.py, whose -# ``folder_paths`` stub (a real module, so ``patch(..., create=True)`` can add -# and remove attributes) the later modules rely on. Install the same stub -# before test_api_images would install a MagicMock in its place. -if "folder_paths" not in sys.modules: - _stub = types.ModuleType("folder_paths") - _stub.models_dir = tempfile.gettempdir() - _stub.base_path = tempfile.gettempdir() - _stub.get_output_directory = tempfile.gettempdir - sys.modules["folder_paths"] = _stub - try: from test_api_images import ImageAPITestCase, make_png from open_handles import assert_closed, open_handles_under diff --git a/tests/test_api_autotag.py b/tests/test_api_autotag.py index 6b9e2d7d..fbdf9eac 100644 --- a/tests/test_api_autotag.py +++ b/tests/test_api_autotag.py @@ -11,7 +11,6 @@ import shutil import sys import tempfile import threading -import types import unittest from unittest.mock import MagicMock from pathlib import Path @@ -23,12 +22,12 @@ sys.modules.setdefault("server", _mock_server) # py.config imports it at module sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -if "folder_paths" not in sys.modules: - _stub = types.ModuleType("folder_paths") - _stub.models_dir = tempfile.gettempdir() - _stub.base_path = tempfile.gettempdir() - _stub.get_output_directory = tempfile.gettempdir - sys.modules["folder_paths"] = _stub +try: + from host_stubs import install_folder_paths_stub +except ImportError: # imported as tests.test_api_autotag + from tests.host_stubs import install_folder_paths_stub + +install_folder_paths_stub() from aiohttp import web from aiohttp.test_utils import AioHTTPTestCase diff --git a/tests/test_api_images.py b/tests/test_api_images.py index 2e5d0739..18062bb1 100644 --- a/tests/test_api_images.py +++ b/tests/test_api_images.py @@ -18,7 +18,12 @@ from unittest.mock import AsyncMock, MagicMock, patch sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # ComfyUI-only modules are stubbed so the API can be imported standalone. -sys.modules.setdefault("folder_paths", MagicMock()) +try: + from host_stubs import install_folder_paths_stub +except ImportError: # imported as tests.test_api_images + from tests.host_stubs import install_folder_paths_stub + +install_folder_paths_stub() sys.modules.setdefault("server", MagicMock()) from aiohttp import web # noqa: E402 diff --git a/tests/test_api_prompts.py b/tests/test_api_prompts.py index 2cfb7a09..c4af9c68 100644 --- a/tests/test_api_prompts.py +++ b/tests/test_api_prompts.py @@ -11,7 +11,12 @@ from unittest.mock import MagicMock, patch sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -sys.modules.setdefault("folder_paths", MagicMock()) +try: + from host_stubs import install_folder_paths_stub +except ImportError: # imported as tests.test_api_prompts + from tests.host_stubs import install_folder_paths_stub + +install_folder_paths_stub() sys.modules.setdefault("server", MagicMock()) from aiohttp import web # noqa: E402