mirror of
https://github.com/Comfy-Org/ComfyUI.git
synced 2026-08-28 11:57:41 +08:00
fix(assets): restore display_name and file_path as served fields; unify error envelopes (review-5, review2-8)
This commit is contained in:
@@ -306,9 +306,13 @@ def _build_asset_response(
|
||||
else:
|
||||
preview_url = None
|
||||
if result.ref.file_path:
|
||||
paths = compute_asset_response_paths(result.ref.file_path)
|
||||
logical_path = paths[0] if paths else None
|
||||
display_name = paths[1] if paths else None
|
||||
# In-root loader path (model category dropped): what model loaders consume.
|
||||
loader_path = result.ref.loader_path
|
||||
else:
|
||||
logical_path, display_name = None, None
|
||||
loader_path = None
|
||||
asset_content_hash = result.asset.hash if result.asset else None
|
||||
return schemas_out.Asset(
|
||||
@@ -316,6 +320,8 @@ def _build_asset_response(
|
||||
name=result.ref.name,
|
||||
hash=asset_content_hash,
|
||||
loader_path=loader_path,
|
||||
display_name=display_name,
|
||||
file_path=logical_path,
|
||||
size=int(result.asset.size_bytes) if result.asset else None,
|
||||
mime_type=result.asset.mime_type if result.asset else None,
|
||||
tags=result.tags,
|
||||
@@ -337,6 +343,9 @@ def _build_record_response(
|
||||
preview_paths: dict[str, str],
|
||||
) -> schemas_out.Asset:
|
||||
content = record.content
|
||||
paths = compute_asset_response_paths(content.path)
|
||||
logical_path = paths[0] if paths else None
|
||||
display_name = paths[1] if paths else None
|
||||
if record.preview_id:
|
||||
preview_url = _build_view_url(preview_paths.get(record.preview_id))
|
||||
else:
|
||||
@@ -353,6 +362,8 @@ def _build_record_response(
|
||||
name=record.name,
|
||||
hash=content.hash,
|
||||
loader_path=record.loader_path,
|
||||
display_name=display_name,
|
||||
file_path=logical_path,
|
||||
size=content.size_bytes,
|
||||
mime_type=record.mime_type,
|
||||
tags=tags,
|
||||
@@ -452,12 +463,8 @@ async def list_assets_route(request: web.Request) -> web.Response:
|
||||
GET request to list assets.
|
||||
"""
|
||||
if "metadata_filter" in request.query:
|
||||
return web.json_response(
|
||||
{
|
||||
"error": "UNSUPPORTED_PARAM",
|
||||
"message": "metadata_filter is no longer supported",
|
||||
},
|
||||
status=400,
|
||||
return _build_error_response(
|
||||
400, "UNSUPPORTED_PARAM", "metadata_filter is no longer supported"
|
||||
)
|
||||
|
||||
query_dict = get_query_dict(request)
|
||||
@@ -977,12 +984,8 @@ async def delete_asset_tags(request: web.Request) -> web.Response:
|
||||
async def get_tags_refine(request: web.Request) -> web.Response:
|
||||
"""GET request to get tag histogram for filtered assets."""
|
||||
if "metadata_filter" in request.query:
|
||||
return web.json_response(
|
||||
{
|
||||
"error": "UNSUPPORTED_PARAM",
|
||||
"message": "metadata_filter is no longer supported",
|
||||
},
|
||||
status=400,
|
||||
return _build_error_response(
|
||||
400, "UNSUPPORTED_PARAM", "metadata_filter is no longer supported"
|
||||
)
|
||||
|
||||
query_dict = get_query_dict(request)
|
||||
|
||||
@@ -15,7 +15,14 @@ class Asset(BaseModel):
|
||||
default=None,
|
||||
description="The value a loader consumes to load this asset. `None` when no loader can resolve the file.",
|
||||
)
|
||||
display_name: str | None = Field(default=None, exclude=True)
|
||||
display_name: str | None = Field(
|
||||
default=None,
|
||||
description="Human-facing label for the asset. Not unique.",
|
||||
)
|
||||
file_path: str | None = Field(
|
||||
default=None,
|
||||
description='Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors").',
|
||||
)
|
||||
size: int | None = None
|
||||
mime_type: str | None = None
|
||||
tags: list[str] = Field(default_factory=list)
|
||||
|
||||
@@ -7,6 +7,10 @@ components:
|
||||
description: Timestamp when the asset was created
|
||||
format: date-time
|
||||
type: string
|
||||
display_name:
|
||||
description: Human-facing label for the asset. Not unique.
|
||||
nullable: true
|
||||
type: string
|
||||
file_path:
|
||||
description: Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors")
|
||||
nullable: true
|
||||
@@ -141,6 +145,10 @@ components:
|
||||
AssetUpdated:
|
||||
description: Response returned when an existing asset is successfully updated.
|
||||
properties:
|
||||
display_name:
|
||||
description: Human-facing label for the asset. Not unique.
|
||||
nullable: true
|
||||
type: string
|
||||
file_path:
|
||||
description: Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors")
|
||||
nullable: true
|
||||
|
||||
@@ -70,6 +70,8 @@ def test_null_stored_loader_path_is_served_as_null(tmp_path: Path):
|
||||
resp = _build_asset_response(result, {})
|
||||
|
||||
assert resp.loader_path is None
|
||||
assert resp.display_name == "checkpoints/bar.safetensors"
|
||||
assert resp.file_path == "models/checkpoints/bar.safetensors"
|
||||
|
||||
|
||||
def test_all_path_fields_null_without_file_path():
|
||||
@@ -79,3 +81,37 @@ def test_all_path_fields_null_without_file_path():
|
||||
resp = _build_asset_response(result, {})
|
||||
|
||||
assert resp.loader_path is None
|
||||
assert resp.display_name is None
|
||||
assert resp.file_path is None
|
||||
|
||||
|
||||
def test_display_name_and_file_path_are_serialized(tmp_path: Path):
|
||||
"""Serialisation guard: both display_name and file_path survive
|
||||
model_dump(mode="json").
|
||||
|
||||
display_name previously carried exclude=True, which silently dropped it
|
||||
from every serialised response; file_path was never wired through at all.
|
||||
Asserting on the dumped payload (not just attribute access) is what would
|
||||
have caught either regression, so this guards the JSON contract directly.
|
||||
"""
|
||||
models = tmp_path / "models"
|
||||
ckpt = models / "checkpoints"
|
||||
ckpt.mkdir(parents=True)
|
||||
f = ckpt / "flux.safetensors"
|
||||
f.touch()
|
||||
|
||||
with patch("app.assets.services.path_utils.folder_paths") as mock_fp, patch(
|
||||
"app.assets.services.path_utils.get_comfy_models_folders",
|
||||
return_value=[("checkpoints", [str(ckpt)], {".safetensors"})],
|
||||
):
|
||||
mock_fp.get_input_directory.return_value = str(tmp_path / "in")
|
||||
mock_fp.get_output_directory.return_value = str(tmp_path / "out")
|
||||
mock_fp.get_temp_directory.return_value = str(tmp_path / "tmp")
|
||||
mock_fp.models_dir = str(models)
|
||||
|
||||
result = _make_result(file_path=str(f), loader_path=None)
|
||||
resp = _build_asset_response(result, {})
|
||||
dumped = resp.model_dump(mode="json")
|
||||
|
||||
assert dumped["display_name"] == "checkpoints/flux.safetensors"
|
||||
assert dumped["file_path"] == "models/checkpoints/flux.safetensors"
|
||||
|
||||
@@ -43,8 +43,11 @@ def test_record_list_rejects_metadata_filter(http, api_base):
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {
|
||||
"error": "UNSUPPORTED_PARAM",
|
||||
"message": "metadata_filter is no longer supported",
|
||||
"error": {
|
||||
"code": "UNSUPPORTED_PARAM",
|
||||
"message": "metadata_filter is no longer supported",
|
||||
"details": {},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ def test_tag_refine_rejects_metadata_filter(http, api_base):
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {
|
||||
"error": "UNSUPPORTED_PARAM",
|
||||
"message": "metadata_filter is no longer supported",
|
||||
"error": {
|
||||
"code": "UNSUPPORTED_PARAM",
|
||||
"message": "metadata_filter is no longer supported",
|
||||
"details": {},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user