From 3eba2dcf2d60d965253e5e8ec3e2d9f4eb69d60a Mon Sep 17 00:00:00 2001 From: Luke Mino-Altherr Date: Wed, 25 Mar 2026 19:59:59 -0700 Subject: [PATCH] fix(assets): recognize temp directory in asset category resolution (#13159) --- app/assets/services/path_utils.py | 12 ++- .../assets_test/services/test_path_utils.py | 81 +++++++++++++++++++ 2 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 tests-unit/assets_test/services/test_path_utils.py diff --git a/app/assets/services/path_utils.py b/app/assets/services/path_utils.py index f5dd7f7fd..892140ffb 100644 --- a/app/assets/services/path_utils.py +++ b/app/assets/services/path_utils.py @@ -93,12 +93,13 @@ def compute_relative_filename(file_path: str) -> str | None: def get_asset_category_and_relative_path( file_path: str, -) -> tuple[Literal["input", "output", "models"], str]: +) -> tuple[Literal["input", "output", "temp", "models"], str]: """Determine which root category a file path belongs to. Categories: - 'input': under folder_paths.get_input_directory() - 'output': under folder_paths.get_output_directory() + - 'temp': under folder_paths.get_temp_directory() - 'models': under any base path from get_comfy_models_folders() Returns: @@ -129,7 +130,12 @@ def get_asset_category_and_relative_path( if _check_is_within(fp_abs, output_base): return "output", _compute_relative(fp_abs, output_base) - # 3) models (check deepest matching base to avoid ambiguity) + # 3) temp + temp_base = os.path.abspath(folder_paths.get_temp_directory()) + if _check_is_within(fp_abs, temp_base): + return "temp", _compute_relative(fp_abs, temp_base) + + # 4) models (check deepest matching base to avoid ambiguity) best: tuple[int, str, str] | None = None # (base_len, bucket, rel_inside_bucket) for bucket, bases in get_comfy_models_folders(): for b in bases: @@ -146,7 +152,7 @@ def get_asset_category_and_relative_path( return "models", os.path.relpath(os.path.join(os.sep, combined), os.sep) raise ValueError( - f"Path is not within input, output, or configured model bases: {file_path}" + f"Path is not within input, output, temp, or configured model bases: {file_path}" ) diff --git a/tests-unit/assets_test/services/test_path_utils.py b/tests-unit/assets_test/services/test_path_utils.py new file mode 100644 index 000000000..3fa905f9a --- /dev/null +++ b/tests-unit/assets_test/services/test_path_utils.py @@ -0,0 +1,81 @@ +"""Tests for path_utils – asset category resolution.""" +import os +import tempfile +from pathlib import Path +from unittest.mock import patch + +import pytest + +from app.assets.services.path_utils import get_asset_category_and_relative_path + + +@pytest.fixture +def fake_dirs(): + """Create temporary input, output, and temp directories.""" + with tempfile.TemporaryDirectory() as root: + root_path = Path(root) + input_dir = root_path / "input" + output_dir = root_path / "output" + temp_dir = root_path / "temp" + models_dir = root_path / "models" / "checkpoints" + for d in (input_dir, output_dir, temp_dir, models_dir): + d.mkdir(parents=True) + + with patch("app.assets.services.path_utils.folder_paths") as mock_fp: + mock_fp.get_input_directory.return_value = str(input_dir) + mock_fp.get_output_directory.return_value = str(output_dir) + mock_fp.get_temp_directory.return_value = str(temp_dir) + + with patch( + "app.assets.services.path_utils.get_comfy_models_folders", + return_value=[("checkpoints", [str(models_dir)])], + ): + yield { + "input": input_dir, + "output": output_dir, + "temp": temp_dir, + "models": models_dir, + } + + +class TestGetAssetCategoryAndRelativePath: + def test_input_file(self, fake_dirs): + f = fake_dirs["input"] / "photo.png" + f.touch() + cat, rel = get_asset_category_and_relative_path(str(f)) + assert cat == "input" + assert rel == "photo.png" + + def test_output_file(self, fake_dirs): + f = fake_dirs["output"] / "result.png" + f.touch() + cat, rel = get_asset_category_and_relative_path(str(f)) + assert cat == "output" + assert rel == "result.png" + + def test_temp_file(self, fake_dirs): + """Regression: temp files must be categorised, not raise ValueError.""" + f = fake_dirs["temp"] / "GLSLShader_output_00004_.png" + f.touch() + cat, rel = get_asset_category_and_relative_path(str(f)) + assert cat == "temp" + assert rel == "GLSLShader_output_00004_.png" + + def test_temp_file_in_subfolder(self, fake_dirs): + sub = fake_dirs["temp"] / "sub" + sub.mkdir() + f = sub / "ComfyUI_temp_tczip_00004_.png" + f.touch() + cat, rel = get_asset_category_and_relative_path(str(f)) + assert cat == "temp" + assert os.path.normpath(rel) == os.path.normpath("sub/ComfyUI_temp_tczip_00004_.png") + + def test_model_file(self, fake_dirs): + f = fake_dirs["models"] / "model.safetensors" + f.touch() + cat, rel = get_asset_category_and_relative_path(str(f)) + assert cat == "models" + + def test_unknown_path_raises(self, fake_dirs): + with pytest.raises(ValueError, match="not within"): + get_asset_category_and_relative_path("/some/random/path.png")